|
|
- <?php
- /**
- * This file is a part of Quasi CMS
- *@package Quasi
- */
- if(!defined('QUASICMS') ) die('No Quasi.');
-
- if (!defined("AUTHORIZENETAIMACTION.CLASS.PHP")){
- define("AUTHORIZENETAIMACTION.CLASS.PHP",1);
-
- /**
- * Class AuthorizeNetAIMAction - Authorize.net AIM payment action
- *
- * This class provides an interface to the Authorize.net AIM API. It sends credit card and
- * order information (via SSL) to the API server and handles the response. It will set
- * Approved = true on success and store any message returned. If the transaction is
- * not approved the order will be deleted and error messages are available for display.
- * Additionally, the error code and error reason code will be stored. If the transaction is
- * approved the order status will be updated, order_status_history and order_totals will
- * be inserted and a confirmation email sent to the customer in the base class.
- *
- *@todo
- * - deal with "Transaction Id"? Might log them like PayPal ..
- * - handle errors better, messages - eg. what failed ..
- * - implement address verification check - ie. add ship_to_* fields and handle response
- * - add optional customer email notification (from authorize)?
- * - add "Send Shipping address .." option?
- *
- *
- *@author Erik Winn <erikwinnmail@yahoo.com>
- *
- * $Id: AuthorizeNetAIMAction.class.php 458 2008-12-23 20:12:46Z erikwinn $
- *@version 0.1
- *
- *@copyright (C) 2008 by Erik Winn
- *@license GPL v.2
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
-
- *
- *@package Quasi
- * @subpackage Classes
- */
-
- class AuthorizeNetAIMAction extends PaymentActionBase
- {
- /**
- * @var array Name - Value pairs with which to construct AIM POST string
- */
- protected $aryRequestValues = array(
- 'x_login' => '',
- 'x_tran_key' => '',
- 'x_version' => '3.1',
- 'x_delim_char' => '|',
- 'x_delim_data' => 'TRUE',
- 'x_url' => 'FALSE',
- 'x_type' => 'AUTH_CAPTURE',
- 'x_method' => 'CC',
- 'x_relay_response' => 'FALSE',
- 'x_card_num' => '4242424242424242',
- 'x_exp_date' => '1209',
- 'x_card_code' => '', //CCV no.
- 'x_description' => 'Recycled Toner Cartridges',
- 'x_amount' => '12.23',
- 'x_first_name' => 'Charles D.',
- 'x_last_name' => 'Gaulle',
- 'x_address' => '342 N. Main Street #150',
- 'x_city' => 'Ft. Worth',
- 'x_state' => 'TX',
- 'x_country' => 'USA',
- 'x_zip' => '12345',
- 'x_email' => 'FALSE',
- 'x_email_customer' => '', //TRUE | FALSE
- 'x_email_header' => '',
- 'x_email_footer' => '',
- 'x_cust_id' => '',
- 'x_customer_ip' => '',
- 'x_invoice_num' => '',
- );
-
- /**
- *
- * @var array Response values will be stored here
- */
- protected $aryResponseValues;
-
- protected $intResponseCode ;
- protected $intResponseReasonCode ;
- protected $strResponseReasonText ;
- protected $strAVSResponse ;
- // protected $strInvoiceNumber ;
-
- protected $blnSendShippingAddress = false;
-
- /**
- * AuthorizeNetAIMAction Constructor
- * This sets various defaults specific to the Authorize.net API
- *
- * @param Order objOrder - the Order to process
- */
- public function __construct(Order $objOrder)
- {
- //Note: fixme - i don't think we will get a QCallerException here ..
- try {
- parent::__construct($objOrder);
- } catch (QCallerException $objExc) {
- $objExc->IncrementOffset();
- throw $objExc;
- }
- $this->blnTestMode = $objOrder->PaymentMethod->TestMode;
- if($this->blnTestMode)
- {
- $this->strRemoteDomainName = AUTHORIZENET_AIM_TESTURL;
- $this->strRemoteAccountId = AUTHORIZENET_AIM_TESTUSERNAME;
- $this->strTransactionKey = AUTHORIZENET_AIM_TESTTRANSACTIONKEY;
- }
- else
- {
- $this->strRemoteDomainName = AUTHORIZENET_AIM_URL;
- /// FIXME: put these somewhere safer and load it .. currently in config file!
- $this->strRemoteAccountId = AUTHORIZENET_AIM_USERNAME;
- $this->strTransactionKey = AUTHORIZENET_AIM_TRANSACTIONKEY;
- }
-
- $this->strRemoteCgiUrl = '/gateway/transact.dll';
- $this->strRequestType = 'POST';
-
- $this->strTemplateUri = __QUASI_CORE_TEMPLATES__ . '/AuthorizeNetAIMAction.tpl.php';
- }
-
- /**
- * Performs any preparation steps prior to submitting an actual payment.
- *@return bool true on success
- */
- public function PreProcess()
- {
- $this->createRequest();
- return ! $this->HasErrors;
- }
- /**
- * Performs the actual payment submission
- *@return bool true on success
- */
- public function Process()
- {
- $this->submitRequest();
- return ! $this->HasErrors;
- }
- /**
- * Performs any steps necessary after submitting an actual payment.
- * Updating order_status_history, order totals and confirmation email
- * is also called here on approval (these actions actually performed in
- * completeOrder ..)
- *@return bool true on success
- */
- public function PostProcess()
- {
- $this->handleResponse();
- if($this->blnApproved)
- $this->completeOrder();
- return ! $this->HasErrors;
- }
- /**
- * Parses the response from the payment service provider into an array
- * for convenience. It also sets the Response codes, messages, and blnApproved.
- * On failure or error messages will be in strErrors.
- */
- protected function handleResponse()
- {
- $objAuthNetTransaction = new AuthorizeNetTransaction();
- $objAuthNetTransaction->OrderId = $this->objOrder->Id;
- //default to an error ..
- $objAuthNetTransaction->ResponseCode = 3;
- $objAuthNetTransaction->ResponseReasonCode = 555;
- $objAuthNetTransaction->ResponseReasonText = 'Unknown Server Error';
-
- $this->aryResponseValues = array();
- $pos = strpos( $this->strResponse,'|' );
- if(false === $pos)
- {
- $this->intResponseCode = 3;
- $this->intResponseReasonCode = 555;
- }
- else
- {
- //remove everything except the integer at the end just before the pipe (the "ResponseCode")..
- $strTemp = substr($this->strResponse, $pos - 1);
- $this->aryResponseValues = explode('|', $strTemp );
- $objAuthNetTransaction->TransactionId = $this->aryResponseValues[ AuthorizeNetTransaction::TransactionIdIdx ];
- $objAuthNetTransaction->TransactionType = $this->aryResponseValues[ AuthorizeNetTransaction::TransactionTypeIdx ];
- $objAuthNetTransaction->ResponseCode = $this->aryResponseValues[ AuthorizeNetTransaction::ResponseCodeIdx ];
- $objAuthNetTransaction->ResponseSubcode = $this->aryResponseValues[ AuthorizeNetTransaction::ResponseSubcodeIdx ];
- $objAuthNetTransaction->ResponseReasonCode = $this->aryResponseValues[ AuthorizeNetTransaction::ResponseReasonCodeIdx ];
- $objAuthNetTransaction->ResponseReasonText = $this->aryResponseValues[ AuthorizeNetTransaction::ResponseReasonTextIdx ];
- $objAuthNetTransaction->AuthorizationCode = $this->aryResponseValues[ AuthorizeNetTransaction::AuthorizationCodeIdx ];
- $objAuthNetTransaction->AvsResponseCode = $this->aryResponseValues[ AuthorizeNetTransaction::AVSResponseIdx ];
- $objAuthNetTransaction->CcvResponseCode = $this->aryResponseValues[ AuthorizeNetTransaction::CCVResponseIdx ];
- $objAuthNetTransaction->CavResponseCode = $this->aryResponseValues[ AuthorizeNetTransaction::CAVResponseIdx ];
- $objAuthNetTransaction->Amount = $this->aryResponseValues[ AuthorizeNetTransaction::AmountIdx ];
-
- $this->intResponseCode = $objAuthNetTransaction->ResponseCode;
- $this->intResponseReasonCode = $objAuthNetTransaction->ResponseReasonCode;
- $this->strResponseReasonText = $objAuthNetTransaction->ResponseReasonText;
- $this->strAVSResponse = $objAuthNetTransaction->AvsResponseCode;
- }
-
- $objAuthNetTransaction->Save();
-
- switch($this->intResponseCode)
- {
- case '1': //Approved
- $this->blnApproved = true;
- $this->strStatusText = $this->strResponseReasonText;
- $this->blnHasErrors = false;
- break;
- case '2': //Declined
- $this->blnApproved = false;
- $this->strStatusText = $this->strResponseReasonText;
- $this->blnHasErrors = false;
- $this->objOrder->Delete();
- break;
- case '3': //Error
- $this->strErrors = $this->strResponseReasonText;
- /* . '<br />Response code: ' . $this->intResponseCode
- .'<br />Response: ' . $this->strResponse;*/
- switch($this->intResponseReasonCode)
- {
- case '103':
- $this->strErrors .= '<br />Valid Fingerprint, Transaction Key or Password Required. ';
- break;
- case '555':
- $this->strErrors .= '<br /> Invalid server response. ';
- break;
- default:
- $this->strErrors .= '<br />Unknown internal error. ';
- }
- $this->blnApproved = false;
- $this->blnHasErrors = true;
- $this->objOrder->Delete();
- break;
- case '4': //Held for review
- ///@todo handle held for review payments (authnet)
- $this->blnApproved = false;
- $this->blnHasErrors = false;
- break;
- default:
- $this->blnApproved = false;
- $this->blnHasErrors = true;
- $this->strErrors = $this->strResponseReasonText
- . '<br />Unknown Response code: ' . $this->intResponseCode
- .'<br />Response: ' . $this->strResponse;
- // $this->objOrder->Delete();
- }
-
- }
- /**
- * Creates GET query string for the transaction appropriate to the provider API, storing
- * the result in strGETRequest.
- * NOTE: Currently unused - we send a POST ..
- */
- protected function createGETRequest()
- {
- $this->initMerchantFields();
- $this->initTransactionFields();
- $this->initOrderFields();
- $this->initCustomerFields();
- foreach( $this->aryRequestValues as $strName => $strValue )
- if('' != $strValue )
- $this->strGETRequest .= $strName . '=' . urlencode($strValue) . '&';
- $this->strGETRequest = rtrim($this->strGETRequest,'&');
- if('' != $this->strGETRequest )
- $this->blnHasErrors = false;
- }
-
- protected function createPOSTRequest()
- {
- $this->initMerchantFields();
- $this->initTransactionFields();
- $this->initOrderFields();
- $this->initCustomerFields();
- foreach( $this->aryRequestValues as $strName => $strValue )
- if('' != $strValue )
- $this->strPOSTRequest .= $strName . '=' . urlencode($strValue) . '&';
- $this->strPOSTRequest = rtrim($this->strPOSTRequest,'&');
- if('' != $this->strPOSTRequest )
- $this->blnHasErrors = false;
- }
- protected function initMerchantFields()
- {
- $this->aryRequestValues['x_login'] = $this->strRemoteAccountId;
- $this->aryRequestValues['x_tran_key'] = $this->strTransactionKey;
- }
- protected function initTransactionFields($strTransactionId='')
- {
- /* unused - todo: .. not sure what to do with this yet.
- if('' != $strTransactionId)
- $this->aryRequestValues['x_trans_id'] = $strTransactionId;
- else
- $this->aryRequestValues['x_trans_id'] = $this->strTransactionId;
- $this->aryRequestValues['x_auth_code'] = $this->
- */
- $this->aryRequestValues['x_amount'] = $this->fltTotalPrice;
- $this->aryRequestValues['x_card_num'] = $this->strCCNumber;
- $this->aryRequestValues['x_exp_date'] = $this->strCCExpirationMonth . $this->strCCExpirationYear;
-
- //Note - this should be checked on input, this is for testing - remove conditional ..
- if( '' != $this->strCCVNumber )
- $this->aryRequestValues['x_card_code'] = $this->strCCVNumber;
- }
- protected function initOrderFields()
- {
- $this->aryRequestValues['x_invoice_num'] = $this->objOrder->Id;
- $this->aryRequestValues['x_description'] = DEFAULT_ORDER_DESCRIPTION;
- //todo: maybe itemized list here ..
- //foreach (orderitems) $this->aryRequestValues['x_line_item'] ...etc.
- }
- protected function initCustomerFields()
- {
-
- $this->aryRequestValues['x_customer_ip'] = $_SERVER['REMOTE_ADDR'];
- $this->aryRequestValues['x_cust_id'] = $this->objOrder->Account->Id;
- $this->aryRequestValues['x_email'] = $this->objOrder->Account->Person->EmailAddress;
- $this->initAddressFields();
-
- /* todo: optionally have authorize send a confirmation email ..
- $this->aryRequestValues['x_email_customer'] = '';
- $this->aryRequestValues['x_email_header'] = '';
- $this->aryRequestValues['x_email_footer'] = '';
- */
- }
- protected function initAddressFields()
- {
- //todo: if($this->SendShippingAddress)
-
- //We must concatenate all the name fields into first or last name ..
- if( '' != $this->objOrder->BillingNamePrefix )
- {
- $this->aryRequestValues['x_first_name'] = $this->objOrder->BillingNamePrefix . ' ';
- $this->aryRequestValues['x_first_name'] .= $this->objOrder->BillingFirstName;
- }
- else
- $this->aryRequestValues['x_first_name'] = $this->objOrder->BillingFirstName;
-
- if( '' != $this->objOrder->BillingMiddleName )
- $this->aryRequestValues['x_first_name'] .= ' ' . $this->objOrder->BillingMiddleName;
-
- $this->aryRequestValues['x_last_name'] = ' ' . $this->objOrder->BillingLastName;
-
- if( '' != $this->objOrder->BillingNameSuffix )
- $this->aryRequestValues['x_last_name'] .= ' ' . $this->objOrder->BillingNameSuffix;
-
- $this->aryRequestValues['x_address'] = $this->objOrder->BillingStreet1;
-
- //ALERT: There is no field for Street2, County or Suburb so we put them all in address .. this may
- // cause problems ..
- if( '' != $this->objOrder->BillingStreet2 )
- $this->aryRequestValues['x_address'] .= ', ' . $this->objOrder->BillingStreet2;
- if( '' != $this->objOrder->BillingSuburb )
- $this->aryRequestValues['x_address'] .= ', ' . $this->objOrder->BillingSuburb;
- if( '' != $this->objOrder->BillingCounty )
- $this->aryRequestValues['x_address'] .= ', ' . $this->objOrder->BillingCounty;
-
- $this->aryRequestValues['x_city'] = $this->objOrder->BillingCity;
- $this->aryRequestValues['x_state'] = $this->objOrder->BillingState;
- $this->aryRequestValues['x_country'] = $this->objOrder->BillingCountry;
- $this->aryRequestValues['x_zip'] = $this->objOrder->BillingPostalCode;
- }
- public function __get($strName)
- {
- switch ($strName)
- {
- case 'SendShippingAddress':
- return $this->blnSendShippingAddress;
- default:
- try {
- return parent::__get($strName);
- } catch (QCallerException $objExc) {
- $objExc->IncrementOffset();
- throw $objExc;
- }
- }
- }
-
- public function __set($strName, $mixValue)
- {
- switch ($strName)
- {
- case 'SendShippingAddress':
- try {
- $this->blnSendShippingAddress = QType::Cast($mixValue, QType::Boolean );
- } catch (QInvalidCastException $objExc) {
- $objExc->IncrementOffset();
- throw $objExc;
- }
- default:
- try {
- return (parent::__set($strName, $mixValue));
- } catch (QCallerException $objExc) {
- $objExc->IncrementOffset();
- throw $objExc;
- }
- }
- }
-
- }//end class
- }//end define
-
- ?>
|