Overview

Packages

  • currencysymbol
  • MAbout
  • Mage
    • Admin
    • Adminhtml
    • AdminNotification
    • Api
    • Api2
    • Authorizenet
    • Backup
    • Bundle
    • Captcha
    • Catalog
    • CatalogIndex
    • CatalogInventory
    • CatalogRule
    • CatalogSearch
    • Centinel
    • Checkout
    • Cms
    • Compiler
    • Connect
    • Contacts
    • Core
    • Cron
    • CurrencySymbol
    • Customer
    • Dataflow
    • Directory
    • DirtectPost
    • Downloadable
    • Eav
    • GiftMessage
    • GoogleAnalytics
    • GoogleBase
    • GoogleCheckout
    • ImportExport
    • Index
    • Install
    • Log
    • Media
    • Newsletter
    • Oauth
    • Page
    • PageCache
    • Paygate
    • Payment
    • Paypal
    • PaypalUk
    • Persistent
    • Poll
    • ProductAlert
    • Rating
    • Reports
    • Review
    • Rss
    • Rule
    • Sales
    • SalesRule
    • Sedfriend
    • Sendfriend
    • Shipping
    • Sitemap
    • Tag
    • Tax
    • Usa
    • Weee
    • Widget
    • Wishlist
    • XmlConnect
  • None
  • Phoenix
    • Moneybookers
  • PHP
  • Zend
    • Date
    • Mime
    • XmlRpc

Classes

  • Mage_Paygate_Adminhtml_Paygate_Authorizenet_PaymentController
  • Mage_Paygate_Authorizenet_PaymentController
  • Mage_Paygate_Block_Authorizenet_Form_Cc
  • Mage_Paygate_Block_Authorizenet_Info_Cc
  • Mage_Paygate_Helper_Data
  • Mage_Paygate_Model_Authorizenet
  • Mage_Paygate_Model_Authorizenet_Cards
  • Mage_Paygate_Model_Authorizenet_Debug
  • Mage_Paygate_Model_Authorizenet_Result
  • Mage_Paygate_Model_Authorizenet_Source_Cctype
  • Mage_Paygate_Model_Authorizenet_Source_PaymentAction
  • Mage_Paygate_Model_Mysql4_Authorizenet_Debug
  • Mage_Paygate_Model_Mysql4_Authorizenet_Debug_Collection
  • Mage_Paygate_Model_Resource_Authorizenet_Debug
  • Mage_Paygate_Model_Resource_Authorizenet_Debug_Collection
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * Magento
   4:  *
   5:  * NOTICE OF LICENSE
   6:  *
   7:  * This source file is subject to the Open Software License (OSL 3.0)
   8:  * that is bundled with this package in the file LICENSE.txt.
   9:  * It is also available through the world-wide-web at this URL:
  10:  * http://opensource.org/licenses/osl-3.0.php
  11:  * If you did not receive a copy of the license and are unable to
  12:  * obtain it through the world-wide-web, please send an email
  13:  * to license@magentocommerce.com so we can send you a copy immediately.
  14:  *
  15:  * DISCLAIMER
  16:  *
  17:  * Do not edit or add to this file if you wish to upgrade Magento to newer
  18:  * versions in the future. If you wish to customize Magento for your
  19:  * needs please refer to http://www.magentocommerce.com for more information.
  20:  *
  21:  * @category    Mage
  22:  * @package     Mage_Paygate
  23:  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24:  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  25:  */
  26: 
  27: 
  28: class Mage_Paygate_Model_Authorizenet extends Mage_Payment_Model_Method_Cc
  29: {
  30:     /*
  31:      * AIM gateway url
  32:      */
  33:     const CGI_URL = 'https://secure.authorize.net/gateway/transact.dll';
  34: 
  35:     /*
  36:      * Transaction Details gateway url
  37:      */
  38:     const CGI_URL_TD = 'https://apitest.authorize.net/xml/v1/request.api';
  39: 
  40:     const REQUEST_METHOD_CC     = 'CC';
  41:     const REQUEST_METHOD_ECHECK = 'ECHECK';
  42: 
  43:     const REQUEST_TYPE_AUTH_CAPTURE = 'AUTH_CAPTURE';
  44:     const REQUEST_TYPE_AUTH_ONLY    = 'AUTH_ONLY';
  45:     const REQUEST_TYPE_CAPTURE_ONLY = 'CAPTURE_ONLY';
  46:     const REQUEST_TYPE_CREDIT       = 'CREDIT';
  47:     const REQUEST_TYPE_VOID         = 'VOID';
  48:     const REQUEST_TYPE_PRIOR_AUTH_CAPTURE = 'PRIOR_AUTH_CAPTURE';
  49: 
  50:     const ECHECK_ACCT_TYPE_CHECKING = 'CHECKING';
  51:     const ECHECK_ACCT_TYPE_BUSINESS = 'BUSINESSCHECKING';
  52:     const ECHECK_ACCT_TYPE_SAVINGS  = 'SAVINGS';
  53: 
  54:     const ECHECK_TRANS_TYPE_CCD = 'CCD';
  55:     const ECHECK_TRANS_TYPE_PPD = 'PPD';
  56:     const ECHECK_TRANS_TYPE_TEL = 'TEL';
  57:     const ECHECK_TRANS_TYPE_WEB = 'WEB';
  58: 
  59:     const RESPONSE_DELIM_CHAR = '(~)';
  60: 
  61:     const RESPONSE_CODE_APPROVED = 1;
  62:     const RESPONSE_CODE_DECLINED = 2;
  63:     const RESPONSE_CODE_ERROR    = 3;
  64:     const RESPONSE_CODE_HELD     = 4;
  65: 
  66:     const RESPONSE_REASON_CODE_APPROVED = 1;
  67:     const RESPONSE_REASON_CODE_NOT_FOUND = 16;
  68:     const RESPONSE_REASON_CODE_PARTIAL_APPROVE = 295;
  69:     const RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED = 252;
  70:     const RESPONSE_REASON_CODE_PENDING_REVIEW = 253;
  71:     const RESPONSE_REASON_CODE_PENDING_REVIEW_DECLINED = 254;
  72: 
  73:     const PARTIAL_AUTH_CARDS_LIMIT = 5;
  74: 
  75:     const PARTIAL_AUTH_LAST_SUCCESS         = 'last_success';
  76:     const PARTIAL_AUTH_LAST_DECLINED        = 'last_declined';
  77:     const PARTIAL_AUTH_ALL_CANCELED         = 'all_canceled';
  78:     const PARTIAL_AUTH_CARDS_LIMIT_EXCEEDED = 'card_limit_exceeded';
  79:     const PARTIAL_AUTH_DATA_CHANGED         = 'data_changed';
  80: 
  81:     const METHOD_CODE = 'authorizenet';
  82: 
  83:     const TRANSACTION_STATUS_EXPIRED = 'expired';
  84: 
  85:     protected $_code  = self::METHOD_CODE;
  86: 
  87:     /**
  88:      * Form block type
  89:      */
  90:     protected $_formBlockType = 'paygate/authorizenet_form_cc';
  91: 
  92:     /**
  93:      * Info block type
  94:      */
  95:     protected $_infoBlockType = 'paygate/authorizenet_info_cc';
  96: 
  97:     /**
  98:      * Availability options
  99:      */
 100:     protected $_isGateway               = true;
 101:     protected $_canAuthorize            = true;
 102:     protected $_canCapture              = true;
 103:     protected $_canCapturePartial       = false;
 104:     protected $_canRefund               = true;
 105:     protected $_canRefundInvoicePartial = true;
 106:     protected $_canVoid                 = true;
 107:     protected $_canUseInternal          = true;
 108:     protected $_canUseCheckout          = true;
 109:     protected $_canUseForMultishipping  = true;
 110:     protected $_canSaveCc = false;
 111:     protected $_canFetchTransactionInfo = true;
 112: 
 113:     protected $_allowCurrencyCode = array('USD');
 114: 
 115:     /**
 116:      * Fields that should be replaced in debug with '***'
 117:      *
 118:      * @var array
 119:      */
 120:     protected $_debugReplacePrivateDataKeys = array('x_login', 'x_tran_key',
 121:                                                     'x_card_num', 'x_exp_date',
 122:                                                     'x_card_code', 'x_bank_aba_code',
 123:                                                     'x_bank_name', 'x_bank_acct_num',
 124:                                                     'x_bank_acct_type','x_bank_acct_name',
 125:                                                     'x_echeck_type');
 126: 
 127:     /**
 128:      * Key for storing fraud transaction flag in additional information of payment model
 129:      * @var string
 130:      */
 131:     protected $_isTransactionFraud = 'is_transaction_fraud';
 132: 
 133:     /**
 134:      * Key for storing transaction id in additional information of payment model
 135:      * @var string
 136:      */
 137:     protected $_realTransactionIdKey = 'real_transaction_id';
 138: 
 139:     /**
 140:      * Key for storing split tender id in additional information of payment model
 141:      * @var string
 142:      */
 143:     protected $_splitTenderIdKey = 'split_tender_id';
 144: 
 145:     /**
 146:      * Key for storing locking gateway actions flag in additional information of payment model
 147:      * @var string
 148:      */
 149:     protected $_isGatewayActionsLockedKey = 'is_gateway_actions_locked';
 150: 
 151:     /**
 152:      * Key for storing partial authorization last action state in session
 153:      * @var string
 154:      */
 155:     protected $_partialAuthorizationLastActionStateSessionKey = 'paygate_authorizenet_last_action_state';
 156: 
 157:     /**
 158:      * Key for storing partial authorization checksum in session
 159:      * @var string
 160:      */
 161:     protected $_partialAuthorizationChecksumSessionKey = 'paygate_authorizenet_checksum';
 162: 
 163:     /**
 164:      * Fields for creating place request checksum
 165:      *
 166:      * @var array
 167:      */
 168:     protected $_partialAuthorizationChecksumDataKeys = array(
 169:         'x_version', 'x_test_request', 'x_login', 'x_test_request', 'x_allow_partial_auth', 'x_amount',
 170:         'x_currency_code', 'x_type', 'x_first_name', 'x_last_name', 'x_company', 'x_address', 'x_city', 'x_state',
 171:         'x_zip', 'x_country', 'x_phone', 'x_fax', 'x_cust_id', 'x_customer_ip', 'x_customer_tax_id', 'x_email',
 172:         'x_email_customer', 'x_merchant_email', 'x_ship_to_first_name', 'x_ship_to_last_name', 'x_ship_to_company',
 173:         'x_ship_to_address', 'x_ship_to_city', 'x_ship_to_state', 'x_ship_to_zip', 'x_ship_to_country', 'x_po_num',
 174:         'x_tax', 'x_freight'
 175:     );
 176: 
 177:     /**
 178:      * Centinel cardinal fields map
 179:      *
 180:      * @var array
 181:      */
 182:     protected $_centinelFieldMap = array(
 183:         'centinel_cavv' => 'x_cardholder_authentication_value',
 184:         'centinel_eci'  => 'x_authentication_indicator'
 185:     );
 186: 
 187:     /**
 188:      * Check method for processing with base currency
 189:      *
 190:      * @param string $currencyCode
 191:      * @return boolean
 192:      */
 193:     public function canUseForCurrency($currencyCode)
 194:     {
 195:         if (!in_array($currencyCode, $this->getAcceptedCurrencyCodes())) {
 196:             return false;
 197:         }
 198:         return true;
 199:     }
 200: 
 201:     /**
 202:      * Return array of currency codes supplied by Payment Gateway
 203:      *
 204:      * @return array
 205:      */
 206:     public function getAcceptedCurrencyCodes()
 207:     {
 208:         if (!$this->hasData('_accepted_currency')) {
 209:             $acceptedCurrencyCodes = $this->_allowCurrencyCode;
 210:             $acceptedCurrencyCodes[] = $this->getConfigData('currency');
 211:             $this->setData('_accepted_currency', $acceptedCurrencyCodes);
 212:         }
 213:         return $this->_getData('_accepted_currency');
 214:     }
 215: 
 216:     /**
 217:      * Check capture availability
 218:      *
 219:      * @return bool
 220:      */
 221:     public function canCapture()
 222:     {
 223:         if ($this->_isGatewayActionsLocked($this->getInfoInstance())) {
 224:             return false;
 225:         }
 226:         if ($this->_isPreauthorizeCapture($this->getInfoInstance())) {
 227:             return true;
 228:         }
 229: 
 230:         /**
 231:          * If there are not transactions it is placing order and capturing is available
 232:          */
 233:         foreach($this->getCardsStorage()->getCards() as $card) {
 234:             $lastTransaction = $this->getInfoInstance()->getTransaction($card->getLastTransId());
 235:             if ($lastTransaction) {
 236:                 return false;
 237:             }
 238:         }
 239:         return true;
 240:     }
 241: 
 242:     /**
 243:      * Check refund availability
 244:      *
 245:      * @return bool
 246:      */
 247:     public function canRefund()
 248:     {
 249:         if ($this->_isGatewayActionsLocked($this->getInfoInstance())
 250:             || $this->getCardsStorage()->getCardsCount() <= 0
 251:         ) {
 252:             return false;
 253:         }
 254:         foreach($this->getCardsStorage()->getCards() as $card) {
 255:             $lastTransaction = $this->getInfoInstance()->getTransaction($card->getLastTransId());
 256:             if ($lastTransaction
 257:                 && $lastTransaction->getTxnType() == Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE
 258:                 && !$lastTransaction->getIsClosed()
 259:             ) {
 260:                 return true;
 261:             }
 262:         }
 263:         return false;
 264:     }
 265: 
 266:     /**
 267:      * Check void availability
 268:      *
 269:      * @param   Varien_Object $invoicePayment
 270:      * @return  bool
 271:      */
 272:     public function canVoid(Varien_Object $payment)
 273:     {
 274:         if ($this->_isGatewayActionsLocked($this->getInfoInstance())) {
 275:             return false;
 276:         }
 277:         return $this->_isPreauthorizeCapture($this->getInfoInstance());
 278:     }
 279: 
 280:     /**
 281:      * Set partial authorization last action state into session
 282:      *
 283:      * @param string $message
 284:      * @return Mage_Paygate_Model_Authorizenet
 285:      */
 286:     public function setPartialAuthorizationLastActionState($state)
 287:     {
 288:         $this->_getSession()->setData($this->_partialAuthorizationLastActionStateSessionKey, $state);
 289:         return $this;
 290:     }
 291: 
 292:     /**
 293:      * Return partial authorization last action state from session
 294:      *
 295:      * @return string
 296:      */
 297:     public function getPartialAuthorizationLastActionState()
 298:     {
 299:         return $this->_getSession()->getData($this->_partialAuthorizationLastActionStateSessionKey);
 300:     }
 301: 
 302:     /**
 303:      * Unset partial authorization last action state in session
 304:      *
 305:      * @return Mage_Paygate_Model_Authorizenet
 306:      */
 307:     public function unsetPartialAuthorizationLastActionState()
 308:     {
 309:         $this->_getSession()->setData($this->_partialAuthorizationLastActionStateSessionKey, false);
 310:         return $this;
 311:     }
 312: 
 313:     /**
 314:      * Send authorize request to gateway
 315:      *
 316:      * @param  Mage_Payment_Model_Info $payment
 317:      * @param  decimal $amount
 318:      * @return Mage_Paygate_Model_Authorizenet
 319:      */
 320:     public function authorize(Varien_Object $payment, $amount)
 321:     {
 322:         if ($amount <= 0) {
 323:             Mage::throwException(Mage::helper('paygate')->__('Invalid amount for authorization.'));
 324:         }
 325: 
 326:         $this->_initCardsStorage($payment);
 327: 
 328:         if ($this->isPartialAuthorization($payment)) {
 329:             $this->_partialAuthorization($payment, $amount, self::REQUEST_TYPE_AUTH_ONLY);
 330:             $payment->setSkipTransactionCreation(true);
 331:             return $this;
 332:         }
 333: 
 334:         $this->_place($payment, $amount, self::REQUEST_TYPE_AUTH_ONLY);
 335:         $payment->setSkipTransactionCreation(true);
 336:         return $this;
 337:     }
 338: 
 339:     /**
 340:      * Send capture request to gateway
 341:      *
 342:      * @param Mage_Payment_Model_Info $payment
 343:      * @param decimal $amount
 344:      * @return Mage_Paygate_Model_Authorizenet
 345:      */
 346:     public function capture(Varien_Object $payment, $amount)
 347:     {
 348:         if ($amount <= 0) {
 349:             Mage::throwException(Mage::helper('paygate')->__('Invalid amount for capture.'));
 350:         }
 351:         $this->_initCardsStorage($payment);
 352:         if ($this->_isPreauthorizeCapture($payment)) {
 353:             $this->_preauthorizeCapture($payment, $amount);
 354:         } else if ($this->isPartialAuthorization($payment)) {
 355:             $this->_partialAuthorization($payment, $amount, self::REQUEST_TYPE_AUTH_CAPTURE);
 356:         } else {
 357:             $this->_place($payment, $amount, self::REQUEST_TYPE_AUTH_CAPTURE);
 358:         }
 359:         $payment->setSkipTransactionCreation(true);
 360:         return $this;
 361:     }
 362: 
 363:     /**
 364:      * Void the payment through gateway
 365:      *
 366:      * @param  Mage_Payment_Model_Info $payment
 367:      * @return Mage_Paygate_Model_Authorizenet
 368:      */
 369:     public function void(Varien_Object $payment)
 370:     {
 371:         $cardsStorage = $this->getCardsStorage($payment);
 372: 
 373:         $messages = array();
 374:         $isSuccessful = false;
 375:         $isFiled = false;
 376:         foreach($cardsStorage->getCards() as $card) {
 377:             try {
 378:                 $newTransaction = $this->_voidCardTransaction($payment, $card);
 379:                 $messages[] = $newTransaction->getMessage();
 380:                 $isSuccessful = true;
 381:             } catch (Exception $e) {
 382:                 $messages[] = $e->getMessage();
 383:                 $isFiled = true;
 384:                 continue;
 385:             }
 386:             $cardsStorage->updateCard($card);
 387:         }
 388: 
 389:         if ($isFiled) {
 390:             $this->_processFailureMultitransactionAction($payment, $messages, $isSuccessful);
 391:         }
 392: 
 393:         $payment->setSkipTransactionCreation(true);
 394:         return $this;
 395:     }
 396: 
 397:     /**
 398:      * Cancel the payment through gateway
 399:      *
 400:      * @param  Mage_Payment_Model_Info $payment
 401:      * @return Mage_Paygate_Model_Authorizenet
 402:      */
 403:     public function cancel(Varien_Object $payment)
 404:     {
 405:         return $this->void($payment);
 406:     }
 407: 
 408:     /**
 409:      * Refund the amount with transaction id
 410:      *
 411:      * @param Mage_Payment_Model_Info $payment
 412:      * @param decimal $amount
 413:      * @return Mage_Paygate_Model_Authorizenet
 414:      * @throws Mage_Core_Exception
 415:      */
 416:     public function refund(Varien_Object $payment, $requestedAmount)
 417:     {
 418:         $cardsStorage = $this->getCardsStorage($payment);
 419: 
 420:         if ($this->_formatAmount(
 421:                 $cardsStorage->getCapturedAmount() - $cardsStorage->getRefundedAmount()
 422:             ) < $requestedAmount
 423:         ) {
 424:             Mage::throwException(Mage::helper('paygate')->__('Invalid amount for refund.'));
 425:         }
 426: 
 427:         $messages = array();
 428:         $isSuccessful = false;
 429:         $isFiled = false;
 430:         foreach($cardsStorage->getCards() as $card) {
 431:             if ($requestedAmount > 0) {
 432:                 $cardAmountForRefund = $this->_formatAmount($card->getCapturedAmount() - $card->getRefundedAmount());
 433:                 if ($cardAmountForRefund <= 0) {
 434:                     continue;
 435:                 }
 436:                 if ($cardAmountForRefund > $requestedAmount) {
 437:                     $cardAmountForRefund = $requestedAmount;
 438:                 }
 439:                 try {
 440:                     $newTransaction = $this->_refundCardTransaction($payment, $cardAmountForRefund, $card);
 441:                     $messages[] = $newTransaction->getMessage();
 442:                     $isSuccessful = true;
 443:                 } catch (Exception $e) {
 444:                     $messages[] = $e->getMessage();
 445:                     $isFiled = true;
 446:                     continue;
 447:                 }
 448:                 $card->setRefundedAmount($this->_formatAmount($card->getRefundedAmount() + $cardAmountForRefund));
 449:                 $cardsStorage->updateCard($card);
 450:                 $requestedAmount = $this->_formatAmount($requestedAmount - $cardAmountForRefund);
 451:             } else {
 452:                 $payment->setSkipTransactionCreation(true);
 453:                 return $this;
 454:             }
 455:         }
 456: 
 457:         if ($isFiled) {
 458:             $this->_processFailureMultitransactionAction($payment, $messages, $isSuccessful);
 459:         }
 460: 
 461:         $payment->setSkipTransactionCreation(true);
 462:         return $this;
 463:     }
 464: 
 465:     /**
 466:      * Cancel partial authorizations and flush current split_tender_id record
 467:      *
 468:      * @param Mage_Payment_Model_Info $payment
 469:      */
 470:     public function cancelPartialAuthorization(Mage_Payment_Model_Info $payment) {
 471:         if (!$payment->getAdditionalInformation($this->_splitTenderIdKey)) {
 472:             Mage::throwException(Mage::helper('paygate')->__('Invalid split tenderId ID.'));
 473:         }
 474: 
 475:         $request = $this->_getRequest();
 476:         $request->setXSplitTenderId($payment->getAdditionalInformation($this->_splitTenderIdKey));
 477: 
 478:         $request
 479:             ->setXType(self::REQUEST_TYPE_VOID)
 480:             ->setXMethod(self::REQUEST_METHOD_CC);
 481:         $result = $this->_postRequest($request);
 482: 
 483:         switch ($result->getResponseCode()) {
 484:             case self::RESPONSE_CODE_APPROVED:
 485:                 $payment->setAdditionalInformation($this->_splitTenderIdKey, null);
 486:                 $this->_getSession()->setData($this->_partialAuthorizationChecksumSessionKey, null);
 487:                 $this->getCardsStorage($payment)->flushCards();
 488:                 $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_ALL_CANCELED);
 489:                 return;
 490:             default:
 491:                 Mage::throwException(Mage::helper('paygate')->__('Payment canceling error.'));
 492:         }
 493: 
 494:     }
 495: 
 496:     /**
 497:      * Send request with new payment to gateway
 498:      *
 499:      * @param Mage_Payment_Model_Info $payment
 500:      * @param decimal $amount
 501:      * @param string $requestType
 502:      * @return Mage_Paygate_Model_Authorizenet
 503:      * @throws Mage_Core_Exception
 504:      */
 505:     protected function _place($payment, $amount, $requestType)
 506:     {
 507:         $payment->setAnetTransType($requestType);
 508:         $payment->setAmount($amount);
 509:         $request= $this->_buildRequest($payment);
 510:         $result = $this->_postRequest($request);
 511: 
 512:         switch ($requestType) {
 513:             case self::REQUEST_TYPE_AUTH_ONLY:
 514:                 $newTransactionType = Mage_Sales_Model_Order_Payment_Transaction::TYPE_AUTH;
 515:                 $defaultExceptionMessage = Mage::helper('paygate')->__('Payment authorization error.');
 516:                 break;
 517:             case self::REQUEST_TYPE_AUTH_CAPTURE:
 518:                 $newTransactionType = Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE;
 519:                 $defaultExceptionMessage = Mage::helper('paygate')->__('Payment capturing error.');
 520:                 break;
 521:         }
 522: 
 523:         switch ($result->getResponseCode()) {
 524:             case self::RESPONSE_CODE_APPROVED:
 525:                 $this->getCardsStorage($payment)->flushCards();
 526:                 $card = $this->_registerCard($result, $payment);
 527:                 $this->_addTransaction(
 528:                     $payment,
 529:                     $card->getLastTransId(),
 530:                     $newTransactionType,
 531:                     array('is_transaction_closed' => 0),
 532:                     array($this->_realTransactionIdKey => $card->getLastTransId()),
 533:                     Mage::helper('paygate')->getTransactionMessage(
 534:                         $payment, $requestType, $card->getLastTransId(), $card, $amount
 535:                     )
 536:                 );
 537:                 if ($requestType == self::REQUEST_TYPE_AUTH_CAPTURE) {
 538:                     $card->setCapturedAmount($card->getProcessedAmount());
 539:                     $this->getCardsStorage($payment)->updateCard($card);
 540:                 }
 541:                 return $this;
 542:             case self::RESPONSE_CODE_HELD:
 543:                 if ($result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED
 544:                     || $result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_PENDING_REVIEW
 545:                 ) {
 546:                     $card = $this->_registerCard($result, $payment);
 547:                     $this->_addTransaction(
 548:                         $payment,
 549:                         $card->getLastTransId(),
 550:                         $newTransactionType,
 551:                         array('is_transaction_closed' => 0),
 552:                         array(
 553:                             $this->_realTransactionIdKey => $card->getLastTransId(),
 554:                             $this->_isTransactionFraud => true
 555:                         ),
 556:                         Mage::helper('paygate')->getTransactionMessage(
 557:                             $payment, $requestType, $card->getLastTransId(), $card, $amount
 558:                         )
 559:                     );
 560:                     if ($requestType == self::REQUEST_TYPE_AUTH_CAPTURE) {
 561:                         $card->setCapturedAmount($card->getProcessedAmount());
 562:                         $this->getCardsStorage()->updateCard($card);
 563:                     }
 564:                     $payment
 565:                         ->setIsTransactionPending(true)
 566:                         ->setIsFraudDetected(true);
 567:                     return $this;
 568:                 }
 569:                 if ($result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_PARTIAL_APPROVE) {
 570:                     $checksum = $this->_generateChecksum($request, $this->_partialAuthorizationChecksumDataKeys);
 571:                     $this->_getSession()->setData($this->_partialAuthorizationChecksumSessionKey, $checksum);
 572:                     if ($this->_processPartialAuthorizationResponse($result, $payment)) {
 573:                         return $this;
 574:                     }
 575:                 }
 576:                 Mage::throwException($defaultExceptionMessage);
 577:             case self::RESPONSE_CODE_DECLINED:
 578:             case self::RESPONSE_CODE_ERROR:
 579:                 Mage::throwException($this->_wrapGatewayError($result->getResponseReasonText()));
 580:             default:
 581:                 Mage::throwException($defaultExceptionMessage);
 582:         }
 583:         return $this;
 584:     }
 585: 
 586:     /**
 587:      * Send request with new payment to gateway during partial authorization process
 588:      *
 589:      * @param Mage_Payment_Model_Info $payment
 590:      * @param decimal $amount
 591:      * @param string $requestType
 592:      * @return Mage_Paygate_Model_Authorizenet
 593:      */
 594:     protected function _partialAuthorization($payment, $amount, $requestType)
 595:     {
 596:         $payment->setAnetTransType($requestType);
 597: 
 598:         /*
 599:          * Try to build checksum of first request and compare with current checksum
 600:          */
 601:         if ($this->getConfigData('partial_authorization_checksum_checking')) {
 602:             $payment->setAmount($amount);
 603:             $firstPlacingRequest= $this->_buildRequest($payment);
 604:             $newChecksum = $this->_generateChecksum($firstPlacingRequest, $this->_partialAuthorizationChecksumDataKeys);
 605:             $previosChecksum = $this->_getSession()->getData($this->_partialAuthorizationChecksumSessionKey);
 606:             if ($newChecksum != $previosChecksum) {
 607:                 $quotePayment = $payment->getOrder()->getQuote()->getPayment();
 608:                 $this->cancelPartialAuthorization($payment);
 609:                 $this->_clearAssignedData($quotePayment);
 610:                 $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_DATA_CHANGED);
 611:                 $quotePayment->setAdditionalInformation($payment->getAdditionalInformation());
 612:                 throw new Mage_Payment_Model_Info_Exception(
 613:                     Mage::helper('paygate')->__('Shopping cart contents and/or address has been changed.')
 614:                 );
 615:             }
 616:         }
 617: 
 618:         $amount = $amount - $this->getCardsStorage()->getProcessedAmount();
 619:         if ($amount <= 0) {
 620:             Mage::throwException(Mage::helper('paygate')->__('Invalid amount for partial authorization.'));
 621:         }
 622:         $payment->setAmount($amount);
 623:         $request = $this->_buildRequest($payment);
 624:         $result = $this->_postRequest($request);
 625:         $this->_processPartialAuthorizationResponse($result, $payment);
 626: 
 627:         switch ($requestType) {
 628:             case self::REQUEST_TYPE_AUTH_ONLY:
 629:                 $newTransactionType = Mage_Sales_Model_Order_Payment_Transaction::TYPE_AUTH;
 630:                 break;
 631:             case self::REQUEST_TYPE_AUTH_CAPTURE:
 632:                 $newTransactionType = Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE;
 633:                 break;
 634:         }
 635: 
 636:         foreach ($this->getCardsStorage()->getCards() as $card) {
 637:             $this->_addTransaction(
 638:                 $payment,
 639:                 $card->getLastTransId(),
 640:                 $newTransactionType,
 641:                 array('is_transaction_closed' => 0),
 642:                 array($this->_realTransactionIdKey => $card->getLastTransId()),
 643:                 Mage::helper('paygate')->getTransactionMessage(
 644:                     $payment, $requestType, $card->getLastTransId(), $card, $card->getProcessedAmount()
 645:                 )
 646:             );
 647:             if ($requestType == self::REQUEST_TYPE_AUTH_CAPTURE) {
 648:                 $card->setCapturedAmount($card->getProcessedAmount());
 649:                 $this->getCardsStorage()->updateCard($card);
 650:             }
 651:         }
 652:         $this->_getSession()->setData($this->_partialAuthorizationChecksumSessionKey, null);
 653:         return $this;
 654:     }
 655: 
 656:     /**
 657:      * Return true if there are authorized transactions
 658:      *
 659:      * @param Mage_Payment_Model_Info $payment
 660:      * @return bool
 661:      */
 662:     protected function _isPreauthorizeCapture($payment)
 663:     {
 664:         if ($this->getCardsStorage()->getCardsCount() <= 0) {
 665:             return false;
 666:         }
 667:         foreach($this->getCardsStorage()->getCards() as $card) {
 668:             $lastTransaction = $payment->getTransaction($card->getLastTransId());
 669:             if (!$lastTransaction
 670:                 || $lastTransaction->getTxnType() != Mage_Sales_Model_Order_Payment_Transaction::TYPE_AUTH
 671:             ) {
 672:                 return false;
 673:             }
 674:         }
 675:         return true;
 676:     }
 677: 
 678:     /**
 679:      * Send capture request to gateway for capture authorized transactions
 680:      *
 681:      * @param Mage_Payment_Model_Info $payment
 682:      * @param decimal $amount
 683:      * @return Mage_Paygate_Model_Authorizenet
 684:      */
 685:     protected function _preauthorizeCapture($payment, $requestedAmount)
 686:     {
 687:         $cardsStorage = $this->getCardsStorage($payment);
 688: 
 689:         if ($this->_formatAmount(
 690:                 $cardsStorage->getProcessedAmount() - $cardsStorage->getCapturedAmount()
 691:             ) < $requestedAmount
 692:         ) {
 693:             Mage::throwException(Mage::helper('paygate')->__('Invalid amount for capture.'));
 694:         }
 695: 
 696:         $messages = array();
 697:         $isSuccessful = false;
 698:         $isFiled = false;
 699:         foreach($cardsStorage->getCards() as $card) {
 700:             if ($requestedAmount > 0) {
 701:                 $cardAmountForCapture = $card->getProcessedAmount();
 702:                 if ($cardAmountForCapture > $requestedAmount) {
 703:                     $cardAmountForCapture = $requestedAmount;
 704:                 }
 705:                 try {
 706:                     $newTransaction = $this->_preauthorizeCaptureCardTransaction(
 707:                         $payment, $cardAmountForCapture , $card
 708:                     );
 709:                     $messages[] = $newTransaction->getMessage();
 710:                     $isSuccessful = true;
 711:                 } catch (Exception $e) {
 712:                     $messages[] = $e->getMessage();
 713:                     $isFiled = true;
 714:                     continue;
 715:                 }
 716:                 $card->setCapturedAmount($cardAmountForCapture);
 717:                 $cardsStorage->updateCard($card);
 718:                 $requestedAmount = $this->_formatAmount($requestedAmount - $cardAmountForCapture);
 719:             } else {
 720:                 /**
 721:                  * This functional is commented because partial capture is disable. See self::_canCapturePartial.
 722:                  */
 723:                 //$this->_voidCardTransaction($payment, $card);
 724:             }
 725:         }
 726: 
 727:         if ($isFiled) {
 728:             $this->_processFailureMultitransactionAction($payment, $messages, $isSuccessful);
 729:         }
 730:         return $this;
 731:     }
 732: 
 733:     /**
 734:      * Send capture request to gateway for capture authorized transactions of card
 735:      *
 736:      * @param Mage_Payment_Model_Info $payment
 737:      * @param decimal $amount
 738:      * @param Varien_Object $card
 739:      * @return Mage_Sales_Model_Order_Payment_Transaction
 740:      */
 741:     protected function _preauthorizeCaptureCardTransaction($payment, $amount, $card)
 742:     {
 743:         $authTransactionId = $card->getLastTransId();
 744:         $authTransaction = $payment->getTransaction($authTransactionId);
 745:         $realAuthTransactionId = $authTransaction->getAdditionalInformation($this->_realTransactionIdKey);
 746: 
 747:         $payment->setAnetTransType(self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE);
 748:         $payment->setXTransId($realAuthTransactionId);
 749:         $payment->setAmount($amount);
 750: 
 751:         $request= $this->_buildRequest($payment);
 752:         $result = $this->_postRequest($request);
 753: 
 754:         switch ($result->getResponseCode()) {
 755:             case self::RESPONSE_CODE_APPROVED:
 756:                 if ($result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_APPROVED) {
 757:                     $captureTransactionId = $result->getTransactionId() . '-capture';
 758:                     $card->setLastTransId($captureTransactionId);
 759:                     return $this->_addTransaction(
 760:                         $payment,
 761:                         $captureTransactionId,
 762:                         Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE,
 763:                         array(
 764:                             'is_transaction_closed' => 0,
 765:                             'parent_transaction_id' => $authTransactionId
 766:                         ),
 767:                         array($this->_realTransactionIdKey => $result->getTransactionId()),
 768:                         Mage::helper('paygate')->getTransactionMessage(
 769:                             $payment, self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE, $result->getTransactionId(), $card, $amount
 770:                         )
 771:                     );
 772:                 }
 773:                 $exceptionMessage = $this->_wrapGatewayError($result->getResponseReasonText());
 774:                 break;
 775:             case self::RESPONSE_CODE_HELD:
 776:             case self::RESPONSE_CODE_DECLINED:
 777:             case self::RESPONSE_CODE_ERROR:
 778:                 $exceptionMessage = $this->_wrapGatewayError($result->getResponseReasonText());
 779:                 break;
 780:             default:
 781:                 $exceptionMessage = Mage::helper('paygate')->__('Payment capturing error.');
 782:                 break;
 783:         }
 784: 
 785:         $exceptionMessage = Mage::helper('paygate')->getTransactionMessage(
 786:             $payment, self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE, $realAuthTransactionId, $card, $amount, $exceptionMessage
 787:         );
 788:         Mage::throwException($exceptionMessage);
 789:     }
 790: 
 791:     /**
 792:      * Void the card transaction through gateway
 793:      *
 794:      * @param Mage_Payment_Model_Info $payment
 795:      * @param Varien_Object $card
 796:      * @return Mage_Sales_Model_Order_Payment_Transaction
 797:      */
 798:     protected function _voidCardTransaction($payment, $card)
 799:     {
 800:         $authTransactionId = $card->getLastTransId();
 801:         $authTransaction = $payment->getTransaction($authTransactionId);
 802:         $realAuthTransactionId = $authTransaction->getAdditionalInformation($this->_realTransactionIdKey);
 803: 
 804:         $payment->setAnetTransType(self::REQUEST_TYPE_VOID);
 805:         $payment->setXTransId($realAuthTransactionId);
 806: 
 807:         $request= $this->_buildRequest($payment);
 808:         $result = $this->_postRequest($request);
 809: 
 810:         switch ($result->getResponseCode()) {
 811:             case self::RESPONSE_CODE_APPROVED:
 812:                 if ($result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_APPROVED) {
 813:                     $voidTransactionId = $result->getTransactionId() . '-void';
 814:                     $card->setLastTransId($voidTransactionId);
 815:                     return $this->_addTransaction(
 816:                         $payment,
 817:                         $voidTransactionId,
 818:                         Mage_Sales_Model_Order_Payment_Transaction::TYPE_VOID,
 819:                         array(
 820:                             'is_transaction_closed' => 1,
 821:                             'should_close_parent_transaction' => 1,
 822:                             'parent_transaction_id' => $authTransactionId
 823:                         ),
 824:                         array($this->_realTransactionIdKey => $result->getTransactionId()),
 825:                         Mage::helper('paygate')->getTransactionMessage(
 826:                             $payment, self::REQUEST_TYPE_VOID, $result->getTransactionId(), $card
 827:                         )
 828:                     );
 829:                 }
 830:                 $exceptionMessage = $this->_wrapGatewayError($result->getResponseReasonText());
 831:                 break;
 832:             case self::RESPONSE_CODE_DECLINED:
 833:             case self::RESPONSE_CODE_ERROR:
 834:             if ($result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_NOT_FOUND
 835:                 && $this->_isTransactionExpired($realAuthTransactionId)
 836:             ) {
 837:                 $voidTransactionId = $realAuthTransactionId . '-void';
 838:                 return $this->_addTransaction(
 839:                     $payment,
 840:                     $voidTransactionId,
 841:                     Mage_Sales_Model_Order_Payment_Transaction::TYPE_VOID,
 842:                     array(
 843:                         'is_transaction_closed' => 1,
 844:                         'should_close_parent_transaction' => 1,
 845:                         'parent_transaction_id' => $authTransactionId
 846:                     ),
 847:                     array(),
 848:                     Mage::helper('paygate')->getExtendedTransactionMessage(
 849:                         $payment,
 850:                         self::REQUEST_TYPE_VOID,
 851:                         null,
 852:                         $card,
 853:                         false,
 854:                         false,
 855:                         Mage::helper('paygate')->__(
 856:                             'Parent Authorize.Net transaction (ID %s) expired',
 857:                             $realAuthTransactionId
 858:                         )
 859:                     )
 860:                 );
 861:             }
 862:                 $exceptionMessage = $this->_wrapGatewayError($result->getResponseReasonText());
 863:                 break;
 864:             default:
 865:                 $exceptionMessage = Mage::helper('paygate')->__('Payment voiding error.');
 866:                 break;
 867:         }
 868: 
 869:         $exceptionMessage = Mage::helper('paygate')->getTransactionMessage(
 870:             $payment, self::REQUEST_TYPE_VOID, $realAuthTransactionId, $card, false, $exceptionMessage
 871:         );
 872:         Mage::throwException($exceptionMessage);
 873:     }
 874: 
 875:     /**
 876:      * Check if transaction is expired
 877:      *
 878:      * @param  string $realAuthTransactionId
 879:      * @return bool
 880:      */
 881:     protected function _isTransactionExpired($realAuthTransactionId)
 882:     {
 883:         $transactionDetails = $this->_getTransactionDetails($realAuthTransactionId);
 884:         return $transactionDetails->getTransactionStatus() == self::TRANSACTION_STATUS_EXPIRED;
 885:     }
 886: 
 887:     /**
 888:      * Refund the card transaction through gateway
 889:      *
 890:      * @param Mage_Payment_Model_Info $payment
 891:      * @param Varien_Object $card
 892:      * @return Mage_Sales_Model_Order_Payment_Transaction
 893:      */
 894:     protected function _refundCardTransaction($payment, $amount, $card)
 895:     {
 896:         /**
 897:          * Card has last transaction with type "refund" when all captured amount is refunded.
 898:          * Until this moment card has last transaction with type "capture".
 899:          */
 900:         $captureTransactionId = $card->getLastTransId();
 901:         $captureTransaction = $payment->getTransaction($captureTransactionId);
 902:         $realCaptureTransactionId = $captureTransaction->getAdditionalInformation($this->_realTransactionIdKey);
 903: 
 904:         $payment->setAnetTransType(self::REQUEST_TYPE_CREDIT);
 905:         $payment->setXTransId($realCaptureTransactionId);
 906:         $payment->setAmount($amount);
 907: 
 908:         $request = $this->_buildRequest($payment);
 909:         $request->setXCardNum($card->getCcLast4());
 910:         $result = $this->_postRequest($request);
 911: 
 912:         switch ($result->getResponseCode()) {
 913:             case self::RESPONSE_CODE_APPROVED:
 914:                 if ($result->getResponseReasonCode() == self::RESPONSE_REASON_CODE_APPROVED) {
 915:                     $refundTransactionId = $result->getTransactionId() . '-refund';
 916:                     $shouldCloseCaptureTransaction = 0;
 917:                     /**
 918:                      * If it is last amount for refund, transaction with type "capture" will be closed
 919:                      * and card will has last transaction with type "refund"
 920:                      */
 921:                     if ($this->_formatAmount($card->getCapturedAmount() - $card->getRefundedAmount()) == $amount) {
 922:                         $card->setLastTransId($refundTransactionId);
 923:                         $shouldCloseCaptureTransaction = 1;
 924:                     }
 925:                     return $this->_addTransaction(
 926:                         $payment,
 927:                         $refundTransactionId,
 928:                         Mage_Sales_Model_Order_Payment_Transaction::TYPE_REFUND,
 929:                         array(
 930:                             'is_transaction_closed' => 1,
 931:                             'should_close_parent_transaction' => $shouldCloseCaptureTransaction,
 932:                             'parent_transaction_id' => $captureTransactionId
 933:                         ),
 934:                         array($this->_realTransactionIdKey => $result->getTransactionId()),
 935:                         Mage::helper('paygate')->getTransactionMessage(
 936:                             $payment, self::REQUEST_TYPE_CREDIT, $result->getTransactionId(), $card, $amount
 937:                         )
 938:                     );
 939:                 }
 940:                 $exceptionMessage = $this->_wrapGatewayError($result->getResponseReasonText());
 941:                 break;
 942:             case self::RESPONSE_CODE_DECLINED:
 943:             case self::RESPONSE_CODE_ERROR:
 944:                 $exceptionMessage = $this->_wrapGatewayError($result->getResponseReasonText());
 945:                 break;
 946:             default:
 947:                 $exceptionMessage = Mage::helper('paygate')->__('Payment refunding error.');
 948:                 break;
 949:         }
 950: 
 951:         $exceptionMessage = Mage::helper('paygate')->getTransactionMessage(
 952:             $payment, self::REQUEST_TYPE_CREDIT, $realCaptureTransactionId, $card, $amount, $exceptionMessage
 953:         );
 954:         Mage::throwException($exceptionMessage);
 955:     }
 956: 
 957:     /**
 958:      * Init cards storage model
 959:      *
 960:      * @param Mage_Payment_Model_Info $payment
 961:      */
 962:     protected function _initCardsStorage($payment)
 963:     {
 964:         $this->_cardsStorage = Mage::getModel('paygate/authorizenet_cards')->setPayment($payment);
 965:     }
 966: 
 967:     /**
 968:      * Return cards storage model
 969:      *
 970:      * @param Mage_Payment_Model_Info $payment
 971:      * @return Mage_Paygate_Model_Authorizenet_Cards
 972:      */
 973:     public function getCardsStorage($payment = null)
 974:     {
 975:         if (is_null($payment)) {
 976:             $payment = $this->getInfoInstance();
 977:         }
 978:         if (is_null($this->_cardsStorage)) {
 979:             $this->_initCardsStorage($payment);
 980:         }
 981:         return $this->_cardsStorage;
 982:     }
 983: 
 984:     /**
 985:      * If parial authorization is started method will returne true
 986:      *
 987:      * @param Mage_Payment_Model_Info $payment
 988:      * @return bool
 989:      */
 990:     public function isPartialAuthorization($payment = null)
 991:     {
 992:         if (is_null($payment)) {
 993:             $payment = $this->getInfoInstance();
 994:         }
 995:         return $payment->getAdditionalInformation($this->_splitTenderIdKey);
 996:     }
 997: 
 998:     /**
 999:      * Mock capture transaction id in invoice
1000:      *
1001:      * @param Mage_Sales_Model_Order_Invoice $invoice
1002:      * @param Mage_Sales_Model_Order_Payment $payment
1003:      * @return Mage_Payment_Model_Method_Abstract
1004:      */
1005:     public function processInvoice($invoice, $payment)
1006:     {
1007:         $invoice->setTransactionId(1);
1008:         return $this;
1009:     }
1010: 
1011:     /**
1012:      * Set transaction ID into creditmemo for informational purposes
1013:      * @param Mage_Sales_Model_Order_Creditmemo $creditmemo
1014:      * @param Mage_Sales_Model_Order_Payment $payment
1015:      * @return Mage_Payment_Model_Method_Abstract
1016:      */
1017:     public function processCreditmemo($creditmemo, $payment)
1018:     {
1019:         $creditmemo->setTransactionId(1);
1020:         return $this;
1021:     }
1022: 
1023:     /**
1024:      * Fetch transaction details info
1025:      *
1026:      * Update transaction info if there is one placing transaction only
1027:      *
1028:      * @param Mage_Payment_Model_Info $payment
1029:      * @param string $transactionId
1030:      * @return array
1031:      */
1032:     public function fetchTransactionInfo(Mage_Payment_Model_Info $payment, $transactionId)
1033:     {
1034:         $cardsStorage = $this->getCardsStorage($payment);
1035:         if ($cardsStorage->getCardsCount() != 1) {
1036:             return parent::fetchTransactionInfo($payment, $transactionId);
1037:         }
1038:         $cards = $cardsStorage->getCards();
1039:         $card = array_shift($cards);
1040:         $transactionId = $card->getLastTransId();
1041:         $transaction = $payment->getTransaction($transactionId);
1042: 
1043:         if (!$transaction->getAdditionalInformation($this->_isTransactionFraud)) {
1044:             return parent::fetchTransactionInfo($payment, $transactionId);
1045:         }
1046: 
1047:         $response = $this->_getTransactionDetails($transactionId);
1048:         if ($response->getResponseCode() == self::RESPONSE_CODE_APPROVED) {
1049:             $transaction->setAdditionalInformation($this->_isTransactionFraud, false);
1050:             $payment->setIsTransactionApproved(true);
1051:         } elseif ($response->getResponseReasonCode() == self::RESPONSE_REASON_CODE_PENDING_REVIEW_DECLINED) {
1052:             $payment->setIsTransactionDenied(true);
1053:         }
1054:         return parent::fetchTransactionInfo($payment, $transactionId);
1055:     }
1056: 
1057:     /**
1058:      * Set split_tender_id to quote payment if neeeded
1059:      *
1060:      * @param Varien_Object $response
1061:      * @param Mage_Sales_Model_Order_Payment $payment
1062:      * @return bool
1063:      */
1064:     protected function _processPartialAuthorizationResponse($response, $orderPayment) {
1065:         if (!$response->getSplitTenderId()) {
1066:             return false;
1067:         }
1068: 
1069:         $quotePayment = $orderPayment->getOrder()->getQuote()->getPayment();
1070:         $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_LAST_DECLINED);
1071:         $exceptionMessage = null;
1072: 
1073:         try {
1074:             switch ($response->getResponseCode()) {
1075:                 case self::RESPONSE_CODE_APPROVED:
1076:                     $this->_registerCard($response, $orderPayment);
1077:                     $this->_clearAssignedData($quotePayment);
1078:                     $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_LAST_SUCCESS);
1079:                     return true;
1080:                 case self::RESPONSE_CODE_HELD:
1081:                     if ($response->getResponseReasonCode() != self::RESPONSE_REASON_CODE_PARTIAL_APPROVE) {
1082:                         return false;
1083:                     }
1084:                     if ($this->getCardsStorage($orderPayment)->getCardsCount() + 1 >= self::PARTIAL_AUTH_CARDS_LIMIT) {
1085:                         $this->cancelPartialAuthorization($orderPayment);
1086:                         $this->_clearAssignedData($quotePayment);
1087:                         $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_CARDS_LIMIT_EXCEEDED);
1088:                         $quotePayment->setAdditionalInformation($orderPayment->getAdditionalInformation());
1089:                         $exceptionMessage = Mage::helper('paygate')->__('You have reached the maximum number of credit card allowed to be used for the payment.');
1090:                         break;
1091:                     }
1092:                     $orderPayment->setAdditionalInformation($this->_splitTenderIdKey, $response->getSplitTenderId());
1093:                     $this->_registerCard($response, $orderPayment);
1094:                     $this->_clearAssignedData($quotePayment);
1095:                     $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_LAST_SUCCESS);
1096:                     $quotePayment->setAdditionalInformation($orderPayment->getAdditionalInformation());
1097:                     $exceptionMessage = null;
1098:                     break;
1099:                 case self::RESPONSE_CODE_DECLINED:
1100:                 case self::RESPONSE_CODE_ERROR:
1101:                     $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_LAST_DECLINED);
1102:                     $quotePayment->setAdditionalInformation($orderPayment->getAdditionalInformation());
1103:                     $exceptionMessage = $this->_wrapGatewayError($response->getResponseReasonText());
1104:                     break;
1105:                 default:
1106:                     $this->setPartialAuthorizationLastActionState(self::PARTIAL_AUTH_LAST_DECLINED);
1107:                     $quotePayment->setAdditionalInformation($orderPayment->getAdditionalInformation());
1108:                     $exceptionMessage = $this->_wrapGatewayError(
1109:                             Mage::helper('paygate')->__('Payment partial authorization error.')
1110:                         );
1111:             }
1112:         } catch (Exception $e) {
1113:             $exceptionMessage = $e->getMessage();
1114:         }
1115: 
1116:         throw new Mage_Payment_Model_Info_Exception($exceptionMessage);
1117:     }
1118: 
1119:     /**
1120:      * Return authorize payment request
1121:      *
1122:      * @return Mage_Paygate_Model_Authorizenet_Request
1123:      */
1124:     protected function _getRequest()
1125:     {
1126:         $request = Mage::getModel('paygate/authorizenet_request')
1127:             ->setXVersion(3.1)
1128:             ->setXDelimData('True')
1129:             ->setXRelayResponse('False')
1130:             ->setXTestRequest($this->getConfigData('test') ? 'TRUE' : 'FALSE')
1131:             ->setXLogin($this->getConfigData('login'))
1132:             ->setXTranKey($this->getConfigData('trans_key'));
1133: 
1134:         return $request;
1135:     }
1136: 
1137:     /**
1138:      * Prepare request to gateway
1139:      *
1140:      * @link http://www.authorize.net/support/AIM_guide.pdf
1141:      * @param Mage_Payment_Model_Info $payment
1142:      * @return Mage_Paygate_Model_Authorizenet_Request
1143:      */
1144:     protected function _buildRequest(Varien_Object $payment)
1145:     {
1146:         $order = $payment->getOrder();
1147: 
1148:         $this->setStore($order->getStoreId());
1149: 
1150:         $request = $this->_getRequest()
1151:             ->setXType($payment->getAnetTransType())
1152:             ->setXMethod(self::REQUEST_METHOD_CC);
1153: 
1154:         if ($order && $order->getIncrementId()) {
1155:             $request->setXInvoiceNum($order->getIncrementId());
1156:         }
1157: 
1158:         if($payment->getAmount()){
1159:             $request->setXAmount($payment->getAmount(),2);
1160:             $request->setXCurrencyCode($order->getBaseCurrencyCode());
1161:         }
1162: 
1163:         switch ($payment->getAnetTransType()) {
1164:             case self::REQUEST_TYPE_AUTH_CAPTURE:
1165:                 $request->setXAllowPartialAuth($this->getConfigData('allow_partial_authorization') ? 'True' : 'False');
1166:                 if ($payment->getAdditionalInformation($this->_splitTenderIdKey)) {
1167:                     $request->setXSplitTenderId($payment->getAdditionalInformation($this->_splitTenderIdKey));
1168:                 }
1169:                 break;
1170:             case self::REQUEST_TYPE_AUTH_ONLY:
1171:                 $request->setXAllowPartialAuth($this->getConfigData('allow_partial_authorization') ? 'True' : 'False');
1172:                 if ($payment->getAdditionalInformation($this->_splitTenderIdKey)) {
1173:                     $request->setXSplitTenderId($payment->getAdditionalInformation($this->_splitTenderIdKey));
1174:                 }
1175:                 break;
1176:             case self::REQUEST_TYPE_CREDIT:
1177:                 /**
1178:                  * Send last 4 digits of credit card number to authorize.net
1179:                  * otherwise it will give an error
1180:                  */
1181:                 $request->setXCardNum($payment->getCcLast4());
1182:                 $request->setXTransId($payment->getXTransId());
1183:                 break;
1184:             case self::REQUEST_TYPE_VOID:
1185:                 $request->setXTransId($payment->getXTransId());
1186:                 break;
1187:             case self::REQUEST_TYPE_PRIOR_AUTH_CAPTURE:
1188:                 $request->setXTransId($payment->getXTransId());
1189:                 break;
1190:             case self::REQUEST_TYPE_CAPTURE_ONLY:
1191:                 $request->setXAuthCode($payment->getCcAuthCode());
1192:                 break;
1193:         }
1194: 
1195:         if ($this->getIsCentinelValidationEnabled()){
1196:             $params  = $this->getCentinelValidator()->exportCmpiData(array());
1197:             $request = Varien_Object_Mapper::accumulateByMap($params, $request, $this->_centinelFieldMap);
1198:         }
1199: 
1200:         if (!empty($order)) {
1201:             $billing = $order->getBillingAddress();
1202:             if (!empty($billing)) {
1203:                 $request->setXFirstName($billing->getFirstname())
1204:                     ->setXLastName($billing->getLastname())
1205:                     ->setXCompany($billing->getCompany())
1206:                     ->setXAddress($billing->getStreet(1))
1207:                     ->setXCity($billing->getCity())
1208:                     ->setXState($billing->getRegion())
1209:                     ->setXZip($billing->getPostcode())
1210:                     ->setXCountry($billing->getCountry())
1211:                     ->setXPhone($billing->getTelephone())
1212:                     ->setXFax($billing->getFax())
1213:                     ->setXCustId($order->getCustomerId())
1214:                     ->setXCustomerIp($order->getRemoteIp())
1215:                     ->setXCustomerTaxId($billing->getTaxId())
1216:                     ->setXEmail($order->getCustomerEmail())
1217:                     ->setXEmailCustomer($this->getConfigData('email_customer'))
1218:                     ->setXMerchantEmail($this->getConfigData('merchant_email'));
1219:             }
1220: 
1221:             $shipping = $order->getShippingAddress();
1222:             if (!empty($shipping)) {
1223:                 $request->setXShipToFirstName($shipping->getFirstname())
1224:                     ->setXShipToLastName($shipping->getLastname())
1225:                     ->setXShipToCompany($shipping->getCompany())
1226:                     ->setXShipToAddress($shipping->getStreet(1))
1227:                     ->setXShipToCity($shipping->getCity())
1228:                     ->setXShipToState($shipping->getRegion())
1229:                     ->setXShipToZip($shipping->getPostcode())
1230:                     ->setXShipToCountry($shipping->getCountry());
1231:             }
1232: 
1233:             $request->setXPoNum($payment->getPoNumber())
1234:                 ->setXTax($order->getBaseTaxAmount())
1235:                 ->setXFreight($order->getBaseShippingAmount());
1236:         }
1237: 
1238:         if($payment->getCcNumber()){
1239:             $request->setXCardNum($payment->getCcNumber())
1240:                 ->setXExpDate(sprintf('%02d-%04d', $payment->getCcExpMonth(), $payment->getCcExpYear()))
1241:                 ->setXCardCode($payment->getCcCid());
1242:         }
1243: 
1244:         return $request;
1245:     }
1246: 
1247:     /**
1248:      * Post request to gateway and return responce
1249:      *
1250:      * @param Mage_Paygate_Model_Authorizenet_Request $request)
1251:      * @return Mage_Paygate_Model_Authorizenet_Result
1252:      */
1253:     protected function _postRequest(Varien_Object $request)
1254:     {
1255:         $debugData = array('request' => $request->getData());
1256: 
1257:         $result = Mage::getModel('paygate/authorizenet_result');
1258: 
1259:         $client = new Varien_Http_Client();
1260: 
1261:         $uri = $this->getConfigData('cgi_url');
1262:         $client->setUri($uri ? $uri : self::CGI_URL);
1263:         $client->setConfig(array(
1264:             'maxredirects'=>0,
1265:             'timeout'=>30,
1266:             //'ssltransport' => 'tcp',
1267:         ));
1268:         foreach ($request->getData() as $key => $value) {
1269:             $request->setData($key, str_replace(self::RESPONSE_DELIM_CHAR, '', $value));
1270:         }
1271:         $request->setXDelimChar(self::RESPONSE_DELIM_CHAR);
1272: 
1273:         $client->setParameterPost($request->getData());
1274:         $client->setMethod(Zend_Http_Client::POST);
1275: 
1276:         try {
1277:             $response = $client->request();
1278:         } catch (Exception $e) {
1279:             $result->setResponseCode(-1)
1280:                 ->setResponseReasonCode($e->getCode())
1281:                 ->setResponseReasonText($e->getMessage());
1282: 
1283:             $debugData['result'] = $result->getData();
1284:             $this->_debug($debugData);
1285:             Mage::throwException($this->_wrapGatewayError($e->getMessage()));
1286:         }
1287: 
1288:         $responseBody = $response->getBody();
1289: 
1290:         $r = explode(self::RESPONSE_DELIM_CHAR, $responseBody);
1291: 
1292:         if ($r) {
1293:             $result->setResponseCode((int)str_replace('"','',$r[0]))
1294:                 ->setResponseSubcode((int)str_replace('"','',$r[1]))
1295:                 ->setResponseReasonCode((int)str_replace('"','',$r[2]))
1296:                 ->setResponseReasonText($r[3])
1297:                 ->setApprovalCode($r[4])
1298:                 ->setAvsResultCode($r[5])
1299:                 ->setTransactionId($r[6])
1300:                 ->setInvoiceNumber($r[7])
1301:                 ->setDescription($r[8])
1302:                 ->setAmount($r[9])
1303:                 ->setMethod($r[10])
1304:                 ->setTransactionType($r[11])
1305:                 ->setCustomerId($r[12])
1306:                 ->setMd5Hash($r[37])
1307:                 ->setCardCodeResponseCode($r[38])
1308:                 ->setCAVVResponseCode( (isset($r[39])) ? $r[39] : null)
1309:                 ->setSplitTenderId($r[52])
1310:                 ->setAccNumber($r[50])
1311:                 ->setCardType($r[51])
1312:                 ->setRequestedAmount($r[53])
1313:                 ->setBalanceOnCard($r[54])
1314:                 ;
1315:         }
1316:         else {
1317:              Mage::throwException(
1318:                 Mage::helper('paygate')->__('Error in payment gateway.')
1319:             );
1320:         }
1321: 
1322:         $debugData['result'] = $result->getData();
1323:         $this->_debug($debugData);
1324: 
1325:         return $result;
1326:     }
1327: 
1328:     /**
1329:      * Gateway response wrapper
1330:      *
1331:      * @param string $text
1332:      * @return string
1333:      */
1334:     protected function _wrapGatewayError($text)
1335:     {
1336:         return Mage::helper('paygate')->__('Gateway error: %s', $text);
1337:     }
1338: 
1339:     /**
1340:      * Retrieve session object
1341:      *
1342:      * @return Mage_Core_Model_Session_Abstract
1343:      */
1344:     protected function _getSession()
1345:     {
1346:         if (Mage::app()->getStore()->isAdmin()) {
1347:             return Mage::getSingleton('adminhtml/session_quote');
1348:         } else {
1349:             return Mage::getSingleton('checkout/session');
1350:         }
1351:     }
1352: 
1353:     /**
1354:      * It sets card`s data into additional information of payment model
1355:      *
1356:      * @param Mage_Paygate_Model_Authorizenet_Result $response
1357:      * @param Mage_Sales_Model_Order_Payment $payment
1358:      * @return Varien_Object
1359:      */
1360:     protected function _registerCard(Varien_Object $response, Mage_Sales_Model_Order_Payment $payment)
1361:     {
1362:         $cardsStorage = $this->getCardsStorage($payment);
1363:         $card = $cardsStorage->registerCard();
1364:         $card
1365:             ->setRequestedAmount($response->getRequestedAmount())
1366:             ->setBalanceOnCard($response->getBalanceOnCard())
1367:             ->setLastTransId($response->getTransactionId())
1368:             ->setProcessedAmount($response->getAmount())
1369:             ->setCcType($payment->getCcType())
1370:             ->setCcOwner($payment->getCcOwner())
1371:             ->setCcLast4($payment->getCcLast4())
1372:             ->setCcExpMonth($payment->getCcExpMonth())
1373:             ->setCcExpYear($payment->getCcExpYear())
1374:             ->setCcSsIssue($payment->getCcSsIssue())
1375:             ->setCcSsStartMonth($payment->getCcSsStartMonth())
1376:             ->setCcSsStartYear($payment->getCcSsStartYear());
1377: 
1378:         $cardsStorage->updateCard($card);
1379:         $this->_clearAssignedData($payment);
1380:         return $card;
1381:     }
1382: 
1383:     /**
1384:      * Reset assigned data in payment info model
1385:      *
1386:      * @param Mage_Payment_Model_Info
1387:      * @return Mage_Paygate_Model_Authorizenet
1388:      */
1389:     private function _clearAssignedData($payment)
1390:     {
1391:         $payment->setCcType(null)
1392:             ->setCcOwner(null)
1393:             ->setCcLast4(null)
1394:             ->setCcNumber(null)
1395:             ->setCcCid(null)
1396:             ->setCcExpMonth(null)
1397:             ->setCcExpYear(null)
1398:             ->setCcSsIssue(null)
1399:             ->setCcSsStartMonth(null)
1400:             ->setCcSsStartYear(null)
1401:             ;
1402:         return $this;
1403:     }
1404: 
1405:     /**
1406:      * Add payment transaction
1407:      *
1408:      * @param Mage_Sales_Model_Order_Payment $payment
1409:      * @param string $transactionId
1410:      * @param string $transactionType
1411:      * @param array $transactionDetails
1412:      * @param array $transactionAdditionalInfo
1413:      * @return null|Mage_Sales_Model_Order_Payment_Transaction
1414:      */
1415:     protected function _addTransaction(Mage_Sales_Model_Order_Payment $payment, $transactionId, $transactionType,
1416:         array $transactionDetails = array(), array $transactionAdditionalInfo = array(), $message = false
1417:     ) {
1418:         $payment->setTransactionId($transactionId);
1419:         $payment->resetTransactionAdditionalInfo();
1420:         foreach ($transactionDetails as $key => $value) {
1421:             $payment->setData($key, $value);
1422:         }
1423:         foreach ($transactionAdditionalInfo as $key => $value) {
1424:             $payment->setTransactionAdditionalInfo($key, $value);
1425:         }
1426:         $transaction = $payment->addTransaction($transactionType, null, false , $message);
1427:         foreach ($transactionDetails as $key => $value) {
1428:             $payment->unsetData($key);
1429:         }
1430:         $payment->unsLastTransId();
1431: 
1432:         /**
1433:          * It for self using
1434:          */
1435:         $transaction->setMessage($message);
1436: 
1437:         return $transaction;
1438:     }
1439: 
1440:     /**
1441:      * Round up and cast specified amount to float or string
1442:      *
1443:      * @param string|float $amount
1444:      * @param bool $asFloat
1445:      * @return string|float
1446:      */
1447:     protected function _formatAmount($amount, $asFloat = false)
1448:     {
1449:         $amount = sprintf('%.2F', $amount); // "f" depends on locale, "F" doesn't
1450:         return $asFloat ? (float)$amount : $amount;
1451:     }
1452: 
1453:     /**
1454:      * If gateway actions are locked return true
1455:      *
1456:      * @param  Mage_Payment_Model_Info $payment
1457:      * @return bool
1458:      */
1459:     protected function _isGatewayActionsLocked($payment)
1460:     {
1461:         return $payment->getAdditionalInformation($this->_isGatewayActionsLockedKey);
1462:     }
1463: 
1464:     /**
1465:      * Process exceptions for gateway action with a lot of transactions
1466:      *
1467:      * @param  Mage_Payment_Model_Info $payment
1468:      * @param  string $messages
1469:      * @param  bool $isSuccessfulTransactions
1470:      */
1471:     protected function _processFailureMultitransactionAction($payment, $messages, $isSuccessfulTransactions)
1472:     {
1473:         if ($isSuccessfulTransactions) {
1474:             $messages[] = Mage::helper('paygate')->__('Gateway actions are locked because the gateway cannot complete one or more of the transactions. Please log in to your Authorize.Net account to manually resolve the issue(s).');
1475:             /**
1476:              * If there is successful transactions we can not to cancel order but
1477:              * have to save information about processed transactions in order`s comments and disable
1478:              * opportunity to voiding\capturing\refunding in future. Current order and payment will not be saved because we have to
1479:              * load new order object and set information into this object.
1480:              */
1481:             $currentOrderId = $payment->getOrder()->getId();
1482:             $copyOrder = Mage::getModel('sales/order')->load($currentOrderId);
1483:             $copyOrder->getPayment()->setAdditionalInformation($this->_isGatewayActionsLockedKey, 1);
1484:             foreach($messages as $message) {
1485:                 $copyOrder->addStatusHistoryComment($message);
1486:             }
1487:             $copyOrder->save();
1488:         }
1489:         Mage::throwException(Mage::helper('paygate')->convertMessagesToMessage($messages));
1490:     }
1491: 
1492:     /**
1493:      * Generate checksum for object
1494:      *
1495:      * @param Varien_Object $object
1496:      * @param array $checkSumDataKeys
1497:      * @return string
1498:      */
1499:     protected function _generateChecksum(Varien_Object $object, $checkSumDataKeys = array())
1500:     {
1501:         $data = array();
1502:         foreach($checkSumDataKeys as $dataKey) {
1503:             $data[] = $dataKey;
1504:             $data[] = $object->getData($dataKey);
1505:         }
1506:         return md5(implode($data, '_'));
1507:     }
1508: 
1509:     /**
1510:      * This function returns full transaction details for a specified transaction ID.
1511:      *
1512:      * @link http://www.authorize.net/support/ReportingGuide_XML.pdf
1513:      * @link http://developer.authorize.net/api/transaction_details/
1514:      * @param string $transactionId
1515:      * @return Varien_Object
1516:      */
1517:     protected function _getTransactionDetails($transactionId)
1518:     {
1519:         $requestBody = sprintf(
1520:             '<?xml version="1.0" encoding="utf-8"?>'
1521:             . '<getTransactionDetailsRequest xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">'
1522:             . '<merchantAuthentication><name>%s</name><transactionKey>%s</transactionKey></merchantAuthentication>'
1523:             . '<transId>%s</transId>'
1524:             . '</getTransactionDetailsRequest>',
1525:             $this->getConfigData('login'),
1526:             $this->getConfigData('trans_key'),
1527:             $transactionId
1528:         );
1529: 
1530:         $client = new Varien_Http_Client();
1531:         $uri = $this->getConfigData('cgi_url_td');
1532:         $client->setUri($uri ? $uri : self::CGI_URL_TD);
1533:         $client->setConfig(array('timeout'=>45));
1534:         $client->setHeaders(array('Content-Type: text/xml'));
1535:         $client->setMethod(Zend_Http_Client::POST);
1536:         $client->setRawData($requestBody);
1537: 
1538:         $debugData = array('request' => $requestBody);
1539: 
1540:         try {
1541:             $responseBody = $client->request()->getBody();
1542:             $debugData['result'] = $responseBody;
1543:             $this->_debug($debugData);
1544:             libxml_use_internal_errors(true);
1545:             $responseXmlDocument = new Varien_Simplexml_Element($responseBody);
1546:             libxml_use_internal_errors(false);
1547:         } catch (Exception $e) {
1548:             Mage::throwException(Mage::helper('paygate')->__('Payment updating error.'));
1549:         }
1550: 
1551:         $response = new Varien_Object;
1552:         $response
1553:             ->setResponseCode((string)$responseXmlDocument->transaction->responseCode)
1554:             ->setResponseReasonCode((string)$responseXmlDocument->transaction->responseReasonCode)
1555:             ->setTransactionStatus((string)$responseXmlDocument->transaction->transactionStatus)
1556:         ;
1557:         return $response;
1558:     }
1559: }
1560: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0