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_Paypal_Adminhtml_Paypal_ReportsController
  • Mage_Paypal_Block_Adminhtml_Settlement_Details
  • Mage_Paypal_Block_Adminhtml_Settlement_Details_Form
  • Mage_Paypal_Block_Adminhtml_Settlement_Report
  • Mage_Paypal_Block_Adminhtml_Settlement_Report_Grid
  • Mage_Paypal_Block_Adminhtml_System_Config_ApiWizard
  • Mage_Paypal_Block_Adminhtml_System_Config_Field_Country
  • Mage_Paypal_Block_Adminhtml_System_Config_Field_Hidden
  • Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Expanded
  • Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Group
  • Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Hint
  • Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Location
  • Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Payment
  • Mage_Paypal_Block_Adminhtml_System_Config_Fieldset_Store
  • Mage_Paypal_Block_Adminhtml_System_Config_Payflowlink_Advanced
  • Mage_Paypal_Block_Adminhtml_System_Config_Payflowlink_Info
  • Mage_Paypal_Block_Express_Form
  • Mage_Paypal_Block_Express_Review
  • Mage_Paypal_Block_Express_Review_Billing
  • Mage_Paypal_Block_Express_Review_Details
  • Mage_Paypal_Block_Express_Review_Shipping
  • Mage_Paypal_Block_Express_Shortcut
  • Mage_Paypal_Block_Hosted_Pro_Form
  • Mage_Paypal_Block_Hosted_Pro_Iframe
  • Mage_Paypal_Block_Hosted_Pro_Info
  • Mage_Paypal_Block_Iframe
  • Mage_Paypal_Block_Logo
  • Mage_Paypal_Block_Payflow_Advanced_Form
  • Mage_Paypal_Block_Payflow_Advanced_Iframe
  • Mage_Paypal_Block_Payflow_Advanced_Info
  • Mage_Paypal_Block_Payflow_Link_Form
  • Mage_Paypal_Block_Payflow_Link_Iframe
  • Mage_Paypal_Block_Payflow_Link_Info
  • Mage_Paypal_Block_Payment_Info
  • Mage_Paypal_Block_Standard_Form
  • Mage_Paypal_Block_Standard_Redirect
  • Mage_Paypal_Controller_Express_Abstract
  • Mage_Paypal_ExpressController
  • Mage_Paypal_Helper_Data
  • Mage_Paypal_Helper_Hss
  • Mage_Paypal_HostedproController
  • Mage_Paypal_IpnController
  • Mage_Paypal_Model_Api_Abstract
  • Mage_Paypal_Model_Api_Nvp
  • Mage_Paypal_Model_Api_Standard
  • Mage_Paypal_Model_Cart
  • Mage_Paypal_Model_Cert
  • Mage_Paypal_Model_Config
  • Mage_Paypal_Model_Direct
  • Mage_Paypal_Model_Express
  • Mage_Paypal_Model_Express_Checkout
  • Mage_Paypal_Model_Hostedpro
  • Mage_Paypal_Model_Hostedpro_Request
  • Mage_Paypal_Model_Info
  • Mage_Paypal_Model_Ipn
  • Mage_Paypal_Model_Method_Agreement
  • Mage_Paypal_Model_Mysql4_Cert
  • Mage_Paypal_Model_Mysql4_Report_Settlement
  • Mage_Paypal_Model_Mysql4_Report_Settlement_Row
  • Mage_Paypal_Model_Mysql4_Report_Settlement_Row_Collection
  • Mage_Paypal_Model_Mysql4_Setup
  • Mage_Paypal_Model_Observer
  • Mage_Paypal_Model_Payflow_Request
  • Mage_Paypal_Model_Payflowadvanced
  • Mage_Paypal_Model_Payflowlink
  • Mage_Paypal_Model_Payflowpro
  • Mage_Paypal_Model_Payment_Transaction
  • Mage_Paypal_Model_Pro
  • Mage_Paypal_Model_Report_Settlement
  • Mage_Paypal_Model_Report_Settlement_Row
  • Mage_Paypal_Model_Resource_Cert
  • Mage_Paypal_Model_Resource_Report_Settlement
  • Mage_Paypal_Model_Resource_Report_Settlement_Row
  • Mage_Paypal_Model_Resource_Report_Settlement_Row_Collection
  • Mage_Paypal_Model_Resource_Setup
  • Mage_Paypal_Model_Session
  • Mage_Paypal_Model_Standard
  • Mage_Paypal_Model_System_Config_Backend_Cert
  • Mage_Paypal_Model_System_Config_Backend_Cron
  • Mage_Paypal_Model_System_Config_Backend_MerchantCountry
  • Mage_Paypal_Model_System_Config_Source_BuyerCountry
  • Mage_Paypal_Model_System_Config_Source_FetchingSchedule
  • Mage_Paypal_Model_System_Config_Source_Logo
  • Mage_Paypal_Model_System_Config_Source_MerchantCountry
  • Mage_Paypal_Model_System_Config_Source_PaymentActions
  • Mage_Paypal_Model_System_Config_Source_PaymentActions_Express
  • Mage_Paypal_Model_System_Config_Source_RequireBillingAddress
  • Mage_Paypal_Model_System_Config_Source_UrlMethod
  • Mage_Paypal_PayflowadvancedController
  • Mage_Paypal_PayflowController
  • Mage_Paypal_StandardController

Exceptions

  • Mage_Paypal_Exception
  • 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_Paypal
  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:  * NVP API wrappers model
  29:  * @TODO: move some parts to abstract, don't hesitate to throw exceptions on api calls
  30:  */
  31: class Mage_Paypal_Model_Api_Nvp extends Mage_Paypal_Model_Api_Abstract
  32: {
  33:     /**
  34:      * Paypal methods definition
  35:      */
  36:     const DO_DIRECT_PAYMENT = 'DoDirectPayment';
  37:     const DO_CAPTURE = 'DoCapture';
  38:     const DO_AUTHORIZATION = 'DoAuthorization';
  39:     const DO_VOID = 'DoVoid';
  40:     const REFUND_TRANSACTION = 'RefundTransaction';
  41:     const SET_EXPRESS_CHECKOUT = 'SetExpressCheckout';
  42:     const GET_EXPRESS_CHECKOUT_DETAILS = 'GetExpressCheckoutDetails';
  43:     const DO_EXPRESS_CHECKOUT_PAYMENT = 'DoExpressCheckoutPayment';
  44:     const CALLBACK_RESPONSE = 'CallbackResponse';
  45: 
  46:     /**
  47:      * Paypal ManagePendingTransactionStatus actions
  48:      */
  49:     const PENDING_TRANSACTION_ACCEPT = 'Accept';
  50:     const PENDING_TRANSACTION_DENY = 'Deny';
  51: 
  52:     /**
  53:      * Capture types (make authorization close or remain open)
  54:      * @var string
  55:      */
  56:     protected $_captureTypeComplete = 'Complete';
  57:     protected $_captureTypeNotcomplete = 'NotComplete';
  58: 
  59:     /**
  60:      * Global public interface map
  61:      * @var array
  62:      */
  63:     protected $_globalMap = array(
  64:         // each call
  65:         'VERSION'      => 'version',
  66:         'USER'         => 'api_username',
  67:         'PWD'          => 'api_password',
  68:         'SIGNATURE'    => 'api_signature',
  69:         'BUTTONSOURCE' => 'build_notation_code',
  70: 
  71:         // for Unilateral payments
  72:         'SUBJECT'      => 'business_account',
  73: 
  74:         // commands
  75:         'PAYMENTACTION' => 'payment_action',
  76:         'RETURNURL'     => 'return_url',
  77:         'CANCELURL'     => 'cancel_url',
  78:         'INVNUM'        => 'inv_num',
  79:         'TOKEN'         => 'token',
  80:         'CORRELATIONID' => 'correlation_id',
  81:         'SOLUTIONTYPE'  => 'solution_type',
  82:         'GIROPAYCANCELURL'  => 'giropay_cancel_url',
  83:         'GIROPAYSUCCESSURL' => 'giropay_success_url',
  84:         'BANKTXNPENDINGURL' => 'giropay_bank_txn_pending_url',
  85:         'IPADDRESS'         => 'ip_address',
  86:         'NOTIFYURL'         => 'notify_url',
  87:         'RETURNFMFDETAILS'  => 'fraud_management_filters_enabled',
  88:         'NOTE'              => 'note',
  89:         'REFUNDTYPE'        => 'refund_type',
  90:         'ACTION'            => 'action',
  91:         'REDIRECTREQUIRED'  => 'redirect_required',
  92:         'SUCCESSPAGEREDIRECTREQUESTED'  => 'redirect_requested',
  93:         'REQBILLINGADDRESS' => 'require_billing_address',
  94:         // style settings
  95:         'PAGESTYLE'      => 'page_style',
  96:         'HDRIMG'         => 'hdrimg',
  97:         'HDRBORDERCOLOR' => 'hdrbordercolor',
  98:         'HDRBACKCOLOR'   => 'hdrbackcolor',
  99:         'PAYFLOWCOLOR'   => 'payflowcolor',
 100:         'LOCALECODE'     => 'locale_code',
 101:         'PAL'            => 'pal',
 102: 
 103:         // transaction info
 104:         'TRANSACTIONID'   => 'transaction_id',
 105:         'AUTHORIZATIONID' => 'authorization_id',
 106:         'REFUNDTRANSACTIONID' => 'refund_transaction_id',
 107:         'COMPLETETYPE'    => 'complete_type',
 108:         'AMT' => 'amount',
 109:         'ITEMAMT' => 'subtotal_amount',
 110:         'GROSSREFUNDAMT' => 'refunded_amount', // possible mistake, check with API reference
 111: 
 112:         // payment/billing info
 113:         'CURRENCYCODE'  => 'currency_code',
 114:         'PAYMENTSTATUS' => 'payment_status',
 115:         'PENDINGREASON' => 'pending_reason',
 116:         'PROTECTIONELIGIBILITY' => 'protection_eligibility',
 117:         'PAYERID' => 'payer_id',
 118:         'PAYERSTATUS' => 'payer_status',
 119:         'ADDRESSID' => 'address_id',
 120:         'ADDRESSSTATUS' => 'address_status',
 121:         'EMAIL'         => 'email',
 122:             // backwards compatibility
 123:             'FIRSTNAME'     => 'firstname',
 124:             'LASTNAME'      => 'lastname',
 125: 
 126:         // shipping rate
 127:         'SHIPPINGOPTIONNAME' => 'shipping_rate_code',
 128:         'NOSHIPPING'         => 'suppress_shipping',
 129: 
 130:         // paypal direct credit card information
 131:         'CREDITCARDTYPE' => 'credit_card_type',
 132:         'ACCT'           => 'credit_card_number',
 133:         'EXPDATE'        => 'credit_card_expiration_date',
 134:         'CVV2'           => 'credit_card_cvv2',
 135:         'STARTDATE'      => 'maestro_solo_issue_date', // MMYYYY, always six chars, including leading zero
 136:         'ISSUENUMBER'    => 'maestro_solo_issue_number',
 137:         'CVV2MATCH'      => 'cvv2_check_result',
 138:         'AVSCODE'        => 'avs_result',
 139:         // cardinal centinel
 140:         'AUTHSTATUS3DS' => 'centinel_authstatus',
 141:         'MPIVENDOR3DS'  => 'centinel_mpivendor',
 142:         'CAVV'         => 'centinel_cavv',
 143:         'ECI3DS'       => 'centinel_eci',
 144:         'XID'          => 'centinel_xid',
 145:         'VPAS'         => 'centinel_vpas_result',
 146:         'ECISUBMITTED3DS' => 'centinel_eci_result',
 147: 
 148:         // recurring payment profiles
 149: //'TOKEN' => 'token',
 150:         'SUBSCRIBERNAME'    =>'subscriber_name',
 151:         'PROFILESTARTDATE'  => 'start_datetime',
 152:         'PROFILEREFERENCE'  => 'internal_reference_id',
 153:         'DESC'              => 'schedule_description',
 154:         'MAXFAILEDPAYMENTS' => 'suspension_threshold',
 155:         'AUTOBILLAMT'       => 'bill_failed_later',
 156:         'BILLINGPERIOD'     => 'period_unit',
 157:         'BILLINGFREQUENCY'    => 'period_frequency',
 158:         'TOTALBILLINGCYCLES'  => 'period_max_cycles',
 159: //'AMT' => 'billing_amount', // have to use 'amount', see above
 160:         'TRIALBILLINGPERIOD'      => 'trial_period_unit',
 161:         'TRIALBILLINGFREQUENCY'   => 'trial_period_frequency',
 162:         'TRIALTOTALBILLINGCYCLES' => 'trial_period_max_cycles',
 163:         'TRIALAMT'            => 'trial_billing_amount',
 164: // 'CURRENCYCODE' => 'currency_code',
 165:         'SHIPPINGAMT'         => 'shipping_amount',
 166:         'TAXAMT'              => 'tax_amount',
 167:         'INITAMT'             => 'init_amount',
 168:         'FAILEDINITAMTACTION' => 'init_may_fail',
 169:         'PROFILEID'           => 'recurring_profile_id',
 170:         'PROFILESTATUS'       => 'recurring_profile_status',
 171:         'STATUS'              => 'status',
 172: 
 173:         //Next two fields are used for Brazil only
 174:         'TAXID'               => 'buyer_tax_id',
 175:         'TAXIDTYPE'           => 'buyer_tax_id_type',
 176: 
 177:         'BILLINGAGREEMENTID' => 'billing_agreement_id',
 178:         'REFERENCEID' => 'reference_id',
 179:         'BILLINGAGREEMENTSTATUS' => 'billing_agreement_status',
 180:         'BILLINGTYPE' => 'billing_type',
 181:         'SREET' => 'street',
 182:         'CITY' => 'city',
 183:         'STATE' => 'state',
 184:         'COUNTRYCODE' => 'countrycode',
 185:         'ZIP' => 'zip',
 186:         'PAYERBUSINESS' => 'payer_business',
 187:     );
 188: 
 189:     /**
 190:      * Filter callbacks for preparing internal amounts to NVP request
 191:      *
 192:      * @var array
 193:      */
 194:     protected $_exportToRequestFilters = array(
 195:         'AMT'         => '_filterAmount',
 196:         'ITEMAMT'     => '_filterAmount',
 197:         'TRIALAMT'    => '_filterAmount',
 198:         'SHIPPINGAMT' => '_filterAmount',
 199:         'TAXAMT'      => '_filterAmount',
 200:         'INITAMT'     => '_filterAmount',
 201:         'CREDITCARDTYPE' => '_filterCcType',
 202: //        'PROFILESTARTDATE' => '_filterToPaypalDate',
 203:         'AUTOBILLAMT' => '_filterBillFailedLater',
 204:         'BILLINGPERIOD' => '_filterPeriodUnit',
 205:         'TRIALBILLINGPERIOD' => '_filterPeriodUnit',
 206:         'FAILEDINITAMTACTION' => '_filterInitialAmountMayFail',
 207:         'BILLINGAGREEMENTSTATUS' => '_filterBillingAgreementStatus',
 208:         'NOSHIPPING' => '_filterInt',
 209:     );
 210: 
 211:     protected $_importFromRequestFilters = array(
 212:         'REDIRECTREQUIRED'  => '_filterToBool',
 213:         'SUCCESSPAGEREDIRECTREQUESTED'  => '_filterToBool',
 214:         'PAYMENTSTATUS' => '_filterPaymentStatusFromNvpToInfo',
 215:     );
 216: 
 217:     /**
 218:      * Request map for each API call
 219:      * @var array
 220:      */
 221:     protected $_eachCallRequest = array('VERSION', 'USER', 'PWD', 'SIGNATURE', 'BUTTONSOURCE',);
 222: 
 223:     /**
 224:      * SetExpressCheckout request/response map
 225:      * @var array
 226:      */
 227:     protected $_setExpressCheckoutRequest = array(
 228:         'PAYMENTACTION', 'AMT', 'CURRENCYCODE', 'RETURNURL', 'CANCELURL', 'INVNUM', 'SOLUTIONTYPE', 'NOSHIPPING',
 229:         'GIROPAYCANCELURL', 'GIROPAYSUCCESSURL', 'BANKTXNPENDINGURL',
 230:         'PAGESTYLE', 'HDRIMG', 'HDRBORDERCOLOR', 'HDRBACKCOLOR', 'PAYFLOWCOLOR', 'LOCALECODE',
 231:         'BILLINGTYPE', 'SUBJECT', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT', 'REQBILLINGADDRESS',
 232:     );
 233:     protected $_setExpressCheckoutResponse = array('TOKEN');
 234: 
 235:     /**
 236:      * GetExpressCheckoutDetails request/response map
 237:      * @var array
 238:      */
 239:     protected $_getExpressCheckoutDetailsRequest = array('TOKEN', 'SUBJECT',);
 240: 
 241:     /**
 242:      * DoExpressCheckoutPayment request/response map
 243:      * @var array
 244:      */
 245:     protected $_doExpressCheckoutPaymentRequest = array(
 246:         'TOKEN', 'PAYERID', 'PAYMENTACTION', 'AMT', 'CURRENCYCODE', 'IPADDRESS', 'BUTTONSOURCE', 'NOTIFYURL',
 247:         'RETURNFMFDETAILS', 'SUBJECT', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT',
 248:     );
 249:     protected $_doExpressCheckoutPaymentResponse = array(
 250:         'TRANSACTIONID', 'AMT', 'PAYMENTSTATUS', 'PENDINGREASON', 'REDIRECTREQUIRED'
 251:     );
 252: 
 253:     /**
 254:      * DoDirectPayment request/response map
 255:      * @var array
 256:      */
 257:     protected $_doDirectPaymentRequest = array(
 258:         'PAYMENTACTION', 'IPADDRESS', 'RETURNFMFDETAILS',
 259:         'AMT', 'CURRENCYCODE', 'INVNUM', 'NOTIFYURL', 'EMAIL', 'ITEMAMT', 'SHIPPINGAMT', 'TAXAMT',
 260:         'CREDITCARDTYPE', 'ACCT', 'EXPDATE', 'CVV2', 'STARTDATE', 'ISSUENUMBER',
 261:         'AUTHSTATUS3DS', 'MPIVENDOR3DS', 'CAVV', 'ECI3DS', 'XID',
 262:     );
 263:     protected $_doDirectPaymentResponse = array(
 264:         'TRANSACTIONID', 'AMT', 'AVSCODE', 'CVV2MATCH', 'VPAS', 'ECISUBMITTED3DS'
 265:     );
 266: 
 267:     /**
 268:      * DoReauthorization request/response map
 269:      * @var array
 270:      */
 271:     protected $_doReauthorizationRequest = array('AUTHORIZATIONID', 'AMT', 'CURRENCYCODE');
 272:     protected $_doReauthorizationResponse = array(
 273:         'AUTHORIZATIONID', 'PAYMENTSTATUS', 'PENDINGREASON', 'PROTECTIONELIGIBILITY'
 274:     );
 275: 
 276:     /**
 277:      * DoCapture request/response map
 278:      * @var array
 279:      */
 280:     protected $_doCaptureRequest = array('AUTHORIZATIONID', 'COMPLETETYPE', 'AMT', 'CURRENCYCODE', 'NOTE', 'INVNUM',);
 281:     protected $_doCaptureResponse = array('TRANSACTIONID', 'CURRENCYCODE', 'AMT', 'PAYMENTSTATUS', 'PENDINGREASON',);
 282: 
 283: 
 284:     /**
 285:      * DoAuthorization request/response map
 286:      * @var array
 287:      */
 288:     protected $_doAuthorizationRequest = array('TRANSACTIONID', 'AMT', 'CURRENCYCODE');
 289:     protected $_doAuthorizationResponse = array('TRANSACTIONID', 'AMT');
 290: 
 291:     /**
 292:      * DoVoid request map
 293:      * @var array
 294:      */
 295:     protected $_doVoidRequest = array('AUTHORIZATIONID', 'NOTE',);
 296: 
 297:     /**
 298:      * GetTransactionDetailsRequest
 299:      * @var array
 300:      */
 301:     protected $_getTransactionDetailsRequest = array('TRANSACTIONID');
 302:     protected $_getTransactionDetailsResponse = array(
 303:         'PAYERID', 'FIRSTNAME', 'LASTNAME', 'TRANSACTIONID', 'PARENTTRANSACTIONID', 'CURRENCYCODE', 'AMT',
 304:         'PAYMENTSTATUS', 'PENDINGREASON',
 305:     );
 306: 
 307:     /**
 308:      * RefundTransaction request/response map
 309:      * @var array
 310:      */
 311:     protected $_refundTransactionRequest = array('TRANSACTIONID', 'REFUNDTYPE', 'CURRENCYCODE', 'NOTE',);
 312:     protected $_refundTransactionResponse = array('REFUNDTRANSACTIONID', 'GROSSREFUNDAMT',);
 313: 
 314:     /**
 315:      * ManagePendingTransactionStatus request/response map
 316:      */
 317:     protected $_managePendingTransactionStatusRequest = array('TRANSACTIONID', 'ACTION');
 318:     protected $_managePendingTransactionStatusResponse = array('TRANSACTIONID', 'STATUS');
 319: 
 320:     /**
 321:      * GetPalDetails response map
 322:      * @var array
 323:      */
 324:     protected $_getPalDetailsResponse = array('PAL');
 325: 
 326:     /**
 327:      * CreateRecurringPaymentsProfile request/response map
 328:      *
 329:      * @var array
 330:      */
 331:     protected $_createRecurringPaymentsProfileRequest = array(
 332:         'TOKEN', 'SUBSCRIBERNAME', 'PROFILESTARTDATE', 'PROFILEREFERENCE', 'DESC', 'MAXFAILEDPAYMENTS', 'AUTOBILLAMT',
 333:         'BILLINGPERIOD', 'BILLINGFREQUENCY', 'TOTALBILLINGCYCLES', 'AMT', 'TRIALBILLINGPERIOD', 'TRIALBILLINGFREQUENCY',
 334:         'TRIALTOTALBILLINGCYCLES', 'TRIALAMT', 'CURRENCYCODE', 'SHIPPINGAMT', 'TAXAMT', 'INITAMT', 'FAILEDINITAMTACTION'
 335:     );
 336:     protected $_createRecurringPaymentsProfileResponse = array(
 337:         'PROFILEID', 'PROFILESTATUS'
 338:     );
 339: 
 340:     /**
 341:      * Request/response for ManageRecurringPaymentsProfileStatus map
 342:      *
 343:      * @var array
 344:      */
 345:     protected $_manageRecurringPaymentsProfileStatusRequest = array('PROFILEID', 'ACTION');
 346: //    protected $_manageRecurringPaymentsProfileStatusResponse = array('PROFILEID');
 347: 
 348:     /**
 349:      * Request/response for GetRecurringPaymentsProfileDetails
 350:      *
 351:      * @var array
 352:      */
 353:     protected $_getRecurringPaymentsProfileDetailsRequest = array('PROFILEID');
 354:     protected $_getRecurringPaymentsProfileDetailsResponse = array('STATUS', /* TODO: lot of other stuff */);
 355: 
 356:     /**
 357:      * Map for billing address import/export
 358:      * @var array
 359:      */
 360:     protected $_billingAddressMap = array (
 361:         'BUSINESS' => 'company',
 362:         'NOTETEXT' => 'customer_notes',
 363:         'EMAIL' => 'email',
 364:         'FIRSTNAME' => 'firstname',
 365:         'LASTNAME' => 'lastname',
 366:         'MIDDLENAME' => 'middlename',
 367:         'SALUTATION' => 'prefix',
 368:         'SUFFIX' => 'suffix',
 369: 
 370:         'COUNTRYCODE' => 'country_id', // iso-3166 two-character code
 371:         'STATE'    => 'region',
 372:         'CITY'     => 'city',
 373:         'STREET'   => 'street',
 374:         'STREET2'  => 'street2',
 375:         'ZIP'      => 'postcode',
 376:         'PHONENUM' => 'telephone',
 377:     );
 378: 
 379:     /**
 380:      * Map for billing address to do request (not response)
 381:      * Merging with $_billingAddressMap
 382:      *
 383:      * @var array
 384:      */
 385:     protected $_billingAddressMapRequest = array ();
 386: 
 387:     /**
 388:      * Map for shipping address import/export (extends billing address mapper)
 389:      * @var array
 390:      */
 391:     protected $_shippingAddressMap = array(
 392:         'SHIPTOCOUNTRYCODE' => 'country_id',
 393:         'SHIPTOSTATE' => 'region',
 394:         'SHIPTOCITY'    => 'city',
 395:         'SHIPTOSTREET'  => 'street',
 396:         'SHIPTOSTREET2' => 'street2',
 397:         'SHIPTOZIP' => 'postcode',
 398:         'SHIPTOPHONENUM' => 'telephone',
 399:         // 'SHIPTONAME' will be treated manually in address import/export methods
 400:     );
 401: 
 402:     /**
 403:      * Map for callback request
 404:      * @var array
 405:      */
 406:     protected $_callbackRequestMap = array(
 407:         'SHIPTOCOUNTRY' => 'country_id',
 408:         'SHIPTOSTATE' => 'region',
 409:         'SHIPTOCITY'    => 'city',
 410:         'SHIPTOSTREET'  => 'street',
 411:         'SHIPTOSTREET2' => 'street2',
 412:         'SHIPTOZIP' => 'postcode'
 413:     );
 414: 
 415:     /**
 416:      * Payment information response specifically to be collected after some requests
 417:      * @var array
 418:      */
 419:     protected $_paymentInformationResponse = array(
 420:         'PAYERID', 'PAYERSTATUS', 'CORRELATIONID', 'ADDRESSID', 'ADDRESSSTATUS',
 421:         'PAYMENTSTATUS', 'PENDINGREASON', 'PROTECTIONELIGIBILITY', 'EMAIL', 'SHIPPINGOPTIONNAME', 'TAXID', 'TAXIDTYPE'
 422:     );
 423: 
 424:     /**
 425:      * Line items export mapping settings
 426:      * @var array
 427:      */
 428:     protected $_lineItemTotalExportMap = array(
 429:         Mage_Paypal_Model_Cart::TOTAL_SUBTOTAL => 'ITEMAMT',
 430:         Mage_Paypal_Model_Cart::TOTAL_TAX      => 'TAXAMT',
 431:         Mage_Paypal_Model_Cart::TOTAL_SHIPPING => 'SHIPPINGAMT',
 432:     );
 433:     protected $_lineItemExportItemsFormat = array(
 434:         'id'     => 'L_NUMBER%d',
 435:         'name'   => 'L_NAME%d',
 436:         'qty'    => 'L_QTY%d',
 437:         'amount' => 'L_AMT%d',
 438:     );
 439: 
 440:     /**
 441:      * Shipping options export to request mapping settings
 442:      * @var array
 443:      */
 444:     protected $_shippingOptionsExportItemsFormat = array(
 445:         'is_default' => 'L_SHIPPINGOPTIONISDEFAULT%d',
 446:         'amount'     => 'L_SHIPPINGOPTIONAMOUNT%d',
 447:         'code'       => 'L_SHIPPINGOPTIONNAME%d',
 448:         'name'       => 'L_SHIPPINGOPTIONLABEL%d',
 449:         'tax_amount' => 'L_TAXAMT%d',
 450:     );
 451: 
 452:     /**
 453:      * init Billing Agreement request/response map
 454:      * @var array
 455:      */
 456:     protected $_customerBillingAgreementRequest = array('RETURNURL', 'CANCELURL', 'BILLINGTYPE');
 457:     protected $_customerBillingAgreementResponse = array('TOKEN');
 458: 
 459:     /**
 460:      * Billing Agreement details request/response map
 461:      * @var array
 462:      */
 463:     protected $_billingAgreementCustomerDetailsRequest = array('TOKEN');
 464:     protected $_billingAgreementCustomerDetailsResponse = array('EMAIL', 'PAYERID', 'PAYERSTATUS', 'SHIPTOCOUNTRYCODE',
 465:         'PAYERBUSINESS'
 466:     );
 467: 
 468:     /**
 469:      * Create Billing Agreement request/response map
 470:      * @var array
 471:      */
 472:     protected $_createBillingAgreementRequest = array('TOKEN');
 473:     protected $_createBillingAgreementResponse = array('BILLINGAGREEMENTID');
 474: 
 475:     /**
 476:      * Update Billing Agreement request/response map
 477:      * @var array
 478:      */
 479:     protected $_updateBillingAgreementRequest = array(
 480:         'REFERENCEID', 'BILLINGAGREEMENTDESCRIPTION', 'BILLINGAGREEMENTSTATUS', 'BILLINGAGREEMENTCUSTOM'
 481:     );
 482:     protected $_updateBillingAgreementResponse = array(
 483:         'REFERENCEID', 'BILLINGAGREEMENTDESCRIPTION', 'BILLINGAGREEMENTSTATUS', 'BILLINGAGREEMENTCUSTOM'
 484:     );
 485: 
 486:     /**
 487:      * Do Reference Transaction request/response map
 488:      *
 489:      * @var array
 490:      */
 491:     protected $_doReferenceTransactionRequest = array('REFERENCEID', 'PAYMENTACTION', 'AMT', 'ITEMAMT', 'SHIPPINGAMT',
 492:         'TAXAMT', 'INVNUM', 'NOTIFYURL'
 493:     );
 494: 
 495:     protected $_doReferenceTransactionResponse = array('BILLINGAGREEMENTID', 'TRANSACTIONID');
 496: 
 497:     /**
 498:      * Fields that should be replaced in debug with '***'
 499:      *
 500:      * @var array
 501:      */
 502:     protected $_debugReplacePrivateDataKeys = array(
 503: 
 504:         'ACCT', 'EXPDATE', 'CVV2', 'CARDISSUE', 'CARDSTART', 'CREDITCARDTYPE', 'USER', 'PWD', 'SIGNATURE'
 505: 
 506:     );
 507: 
 508:     /**
 509:      * Map of credit card types supported by this API
 510:      * @var array
 511:      */
 512:     protected $_supportedCcTypes = array(
 513:         'VI' => 'Visa', 'MC' => 'MasterCard', 'DI' => 'Discover', 'AE' => 'Amex', 'SM' => 'Maestro', 'SO' => 'Solo');
 514: 
 515:     /**
 516:      * Required fields in the response
 517:      *
 518:      * @var array
 519:      */
 520:     protected $_requiredResponseParams = array(
 521:         self::DO_DIRECT_PAYMENT => array('ACK', 'CORRELATIONID', 'AMT')
 522:     );
 523: 
 524:     /**
 525:      * Warning codes recollected after each API call
 526:      *
 527:      * @var array
 528:      */
 529:     protected $_callWarnings = array();
 530: 
 531:     /**
 532:      * Error codes recollected after each API call
 533:      *
 534:      * @var array
 535:      */
 536:     protected $_callErrors = array();
 537: 
 538:     /**
 539:      * Whether to return raw response information after each call
 540:      *
 541:      * @var bool
 542:      */
 543:     protected $_rawResponseNeeded = false;
 544: 
 545:     /**
 546:      * API endpoint getter
 547:      *
 548:      * @return string
 549:      */
 550:     public function getApiEndpoint()
 551:     {
 552:         $url = $this->getUseCertAuthentication() ? 'https://api%s.paypal.com/nvp' : 'https://api-3t%s.paypal.com/nvp';
 553:         return sprintf($url, $this->_config->sandboxFlag ? '.sandbox' : '');
 554:     }
 555: 
 556:     /**
 557:      * Return Paypal Api version
 558:      *
 559:      * @return string
 560:      */
 561:     public function getVersion()
 562:     {
 563:         return '72.0';
 564:     }
 565: 
 566:     /**
 567:      * Retrieve billing agreement type
 568:      *
 569:      * @return string
 570:      */
 571:     public function getBillingAgreementType()
 572:     {
 573:         return 'MerchantInitiatedBilling';
 574:     }
 575: 
 576:     /**
 577:      * SetExpressCheckout call
 578:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_SetExpressCheckout
 579:      * TODO: put together style and giropay settings
 580:      */
 581:     public function callSetExpressCheckout()
 582:     {
 583:         $this->_prepareExpressCheckoutCallRequest($this->_setExpressCheckoutRequest);
 584:         $request = $this->_exportToRequest($this->_setExpressCheckoutRequest);
 585:         $this->_exportLineItems($request);
 586: 
 587:         // import/suppress shipping address, if any
 588:         $options = $this->getShippingOptions();
 589:         if ($this->getAddress()) {
 590:             $request = $this->_importAddresses($request);
 591:             $request['ADDROVERRIDE'] = 1;
 592:         } elseif ($options && (count($options) <= 10)) { // doesn't support more than 10 shipping options
 593:             $request['CALLBACK'] = $this->getShippingOptionsCallbackUrl();
 594:             $request['CALLBACKTIMEOUT'] = 6; // max value
 595:             $request['MAXAMT'] = $request['AMT'] + 999.00; // it is impossible to calculate max amount
 596:             $this->_exportShippingOptions($request);
 597:         }
 598: 
 599:         // add recurring profiles information
 600:         $i = 0;
 601:         foreach ($this->_recurringPaymentProfiles as $profile) {
 602:             $request["L_BILLINGTYPE{$i}"] = 'RecurringPayments';
 603:             $request["L_BILLINGAGREEMENTDESCRIPTION{$i}"] = $profile->getScheduleDescription();
 604:             $i++;
 605:         }
 606: 
 607:         $response = $this->call(self::SET_EXPRESS_CHECKOUT, $request);
 608:         $this->_importFromResponse($this->_setExpressCheckoutResponse, $response);
 609:     }
 610: 
 611:     /**
 612:      * GetExpressCheckoutDetails call
 613:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_GetExpressCheckoutDetails
 614:      */
 615:     function callGetExpressCheckoutDetails()
 616:     {
 617:         $this->_prepareExpressCheckoutCallRequest($this->_getExpressCheckoutDetailsRequest);
 618:         $request = $this->_exportToRequest($this->_getExpressCheckoutDetailsRequest);
 619:         $response = $this->call(self::GET_EXPRESS_CHECKOUT_DETAILS, $request);
 620:         $this->_importFromResponse($this->_paymentInformationResponse, $response);
 621:         $this->_exportAddressses($response);
 622:     }
 623: 
 624:     /**
 625:      * DoExpressCheckout call
 626:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoExpressCheckoutPayment
 627:      */
 628:     public function callDoExpressCheckoutPayment()
 629:     {
 630:         $this->_prepareExpressCheckoutCallRequest($this->_doExpressCheckoutPaymentRequest);
 631:         $request = $this->_exportToRequest($this->_doExpressCheckoutPaymentRequest);
 632:         $this->_exportLineItems($request);
 633: 
 634:         if ($this->getAddress()) {
 635:             $request = $this->_importAddresses($request);
 636:             $request['ADDROVERRIDE'] = 1;
 637:         }
 638: 
 639:         $response = $this->call(self::DO_EXPRESS_CHECKOUT_PAYMENT, $request);
 640:         $this->_importFromResponse($this->_paymentInformationResponse, $response);
 641:         $this->_importFromResponse($this->_doExpressCheckoutPaymentResponse, $response);
 642:         $this->_importFromResponse($this->_createBillingAgreementResponse, $response);
 643:     }
 644: 
 645:     /**
 646:      * Process a credit card payment
 647:      */
 648:     public function callDoDirectPayment()
 649:     {
 650:         $request = $this->_exportToRequest($this->_doDirectPaymentRequest);
 651:         $this->_exportLineItems($request);
 652:         if ($this->getAddress()) {
 653:             $request = $this->_importAddresses($request);
 654:         }
 655:         $response = $this->call(self::DO_DIRECT_PAYMENT, $request);
 656:         $this->_importFromResponse($this->_doDirectPaymentResponse, $response);
 657:     }
 658: 
 659:     /**
 660:      * Do Reference Transaction call
 661:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoReferenceTransaction
 662:      */
 663:     public function callDoReferenceTransaction()
 664:     {
 665:         $request = $this->_exportToRequest($this->_doReferenceTransactionRequest);
 666:         $this->_exportLineItems($request);
 667:         $response = $this->call('DoReferenceTransaction', $request);
 668:         $this->_importFromResponse($this->_doReferenceTransactionResponse, $response);
 669:     }
 670: 
 671:     /**
 672:      * Check whether the last call was returned with fraud warning
 673:      *
 674:      * @return bool
 675:      */
 676:     public function getIsFraudDetected()
 677:     {
 678:         return in_array(11610, $this->_callWarnings);
 679:     }
 680: 
 681:     /**
 682:      * Made additional request to paypal to get autharization id
 683:      */
 684:     public function callDoReauthorization()
 685:     {
 686:         $request = $this->_export($this->_doReauthorizationRequest);
 687:         $response = $this->call('DoReauthorization', $request);
 688:         $this->_import($response, $this->_doReauthorizationResponse);
 689:     }
 690: 
 691:     /**
 692:      * DoCapture call
 693:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoCapture
 694:      */
 695:     public function callDoCapture()
 696:     {
 697:         $this->setCompleteType($this->_getCaptureCompleteType());
 698:         $request = $this->_exportToRequest($this->_doCaptureRequest);
 699:         $response = $this->call(self::DO_CAPTURE, $request);
 700:         $this->_importFromResponse($this->_paymentInformationResponse, $response);
 701:         $this->_importFromResponse($this->_doCaptureResponse, $response);
 702:     }
 703: 
 704:     /**
 705:      * DoAuthorization call
 706:      *
 707:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoAuthorization
 708:      * @return Mage_Paypal_Model_Api_Nvp
 709:      */
 710:     public function callDoAuthorization()
 711:     {
 712:         $request = $this->_exportToRequest($this->_doAuthorizationRequest);
 713:         $response = $this->call(self::DO_AUTHORIZATION, $request);
 714:         $this->_importFromResponse($this->_paymentInformationResponse, $response);
 715:         $this->_importFromResponse($this->_doAuthorizationResponse, $response);
 716: 
 717:         return $this;
 718:     }
 719: 
 720: 
 721:     /**
 722:      * DoVoid call
 723:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_DoVoid
 724:      */
 725:     public function callDoVoid()
 726:     {
 727:         $request = $this->_exportToRequest($this->_doVoidRequest);
 728:         $this->call(self::DO_VOID, $request);
 729:     }
 730: 
 731:     /**
 732:      * GetTransactionDetails
 733:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_GetTransactionDetails
 734:      */
 735:     public function callGetTransactionDetails()
 736:     {
 737:         $request = $this->_exportToRequest($this->_getTransactionDetailsRequest);
 738:         $response = $this->call('GetTransactionDetails', $request);
 739:         $this->_importFromResponse($this->_getTransactionDetailsResponse, $response);
 740:     }
 741: 
 742:     /**
 743:      * RefundTransaction call
 744:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_RefundTransaction
 745:      */
 746:     public function callRefundTransaction()
 747:     {
 748:         $request = $this->_exportToRequest($this->_refundTransactionRequest);
 749:         if ($this->getRefundType() === Mage_Paypal_Model_Config::REFUND_TYPE_PARTIAL) {
 750:             $request['AMT'] = $this->getAmount();
 751:         }
 752:         $response = $this->call(self::REFUND_TRANSACTION, $request);
 753:         $this->_importFromResponse($this->_refundTransactionResponse, $response);
 754:     }
 755: 
 756:     /**
 757:      * ManagePendingTransactionStatus
 758:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_ManagePendingTransactionStatus
 759:      */
 760:     public function callManagePendingTransactionStatus()
 761:     {
 762:         $request = $this->_exportToRequest($this->_managePendingTransactionStatusRequest);
 763:         if (isset($request['ACTION'])) {
 764:             $request['ACTION'] = $this->_filterPaymentReviewAction($request['ACTION']);
 765:         }
 766:         $response = $this->call('ManagePendingTransactionStatus', $request);
 767:         $this->_importFromResponse($this->_managePendingTransactionStatusResponse, $response);
 768:     }
 769: 
 770:     /**
 771:      * getPalDetails call
 772:      * @link https://www.x.com/docs/DOC-1300
 773:      * @link https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECButtonIntegration
 774:      */
 775:     public function callGetPalDetails()
 776:     {
 777:         $response = $this->call('getPalDetails', array());
 778:         $this->_importFromResponse($this->_getPalDetailsResponse, $response);
 779:     }
 780: 
 781:     /**
 782:      * Set Customer BillingA greement call
 783:      *
 784:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_SetCustomerBillingAgreement
 785:      */
 786:     public function callSetCustomerBillingAgreement()
 787:     {
 788:         $request = $this->_exportToRequest($this->_customerBillingAgreementRequest);
 789:         $response = $this->call('SetCustomerBillingAgreement', $request);
 790:         $this->_importFromResponse($this->_customerBillingAgreementResponse, $response);
 791:     }
 792: 
 793:     /**
 794:      * Get Billing Agreement Customer Details call
 795:      *
 796:      * @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_GetBillingAgreementCustomerDetails
 797:      */
 798:     public function callGetBillingAgreementCustomerDetails()
 799:     {
 800:         $request = $this->_exportToRequest($this->_billingAgreementCustomerDetailsRequest);
 801:         $response = $this->call('GetBillingAgreementCustomerDetails', $request);
 802:         $this->_importFromResponse($this->_billingAgreementCustomerDetailsResponse, $response);
 803:     }
 804: 
 805:     /**
 806:      * Create Billing Agreement call
 807:      *
 808:      */
 809:     public function callCreateBillingAgreement()
 810:     {
 811:         $request = $this->_exportToRequest($this->_createBillingAgreementRequest);
 812:         $response = $this->call('CreateBillingAgreement', $request);
 813:         $this->_importFromResponse($this->_createBillingAgreementResponse, $response);
 814:     }
 815: 
 816:     /**
 817:      * Billing Agreement Update call
 818:      *
 819:      */
 820:     public function callUpdateBillingAgreement()
 821:     {
 822:         $request = $this->_exportToRequest($this->_updateBillingAgreementRequest);
 823:         try {
 824:         $response = $this->call('BillAgreementUpdate', $request);
 825:         } catch (Mage_Core_Exception $e) {
 826:             if (in_array(10201, $this->_callErrors)) {
 827:                 $this->setIsBillingAgreementAlreadyCancelled(true);
 828:             }
 829:             throw $e;
 830:         }
 831:         $this->_importFromResponse($this->_updateBillingAgreementResponse, $response);
 832:     }
 833: 
 834:     /**
 835:      * CreateRecurringPaymentsProfile call
 836:      */
 837:     public function callCreateRecurringPaymentsProfile()
 838:     {
 839:         $request = $this->_exportToRequest($this->_createRecurringPaymentsProfileRequest);
 840:         $response = $this->call('CreateRecurringPaymentsProfile', $request);
 841:         $this->_importFromResponse($this->_createRecurringPaymentsProfileResponse, $response);
 842:         $this->_analyzeRecurringProfileStatus($this->getRecurringProfileStatus(), $this);
 843:     }
 844: 
 845:     /**
 846:      * ManageRecurringPaymentsProfileStatus call
 847:      */
 848:     public function callManageRecurringPaymentsProfileStatus()
 849:     {
 850:         $request = $this->_exportToRequest($this->_manageRecurringPaymentsProfileStatusRequest);
 851:         if (isset($request['ACTION'])) {
 852:             $request['ACTION'] = $this->_filterRecurringProfileActionToNvp($request['ACTION']);
 853:         }
 854:         try {
 855:             $response = $this->call('ManageRecurringPaymentsProfileStatus', $request);
 856:         } catch (Mage_Core_Exception $e) {
 857:             if ((in_array(11556, $this->_callErrors) && 'Cancel' === $request['ACTION'])
 858:                 || (in_array(11557, $this->_callErrors) && 'Suspend' === $request['ACTION'])
 859:                 || (in_array(11558, $this->_callErrors) && 'Reactivate' === $request['ACTION'])
 860:             ) {
 861:                 Mage::throwException(Mage::helper('paypal')->__('Unable to change status. Current status is not correspond to real status.'));
 862:             }
 863:             throw $e;
 864:         }
 865:     }
 866: 
 867:     /**
 868:      * GetRecurringPaymentsProfileDetails call
 869:      */
 870:     public function callGetRecurringPaymentsProfileDetails(Varien_Object $result)
 871:     {
 872:         $request = $this->_exportToRequest($this->_getRecurringPaymentsProfileDetailsRequest);
 873:         $response = $this->call('GetRecurringPaymentsProfileDetails', $request);
 874:         $this->_importFromResponse($this->_getRecurringPaymentsProfileDetailsResponse, $response);
 875:         $this->_analyzeRecurringProfileStatus($this->getStatus(), $result);
 876:     }
 877: 
 878:     /**
 879:      * Import callback request array into $this public data
 880:      *
 881:      * @param array $request
 882:      * @return Varien_Object
 883:      */
 884:     public function prepareShippingOptionsCallbackAddress(array $request)
 885:     {
 886:         $address = new Varien_Object();
 887:         Varien_Object_Mapper::accumulateByMap($request, $address, $this->_callbackRequestMap);
 888:         $address->setExportedKeys(array_values($this->_callbackRequestMap));
 889:         $this->_applyStreetAndRegionWorkarounds($address);
 890:         return $address;
 891:     }
 892: 
 893:     /**
 894:      * Prepare response for shipping options callback
 895:      *
 896:      * @return string
 897:      */
 898:     public function formatShippingOptionsCallback()
 899:     {
 900:         $response = array();
 901:         if (!$this->_exportShippingOptions($response)) {
 902:             $response['NO_SHIPPING_OPTION_DETAILS'] = '1';
 903:         }
 904:         $response = $this->_addMethodToRequest(self::CALLBACK_RESPONSE, $response);
 905:         return $this->_buildQuery($response);
 906:     }
 907: 
 908:     /**
 909:      * Add method to request array
 910:      *
 911:      * @param string $methodName
 912:      * @param array $request
 913:      * @return array
 914:      */
 915:     protected function _addMethodToRequest($methodName, $request)
 916:     {
 917:         $request['METHOD'] = $methodName;
 918:         return $request;
 919:     }
 920: 
 921:     /**
 922:      * Do the API call
 923:      *
 924:      * @param string $methodName
 925:      * @param array $request
 926:      * @return array
 927:      * @throws Mage_Core_Exception
 928:      */
 929:     public function call($methodName, array $request)
 930:     {
 931:         $request = $this->_addMethodToRequest($methodName, $request);
 932:         $eachCallRequest = $this->_prepareEachCallRequest($methodName);
 933:         if ($this->getUseCertAuthentication()) {
 934:             if ($key = array_search('SIGNATURE', $eachCallRequest)) {
 935:                 unset($eachCallRequest[$key]);
 936:             }
 937:         }
 938:         $request = $this->_exportToRequest($eachCallRequest, $request);
 939:         $debugData = array('url' => $this->getApiEndpoint(), $methodName => $request);
 940: 
 941:         try {
 942:             $http = new Varien_Http_Adapter_Curl();
 943:             $config = array(
 944:                 'timeout'    => 30,
 945:                 'verifypeer' => $this->_config->verifyPeer
 946:             );
 947: 
 948:             if ($this->getUseProxy()) {
 949:                 $config['proxy'] = $this->getProxyHost(). ':' . $this->getProxyPort();
 950:             }
 951:             if ($this->getUseCertAuthentication()) {
 952:                 $config['ssl_cert'] = $this->getApiCertificate();
 953:             }
 954:             $http->setConfig($config);
 955:             $http->write(Zend_Http_Client::POST, $this->getApiEndpoint(), '1.1', array(), $this->_buildQuery($request));
 956:             $response = $http->read();
 957:         } catch (Exception $e) {
 958:             $debugData['http_error'] = array('error' => $e->getMessage(), 'code' => $e->getCode());
 959:             $this->_debug($debugData);
 960:             throw $e;
 961:         }
 962: 
 963:         $response = preg_split('/^\r?$/m', $response, 2);
 964:         $response = trim($response[1]);
 965:         $response = $this->_deformatNVP($response);
 966: 
 967:         $debugData['response'] = $response;
 968:         $this->_debug($debugData);
 969: 
 970:         // handle transport error
 971:         if ($http->getErrno()) {
 972:             Mage::logException(new Exception(
 973:                 sprintf('PayPal NVP CURL connection error #%s: %s', $http->getErrno(), $http->getError())
 974:             ));
 975:             $http->close();
 976: 
 977:             Mage::throwException(Mage::helper('paypal')->__('Unable to communicate with the PayPal gateway.'));
 978:         }
 979: 
 980:         // cUrl resource must be closed after checking it for errors
 981:         $http->close();
 982: 
 983:         if (!$this->_validateResponse($methodName, $response)) {
 984:             Mage::logException(new Exception(
 985:                 Mage::helper('paypal')->__("PayPal response hasn't required fields.")
 986:             ));
 987:             Mage::throwException(Mage::helper('paypal')->__('There was an error processing your order. Please contact us or try again later.'));
 988:         }
 989: 
 990:         $this->_callErrors = array();
 991:         if ($this->_isCallSuccessful($response)) {
 992:             if ($this->_rawResponseNeeded) {
 993:                 $this->setRawSuccessResponseData($response);
 994:             }
 995:             return $response;
 996:         }
 997:         $this->_handleCallErrors($response);
 998:         return $response;
 999:     }
1000: 
1001:     /**
1002:      * Setter for 'raw response needed' flag
1003:      *
1004:      * @param bool $flag
1005:      * @return Mage_Paypal_Model_Api_Nvp
1006:      */
1007:     public function setRawResponseNeeded($flag)
1008:     {
1009:         $this->_rawResponseNeeded = $flag;
1010:         return $this;
1011:     }
1012: 
1013:     /**
1014:      * Handle logical errors
1015:      *
1016:      * @param array
1017:      */
1018:     protected function _handleCallErrors($response)
1019:     {
1020:         $errors = array();
1021:         for ($i = 0; isset($response["L_ERRORCODE{$i}"]); $i++) {
1022:             $longMessage = isset($response["L_LONGMESSAGE{$i}"])
1023:                 ? preg_replace('/\.$/', '', $response["L_LONGMESSAGE{$i}"]) : '';
1024:             $shortMessage = preg_replace('/\.$/', '', $response["L_SHORTMESSAGE{$i}"]);
1025:             $errors[] = $longMessage
1026:                 ? sprintf('%s (#%s: %s).', $longMessage, $response["L_ERRORCODE{$i}"], $shortMessage)
1027:                 : sprintf('#%s: %s.', $response["L_ERRORCODE{$i}"], $shortMessage);
1028:             $this->_callErrors[] = $response["L_ERRORCODE{$i}"];
1029:         }
1030:         if ($errors) {
1031:             $errors = implode(' ', $errors);
1032:             $e = Mage::exception('Mage_Core', sprintf('PayPal NVP gateway errors: %s Correlation ID: %s. Version: %s.',
1033:                 $errors,
1034:                 isset($response['CORRELATIONID']) ? $response['CORRELATIONID'] : '',
1035:                 isset($response['VERSION']) ? $response['VERSION'] : ''
1036:             ));
1037:             Mage::logException($e);
1038:             $e->setMessage(Mage::helper('paypal')->__('PayPal gateway has rejected request. %s', $errors));
1039:             throw $e;
1040:         }
1041:     }
1042: 
1043:     /**
1044:      * Catch success calls and collect warnings
1045:      *
1046:      * @param array
1047:      * @return bool| success flag
1048:      */
1049:     protected function _isCallSuccessful($response)
1050:     {
1051:         if (!isset($response['ACK'])) {
1052:             return false;
1053:         }
1054: 
1055:         $ack = strtoupper($response['ACK']);
1056:         $this->_callWarnings = array();
1057:         if ($ack == 'SUCCESS' || $ack == 'SUCCESSWITHWARNING') {
1058:             // collect warnings
1059:             if ($ack == 'SUCCESSWITHWARNING') {
1060:                 for ($i = 0; isset($response["L_ERRORCODE{$i}"]); $i++) {
1061:                     $this->_callWarnings[] = $response["L_ERRORCODE{$i}"];
1062:                 }
1063:             }
1064:             return true;
1065:         }
1066:         return false;
1067:     }
1068: 
1069:     /**
1070:      * Validate response array.
1071:      *
1072:      * @param string $method
1073:      * @param array $response
1074:      * @return bool
1075:      */
1076:     protected function _validateResponse($method, $response)
1077:     {
1078:         if (isset($this->_requiredResponseParams[$method])) {
1079:             foreach ($this->_requiredResponseParams[$method] as $param) {
1080:                 if (!isset($response[$param])) {
1081:                     return false;
1082:                 }
1083:             }
1084:         }
1085:         return true;
1086:     }
1087: 
1088:     /**
1089:      * Parse an NVP response string into an associative array
1090:      * @param string $nvpstr
1091:      * @return array
1092:      */
1093:     protected function _deformatNVP($nvpstr)
1094:     {
1095:         $intial=0;
1096:         $nvpArray = array();
1097: 
1098:         $nvpstr = strpos($nvpstr, "\r\n\r\n")!==false ? substr($nvpstr, strpos($nvpstr, "\r\n\r\n")+4) : $nvpstr;
1099: 
1100:         while(strlen($nvpstr)) {
1101:             //postion of Key
1102:             $keypos= strpos($nvpstr,'=');
1103:             //position of value
1104:             $valuepos = strpos($nvpstr,'&') ? strpos($nvpstr,'&'): strlen($nvpstr);
1105: 
1106:             /*getting the Key and Value values and storing in a Associative Array*/
1107:             $keyval=substr($nvpstr,$intial,$keypos);
1108:             $valval=substr($nvpstr,$keypos+1,$valuepos-$keypos-1);
1109:             //decoding the respose
1110:             $nvpArray[urldecode($keyval)] =urldecode( $valval);
1111:             $nvpstr=substr($nvpstr,$valuepos+1,strlen($nvpstr));
1112:          }
1113:         return $nvpArray;
1114:     }
1115: 
1116:     /**
1117:      * NVP doesn't support passing discount total as a separate amount - add it as a line item
1118:      *
1119:      * @param array $request
1120:      * @param int $i
1121:      * @return true|null
1122:      */
1123:     protected function _exportLineItems(array &$request, $i = 0)
1124:     {
1125:         if (!$this->_cart) {
1126:             return;
1127:         }
1128:         $this->_cart->isDiscountAsItem(true);
1129:         return parent::_exportLineItems($request, $i);
1130:     }
1131: 
1132:     /**
1133:      * Create billing and shipping addresses basing on response data
1134:      * @param array $data
1135:      */
1136:     protected function _exportAddressses($data)
1137:     {
1138:         $address = new Varien_Object();
1139:         Varien_Object_Mapper::accumulateByMap($data, $address, $this->_billingAddressMap);
1140:         $address->setExportedKeys(array_values($this->_billingAddressMap));
1141:         $this->_applyStreetAndRegionWorkarounds($address);
1142:         $this->setExportedBillingAddress($address);
1143:         // assume there is shipping address if there is at least one field specific to shipping
1144:         if (isset($data['SHIPTONAME'])) {
1145:             $shippingAddress = clone $address;
1146:             Varien_Object_Mapper::accumulateByMap($data, $shippingAddress, $this->_shippingAddressMap);
1147:             $this->_applyStreetAndRegionWorkarounds($shippingAddress);
1148:             // PayPal doesn't provide detailed shipping name fields, so the name will be overwritten
1149:             $firstName = $data['SHIPTONAME'];
1150:             $lastName = null;
1151:             if (isset($data['FIRSTNAME']) && $data['LASTNAME']) {
1152:                 $firstName = $data['FIRSTNAME'];
1153:                 $lastName = $data['LASTNAME'];
1154:             }
1155:             $shippingAddress->addData(array(
1156:                 'prefix'     => null,
1157:                 'firstname'  => $firstName,
1158:                 'middlename' => null,
1159:                 'lastname'   => $lastName,
1160:                 'suffix'     => null,
1161:             ));
1162:             $this->setExportedShippingAddress($shippingAddress);
1163:         }
1164:     }
1165: 
1166:     /**
1167:      * Adopt specified address object to be compatible with Magento
1168:      *
1169:      * @param Varien_Object $address
1170:      */
1171:     protected function _applyStreetAndRegionWorkarounds(Varien_Object $address)
1172:     {
1173:         // merge street addresses into 1
1174:         if ($address->hasStreet2()) {
1175:              $address->setStreet(implode("\n", array($address->getStreet(), $address->getStreet2())));
1176:              $address->unsStreet2();
1177:         }
1178:         // attempt to fetch region_id from directory
1179:         if ($address->getCountryId() && $address->getRegion()) {
1180:             $regions = Mage::getModel('directory/country')->loadByCode($address->getCountryId())->getRegionCollection()
1181:                 ->addRegionCodeFilter($address->getRegion())
1182:                 ->setPageSize(1)
1183:             ;
1184:             foreach ($regions as $region) {
1185:                 $address->setRegionId($region->getId());
1186:                 $address->setExportedKeys(array_merge($address->getExportedKeys(), array('region_id')));
1187:                 break;
1188:             }
1189:         }
1190:     }
1191: 
1192:     /**
1193:      * Adopt specified request array to be compatible with Paypal
1194:      * Puerto Rico should be as state of USA and not as a country
1195:      *
1196:      * @param array $request
1197:      */
1198:     protected function _applyCountryWorkarounds(&$request)
1199:     {
1200:         if (isset($request['SHIPTOCOUNTRYCODE']) && $request['SHIPTOCOUNTRYCODE'] == 'PR') {
1201:             $request['SHIPTOCOUNTRYCODE'] = 'US';
1202:             $request['SHIPTOSTATE']       = 'PR';
1203:         }
1204:     }
1205: 
1206:     /**
1207:      * Prepare request data basing on provided address
1208:      *
1209:      * @deprecated after 1.4.2.0-beta1, use _importAddresses() instead
1210:      *
1211:      * @param Varien_Object $address
1212:      * @param array $to
1213:      * @return array
1214:      */
1215:     protected function _importAddress(Varien_Object $address, array $to)
1216:     {
1217:         $this->setAddress($address);
1218:         return $this->_importAddresses($to);
1219:     }
1220: 
1221:     /**
1222:      * Prepare request data basing on provided addresses
1223:      *
1224:      * @param array $to
1225:      * @return array
1226:      */
1227:     protected function _importAddresses(array $to)
1228:     {
1229:         $billingAddress  = ($this->getBillingAddress()) ? $this->getBillingAddress() : $this->getAddress();
1230:         $shippingAddress = $this->getAddress();
1231: 
1232:         $to = Varien_Object_Mapper::accumulateByMap(
1233:             $billingAddress,
1234:             $to,
1235:             array_merge(array_flip($this->_billingAddressMap), $this->_billingAddressMapRequest)
1236:         );
1237:         if ($regionCode = $this->_lookupRegionCodeFromAddress($billingAddress)) {
1238:             $to['STATE'] = $regionCode;
1239:         }
1240:         if (!$this->getSuppressShipping()) {
1241:             $to = Varien_Object_Mapper::accumulateByMap($shippingAddress, $to, array_flip($this->_shippingAddressMap));
1242:             if ($regionCode = $this->_lookupRegionCodeFromAddress($shippingAddress)) {
1243:                 $to['SHIPTOSTATE'] = $regionCode;
1244:             }
1245:             $this->_importStreetFromAddress($shippingAddress, $to, 'SHIPTOSTREET', 'SHIPTOSTREET2');
1246:             $this->_importStreetFromAddress($billingAddress, $to, 'STREET', 'STREET2');
1247:             $to['SHIPTONAME'] = $shippingAddress->getName();
1248:         }
1249:         $this->_applyCountryWorkarounds($to);
1250:         return $to;
1251:     }
1252: 
1253:     /**
1254:      * Filter for credit card type
1255:      *
1256:      * @param string $value
1257:      * @return string
1258:      */
1259:     protected function _filterCcType($value)
1260:     {
1261:         if (isset($this->_supportedCcTypes[$value])) {
1262:             return $this->_supportedCcTypes[$value];
1263:         }
1264:         return '';
1265:     }
1266: 
1267:     /**
1268:      * Filter for true/false values (converts to boolean)
1269:      *
1270:      * @param mixed $value
1271:      * @return mixed
1272:      */
1273:     protected function _filterToBool($value)
1274:     {
1275:         if ('false' === $value || '0' === $value) {
1276:             return false;
1277:         } elseif ('true' === $value || '1' === $value) {
1278:             return true;
1279:         }
1280:         return $value;
1281:     }
1282: 
1283:     /**
1284:      * Filter for 'AUTOBILLAMT'
1285:      *
1286:      * @param string $value
1287:      * @return string
1288:      */
1289:     protected function _filterBillFailedLater($value)
1290:     {
1291:         return $value ? 'AddToNextBilling' : 'NoAutoBill';
1292:     }
1293: 
1294:     /**
1295:      * Filter for 'BILLINGPERIOD' and 'TRIALBILLINGPERIOD'
1296:      *
1297:      * @param string $value
1298:      * @return string
1299:      */
1300:     protected function _filterPeriodUnit($value)
1301:     {
1302:         switch ($value) {
1303:             case 'day':        return 'Day';
1304:             case 'week':       return 'Week';
1305:             case 'semi_month': return 'SemiMonth';
1306:             case 'month':      return 'Month';
1307:             case 'year':       return 'Year';
1308:         }
1309:     }
1310: 
1311:     /**
1312:      * Filter for 'FAILEDINITAMTACTION'
1313:      *
1314:      * @param string $value
1315:      * @return string
1316:      */
1317:     protected function _filterInitialAmountMayFail($value)
1318:     {
1319:         return $value ? 'ContinueOnFailure' : 'CancelOnFailure';
1320:     }
1321: 
1322:     /**
1323:      * Filter for billing agreement status
1324:      *
1325:      * @param string $value
1326:      * @return string
1327:      */
1328:     protected function _filterBillingAgreementStatus($value)
1329:     {
1330:         switch ($value) {
1331:             case 'canceled':    return 'Canceled';
1332:             case 'active':      return 'Active';
1333:         }
1334:     }
1335: 
1336:     /**
1337:      * Convert payment status from NVP format to paypal/info model format
1338:      *
1339:      * @param string $value
1340:      * @return string|null
1341:      */
1342:     protected function _filterPaymentStatusFromNvpToInfo($value)
1343:     {
1344:         switch ($value) {
1345:             case 'None': return Mage_Paypal_Model_Info::PAYMENTSTATUS_NONE;
1346:             case 'Completed': return Mage_Paypal_Model_Info::PAYMENTSTATUS_COMPLETED;
1347:             case 'Denied': return Mage_Paypal_Model_Info::PAYMENTSTATUS_DENIED;
1348:             case 'Expired': return Mage_Paypal_Model_Info::PAYMENTSTATUS_EXPIRED;
1349:             case 'Failed': return Mage_Paypal_Model_Info::PAYMENTSTATUS_FAILED;
1350:             case 'In-Progress': return Mage_Paypal_Model_Info::PAYMENTSTATUS_INPROGRESS;
1351:             case 'Pending': return Mage_Paypal_Model_Info::PAYMENTSTATUS_PENDING;
1352:             case 'Refunded': return Mage_Paypal_Model_Info::PAYMENTSTATUS_REFUNDED;
1353:             case 'Partially-Refunded': return Mage_Paypal_Model_Info::PAYMENTSTATUS_REFUNDEDPART;
1354:             case 'Reversed': return Mage_Paypal_Model_Info::PAYMENTSTATUS_REVERSED;
1355:             case 'Canceled-Reversal': return Mage_Paypal_Model_Info::PAYMENTSTATUS_UNREVERSED;
1356:             case 'Processed': return Mage_Paypal_Model_Info::PAYMENTSTATUS_PROCESSED;
1357:             case 'Voided': return Mage_Paypal_Model_Info::PAYMENTSTATUS_VOIDED;
1358:         }
1359:     }
1360: 
1361:     /**
1362:      * Convert payment review action to NVP-compatible value
1363:      *
1364:      * @param string $value
1365:      * @return string|null
1366:      */
1367:     protected function _filterPaymentReviewAction($value)
1368:     {
1369:         switch ($value) {
1370:             case Mage_Paypal_Model_Pro::PAYMENT_REVIEW_ACCEPT:
1371:                 return 'Accept';
1372:             case Mage_Paypal_Model_Pro::PAYMENT_REVIEW_DENY:
1373:                 return 'Deny';
1374:         }
1375:     }
1376: 
1377:     /**
1378:      * Convert RP management action to NVP format
1379:      *
1380:      * @param string $value
1381:      * @return string|null
1382:      */
1383:     protected function _filterRecurringProfileActionToNvp($value)
1384:     {
1385:         switch ($value) {
1386:             case 'cancel': return 'Cancel';
1387:             case 'suspend':  return 'Suspend';
1388:             case 'activate': return 'Reactivate';
1389:         }
1390:     }
1391: 
1392:     /**
1393:      * Check the obtained RP status in NVP format and specify the profile state
1394:      *
1395:      * @param string $value
1396:      * @param Varien_Object $result
1397:      */
1398:     protected function _analyzeRecurringProfileStatus($value, Varien_Object $result)
1399:     {
1400:         switch ($value) {
1401:             case 'ActiveProfile':
1402:             case 'Active':
1403:                 $result->setIsProfileActive(true);
1404:                 break;
1405:             case 'PendingProfile':
1406:                 $result->setIsProfilePending(true);
1407:                 break;
1408:             case 'CancelledProfile':
1409:             case 'Cancelled':
1410:                 $result->setIsProfileCanceled(true);
1411:                 break;
1412:             case 'SuspendedProfile':
1413:             case 'Suspended':
1414:                 $result->setIsProfileSuspended(true);
1415:                 break;
1416:             case 'ExpiredProfile':
1417:             case 'Expired': // ??
1418:                 $result->setIsProfileExpired(true);
1419:                 break;
1420:         }
1421:     }
1422: 
1423:     /**
1424:      * Return capture type
1425:      *
1426:      * @param Varien_Object $payment
1427:      * @return string
1428:      */
1429:     protected function _getCaptureCompleteType()
1430:     {
1431:         return ($this->getIsCaptureComplete())
1432:                 ? $this->_captureTypeComplete
1433:                 : $this->_captureTypeNotcomplete;
1434:     }
1435: 
1436:     /**
1437:      * Return each call request without unused fields in case of Express Checkout Unilateral payments
1438:      *
1439:      * @param string $methodName Current method name
1440:      * @return array
1441:      */
1442:     protected function _prepareEachCallRequest($methodName)
1443:     {
1444:         $expressCheckooutMetods = array(
1445:             self::SET_EXPRESS_CHECKOUT, self::GET_EXPRESS_CHECKOUT_DETAILS, self::DO_EXPRESS_CHECKOUT_PAYMENT
1446:         );
1447:         if (!in_array($methodName, $expressCheckooutMetods) || !$this->_config->shouldUseUnilateralPayments()) {
1448:             return $this->_eachCallRequest;
1449:         }
1450:         return array_diff($this->_eachCallRequest, array('USER', 'PWD', 'SIGNATURE'));
1451:     }
1452: 
1453:     /**
1454:      * Check the EC request against unilateral payments mode and remove the SUBJECT if needed
1455:      *
1456:      * @param &array $requestFields
1457:      */
1458:     protected function _prepareExpressCheckoutCallRequest(&$requestFields)
1459:     {
1460:         if (!$this->_config->shouldUseUnilateralPayments()) {
1461:             if ($key = array_search('SUBJECT', $requestFields)) {
1462:                 unset($requestFields[$key]);
1463:             }
1464:         }
1465:     }
1466: }
1467: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0