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
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 .= <<