Skip to content

Extensions to Pr36 #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" }
},
"require": {
"omnipay/common": "~2.2"
"omnipay/common": "~2.5"
},
"require-dev": {
"omnipay/tests": "~2.0"
Expand Down
44 changes: 44 additions & 0 deletions src/AIMGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@
*/
class AIMGateway extends AbstractGateway
{
/**
* The device type collecting credit card data.
*/
const DEVICE_TYPE_UNKNOWN = 1;
const DEVICE_TYPE_UNATTENDED_TERMINAL = 2;
const DEVICE_TYPE_SELF_SERVICE_TERMINAL = 3;
const DEVICE_TYPE_ELECTRONIC_CASH_REGISTER = 4;
const DEVICE_TYPE_PC_TERMINAL = 5;
const DEVICE_TYPE_AIRPAY = 6;
const DEVICE_TYPE_WIRELESS_POS = 7;
const DEVICE_TYPE_WEBSITE = 8;
const DEVICE_TYPE_DIAL_TERMINAL = 9;
const DEVICE_TYPE_VIRTUAL_TERMINAL = 10;

public function getName()
{
return 'Authorize.Net AIM';
Expand All @@ -29,6 +43,7 @@ public function getDefaultParameters()
'hashSecret' => '',
'liveEndpoint' => 'https://api2.authorize.net/xml/v1/request.api',
'developerEndpoint' => 'https://apitest.authorize.net/xml/v1/request.api',
'deviceType' => static::DEVICE_TYPE_UNKNOWN
);
}

Expand Down Expand Up @@ -108,6 +123,35 @@ public function setDuplicateWindow($value)
return $this->setParameter('duplicateWindow', $value);
}

public function getDeviceType()
{
return $this->getParameter('deviceType');
}

/**
* Sets the type of device used to collect the credit card data.
* A device type is required for card present transactions.
*
* 1 = Unknown
* 2 = Unattended Terminal
* 3 = Self Service Terminal
* 4 = Electronic Cash Register
* 5 = Personal Computer-Based Terminal
* 6 = AirPay
* 7 = Wireless POS
* 8 = Website
* 9 = Dial Terminal
* 10 = Virtual Terminal
*
* @see http://developer.authorize.net/api/reference/#payment-transactions-charge-a-credit-card
* @param $value
* @return $this
*/
public function setDeviceType($value)
{
return $this->setParameter('deviceType', $value);
}

/**
* @param array $parameters
* @return AIMAuthorizeRequest
Expand Down
27 changes: 21 additions & 6 deletions src/Message/AIMAbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ public function setSolutionId($value)
return $this->setParameter('solutionId', $value);
}

public function getDeviceType()
{
return $this->getParameter('deviceType');
}

public function setDeviceType($value)
{
return $this->setParameter('deviceType', $value);
}

/**
* @return TransactionReference
*/
Expand Down Expand Up @@ -325,18 +335,23 @@ protected function addTransactionSettings(\SimpleXMLElement $data)
$i = 0;

// The test mode setting indicates whether or not this is a live request or a test request
$data->transactionRequest->transactionSettings->setting[$i]->settingName = 'testRequest';
$data->transactionRequest->transactionSettings->setting[$i]->settingValue = $this->getTestMode()
? 'true'
: 'false';
$transactionRequest = $data->transactionRequest;
$transactionRequest->transactionSettings->setting[$i]->settingName = 'testRequest';
$transactionRequest->transactionSettings->setting[$i]->settingValue = $this->getTestMode() ? 'true' : 'false';

// The duplicate window setting specifies the threshold for AuthorizeNet's duplicate transaction detection logic
if (!is_null($this->getDuplicateWindow())) {
$i++;
$data->transactionRequest->transactionSettings->setting[$i]->settingName = 'duplicateWindow';
$data->transactionRequest->transactionSettings->setting[$i]->settingValue = $this->getDuplicateWindow();
$transactionRequest->transactionSettings->setting[$i]->settingName = 'duplicateWindow';
$transactionRequest->transactionSettings->setting[$i]->settingValue = $this->getDuplicateWindow();
}

return $data;
}

protected function isCardPresent()
{
// If the credit card has track data, then consider this a "card present" scenario
return ($card = $this->getCard()) && $card->getTracks();
}
}
34 changes: 30 additions & 4 deletions src/Message/AIMAuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function getData()
$this->addSolutionId($data);
$this->addBillingData($data);
$this->addCustomerIP($data);
$this->addRetail($data);
$this->addTransactionSettings($data);

return $data;
Expand All @@ -36,13 +37,29 @@ protected function addPayment(\SimpleXMLElement $data)
return;
}

// The CreditCard object must be present.
$this->validate('card');

/** @var CreditCard $card */
$card = $this->getCard();
$card->validate();
$data->transactionRequest->payment->creditCard->cardNumber = $card->getNumber();
$data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my');
$data->transactionRequest->payment->creditCard->cardCode = $card->getCvv();

if ($card->getTracks()) {
// Card present
if ($track1 = $card->getTrack1()) {
$data->transactionRequest->payment->trackData->track1 = $track1;
} elseif ($track2 = $card->getTrack2()) {
$data->transactionRequest->payment->trackData->track2 = $track2;
}
} else {
// Card not present.

// Validate sufficient card details have been supplied.
$card->validate();

$data->transactionRequest->payment->creditCard->cardNumber = $card->getNumber();
$data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my');
$data->transactionRequest->payment->creditCard->cardCode = $card->getCvv();
}
}

protected function addCustomerIP(\SimpleXMLElement $data)
Expand All @@ -52,4 +69,13 @@ protected function addCustomerIP(\SimpleXMLElement $data)
$data->transactionRequest->customerIP = $ip;
}
}

protected function addRetail(\SimpleXMLElement $data)
{
if ($this->isCardPresent()) {
// Retail element is required for card present transactions
$data->transactionRequest->retail->marketType = 2;
$data->transactionRequest->retail->deviceType = $this->getDeviceType();
}
}
}
50 changes: 30 additions & 20 deletions src/Message/CIMAuthorizeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,48 @@ class CIMAuthorizeRequest extends AIMAuthorizeRequest
{
protected function addPayment(\SimpleXMLElement $data)
{
$this->validate('cardReference');
if ($this->isCardPresent()) {
// Prefer the track data if present over the payment profile (better rate)
return parent::addPayment($data);
} else {
$this->validate('cardReference');

/** @var mixed $req */
$req = $data->transactionRequest;
/** @var mixed $req */
$req = $data->transactionRequest;

/** @var CardReference $cardRef */
$cardRef = $this->getCardReference(false);
/** @var CardReference $cardRef */
$cardRef = $this->getCardReference(false);

$req->profile->customerProfileId = $cardRef->getCustomerProfileId();
$req->profile->customerProfileId = $cardRef->getCustomerProfileId();

$req->profile->paymentProfile->paymentProfileId = $cardRef->getPaymentProfileId();
$req->profile->paymentProfile->paymentProfileId = $cardRef->getPaymentProfileId();

if ($shippingProfileId = $cardRef->getShippingProfileId()) {
$req->profile->shippingProfileId = $shippingProfileId;
}
if ($shippingProfileId = $cardRef->getShippingProfileId()) {
$req->profile->shippingProfileId = $shippingProfileId;
}

$invoiceNumber = $this->getInvoiceNumber();
if (!empty($invoiceNumber)) {
$req->order->invoiceNumber = $invoiceNumber;
}
$invoiceNumber = $this->getInvoiceNumber();
if (!empty($invoiceNumber)) {
$req->order->invoiceNumber = $invoiceNumber;
}

$description = $this->getDescription();
if (!empty($description)) {
$req->order->description = $description;
$description = $this->getDescription();
if (!empty($description)) {
$req->order->description = $description;
}

return $data;
}

return $data;
}

protected function addBillingData(\SimpleXMLElement $data)
{
// Do nothing since billing information is already part of the customer profile
return $data;
if ($this->isCardPresent()) {
return parent::addBillingData($data);
} else {
// Do nothing since billing information is already part of the customer profile
return $data;
}
}
}
10 changes: 10 additions & 0 deletions src/Message/SIMAbstractRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ public function getInvoiceNumber()
return $this->getParameter('invoiceNumber');
}

public function getDeviceType()
{
return $this->getParameter('deviceType');
}

public function setDeviceType($value)
{
return $this->setParameter('deviceType', $value);
}

/**
* Base data used only for the AIM API.
*/
Expand Down
17 changes: 17 additions & 0 deletions tests/AIMGatewayIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,21 @@ public function testPurchaseRefundAutoVoid()
$response = $request->send();
$this->assertTrue($response->isSuccessful(), 'Automatic void should succeed');
}

public function testPurchaseCardPresent()
{
$amount = rand(10, 100) . '.' . rand(0, 99);
$card = array(
'number' => '4242424242424242',
'expiryMonth' => rand(1, 12),
'expiryYear' => gmdate('Y') + rand(1, 5),
'tracks' => '%B4242424242424242^SMITH/JOHN ^2511126100000000000000444000000?;4242424242424242=25111269999944401?'
);
$request = $this->gateway->purchase(array(
'amount' => $amount,
'card' => $card
));
$response = $request->send();
$this->assertTrue($response->isSuccessful());
}
}
51 changes: 51 additions & 0 deletions tests/Message/AIMAuthorizeRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public function testGetData()
$setting = $data->transactionRequest->transactionSettings->setting[0];
$this->assertEquals('testRequest', $setting->settingName);
$this->assertEquals('false', $setting->settingValue);
$this->assertObjectNotHasAttribute('trackData', $data->transactionRequest->payment);
$this->assertObjectNotHasAttribute('retail', $data->transactionRequest);
}

public function testGetDataTestMode()
Expand Down Expand Up @@ -89,4 +91,53 @@ public function testShouldIncludeDuplicateWindowSetting()
$this->assertEquals('duplicateWindow', $setting->settingName);
$this->assertEquals('0', $setting->settingValue);
}

public function testGetDataCardPresentTrack1()
{
$card = $this->getValidCard();
$card['tracks'] = '%B4242424242424242^SMITH/JOHN ^2511126100000000000000444000000?;4242424242424242=25111269999944401?';

// If sending tracks, then the card number and expiry date are not required.
unset($card['number']);
unset($card['expiryMonth']);
unset($card['expiryYear']);
unset($card['cvv']);

$this->request->initialize(array(
'amount' => '12.12',
'card' => $card,
'deviceType' => 1
));

$data = $this->request->getData();

$this->assertEquals('12.12', $data->transactionRequest->amount);
$this->assertEquals(
'%B4242424242424242^SMITH/JOHN ^2511126100000000000000444000000?',
$data->transactionRequest->payment->trackData->track1);
$this->assertObjectNotHasAttribute('creditCard', $data->transactionRequest->payment);
$this->assertEquals('2', $data->transactionRequest->retail->marketType);
$this->assertEquals('1', $data->transactionRequest->retail->deviceType);
}

public function testGetDataCardPresentTrack2()
{
$card = $this->getValidCard();
$card['tracks'] = ';4242424242424242=25111269999944401?';
$this->request->initialize(array(
'amount' => '12.12',
'card' => $card,
'deviceType' => 1
));

$data = $this->request->getData();

$this->assertEquals('12.12', $data->transactionRequest->amount);
$this->assertEquals(
';4242424242424242=25111269999944401?',
$data->transactionRequest->payment->trackData->track2);
$this->assertObjectNotHasAttribute('creditCard', $data->transactionRequest->payment);
$this->assertEquals('2', $data->transactionRequest->retail->marketType);
$this->assertEquals('1', $data->transactionRequest->retail->deviceType);
}
}
15 changes: 15 additions & 0 deletions tests/Message/CIMAuthorizeRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,19 @@ public function testGetData()
$this->assertEquals('00001234', $data->transactionRequest->order->invoiceNumber);
$this->assertEquals('Test authorize transaction', $data->transactionRequest->order->description);
}

public function testShouldUseTrackDataIfCardPresent()
{
$card = $this->getValidCard();
$card['tracks'] = '%B4242424242424242^SMITH/JOHN ^2511126100000000000000444000000?;4242424242424242=25111269999944401?';
$this->request->initialize(array(
'card' => $card,
'amount' => 21.00
));

$data = $this->request->getData();

$this->assertObjectNotHasAttribute('profile', $data->transactionRequest);
$this->assertObjectHasAttribute('trackData', $data->transactionRequest->payment);
}
}