v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT getConfig('hosted')) return false; else return true; } function allowPartialRefunds() { return true; } public function getRecurringType() { return self::REPORTS_CRONREBILL; } public function getFormOptions() { $ret = parent::getFormOptions(); $ret[] = self::CC_PHONE; return $ret; } public function getSupportedCurrencies() { return array('USD', 'EUR', 'GBP', 'CAD'); } public function isConfigured() { return strlen($this->getConfig('login')) && strlen($this->getConfig('tkey')); } public function _doBill(Invoice $invoice, $doFirst, CcRecord $cc, Am_Paysystem_Result $result) { if (!$this->getConfig('hosted')) { $user = $invoice->getUser(); if ($cc->user_id != $user->pk()) throw new Am_Exception_Paysystem("Assertion failed: cc.user_id != user.user_id"); // will be stored only if cc# or expiration changed $this->storeCreditCard($cc, $result); if (!$result->isSuccess()) return; $user->refresh(); // we have both profile id and payment id, run the necessary transaction now if amount > 0 $result->reset(); } //moved from AIM to CIM elseif(!$invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY)) { $cc = $this->getDi()->ccRecordTable->findFirstByUserId($invoice->user_id); if (!$cc) throw new Am_Exception_Paysystem("No credit card saved, cannot rebill"); $user = $invoice->getUser(); if ($cc->user_id != $user->pk()) throw new Am_Exception_Paysystem("Assertion failed: cc.user_id != user.user_id"); // will be stored only if cc# or expiration changed $this->storeCreditCard($cc, $result); if (!$result->isSuccess()) return; $user->refresh(); // we have both profile id and payment id, run the necessary transaction now if amount > 0 $result->reset(); } $this->_doTheBill($invoice, $doFirst, $cc, $result); } /* process invoice after creating payment profile */ public function _doTheBill(Invoice $invoice, $doFirst, CcRecord $cc, Am_Paysystem_Result $result) { if ($doFirst && (doubleval($invoice->first_total) <= 0)) { // free trial $tr = new Am_Paysystem_Transaction_Free($this); $tr->setInvoice($invoice); $tr->process(); $result->setSuccess($tr); } else { //fix for previously not saved payment profile if(!$invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY)) $this->loadLastProfile($invoice); $tr = new Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfileTransaction($this, $invoice, $doFirst); $tr->run($result); } } /** * Attempt to laod payment profile from Authorize.Net * if profile exists, it is set in user's record. * * Return Am_Paysystem_result * @param Invoice $invoice * @return Am_Paysystem_Result $result; */ public function loadLastProfile(Invoice $invoice) { // fetch list of payment profiles from Auth.Net and save latest to customer $result = new Am_Paysystem_Result(); $tr = new Am_Paysystem_Transaction_AuthorizeCim_GetCustomerProfile($this, $invoice, $invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY)); $tr->run($result); if ($result->isSuccess()) { $invoice->getUser()->data()->set(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY, $tr->getUniqId())->update(); } return $result; } public function _initSetupForm(Am_Form_Setup $form) { $label = "Use Hosted Version (recommended)\n". "this option allows you to display credit card input right on your website\n". "(as a popup) and in the same time it does not require PCI DSS compliance\n". "Maxmind verification will not work if enable this option"; if ('https' != substr(ROOT_SURL,0,5)) $label .= "\n" . 'This option requires https on your site'; $form->addAdvCheckbox('hosted')->setLabel($label); $form->addText("login")->setLabel("API Login ID\n" . 'can be obtained from the same page as Transaction Key (see below)'); $form->addText("tkey")->setLabel("Transaction Key\n" . "The transaction key is generated by the system and can be obtained from Merchant Interface. To obtain the transaction key from the Merchant Interface: * Log into the Merchant Interface * Select [Settings] from the Main Menu * Click on [API Login ID and Transaction Key] in the Security section * Type in the answer to the secret question configured on setup * Click Submit"); $form->addSelect("validationMode") ->setLabel("Validation mode for creating customer profile" . "\n" . "Validation mode allows you to generate a test transaction at the time you create a customer payment profile. In Test Mode, only field validation is performed. In Live Mode, a transaction is generated and submitted to the processor with the amount of $0.01. If successful, the transaction is immediately voided. When a value of \"none\" is submitted, no additional validation is performed. ") ->loadOptions(array( 'liveMode' => 'liveMode', 'testMode' => 'testMode', 'none' => 'none' )); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled" . "\n" . "The Test Mode requires a separate developer test account, which can be set up by filling out the following form: http://developer.authorize.net/testaccount"); } public function getMerchantCustomerId($userOrId) { if ($userOrId instanceof User) $userOrId = $userOrId->pk(); return $userOrId . '-' . substr($this->getDi()->security->siteHash('cim'), 0, 5); } public function storeCreditCard(CcRecord $cc, Am_Paysystem_Result $result) { $user = $this->getDi()->userTable->load($cc->user_id); $profileId = $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY); if ($this->invoice) { // to link log records with current invoice $invoice = $this->invoice; } else { // updating credit card info? $invoice = $this->getDi()->invoiceRecord; $invoice->invoice_id = 0; $invoice->user_id = $user->pk(); } // compare stored cc for that user may be we don't need to refresh? if ($profileId && ($cc->cc_number != '0000000000000000')) { $storedCc = $this->getDi()->ccRecordTable->findFirstByUserId($user->pk()); if ($storedCc && (($storedCc->cc != $cc->maskCc($cc->cc_number)) || ($storedCc->cc_expire != $cc->cc_expire))) { $tr = new Am_Paysystem_Transaction_AuthorizeCim_UpdateCustomerPaymentProfile($this, $invoice, $cc); $tr->run($result); if($result->isFailure()){ // Try to delete all profiles and create new one. $result->reset(); $user->data() ->set(self::USER_PROFILE_KEY, null) ->set(self::PAYMENT_PROFILE_KEY, null) ->update(); $deleteTr = new Am_Paysystem_Transaction_AuthorizeCim_DeleteCustomerProfile($this, $invoice, $profileId); $deleteTr->run($res = new Am_Paysystem_Result); $profileId = null; } } } if (!$profileId) { try { $tr = new Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfile($this, $invoice, $cc); $tr->run($result); if (!$result->isSuccess()) { if($tr->getErrorCode() == 'E00039') { $error = $result->getLastError(); if(preg_match('/A duplicate record with ID (\d+) already exists/', $error, $regs) && $regs[1]) { $user->data()->set(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY, $regs[1])->update(); $result->reset(); $result->setSuccess(); } else { return; } } else if($tr->getErrorCode() == 'E00027') { // Authorize.Net has 2 minutes timeframe before each provide validation attempt in live mode. // If interval between two createCustomerProfile requests is less then 2 minutes Duplicate error will be returned. // We need to inform customer about such delay. $error = $result->getLastError(); if(preg_match('/A duplicate transaction has been submitted/', $error)) { $result->setFailed(___("A duplicate transaction has been submitted. Please wait 2 minutes before next attempt")); } else { return; } } else { return; } }else{ $user->data()->set(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY, $tr->getProfileId())->update(); $user->data()->set(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY, $tr->getPaymentId())->update(); } } catch (Am_Exception_Paysystem $e) { $result->setFailed($e->getPublicError()); return false; } } $paymentProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY); if (!$paymentProfileId) { try { $tr = new Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerPaymentProfile($this, $invoice, $cc); $tr->run($result); if (!$result->isSuccess()) return; $user->data()->set(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY, $tr->getProfileId())->update(); } catch (Am_Exception_Paysystem $e) { $result->setFailed($e->getPublicError()); return false; } } /// $cc->cc = $cc->maskCc(@$cc->cc_number); $cc->cc_number = '0000000000000000'; if ($cc->pk()) $cc->update(); else $cc->replace(); $result->setSuccess(); } public function getReadme() { return <<You need to enable CIM service in your authorize.net account to use this plugin. (Tools -> Customer Information Manager -> Sign Up Now) This is a paid service. 1. Enable and configure plugin in aMember CP -> Setup -> Plugins 2. You NEED to use external cron with this plugins (See aMember CP -> Configuration -> Setup/Configuration -> Advanced) CUT; } function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { $trans = new Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfileTransactionRefund($this, $payment->getInvoice(), $payment, $amount); $trans->run($result); } function createCustomerProfile(Invoice $invoice){ $tr = new Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfile($this, $invoice); $result = new Am_Paysystem_Result(); $tr->run($result); if (!$result->isSuccess()) { if($tr->getErrorCode() == 'E00039') { $error = $result->getLastError(); if(preg_match('/A duplicate record with ID (\d+) already exists/', $error, $regs) && $regs[1]) { $invoice->getUser()->data()->set(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY, $regs[1])->update(); return; } else { throw new Am_Exception_Paysystem("Failed Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfile " . $result->getLastError()); } } else if($tr->getErrorCode() == 'E00027') { // Authorize.Net has 2 minutes timeframe before each provide validation attempt in live mode. // If interval between two createCustomerProfile requests is less then 2 minutes Duplicate error will be returned. // We need to inform customer about such delay. $error = $result->getLastError(); if(preg_match('/A duplicate transaction has been submitted/', $error)) { throw new Am_Exception_Paysystem(___("A duplicate transaction has been submitted. Please wait 2 minutes before next attempt")); } else { throw new Am_Exception_Paysystem("Failed Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfile " . $result->getLastError()); } } throw new Am_Exception_Paysystem("Failed Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfile " . $result->getLastError()); } $invoice->getUser()->data()->set(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY, $tr->getProfileId())->update(); return $tr->getProfileId(); } function getHostedProfilePageToken() { $user = $this->getDi()->userTable->load($this->invoice->user_id); $profileId = $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY); $invoice = $this->invoice; if (!$profileId) $profileId = $this->createCustomerProfile ($invoice); $tr = new Am_Paysystem_Transaction_AuthorizeCim_GetHostedProfilePageRequest($this, $invoice, $profileId); $result = new Am_Paysystem_Result(); $tr->run($result); if(!$tr->getUniqId() && ($tr->getErrorCode() == 'E00040')){ // Profile doesn't exists on Authorize.NET $profileId = $this->createCustomerProfile($invoice); $tr = new Am_Paysystem_Transaction_AuthorizeCim_GetHostedProfilePageRequest($this, $invoice, $profileId); $result = new Am_Paysystem_Result(); $tr->run($result); } if (!$tr->getUniqId()) throw new Am_Exception_Paysystem("Could not get hosted-profile-page-token from authorize.net - connection problem"); return $tr->getUniqId(); } // use custom controller protected function createController(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($this->getConfig('hosted')) return new Am_Mvc_Controller_CreditCard_AuthorizeNet($request, $response, $invokeArgs); else return parent::createController($request, $response, $invokeArgs); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'iframe') { $p = $this->createController($request, $response, $invokeArgs); $p->setPlugin($this); $p->run(); return; } parent::directAction($request, $response, $invokeArgs); } public function getUpdateCcLink($user) { $inv = $this->getDi()->invoiceTable->findFirstBy(array('user_id' => $user->pk(), 'paysys_id' => $this->getId()), 0, 1); if ($inv) return $this->getPluginUrl('update'); } public function canUseMaxmind() { return true; } } abstract class Am_Paysystem_Transaction_AuthorizeCim extends Am_Paysystem_Transaction_CreditCard { protected $apiName = null; protected $aimResponse = null; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, $doFirst = true) { parent::__construct($plugin, $invoice, $plugin->createHttpRequest(), $doFirst); $this->request->setHeader('Content-type', 'text/xml'); $this->request->setBody($this->createXml($this->apiName)->asXml()); $this->request->setMethod(Am_HttpRequest::METHOD_POST); $this->request->setUrl(!$this->plugin->getConfig('testing') ? Am_Paysystem_AuthorizeCim::LIVE_URL : Am_Paysystem_AuthorizeCim::SANDBOX_URL); } /** @return SimpleXmlElement */ protected function createXml($name) { $xml = new SimpleXmlElement('<'.$name.'/>'); $xml['xmlns'] = 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'; $xml->merchantAuthentication->name = $this->plugin->getConfig('login'); $xml->merchantAuthentication->transactionKey = $this->plugin->getConfig('tkey'); return $xml; } public function parseResponse() { $body = trim($this->response->getBody()); $body = str_replace('xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"', '', $body); $this->xml = new SimpleXMLElement($body); } public function parseAimString($string) { $vars = explode(',', $string); $this->aimResponse = new stdclass; if (count($vars) < 10) { $this->aimResponse->error_message = "Unrecognized response from Authorize.Net: " . $string; return false; } // Set all fields $this->aimResponse->aimResponse_code = $vars[0]; $this->aimResponse->aimResponse_subcode = $vars[1]; $this->aimResponse->aimResponse_reason_code = $vars[2]; $this->aimResponse->aimResponse_reason_text = $vars[3]; $this->aimResponse->authorization_code = $vars[4]; $this->aimResponse->avs_response = $vars[5]; $this->aimResponse->transaction_id = $vars[6]; $this->aimResponse->invoice_number = $vars[7]; $this->aimResponse->description = $vars[8]; $this->aimResponse->amount = $vars[9]; $this->aimResponse->method = $vars[10]; $this->aimResponse->transaction_type = $vars[11]; $this->aimResponse->customer_id = $vars[12]; $this->aimResponse->first_name = $vars[13]; $this->aimResponse->last_name = $vars[14]; $this->aimResponse->company = $vars[15]; $this->aimResponse->address = $vars[16]; $this->aimResponse->city = $vars[17]; $this->aimResponse->state = $vars[18]; $this->aimResponse->zip_code = $vars[19]; $this->aimResponse->country = $vars[20]; $this->aimResponse->phone = $vars[21]; $this->aimResponse->fax = $vars[22]; $this->aimResponse->email_address = $vars[23]; $this->aimResponse->ship_to_first_name = $vars[24]; $this->aimResponse->ship_to_last_name = $vars[25]; $this->aimResponse->ship_to_company = $vars[26]; $this->aimResponse->ship_to_address = $vars[27]; $this->aimResponse->ship_to_city = $vars[28]; $this->aimResponse->ship_to_state = $vars[29]; $this->aimResponse->ship_to_zip_code = $vars[30]; $this->aimResponse->ship_to_country = $vars[31]; $this->aimResponse->tax = $vars[32]; $this->aimResponse->duty = $vars[33]; $this->aimResponse->freight = $vars[34]; $this->aimResponse->tax_exempt = $vars[35]; $this->aimResponse->purchase_order_number= $vars[36]; $this->aimResponse->md5_hash = $vars[37]; $this->aimResponse->card_code_response = $vars[38]; $this->aimResponse->cavv_response = $vars[39]; $this->aimResponse->account_number = $vars[40]; $this->aimResponse->card_type = $vars[51]; $this->aimResponse->split_tender_id = $vars[52]; $this->aimResponse->requested_amount = $vars[53]; $this->aimResponse->balance_on_card = $vars[54]; return true; } } class Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfile extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'createCustomerProfileRequest'; /** @var CcRecord */ protected $cc; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, CcRecord $cc = null) { $this->cc = $cc; parent::__construct($plugin, $invoice); } protected function createXml($name) { $xml = parent::createXml($name); $user = $this->invoice->getUser(); $xml->profile->merchantCustomerId = $this->plugin->getMerchantCustomerId($this->cc ? $this->cc->user_id : $this->invoice->user_id); $xml->profile->description = "Username: $user->login"; $xml->profile->email = $user->email; if ($this->cc) { $xml->profile->paymentProfiles->billTo->firstName = $this->cc->cc_name_f; $xml->profile->paymentProfiles->billTo->lastName = $this->cc->cc_name_l; $xml->profile->paymentProfiles->billTo->address = $this->cc->cc_street; $xml->profile->paymentProfiles->billTo->city = $this->cc->cc_city; $xml->profile->paymentProfiles->billTo->state = $this->cc->cc_state; $xml->profile->paymentProfiles->billTo->zip = $this->cc->cc_zip; $xml->profile->paymentProfiles->billTo->country = $this->cc->cc_country; $xml->profile->paymentProfiles->billTo->phoneNumber = $this->cc->cc_phone; $xml->profile->paymentProfiles->payment->creditCard->cardNumber = $this->cc->cc_number; $xml->profile->paymentProfiles->payment->creditCard->expirationDate = $this->cc->getExpire('20%2$02d-%1$02d'); if (strlen($this->cc->getCvv())) $xml->profile->paymentProfiles->payment->creditCard->cardCode = $this->cc->getCvv(); $xml->validationMode = $this->getPlugin()->getConfig('validationMode', 'liveMode'); } return $xml; } public function validate() { if ($this->xml->getName() != 'createCustomerProfileResponse') { $this->result->setFailed(___('Payment failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed((string)$this->xml->messages->message->text); return; } $this->result->setSuccess(); return true; } function getProfileId() { return (string)$this->xml->customerProfileId; } function getPaymentId() { return (string)$this->xml->customerPaymentProfileIdList->numericString; } public function getUniqId() { return (string)$this->xml->customerProfileId; } public function processValidated() { } public function getErrorCode(){ return (string)$this->xml->messages->message->code; } } class Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerPaymentProfile extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'createCustomerPaymentProfileRequest'; /** @var CcRecord */ protected $cc; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, CcRecord $cc = null) { $this->cc = $cc; parent::__construct($plugin, $invoice); } protected function createXml($name) { $xml = parent::createXml($name); $user = $this->invoice->getUser(); $xml->customerProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY); if ($this->cc) { $xml->paymentProfile->billTo->firstName = $this->cc->cc_name_f; $xml->paymentProfile->billTo->lastName = $this->cc->cc_name_l; $xml->paymentProfile->billTo->address = $this->cc->cc_street; $xml->paymentProfile->billTo->city = $this->cc->cc_city; $xml->paymentProfile->billTo->state = $this->cc->cc_state; $xml->paymentProfile->billTo->zip = $this->cc->cc_zip; $xml->paymentProfile->billTo->country = $this->cc->cc_country; $xml->paymentProfile->billTo->phoneNumber = $this->cc->cc_phone; $xml->paymentProfile->payment->creditCard->cardNumber = $this->cc->cc_number; $xml->paymentProfile->payment->creditCard->expirationDate = $this->cc->getExpire('20%2$02d-%1$02d'); if (strlen($this->cc->getCvv())) $xml->paymentProfile->payment->creditCard->cardCode = $this->cc->getCvv(); $xml->validationMode = $this->getPlugin()->getConfig('validationMode', 'liveMode'); } return $xml; } public function validate() { if ($this->xml->getName() != 'createCustomerPaymentProfileResponse') { $this->result->setFailed(___('Payment failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed((string)$this->xml->messages->message->text); return; } $this->result->setSuccess(); return true; } function getProfileId() { return (string)$this->xml->customerPaymentProfileId; } public function getUniqId() { return (string)$this->xml->customerPaymentProfileId; } public function processValidated() { } } class Am_Paysystem_Transaction_AuthorizeCim_UpdateCustomerPaymentProfile extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'updateCustomerPaymentProfileRequest'; /** @var CcRecord */ protected $cc; protected $profileId; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, CcRecord $cc = null) { $this->cc = $cc; parent::__construct($plugin, $invoice); } protected function createXml($name) { $xml = parent::createXml($name); $user = $this->invoice->getUser(); $xml->customerProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY); if ($this->cc) { $xml->paymentProfile->billTo->firstName = $this->cc->cc_name_f; $xml->paymentProfile->billTo->lastName = $this->cc->cc_name_l; $xml->paymentProfile->billTo->address = $this->cc->cc_street; $xml->paymentProfile->billTo->city = $this->cc->cc_city; $xml->paymentProfile->billTo->state = $this->cc->cc_state; $xml->paymentProfile->billTo->zip = $this->cc->cc_zip; $xml->paymentProfile->billTo->country = $this->cc->cc_country; $xml->paymentProfile->billTo->phoneNumber = $this->cc->cc_phone; $xml->paymentProfile->payment->creditCard->cardNumber = $this->cc->cc_number; $xml->paymentProfile->payment->creditCard->expirationDate = $this->cc->getExpire('20%2$02d-%1$02d'); if (strlen($this->cc->getCvv())) $xml->paymentProfile->payment->creditCard->cardCode = $this->cc->getCvv(); $xml->validationMode = $this->getPlugin()->getConfig('validationMode', 'liveMode'); $xml->paymentProfile->customerPaymentProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY); } return $xml; } public function validate() { if ($this->xml->getName() != 'updateCustomerPaymentProfileResponse') { $this->result->setFailed(___('Payment failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed((string)$this->xml->messages->message->text); return; } $this->result->setSuccess(); return true; } public function getUniqId() { return uniqid(); } public function processValidated() { } } class Am_Paysystem_Transaction_AuthorizeCim_DeleteCustomerProfile extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'deleteCustomerProfileRequest'; protected $profileId; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, $profileId) { $this->profileId = $profileId; parent::__construct($plugin, $invoice, true); } protected function createXml($name) { $xml = parent::createXml($name); $xml->customerProfileId = $this->profileId; return $xml; } public function validate() { if ($this->xml->getName() != 'deleteCustomerProfileResponse') { $this->result->setFailed(___('Profile update transaction failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed((string)$this->xml->messages->message->text); return; } $this->result->setSuccess(); return true; } public function getUniqId() { return uniqid(); } public function processValidated() { } } class Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfileTransaction extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'createCustomerProfileTransactionRequest'; /** @var object */ protected $aimResponse; protected function createXml($name) { $xml = parent::createXml($name); $xml->transaction->profileTransAuthCapture->amount = $this->doFirst ? $this->invoice->first_total : $this->invoice->second_total; $xml->transaction->profileTransAuthCapture->tax->amount = $this->doFirst ? $this->invoice->first_tax : $this->invoice->second_tax; $xml->transaction->profileTransAuthCapture->shipping->amount = $this->doFirst ? $this->invoice->first_shipping : $this->invoice->second_shipping; foreach ($this->invoice->getItems() as $item) { /* @var $item InvoiceItem */ $line = $xml->transaction->profileTransAuthCapture->addChild('lineItems'); $line->itemId = $item->item_id; $line->name = substr($item->item_title, 0, 30); $line->quantity = $item->qty; $price = $this->doFirst ? $item->first_price : $item->second_price; if ($price) $line->unitPrice = $price; if ($this->doFirst ? $item->first_tax : $item->second_tax) $line->taxable = 'true'; else $line->taxable = 'false'; } $user = $this->invoice->getUser(); $taxAmount = $this->doFirst ? $this->invoice->first_tax : $this->invoice->second_tax; if ($taxAmount) $xml->transaction->profileTransAuthCapture->tax->amount = $taxAmount; $xml->transaction->profileTransAuthCapture->customerProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY); $xml->transaction->profileTransAuthCapture->customerPaymentProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY); $xml->transaction->profileTransAuthCapture->order->description = $this->invoice->getLineDescription(); $xml->transaction->profileTransAuthCapture->order->purchaseOrderNumber = $this->invoice->public_id . '-' . $this->invoice->getPaymentsCount(); $xml->transaction->profileTransAuthCapture->recurringBilling = $this->doFirst ? 'true' : 'false'; $xml->addChild('extraOptions', 'x_Customer_IP=' . ($user->remote_addr ? $user->remote_addr : $_SERVER['REMOTE_ADDR'])); return $xml; } public function validate() { if ($this->xml->getName() != 'createCustomerProfileTransactionResponse') { $this->result->setFailed(___('Payment failed')); return; } if (!$this->parseAimString($this->xml->directResponse)) { $this->result->setFailed(___('Payment failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed(___('Payment failed')); return; } $this->result->setSuccess($this); return true; } public function getUniqId() { return $this->aimResponse->transaction_id; } public function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_AuthorizeCim_CreateCustomerProfileTransactionRefund extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'createCustomerProfileTransactionRequest'; /** @var object */ protected $aimResponse; public $amount; public $transId; function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, InvoicePayment $payment, $amount) { $this->transId = $payment->receipt_id; $this->amount = $amount; parent::__construct($plugin, $invoice); } protected function createXml($name) { $xml = parent::createXml($name); $xml->transaction->profileTransRefund->amount = $this->amount; $user = $this->invoice->getUser(); $xml->transaction->profileTransRefund->customerProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY); $xml->transaction->profileTransRefund->customerPaymentProfileId = $user->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY); $xml->transaction->profileTransRefund->order->description = "Refund for payment: ".$this->transId." amount: ".$this->amount; $xml->transaction->profileTransRefund->order->purchaseOrderNumber = $this->invoice->public_id . '-RFND-' . $this->transId; $xml->transaction->profileTransRefund->transId = $this->transId; return $xml; } public function validate() { if ($this->xml->getName() != 'createCustomerProfileTransactionResponse') { $this->result->setFailed(___('Payment failed')); return; } if (!$this->parseAimString($this->xml->directResponse)) { $this->result->setFailed(___('Payment failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed(___('Payment failed')); return; } $this->result->setSuccess(); return true; } public function getUniqId() { return $this->aimResponse->transaction_id; } public function processValidated() { $this->invoice->addRefund($this, $this->transId, $this->amount); } } class Am_Paysystem_Transaction_AuthorizeCim_GetHostedProfilePageRequest extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'getHostedProfilePageRequest'; /** @var object */ protected $aimResponse; protected $profileId; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, $profileId) { $this->profileId = $profileId; parent::__construct($plugin, $invoice, true); } protected function createXml($name) { $xml = parent::createXml($name); $xml->customerProfileId = $this->profileId; /* $xml->hostedProfileSettings->setting[0]->settingName = 'hostedProfileReturnUrl'; $xml->hostedProfileSettings->setting[0]->settingValue = $this->plugin->getReturnUrl(); $xml->hostedProfileSettings->setting[1]->settingName = 'hostedProfileReturnUrlText'; $xml->hostedProfileSettings->setting[1]->settingValue = 'Return'; $xml->hostedProfileSettings->setting[2]->settingName = 'hostedProfileHeadingBgColor'; $xml->hostedProfileSettings->setting[2]->settingValue = ''; */ $xml->hostedProfileSettings->setting[0]->settingName = 'hostedProfilePageBorderVisible'; $xml->hostedProfileSettings->setting[0]->settingValue = 'false'; $xml->hostedProfileSettings->setting[1]->settingName = 'hostedProfileIFrameCommunicatorUrl'; $xml->hostedProfileSettings->setting[1]->settingValue = $this->getPlugin()->getPluginUrl('iframe'); $xml->hostedProfileSettings->setting[2]->settingName = 'hostedProfileValidationMode'; $xml->hostedProfileSettings->setting[2]->settingValue = $this->getPlugin()->getConfig('validationMode', 'liveMode'); return $xml; } public function validate() { if ($this->xml->getName() != 'getHostedProfilePageResponse') { $this->result->setFailed(___('Payment failed')); return; } if ((string)$this->xml->messages->message->code != 'I00001') { $this->result->setFailed(___('Payment failed')); return; } $this->result->setSuccess($this); return true; } public function getUniqId() { return (string)$this->xml->token;; } public function getErrorCode(){ return (string) $this->xml->messages->message->code; } public function processValidated() { } } class Am_Paysystem_Transaction_AuthorizeCim_GetCustomerProfile extends Am_Paysystem_Transaction_AuthorizeCim { protected $apiName = 'getCustomerProfileRequest'; /** @var object */ protected $aimResponse; protected $profileId; public function __construct(Am_Paysystem_Abstract $plugin, Invoice $invoice, $profileId) { $this->profileId = $profileId; parent::__construct($plugin, $invoice, true); } protected function createXml($name) { $xml = parent::createXml($name); $xml->customerProfileId = $this->profileId; return $xml; } public function validate() { if ($this->xml->getName() != 'getCustomerProfileResponse') { $this->result->setFailed(___('Payment failed')); return; } if (!$this->getUniqId()) { $this->result->setFailed(___('Payment failed')); return; } $this->result->setSuccess($this); return true; } public function getUniqId() { // fetch LAST payment profile id from customer profile $ret = ''; foreach ($this->xml->profile->paymentProfiles as $x) $ret = (string)$x->customerPaymentProfileId; return $ret; } public function processValidated() { } } class Am_Mvc_Controller_CreditCard_AuthorizeNet extends Am_Mvc_Controller { /** @var Am_Paysystem_AuthorizeCim */ protected $plugin; /** @var Invoice */ protected $invoice; public function setPlugin($plugin) { $this->plugin = $plugin; } public function setInvoice($invoice) { $this->invoice = $invoice; } protected function ccError($msg) { $this->view->content .= "".$msg.""; $url = $this->_request->getRequestUri(); $url .= (strchr($url, '?') ? '&' : '?') . 'id=' . $this->_request->get('id'); $url = Am_Html::escape($url); $this->view->content .= " ".___('Return and try again').""; $this->view->display('layout.phtml'); exit; } /** * Process a transaction using saved customer payment profile * and do either success redirect, or display error * @return Am_Paysystem_Result */ protected function ccActionProcessAfterProfileExists() { $result = new Am_Paysystem_Result(); $this->plugin->_doTheBill($this->invoice, true, $this->getDi()->CcRecordTable->createRecord(), $result); if (@$result->errorCode == 'E00040') // Customer Profile ID or Customer Payment Profile ID not found { // cleanup customer payment profile $user = $this->invoice->getUser(); $user->data()->set(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY, null); $tr = new Am_Paysystem_Transaction_AuthorizeCim_DeleteCustomerProfile($this->plugin, $this->invoice, $user->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY)); $tr->run(new Am_Paysystem_Result); $user->data()->set(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY, null); $user->data()->update(); } return $result; } public function ccAction() { $this->view->title = ___('Payment Info'); $this->view->invoice = $this->invoice; $this->view->content = $this->view->render('_receipt.phtml'); if ($this->_request->get('result') == 'success') { if (!$this->invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY)) { $ret = $this->plugin->loadLastProfile($this->invoice); if(!$ret->isSuccess()){ $this->ccError($ret->getLastError()); } // check status here? } $result = $this->ccActionProcessAfterProfileExists(); if ($result->isSuccess()) { $s = new Zend_Session_Namespace($this->plugin->getId()); $s->setExpirationSeconds(60*30); // after 30 minutes we will reset the session $s->ccConfirmed = true; $this->_response->setRedirect($this->plugin->getReturnUrl()); } else { $this->ccError($result->getLastError()); } } else { if ($this->invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY)) { // if we have credit card on file, we will try to use it but we // have to display confirmation first $s = new Zend_Session_Namespace($this->plugin->getId()); $s->setExpirationSeconds(60*30); // after 30 minutes we will reset the session $s->ccConfirmed = !empty($s->ccConfirmed); switch ($this->_request->get('result')) { case 'confirm': $s->ccConfirmed = true; break; case 'new' : break; default: if (!$s->ccConfirmed) return $this->displayReuse(); } if ($s->ccConfirmed) { $result = $this->ccActionProcessAfterProfileExists(); if ($result->isSuccess()) { return $this->_response->setRedirect($this->plugin->getReturnUrl()); } } } else { //try to load previously not saved payment profile if($this->plugin->loadLastProfile($this->invoice)->isSuccess()) { return $this->displayReuse(); } } return $this->displayHostedPage($this->plugin->getCancelUrl()); } } protected function displayReuse() { $result = new Am_Paysystem_Result; $tr = new Am_Paysystem_Transaction_AuthorizeCim_GetCustomerProfile($this->plugin, $this->invoice, $this->invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::USER_PROFILE_KEY)); $tr->run($result); if (!$result->isSuccess()) throw new Am_Exception_Paysystem("Stored customer profile not found"); $payprofileid = $this->invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY); foreach ($tr->xml->profile->paymentProfiles as $pp) { if ($payprofileid == (string)$pp->customerPaymentProfileId) { $card = (string)$pp->payment->creditCard->cardNumber; } } if (empty($card)) throw new Am_Exception_Paysystem("Store payment profile not found"); $text = ___('Click "Continue" to pay this order using stored credit card %s', $card); $continue = ___('Continue'); $use_new_card = ___("Use another card"); $url = $this->_request->assembleUrl(false,true); $action = $this->plugin->getPluginUrl('cc'); $id = Am_Html::escape($this->_request->get('id')); $action = Am_Html::escape($action); $this->view->content .= << $text
   $use_new_card
CUT; $this->view->display('layout.phtml'); } public function updateAction() { $user = $this->getDi()->auth->getUser(true); // dirty hack - load last user invoice to be used in process $this->invoice = $this->getDi()->invoiceTable->findFirstBy(array('user_id' => $user->pk(), 'paysys_id' => $this->plugin->getId()), 0, 1, "invoice_id DESC"); if (!$this->invoice) throw new Am_Exception_InternalError("No active invoices found, but update cc info request received?"); $this->plugin->_setInvoice($this->invoice); $this->view->title = ___('Payment Info'); $this->view->invoice = null; $this->view->content = ""; if ($this->_request->get('result') == 'success') { if(!$user->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY)) { $this->plugin->loadLastProfile($this->invoice); } $this->_redirect(ROOT_SURL . '/member'); } return $this->displayHostedPage(ROOT_SURL . '/member'); } protected function displayHostedPage($cancelUrl) { $id = $this->invoice->getUser()->data()->get(Am_Paysystem_AuthorizeCim::PAYMENT_PROFILE_KEY); if ($id) { $method = 'editPayment'; $id = filterId($id); } else { $method = 'addPayment'; $id = null; } $token = $this->plugin->getHostedProfilePageToken(); $domain = $this->plugin->getConfig('testing') ? 'test' : 'secure'; $cancelUrl = json_encode($cancelUrl); $popupTitle = json_encode(___('Credit Card Info')); $plzwt = ___('Please wait while we process your order...'); $plzwt2 = ___('Click here if you do not want to wait any longer (or if your browser does not automatically forward you).'); $this->view->content .= <<