From d5842009c429ec1cb139939dea9e496f92926f2a Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 2 Aug 2014 11:44:21 +0530 Subject: [PATCH 001/254] Completely separated AIM and SIM classes. Updated AIM to use the new XML API. --- src/AIMGateway.php | 21 ++- src/Message/AIMAbstractRequest.php | 131 ++++++++++++++++++ src/Message/AIMAuthorizeRequest.php | 2 +- ...ptureRequest.php => AIMCaptureRequest.php} | 2 +- src/Message/AIMResponse.php | 77 ++++++++-- src/Message/AIMVoidRequest.php | 2 +- ...ractRequest.php => SIMAbstractRequest.php} | 10 +- src/Message/SIMAuthorizeRequest.php | 2 +- src/Message/SIMCaptureRequest.php | 22 +++ src/Message/SIMCompleteAuthorizeRequest.php | 2 +- tests/AIMGatewayTest.php | 5 + tests/Message/AIMPurchaseRequestTest.php | 3 + tests/Message/AIMResponseTest.php | 26 ++-- tests/Mock/AIMAuthorizeFailure.txt | 16 ++- tests/Mock/AIMAuthorizeSuccess.txt | 16 ++- tests/Mock/AIMCaptureFailure.txt | 16 ++- tests/Mock/AIMCaptureSuccess.txt | 16 ++- tests/Mock/AIMPurchaseFailure.txt | 16 ++- tests/Mock/AIMPurchaseSuccess.txt | 16 ++- tests/Mock/AIMVoidFailure.txt | 16 ++- tests/Mock/AIMVoidSuccess.txt | 16 ++- 21 files changed, 343 insertions(+), 90 deletions(-) create mode 100644 src/Message/AIMAbstractRequest.php rename src/Message/{CaptureRequest.php => AIMCaptureRequest.php} (89%) rename src/Message/{AbstractRequest.php => SIMAbstractRequest.php} (93%) create mode 100644 src/Message/SIMCaptureRequest.php diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 990c5928..9acf115e 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -4,7 +4,8 @@ use Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest; use Omnipay\AuthorizeNet\Message\AIMPurchaseRequest; -use Omnipay\AuthorizeNet\Message\CaptureRequest; +use Omnipay\AuthorizeNet\Message\AIMVoidRequest; +use Omnipay\AuthorizeNet\Message\SIMCaptureRequest; use Omnipay\Common\AbstractGateway; /** @@ -57,21 +58,37 @@ public function setDeveloperMode($value) return $this->setParameter('developerMode', $value); } + /** + * @param array $parameters + * @return AIMAuthorizeRequest + */ public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest', $parameters); } + /** + * @param array $parameters + * @return SIMCaptureRequest + */ public function capture(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\CaptureRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMCaptureRequest', $parameters); } + /** + * @param array $parameters + * @return AIMPurchaseRequest + */ public function purchase(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMPurchaseRequest', $parameters); } + /** + * @param array $parameters + * @return AIMVoidRequest + */ public function void(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMVoidRequest', $parameters); diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php new file mode 100644 index 00000000..64f2ac6d --- /dev/null +++ b/src/Message/AIMAbstractRequest.php @@ -0,0 +1,131 @@ +getParameter('apiLoginId'); + } + + public function setApiLoginId($value) + { + return $this->setParameter('apiLoginId', $value); + } + + public function getTransactionKey() + { + return $this->getParameter('transactionKey'); + } + + public function setTransactionKey($value) + { + return $this->setParameter('transactionKey', $value); + } + + public function getDeveloperMode() + { + return $this->getParameter('developerMode'); + } + + public function setDeveloperMode($value) + { + return $this->setParameter('developerMode', $value); + } + + public function getCustomerId() + { + return $this->getParameter('customerId'); + } + + public function setCustomerId($value) + { + return $this->setParameter('customerId', $value); + } + + public function getHashSecret() + { + return $this->getParameter('hashSecret'); + } + + public function setHashSecret($value) + { + return $this->setParameter('hashSecret', $value); + } + + protected function getBaseData() + { + $data = array(); + $data['x_login'] = $this->getApiLoginId(); + $data['x_tran_key'] = $this->getTransactionKey(); + $data['x_type'] = $this->action; + $data['x_version'] = '3.1'; + $data['x_delim_data'] = 'TRUE'; + $data['x_delim_char'] = ','; + $data['x_encap_char'] = '|'; + $data['x_relay_response'] = 'FALSE'; + + return $data; + } + + protected function getBillingData() + { + $data = array(); + $data['x_amount'] = $this->getAmount(); + $data['x_invoice_num'] = $this->getTransactionId(); + $data['x_description'] = $this->getDescription(); + + if ($card = $this->getCard()) { + // customer billing details + $data['x_first_name'] = $card->getBillingFirstName(); + $data['x_last_name'] = $card->getBillingLastName(); + $data['x_company'] = $card->getBillingCompany(); + $data['x_address'] = trim( + $card->getBillingAddress1() . " \n" . + $card->getBillingAddress2() + ); + $data['x_city'] = $card->getBillingCity(); + $data['x_state'] = $card->getBillingState(); + $data['x_zip'] = $card->getBillingPostcode(); + $data['x_country'] = $card->getBillingCountry(); + $data['x_phone'] = $card->getBillingPhone(); + $data['x_email'] = $card->getEmail(); + + // customer shipping details + $data['x_ship_to_first_name'] = $card->getShippingFirstName(); + $data['x_ship_to_last_name'] = $card->getShippingLastName(); + $data['x_ship_to_company'] = $card->getShippingCompany(); + $data['x_ship_to_address'] = trim( + $card->getShippingAddress1() . " \n" . + $card->getShippingAddress2() + ); + $data['x_ship_to_city'] = $card->getShippingCity(); + $data['x_ship_to_state'] = $card->getShippingState(); + $data['x_ship_to_zip'] = $card->getShippingPostcode(); + $data['x_ship_to_country'] = $card->getShippingCountry(); + } + + return $data; + } + + public function sendData($data) + { + $httpResponse = $this->httpClient->post($this->getEndpoint(), null, $data)->send(); + + return $this->response = new AIMResponse($this, $httpResponse->getBody()); + } + + public function getEndpoint() + { + return $this->getDeveloperMode() ? $this->developerEndpoint : $this->liveEndpoint; + } +} diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 7e58c4d4..3943e947 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -5,7 +5,7 @@ /** * Authorize.Net AIM Authorize Request */ -class AIMAuthorizeRequest extends AbstractRequest +class AIMAuthorizeRequest extends AIMAbstractRequest { protected $action = 'AUTH_ONLY'; diff --git a/src/Message/CaptureRequest.php b/src/Message/AIMCaptureRequest.php similarity index 89% rename from src/Message/CaptureRequest.php rename to src/Message/AIMCaptureRequest.php index 096818cb..a328b027 100644 --- a/src/Message/CaptureRequest.php +++ b/src/Message/AIMCaptureRequest.php @@ -5,7 +5,7 @@ /** * Authorize.Net Capture Request */ -class CaptureRequest extends AbstractRequest +class AIMCaptureRequest extends AIMAbstractRequest { protected $action = 'PRIOR_AUTH_CAPTURE'; diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 9fa0907e..9ed82e47 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -14,45 +14,102 @@ class AIMResponse extends AbstractResponse public function __construct(RequestInterface $request, $data) { $this->request = $request; - $this->data = explode('|,|', substr($data, 1, -1)); - if (count($this->data) < 10) { + // Strip out the xmlns junk so that PHP can parse the XML + $xml = preg_replace('/]+>/', '', (string)$data); + + try { + $xml = simplexml_load_string($xml); + } catch(\Exception $e) { + throw new InvalidResponseException(); + } + + if(!$xml) { throw new InvalidResponseException(); } + + $this->data = $xml; } public function isSuccessful() { - return '1' === $this->getCode(); + return 1 === $this->getResultCode(); } - public function getCode() + /** + * Overall status of the transaction. This field is also known as "Response Code" in Authorize.NET terminology. + * + * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review + */ + public function getResultCode() { - return $this->data[0]; + return intval((string)$this->data->transactionResponse[0]->responseCode); } + /** + * A more detailed version of the Result/Response code. + * + * @return int|null + */ public function getReasonCode() { - return $this->data[2]; + $code = null; + + if(isset($this->data->transactionResponse[0]->messages)) { + // In case of a successful transaction, a "messages" element is present + $code = intval((string)$this->data->transactionResponse[0]->messages[0]->message[0]->code); + + } elseif(isset($this->data->transactionResponse[0]->errors)) { + // In case of an unsuccessful transaction, an "errors" element is present + $code = intval((string)$this->data->transactionResponse[0]->errors[0]->error[0]->errorCode); + } + + return $code; } + /** + * Text description of the status. + * + * @return string|null + */ public function getMessage() { - return $this->data[3]; + $message = null; + + if(isset($this->data->transactionResponse[0]->messages)) { + // In case of a successful transaction, a "messages" element is present + $message = (string)$this->data->transactionResponse[0]->messages[0]->message[0]->description; + + } elseif(isset($this->data->transactionResponse[0]->errors)) { + // In case of an unsuccessful transaction, an "errors" element is present + $message = (string)$this->data->transactionResponse[0]->errors[0]->error[0]->errorText; + } + + return $message; } public function getAuthorizationCode() { - return $this->data[4]; + return (string)$this->data->transactionResponse[0]->authCode; } + /** + * Returns the Address Verification Service return code. + * + * @return string A single character. Can be A, B, E, G, N, P, R, S, U, X, Y, or Z. + */ public function getAVSCode() { - return $this->data[5]; + return (string)$this->data->transactionResponse[0]->avsResultCode; } + /** + * The payment gateway assigned identification number for transaction. + * + * @return string + */ public function getTransactionReference() { - return $this->data[6]; + return (string)$this->data->transactionResponse[0]->transId; } } diff --git a/src/Message/AIMVoidRequest.php b/src/Message/AIMVoidRequest.php index 857dfdbd..4775cd27 100644 --- a/src/Message/AIMVoidRequest.php +++ b/src/Message/AIMVoidRequest.php @@ -5,7 +5,7 @@ /** * Authorize.Net AIM Void Request */ -class AIMVoidRequest extends AbstractRequest +class AIMVoidRequest extends SIMAbstractRequest { protected $action = 'VOID'; diff --git a/src/Message/AbstractRequest.php b/src/Message/SIMAbstractRequest.php similarity index 93% rename from src/Message/AbstractRequest.php rename to src/Message/SIMAbstractRequest.php index a8d45f19..5eb4ed41 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/SIMAbstractRequest.php @@ -2,10 +2,12 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Message\AbstractRequest; + /** - * Authorize.Net Abstract Request + * Authorize.Net SIM Abstract Request */ -abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest +abstract class SIMAbstractRequest extends AbstractRequest { protected $liveEndpoint = 'https://secure.authorize.net/gateway/transact.dll'; protected $developerEndpoint = 'https://test.authorize.net/gateway/transact.dll'; @@ -88,7 +90,7 @@ protected function getBillingData() $data['x_last_name'] = $card->getBillingLastName(); $data['x_company'] = $card->getBillingCompany(); $data['x_address'] = trim( - $card->getBillingAddress1()." \n". + $card->getBillingAddress1() . " \n" . $card->getBillingAddress2() ); $data['x_city'] = $card->getBillingCity(); @@ -103,7 +105,7 @@ protected function getBillingData() $data['x_ship_to_last_name'] = $card->getShippingLastName(); $data['x_ship_to_company'] = $card->getShippingCompany(); $data['x_ship_to_address'] = trim( - $card->getShippingAddress1()." \n". + $card->getShippingAddress1() . " \n" . $card->getShippingAddress2() ); $data['x_ship_to_city'] = $card->getShippingCity(); diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index fc877eb0..c81fbe6c 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -5,7 +5,7 @@ /** * Authorize.Net SIM Authorize Request */ -class SIMAuthorizeRequest extends AbstractRequest +class SIMAuthorizeRequest extends SIMAbstractRequest { protected $action = 'AUTH_ONLY'; diff --git a/src/Message/SIMCaptureRequest.php b/src/Message/SIMCaptureRequest.php new file mode 100644 index 00000000..a6b39cb7 --- /dev/null +++ b/src/Message/SIMCaptureRequest.php @@ -0,0 +1,22 @@ +validate('amount', 'transactionReference'); + + $data = $this->getBaseData(); + $data['x_amount'] = $this->getAmount(); + $data['x_trans_id'] = $this->getTransactionReference(); + + return $data; + } +} diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index e3ecbb4a..e2513029 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -7,7 +7,7 @@ /** * Authorize.Net SIM Complete Authorize Request */ -class SIMCompleteAuthorizeRequest extends AbstractRequest +class SIMCompleteAuthorizeRequest extends SIMAbstractRequest { public function getData() { diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 57ea12bc..86f80913 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -8,6 +8,11 @@ class AIMGatewayTest extends GatewayTestCase { protected $voidOptions; + /** @var AIMGateway */ + protected $gateway; + protected $purchaseOptions; + protected $captureOptions; + public function setUp() { parent::setUp(); diff --git a/tests/Message/AIMPurchaseRequestTest.php b/tests/Message/AIMPurchaseRequestTest.php index a4486e59..5447b17e 100644 --- a/tests/Message/AIMPurchaseRequestTest.php +++ b/tests/Message/AIMPurchaseRequestTest.php @@ -6,6 +6,8 @@ class AIMPurchaseRequestTest extends TestCase { + private $request; + public function setUp() { $this->request = new AIMPurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); @@ -27,5 +29,6 @@ public function testGetData() $this->assertSame('10.0.0.1', $data['x_customer_ip']); $this->assertSame('cust-id', $data['x_cust_id']); $this->assertArrayNotHasKey('x_test_request', $data); + //1 } } diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 98ed2b81..9a50a9af 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -11,7 +11,7 @@ class AIMResponseTest extends TestCase */ public function testConstructEmpty() { - $response = new AIMResponse($this->getMockRequest(), ''); + new AIMResponse($this->getMockRequest(), ''); } public function testAuthorizeSuccess() @@ -22,8 +22,8 @@ public function testAuthorizeSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184493132', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); - $this->assertSame('1', $response->getReasonCode()); + $this->assertSame(1, $response->getResultCode()); + $this->assertSame(1, $response->getReasonCode()); $this->assertSame('GA4OQP', $response->getAuthorizationCode()); $this->assertSame('Y', $response->getAVSCode()); } @@ -36,8 +36,8 @@ public function testAuthorizeFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); - $this->assertSame('5', $response->getReasonCode()); + $this->assertSame(3, $response->getResultCode()); + $this->assertSame(5, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); } @@ -50,8 +50,8 @@ public function testCaptureSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184494531', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); - $this->assertSame('1', $response->getReasonCode()); + $this->assertSame(1, $response->getResultCode()); + $this->assertSame(1, $response->getReasonCode()); $this->assertSame('F51OYG', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); } @@ -64,8 +64,8 @@ public function testCaptureFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); - $this->assertSame('16', $response->getReasonCode()); + $this->assertSame(3, $response->getResultCode()); + $this->assertSame(16, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); } @@ -78,8 +78,8 @@ public function testPurchaseSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184492509', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); - $this->assertSame('1', $response->getReasonCode()); + $this->assertSame(1, $response->getResultCode()); + $this->assertSame(1, $response->getReasonCode()); $this->assertSame('JE6JM1', $response->getAuthorizationCode()); $this->assertSame('Y', $response->getAVSCode()); } @@ -92,8 +92,8 @@ public function testPurchaseFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); - $this->assertSame('5', $response->getReasonCode()); + $this->assertSame(3, $response->getResultCode()); + $this->assertSame(5, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); } diff --git a/tests/Mock/AIMAuthorizeFailure.txt b/tests/Mock/AIMAuthorizeFailure.txt index 67990bf1..7afd8e94 100644 --- a/tests/Mock/AIMAuthorizeFailure.txt +++ b/tests/Mock/AIMAuthorizeFailure.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:23:27 GMT +Date: Sat, 02 Aug 2014 05:20:38 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 326 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 844 -|3|,|1|,|5|,|A valid amount is required.|,||,|P|,|0|,|12345|,|first purchase|,|-0.01|,|CC|,|auth_only|,||,|fjkdsl|,|fdjskl|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|3EB992D927587B9FC7A3D83F651CD7EF|,||,||,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +123456ErrorE00027The transaction was unsuccessful.3P03E71C42C07DA1E3D245A9733AC4685A70XXXX1111Visa5A valid amount is required. diff --git a/tests/Mock/AIMAuthorizeSuccess.txt b/tests/Mock/AIMAuthorizeSuccess.txt index 50cb36f4..ab84ae68 100644 --- a/tests/Mock/AIMAuthorizeSuccess.txt +++ b/tests/Mock/AIMAuthorizeSuccess.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:22:58 GMT +Date: Sat, 02 Aug 2014 05:17:50 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 350 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 884 -|1|,|1|,|1|,|This transaction has been approved.|,|GA4OQP|,|Y|,|2184493132|,|12345|,|first purchase|,|2.00|,|CC|,|auth_only|,||,|fjkdsl|,|fdjskl|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|50D842FB596025E1C7779440D0A62496|,|P|,|2|,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +123456OkI00001Successful.1GA4OQPYP22184493132DEBBE205CFD3D2DD0FD760EEBAAB81CC0XXXX1111Visa1This transaction has been approved. diff --git a/tests/Mock/AIMCaptureFailure.txt b/tests/Mock/AIMCaptureFailure.txt index e675173d..3b153e97 100644 --- a/tests/Mock/AIMCaptureFailure.txt +++ b/tests/Mock/AIMCaptureFailure.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:58:47 GMT +Date: Sat, 02 Aug 2014 05:27:33 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 297 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 843 -|3|,|2|,|16|,|The transaction cannot be found.|,||,|P|,|0|,||,||,|2.00|,|CC|,|prior_auth_capture|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|7432D28FA29C86EFEDBFD80C4767CD8C|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +123456ErrorE00027The transaction was unsuccessful.3P02217228529A6CE7FE3D05349C08757AEC6167D9973016The transaction cannot be found. diff --git a/tests/Mock/AIMCaptureSuccess.txt b/tests/Mock/AIMCaptureSuccess.txt index 67e4562c..26eaae6f 100644 --- a/tests/Mock/AIMCaptureSuccess.txt +++ b/tests/Mock/AIMCaptureSuccess.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:56:28 GMT +Date: Sat, 02 Aug 2014 05:24:31 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 326 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 874 -|1|,|1|,|1|,|This transaction has been approved.|,|F51OYG|,|P|,|2184494531|,||,||,|2.00|,|CC|,|prior_auth_capture|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|7B7038AB4FA82268A512E6B2F571853A|,||,||,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +123456OkI00001Successful.1F51OYGP2184494531221722852063EB140326D174968408461DC35FFB8D0XXXX1111Visa1This transaction has been approved. diff --git a/tests/Mock/AIMPurchaseFailure.txt b/tests/Mock/AIMPurchaseFailure.txt index 84dc2538..ee943e3d 100644 --- a/tests/Mock/AIMPurchaseFailure.txt +++ b/tests/Mock/AIMPurchaseFailure.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:00:47 GMT +Date: Sat, 02 Aug 2014 04:53:02 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 323 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 842 -|3|,|1|,|5|,|A valid amount is required.|,||,|P|,|0|,|12345|,|first purchase|,|-0.01|,|CC|,|auth_capture|,||,|fds|,|fds|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|3EB992D927587B9FC7A3D83F651CD7EF|,||,||,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +1234ErrorE00027The transaction was unsuccessful.3P0A6E047D5E58293477044C2F7EC8DF7280XXXX1111Visa5A valid amount is required. diff --git a/tests/Mock/AIMPurchaseSuccess.txt b/tests/Mock/AIMPurchaseSuccess.txt index cb83def5..bb6a4348 100644 --- a/tests/Mock/AIMPurchaseSuccess.txt +++ b/tests/Mock/AIMPurchaseSuccess.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:00:03 GMT +Date: Fri, 01 Aug 2014 16:27:55 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 347 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 885 -|1|,|1|,|1|,|This transaction has been approved.|,|JE6JM1|,|Y|,|2184492509|,|12345|,|first purchase|,|1.00|,|CC|,|auth_capture|,||,|fds|,|fds|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|35951A3F0A91940575132EA09CA1DC31|,|P|,|2|,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +1234567OkI00001Successful.1JE6JM1YP2218449250980D0CCE771C80625E743A8AFAB6A45EA0XXXX1111Visa1This transaction has been approved. diff --git a/tests/Mock/AIMVoidFailure.txt b/tests/Mock/AIMVoidFailure.txt index 98d083dc..6ad40059 100644 --- a/tests/Mock/AIMVoidFailure.txt +++ b/tests/Mock/AIMVoidFailure.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:00:47 GMT +Date: Sat, 02 Aug 2014 06:08:23 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 309 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 826 -|3|,|2|,|33|,|A valid referenced transaction ID is required.|,||,|P|,|0|,||,||,|0.00|,|CC|,|void|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|554B8CA3AE27C6104986860760858E83|,||,||,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +123456ErrorE00027The transaction was unsuccessful.3P0A6E047D5E58293477044C2F7EC8DF728033A valid referenced transaction ID is required. diff --git a/tests/Mock/AIMVoidSuccess.txt b/tests/Mock/AIMVoidSuccess.txt index d1e638d8..7d02fb4d 100644 --- a/tests/Mock/AIMVoidSuccess.txt +++ b/tests/Mock/AIMVoidSuccess.txt @@ -1,11 +1,13 @@ HTTP/1.1 200 OK -Connection: close -Date: Sat, 16 Feb 2013 04:00:03 GMT +Date: Sat, 02 Aug 2014 06:07:08 GMT Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method X-Powered-By: ASP.NET -Content-Type: text/html -Content-Length: 307 -Cache-Control: private, must-revalidate, max-age=0 -Expires: Tue, 01 Jan 1980 00:00:00 GMT +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 836 -|1|,|1|,|310|,|This transaction has already been voided.|,||,|P|,|0|,||,||,|0.00|,|CC|,|void|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|554B8CA3AE27C6104986860760858E83|,|P|,|2|,||,||,||,||,||,||,||,||,||,||,|XXXX1111|,|Visa|,||,||,||,||,||,||,||,||,||,||,||,||,||,||,||,|| +123456OkI00001Successful.1P02217228520A6E047D5E58293477044C2F7EC8DF7280Visa310This transaction has already been voided. From 7c7578bcbaa1c9b5905a2bd5c481df6debbb4ce5 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 2 Aug 2014 13:38:48 +0530 Subject: [PATCH 002/254] AIM request classes construct XML requests --- src/AIMGateway.php | 4 +- src/Message/AIMAbstractRequest.php | 114 ++++++++++++---------- src/Message/AIMAuthorizeRequest.php | 26 ++--- src/Message/AIMCaptureRequest.php | 8 +- src/Message/AIMPurchaseRequest.php | 2 +- src/Message/AIMVoidRequest.php | 6 +- tests/Message/AIMAuthorizeRequestTest.php | 18 +++- tests/Message/AIMPurchaseRequestTest.php | 13 ++- 8 files changed, 109 insertions(+), 82 deletions(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 9acf115e..32c41f90 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -3,9 +3,9 @@ namespace Omnipay\AuthorizeNet; use Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest; +use Omnipay\AuthorizeNet\Message\AIMCaptureRequest; use Omnipay\AuthorizeNet\Message\AIMPurchaseRequest; use Omnipay\AuthorizeNet\Message\AIMVoidRequest; -use Omnipay\AuthorizeNet\Message\SIMCaptureRequest; use Omnipay\Common\AbstractGateway; /** @@ -69,7 +69,7 @@ public function authorize(array $parameters = array()) /** * @param array $parameters - * @return SIMCaptureRequest + * @return AIMCaptureRequest */ public function capture(array $parameters = array()) { diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 64f2ac6d..52028287 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -2,6 +2,8 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\CreditCard; +use Omnipay\Common\Exception\InvalidRequestException; use Omnipay\Common\Message\AbstractRequest; /** @@ -12,6 +14,8 @@ abstract class AIMAbstractRequest extends AbstractRequest protected $liveEndpoint = 'https://api.authorize.net/xml/v1/request.api'; protected $developerEndpoint = 'https://apitest.authorize.net/xml/v1/request.api'; + protected $action = null; + public function getApiLoginId() { return $this->getParameter('apiLoginId'); @@ -52,66 +56,76 @@ public function setCustomerId($value) return $this->setParameter('customerId', $value); } - public function getHashSecret() + /** + * @return mixed|\SimpleXMLElement + * @throws \Omnipay\Common\Exception\InvalidRequestException + */ + public function getData() { - return $this->getParameter('hashSecret'); - } + $data = new \SimpleXMLElement(''); + $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); - public function setHashSecret($value) - { - return $this->setParameter('hashSecret', $value); - } + // Credentials + $data->merchantAuthentication->name = $this->getApiLoginId(); + $data->merchantAuthentication->transactionKey = $this->getTransactionKey(); - protected function getBaseData() - { - $data = array(); - $data['x_login'] = $this->getApiLoginId(); - $data['x_tran_key'] = $this->getTransactionKey(); - $data['x_type'] = $this->action; - $data['x_version'] = '3.1'; - $data['x_delim_data'] = 'TRUE'; - $data['x_delim_char'] = ','; - $data['x_encap_char'] = '|'; - $data['x_relay_response'] = 'FALSE'; + // User-assigned transaction ID + $txnId = $this->getTransactionId(); + if (!empty($txnId)) $data->refId = $this->getTransactionId(); + + // Transaction type + if (!$this->action) throw new InvalidRequestException(); + $data->transactionRequest->transactionType = $this->action; + + // Test mode setting + $data->transactionRequest->transactionSettings->setting->settingName = 'testRequest'; + $data->transactionRequest->transactionSettings->setting->settingValue = $this->getTestMode() ? 'true' : 'false'; return $data; } - protected function getBillingData() + /** + * Adds billing data to a partially filled request data object. + * + * @param \SimpleXMLElement $data + * @return \SimpleXMLElement + */ + protected function addBillingData(\SimpleXMLElement $data) { - $data = array(); - $data['x_amount'] = $this->getAmount(); - $data['x_invoice_num'] = $this->getTransactionId(); - $data['x_description'] = $this->getDescription(); + /** @var mixed $req */ + $req = $data->transactionRequest; + + // Amount of the purchase + $req->amount = $this->getAmount(); + + // Description of the purchase + $description = $this->getDescription(); + if (!empty($description)) $req->lineItems->lineItem->description = $description; + + // Merchant assigned customer ID + $customer = $this->getCustomerId(); + if (!empty($customer)) $req->customer->id = $customer; + /** @var CreditCard $card */ if ($card = $this->getCard()) { - // customer billing details - $data['x_first_name'] = $card->getBillingFirstName(); - $data['x_last_name'] = $card->getBillingLastName(); - $data['x_company'] = $card->getBillingCompany(); - $data['x_address'] = trim( - $card->getBillingAddress1() . " \n" . - $card->getBillingAddress2() - ); - $data['x_city'] = $card->getBillingCity(); - $data['x_state'] = $card->getBillingState(); - $data['x_zip'] = $card->getBillingPostcode(); - $data['x_country'] = $card->getBillingCountry(); - $data['x_phone'] = $card->getBillingPhone(); - $data['x_email'] = $card->getEmail(); - - // customer shipping details - $data['x_ship_to_first_name'] = $card->getShippingFirstName(); - $data['x_ship_to_last_name'] = $card->getShippingLastName(); - $data['x_ship_to_company'] = $card->getShippingCompany(); - $data['x_ship_to_address'] = trim( - $card->getShippingAddress1() . " \n" . - $card->getShippingAddress2() - ); - $data['x_ship_to_city'] = $card->getShippingCity(); - $data['x_ship_to_state'] = $card->getShippingState(); - $data['x_ship_to_zip'] = $card->getShippingPostcode(); - $data['x_ship_to_country'] = $card->getShippingCountry(); + // A card is present, so include billing and shipping details + $req->billTo->firstName = $card->getBillingFirstName(); + $req->billTo->lastName = $card->getBillingLastName(); + $req->billTo->company = $card->getBillingCompany(); + $req->billTo->address = trim($card->getBillingAddress1() . " \n" . $card->getBillingAddress2()); + $req->billTo->city = $card->getBillingCity(); + $req->billTo->state = $card->getBillingState(); + $req->billTo->zip = $card->getBillingPostcode(); + $req->billTo->country = $card->getBillingCountry(); + + $req->shipTo->firstName = $card->getShippingLastName(); + $req->shipTo->lastName = $card->getShippingLastName(); + $req->shipTo->company = $card->getShippingCompany(); + $req->shipTo->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); + $req->shipTo->city = $card->getShippingCity(); + $req->shipTo->state = $card->getShippingState(); + $req->shipTo->zip = $card->getShippingPostcode(); + $req->shipTo->country = $card->getShippingCountry(); } return $data; diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 3943e947..e1a4097c 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -2,29 +2,31 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\CreditCard; + /** * Authorize.Net AIM Authorize Request */ class AIMAuthorizeRequest extends AIMAbstractRequest { - protected $action = 'AUTH_ONLY'; + protected $action = 'authOnlyTransaction'; public function getData() { $this->validate('amount', 'card'); - $this->getCard()->validate(); - $data = $this->getBaseData(); - $data['x_customer_ip'] = $this->getClientIp(); - $data['x_card_num'] = $this->getCard()->getNumber(); - $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); - $data['x_card_code'] = $this->getCard()->getCvv(); - $data['x_cust_id'] = $this->getCustomerId(); + /** @var CreditCard $card */ + $card = $this->getCard(); + $card->validate(); + + $data = parent::getData(); + $data->transactionRequest->customerIP = $this->getClientIp(); + $data->transactionRequest->payment->creditCard->cardNumber = $card->getNumber(); + $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); + $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); - if ($this->getTestMode()) { - $data['x_test_request'] = 'TRUE'; - } + $this->addBillingData($data); - return array_merge($data, $this->getBillingData()); + return $data; } } diff --git a/src/Message/AIMCaptureRequest.php b/src/Message/AIMCaptureRequest.php index a328b027..0b2e3c93 100644 --- a/src/Message/AIMCaptureRequest.php +++ b/src/Message/AIMCaptureRequest.php @@ -7,15 +7,15 @@ */ class AIMCaptureRequest extends AIMAbstractRequest { - protected $action = 'PRIOR_AUTH_CAPTURE'; + protected $action = 'priorAuthCaptureTransaction'; public function getData() { $this->validate('amount', 'transactionReference'); - $data = $this->getBaseData(); - $data['x_amount'] = $this->getAmount(); - $data['x_trans_id'] = $this->getTransactionReference(); + $data = parent::getData(); + $data->transactionRequest->amount = $this->getAmount(); + $data->transactionRequest->refTransId = $this->getTransactionReference(); return $data; } diff --git a/src/Message/AIMPurchaseRequest.php b/src/Message/AIMPurchaseRequest.php index bfe27572..4efe9c19 100644 --- a/src/Message/AIMPurchaseRequest.php +++ b/src/Message/AIMPurchaseRequest.php @@ -7,5 +7,5 @@ */ class AIMPurchaseRequest extends AIMAuthorizeRequest { - protected $action = 'AUTH_CAPTURE'; + protected $action = 'authCaptureTransaction'; } diff --git a/src/Message/AIMVoidRequest.php b/src/Message/AIMVoidRequest.php index 4775cd27..dc7a768d 100644 --- a/src/Message/AIMVoidRequest.php +++ b/src/Message/AIMVoidRequest.php @@ -7,14 +7,14 @@ */ class AIMVoidRequest extends SIMAbstractRequest { - protected $action = 'VOID'; + protected $action = 'voidTransaction'; public function getData() { $this->validate('transactionReference'); - $data = $this->getBaseData(); - $data['x_trans_id'] = $this->getTransactionReference(); + $data = parent::getData(); + $data->transactionRequest->refTransId = $this->getTransactionReference(); return $data; } diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 350ee935..92a6ac0f 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -6,6 +6,9 @@ class AIMAuthorizeRequestTest extends TestCase { + /** @var AIMAuthorizeRequest */ + protected $request; + public function setUp() { $this->request = new AIMAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest()); @@ -23,10 +26,13 @@ public function testGetData() { $data = $this->request->getData(); - $this->assertSame('AUTH_ONLY', $data['x_type']); - $this->assertSame('10.0.0.1', $data['x_customer_ip']); - $this->assertSame('cust-id', $data['x_cust_id']); - $this->assertArrayNotHasKey('x_test_request', $data); + $this->assertEquals('authOnlyTransaction', $data->transactionRequest->transactionType); + $this->assertEquals('10.0.0.1', $data->transactionRequest->customerIP); + $this->assertEquals('cust-id', $data->transactionRequest->customer->id); + + $setting = $data->transactionRequest->transactionSettings->setting[0]; + $this->assertEquals('testRequest', $setting->settingName); + $this->assertEquals('false', $setting->settingValue); } public function testGetDataTestMode() @@ -35,6 +41,8 @@ public function testGetDataTestMode() $data = $this->request->getData(); - $this->assertSame('TRUE', $data['x_test_request']); + $setting = $data->transactionRequest->transactionSettings->setting[0]; + $this->assertEquals('testRequest', $setting->settingName); + $this->assertEquals('true', $setting->settingValue); } } diff --git a/tests/Message/AIMPurchaseRequestTest.php b/tests/Message/AIMPurchaseRequestTest.php index 5447b17e..e7e47e08 100644 --- a/tests/Message/AIMPurchaseRequestTest.php +++ b/tests/Message/AIMPurchaseRequestTest.php @@ -6,6 +6,7 @@ class AIMPurchaseRequestTest extends TestCase { + /** @var AIMPurchaseRequest */ private $request; public function setUp() @@ -25,10 +26,12 @@ public function testGetData() { $data = $this->request->getData(); - $this->assertSame('AUTH_CAPTURE', $data['x_type']); - $this->assertSame('10.0.0.1', $data['x_customer_ip']); - $this->assertSame('cust-id', $data['x_cust_id']); - $this->assertArrayNotHasKey('x_test_request', $data); - //1 + $this->assertEquals('authCaptureTransaction', $data->transactionRequest->transactionType); + $this->assertEquals('10.0.0.1', $data->transactionRequest->customerIP); + $this->assertEquals('cust-id', $data->transactionRequest->customer->id); + + $setting = $data->transactionRequest->transactionSettings->setting[0]; + $this->assertEquals('testRequest', $setting->settingName); + $this->assertEquals('false', $setting->settingValue); } } From f055372c3d6309b903cddb1bd5029f2ffc72dc1f Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 2 Aug 2014 14:10:28 +0530 Subject: [PATCH 003/254] PSR-2 formatting --- src/Message/AIMAbstractRequest.php | 17 +++++++++++++---- src/Message/AIMResponse.php | 14 +++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 52028287..a5ab232d 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -71,10 +71,15 @@ public function getData() // User-assigned transaction ID $txnId = $this->getTransactionId(); - if (!empty($txnId)) $data->refId = $this->getTransactionId(); + if (!empty($txnId)) { + $data->refId = $this->getTransactionId(); + } // Transaction type - if (!$this->action) throw new InvalidRequestException(); + if (!$this->action) { + // The extending class probably hasn't specified an "action" + throw new InvalidRequestException(); + } $data->transactionRequest->transactionType = $this->action; // Test mode setting @@ -100,11 +105,15 @@ protected function addBillingData(\SimpleXMLElement $data) // Description of the purchase $description = $this->getDescription(); - if (!empty($description)) $req->lineItems->lineItem->description = $description; + if (!empty($description)) { + $req->lineItems->lineItem->description = $description; + } // Merchant assigned customer ID $customer = $this->getCustomerId(); - if (!empty($customer)) $req->customer->id = $customer; + if (!empty($customer)) { + $req->customer->id = $customer; + } /** @var CreditCard $card */ if ($card = $this->getCard()) { diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 9ed82e47..1de2b374 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -2,9 +2,9 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractResponse; use Omnipay\Common\Message\RequestInterface; -use Omnipay\Common\Exception\InvalidResponseException; /** * Authorize.Net AIM Response @@ -20,11 +20,11 @@ public function __construct(RequestInterface $request, $data) try { $xml = simplexml_load_string($xml); - } catch(\Exception $e) { + } catch (\Exception $e) { throw new InvalidResponseException(); } - if(!$xml) { + if (!$xml) { throw new InvalidResponseException(); } @@ -55,11 +55,11 @@ public function getReasonCode() { $code = null; - if(isset($this->data->transactionResponse[0]->messages)) { + if (isset($this->data->transactionResponse[0]->messages)) { // In case of a successful transaction, a "messages" element is present $code = intval((string)$this->data->transactionResponse[0]->messages[0]->message[0]->code); - } elseif(isset($this->data->transactionResponse[0]->errors)) { + } elseif (isset($this->data->transactionResponse[0]->errors)) { // In case of an unsuccessful transaction, an "errors" element is present $code = intval((string)$this->data->transactionResponse[0]->errors[0]->error[0]->errorCode); } @@ -76,11 +76,11 @@ public function getMessage() { $message = null; - if(isset($this->data->transactionResponse[0]->messages)) { + if (isset($this->data->transactionResponse[0]->messages)) { // In case of a successful transaction, a "messages" element is present $message = (string)$this->data->transactionResponse[0]->messages[0]->message[0]->description; - } elseif(isset($this->data->transactionResponse[0]->errors)) { + } elseif (isset($this->data->transactionResponse[0]->errors)) { // In case of an unsuccessful transaction, an "errors" element is present $message = (string)$this->data->transactionResponse[0]->errors[0]->error[0]->errorText; } From 69fe39d70dbea68f0495f63fd31bd0fa3d8b6a47 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 2 Aug 2014 14:26:30 +0530 Subject: [PATCH 004/254] Removed missed dependencies between AIM and SIM --- src/Message/AIMVoidRequest.php | 2 +- src/Message/SIMVoidRequest.php | 21 +++++++++++++++++++++ src/SIMGateway.php | 13 ++++++++++--- tests/SIMGatewayTest.php | 3 +++ 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/Message/SIMVoidRequest.php diff --git a/src/Message/AIMVoidRequest.php b/src/Message/AIMVoidRequest.php index dc7a768d..e866f4a3 100644 --- a/src/Message/AIMVoidRequest.php +++ b/src/Message/AIMVoidRequest.php @@ -5,7 +5,7 @@ /** * Authorize.Net AIM Void Request */ -class AIMVoidRequest extends SIMAbstractRequest +class AIMVoidRequest extends AIMAbstractRequest { protected $action = 'voidTransaction'; diff --git a/src/Message/SIMVoidRequest.php b/src/Message/SIMVoidRequest.php new file mode 100644 index 00000000..e674869e --- /dev/null +++ b/src/Message/SIMVoidRequest.php @@ -0,0 +1,21 @@ +validate('transactionReference'); + + $data = $this->getBaseData(); + $data['x_trans_id'] = $this->getTransactionReference(); + + return $data; + } +} diff --git a/src/SIMGateway.php b/src/SIMGateway.php index 1ef4b4af..0bf0c756 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -2,9 +2,6 @@ namespace Omnipay\AuthorizeNet; -use Omnipay\AuthorizeNet\Message\SIMAuthorizeRequest; -use Omnipay\AuthorizeNet\Message\SIMCompleteAuthorizeRequest; - /** * Authorize.Net SIM Class */ @@ -43,6 +40,11 @@ public function completeAuthorize(array $parameters = array()) return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMCompleteAuthorizeRequest', $parameters); } + public function capture(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMCaptureRequest', $parameters); + } + public function purchase(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMAuthorizeRequest', $parameters); @@ -52,4 +54,9 @@ public function completePurchase(array $parameters = array()) { return $this->completeAuthorize($parameters); } + + public function void(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMVoidRequest', $parameters); + } } diff --git a/tests/SIMGatewayTest.php b/tests/SIMGatewayTest.php index ad5bd2e6..687d399e 100644 --- a/tests/SIMGatewayTest.php +++ b/tests/SIMGatewayTest.php @@ -6,6 +6,9 @@ class SIMGatewayTest extends GatewayTestCase { + /** @var SIMGateway */ + protected $gateway; + public function setUp() { parent::setUp(); From 69eb1c420534782d7c4f6310056f011e9d676950 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 2 Aug 2014 20:25:44 +0530 Subject: [PATCH 005/254] Added functional tests --- src/Message/AIMAbstractRequest.php | 22 +++++---- src/Message/AIMAuthorizeRequest.php | 9 +++- src/Message/AIMCaptureRequest.php | 3 +- src/Message/AIMVoidRequest.php | 3 +- tests/AIMGatewayIntegrationTest.php | 75 +++++++++++++++++++++++++++++ tests/AIMGatewayTest.php | 3 +- 6 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 tests/AIMGatewayIntegrationTest.php diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index a5ab232d..f7ab2ad8 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -60,7 +60,7 @@ public function setCustomerId($value) * @return mixed|\SimpleXMLElement * @throws \Omnipay\Common\Exception\InvalidRequestException */ - public function getData() + public function getBaseData() { $data = new \SimpleXMLElement(''); $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); @@ -82,10 +82,6 @@ public function getData() } $data->transactionRequest->transactionType = $this->action; - // Test mode setting - $data->transactionRequest->transactionSettings->setting->settingName = 'testRequest'; - $data->transactionRequest->transactionSettings->setting->settingValue = $this->getTestMode() ? 'true' : 'false'; - return $data; } @@ -100,9 +96,6 @@ protected function addBillingData(\SimpleXMLElement $data) /** @var mixed $req */ $req = $data->transactionRequest; - // Amount of the purchase - $req->amount = $this->getAmount(); - // Description of the purchase $description = $this->getDescription(); if (!empty($description)) { @@ -140,9 +133,20 @@ protected function addBillingData(\SimpleXMLElement $data) return $data; } + protected function addTestModeSetting(\SimpleXMLElement $data) + { + // Test mode setting + $data->transactionRequest->transactionSettings->setting->settingName = 'testRequest'; + $data->transactionRequest->transactionSettings->setting->settingValue = $this->getTestMode() ? 'true' : 'false'; + + return $data; + } + public function sendData($data) { - $httpResponse = $this->httpClient->post($this->getEndpoint(), null, $data)->send(); + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); return $this->response = new AIMResponse($this, $httpResponse->getBody()); } diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index e1a4097c..915ce990 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -19,13 +19,18 @@ public function getData() $card = $this->getCard(); $card->validate(); - $data = parent::getData(); - $data->transactionRequest->customerIP = $this->getClientIp(); + $data = $this->getBaseData(); + $data->transactionRequest->amount = $this->getAmount(); $data->transactionRequest->payment->creditCard->cardNumber = $card->getNumber(); $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); + $ip = $this->getClientIp(); + if (!empty($ip)) { + $data->transactionRequest->customerIP = $ip; + } $this->addBillingData($data); + $this->addTestModeSetting($data); return $data; } diff --git a/src/Message/AIMCaptureRequest.php b/src/Message/AIMCaptureRequest.php index 0b2e3c93..ea021d3d 100644 --- a/src/Message/AIMCaptureRequest.php +++ b/src/Message/AIMCaptureRequest.php @@ -13,9 +13,10 @@ public function getData() { $this->validate('amount', 'transactionReference'); - $data = parent::getData(); + $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getAmount(); $data->transactionRequest->refTransId = $this->getTransactionReference(); + $this->addTestModeSetting($data); return $data; } diff --git a/src/Message/AIMVoidRequest.php b/src/Message/AIMVoidRequest.php index e866f4a3..78f0f3b1 100644 --- a/src/Message/AIMVoidRequest.php +++ b/src/Message/AIMVoidRequest.php @@ -13,8 +13,9 @@ public function getData() { $this->validate('transactionReference'); - $data = parent::getData(); + $data = $this->getBaseData(); $data->transactionRequest->refTransId = $this->getTransactionReference(); + $this->addTestModeSetting($data); return $data; } diff --git a/tests/AIMGatewayIntegrationTest.php b/tests/AIMGatewayIntegrationTest.php new file mode 100644 index 00000000..c5157b9d --- /dev/null +++ b/tests/AIMGatewayIntegrationTest.php @@ -0,0 +1,75 @@ +gateway = new AIMGateway($this->getHttpClient(), $this->getHttpRequest()); + $this->gateway->setDeveloperMode(true); + $this->gateway->setApiLoginId($apiLoginId); + $this->gateway->setTransactionKey($transactionKey); + } else { + // No credentials were found, so skip this test + $this->markTestSkipped(); + } + } + + public function testPurchaseAndVoid() + { + $request = $this->gateway->purchase(array( + 'amount' => '10.01', + 'card' => $this->getValidCard() + )); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Purchase should succeed'); + $transactionRef = $response->getTransactionReference(); + + $request = $this->gateway->void(array( + 'transactionReference' => $transactionRef + )); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Void should succeed'); + } + + public function testHoldAndCapture() + { + $request = $this->gateway->authorize(array( + 'amount' => '42.42', + 'card' => $this->getValidCard() + )); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Authorization should succeed'); + $transactionRef = $response->getTransactionReference(); + + $request = $this->gateway->capture(array( + 'amount' => '42.42', + 'transactionReference' => $transactionRef + )); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Capture should succeed'); + } +} diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 86f80913..d4fd5822 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -6,12 +6,11 @@ class AIMGatewayTest extends GatewayTestCase { - protected $voidOptions; - /** @var AIMGateway */ protected $gateway; protected $purchaseOptions; protected $captureOptions; + protected $voidOptions; public function setUp() { From 426bc3f248f635349c4c7d0ec8850fae09a1413d Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 13 Aug 2014 12:34:30 +0530 Subject: [PATCH 006/254] Update AuthorizeNet_AIM to support refunds --- src/AIMGateway.php | 10 +++++ src/Message/AIMRefundRequest.php | 31 ++++++++++++++ tests/Message/AIMRefundRequestTest.php | 58 ++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/Message/AIMRefundRequest.php create mode 100644 tests/Message/AIMRefundRequestTest.php diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 32c41f90..52b2508c 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -93,4 +93,14 @@ public function void(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMVoidRequest', $parameters); } + + /** + * @param array $parameters + * @return AIMRefundRequest + */ + public function refund(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMRefundRequest', $parameters); + } + } diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php new file mode 100644 index 00000000..b72092cd --- /dev/null +++ b/src/Message/AIMRefundRequest.php @@ -0,0 +1,31 @@ +validate('transactionReference', 'amount', 'card'); + + /** @var CreditCard $card */ + $card = $this->getCard(); + $card->validate(); + + $data = $this->getBaseData(); + $data->transactionRequest->amount = $this->getParameter('amount'); + $data->transactionRequest->payment->creditCard->cardNumber = $card->getNumber(); + $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); + $data->transactionRequest->refTransId = $this->getTransactionReference(); + $this->addTestModeSetting($data); + + return $data; + } +} \ No newline at end of file diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php new file mode 100644 index 00000000..5d6696af --- /dev/null +++ b/tests/Message/AIMRefundRequestTest.php @@ -0,0 +1,58 @@ +request = new AIMRefundRequest($this->getHttpClient(), $this->getHttpRequest()); + } + + public function testGetData_MissingCardInfo() + { + $this->request->initialize( + array( + 'transactionReference' => '123', + 'amount' => '12.00' + ) + ); + + try { + $this->request->getData(); + } catch(InvalidRequestException $irex) { + return $this->assertEquals($irex->getMessage(), "The card parameter is required"); + } catch(\Exception $e) { + return $this->fail("Invalid exception was thrown: " . $e->getMessage()); + } + + $this->fail("InvalidRequestException should get thrown because card is missing"); + } + + public function testGetData() + { + $this->request->initialize( + array( + 'transactionReference' => 'authnet-transaction-reference', + 'amount' => 12.12, + 'card' => $this->getValidCard() + ) + ); + + $data = $this->request->getData(); + + $this->assertEquals('refundTransaction', $data->transactionRequest->transactionType); + $this->assertEquals('12.12', (string) $data->transactionRequest->amount[0]); + $this->assertEquals('authnet-transaction-reference', $data->transactionRequest->refTransId); + + $setting = $data->transactionRequest->transactionSettings->setting[0]; + $this->assertEquals('testRequest', $setting->settingName); + $this->assertEquals('false', $setting->settingValue); + } +} \ No newline at end of file From 47f47be770960b4d8cc7c6678efc0014ae85af6a Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 13 Aug 2014 15:16:05 +0530 Subject: [PATCH 007/254] Add tests for success and failure responses in AIMGatewayTest --- tests/AIMGatewayTest.php | 28 ++++++++++++++++++++++++++++ tests/Mock/AIMRefundFailure.txt | 13 +++++++++++++ tests/Mock/AIMRefundSuccess.txt | 13 +++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 tests/Mock/AIMRefundFailure.txt create mode 100644 tests/Mock/AIMRefundSuccess.txt diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index d4fd5822..4b7ca928 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -11,6 +11,7 @@ class AIMGatewayTest extends GatewayTestCase protected $purchaseOptions; protected $captureOptions; protected $voidOptions; + protected $refundOptions; public function setUp() { @@ -31,6 +32,12 @@ public function setUp() $this->voidOptions = array( 'transactionReference' => '12345', ); + + $this->refundOptions = array( + 'amount' => '10.00', + 'transactionReference' => '12345', + 'card' => $this->getValidCard() + ); } public function testAuthorizeSuccess() @@ -121,4 +128,25 @@ public function testVoidFailure() $this->assertSame('A valid referenced transaction ID is required.', $response->getMessage()); } + public function testRefundSuccess() + { + $this->setMockHttpResponse('AIMRefundSuccess.txt'); + + $response = $this->gateway->refund($this->refundOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('2217770693', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); + } + + public function testRefundFailure() + { + $this->setMockHttpResponse('AIMRefundFailure.txt'); + + $response = $this->gateway->refund($this->refundOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertSame('0', $response->getTransactionReference()); + $this->assertSame('The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage()); + } } diff --git a/tests/Mock/AIMRefundFailure.txt b/tests/Mock/AIMRefundFailure.txt new file mode 100644 index 00000000..47eb6ed7 --- /dev/null +++ b/tests/Mock/AIMRefundFailure.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Wed, 13 Aug 2014 09:03:29 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 890 + +ErrorE00027The transaction was unsuccessful.3P022177704245EF2F56573F03C214C485756E4873D970XXXX1111Visa54The referenced transaction does not meet the criteria for issuing a credit. \ No newline at end of file diff --git a/tests/Mock/AIMRefundSuccess.txt b/tests/Mock/AIMRefundSuccess.txt new file mode 100644 index 00000000..273e8eb8 --- /dev/null +++ b/tests/Mock/AIMRefundSuccess.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Wed, 13 Aug 2014 09:11:29 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 863 + +2217275263OkI00001Successful.1P22177706932217275263B6A8C28CFF84F92C56354005A0D6BE3D0XXXX1111Visa1This transaction has been approved. \ No newline at end of file From 9f078dbfcd4afe1346e5c5102f33314420e6bcbe Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 13 Aug 2014 18:32:22 +0530 Subject: [PATCH 008/254] Remove support for description attribute. This is because description attribute requires the presence of itemId, name, quantity, unitPrice which is not properly documented in AuthorizeNet's API documentation. --- src/Message/AIMAbstractRequest.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index f7ab2ad8..ff7531c1 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -96,12 +96,6 @@ protected function addBillingData(\SimpleXMLElement $data) /** @var mixed $req */ $req = $data->transactionRequest; - // Description of the purchase - $description = $this->getDescription(); - if (!empty($description)) { - $req->lineItems->lineItem->description = $description; - } - // Merchant assigned customer ID $customer = $this->getCustomerId(); if (!empty($customer)) { From e17f7a7a338834aeb2b1a2d157ace5f39d85c0ac Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 13 Aug 2014 18:33:34 +0530 Subject: [PATCH 009/254] Decouple SIMGateway from AIMGateway --- src/SIMGateway.php | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/SIMGateway.php b/src/SIMGateway.php index 0bf0c756..2e89f54d 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -2,10 +2,12 @@ namespace Omnipay\AuthorizeNet; +use Omnipay\Common\AbstractGateway; + /** * Authorize.Net SIM Class */ -class SIMGateway extends AIMGateway +class SIMGateway extends AbstractGateway { public function getName() { @@ -14,10 +16,43 @@ public function getName() public function getDefaultParameters() { - $parameters = parent::getDefaultParameters(); - $parameters['hashSecret'] = ''; + return array( + 'apiLoginId' => '', + 'transactionKey' => '', + 'testMode' => false, + 'developerMode' => false, + 'hashSecret' => '' + ); + } + + public function getApiLoginId() + { + return $this->getParameter('apiLoginId'); + } + + public function setApiLoginId($value) + { + return $this->setParameter('apiLoginId', $value); + } + + public function getTransactionKey() + { + return $this->getParameter('transactionKey'); + } + + public function setTransactionKey($value) + { + return $this->setParameter('transactionKey', $value); + } - return $parameters; + public function getDeveloperMode() + { + return $this->getParameter('developerMode'); + } + + public function setDeveloperMode($value) + { + return $this->setParameter('developerMode', $value); } public function getHashSecret() From 00d0f8e10b22ad75d8f6ad0a1c2bca00f6bd2caf Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Thu, 14 Aug 2014 15:17:29 +0530 Subject: [PATCH 010/254] Code formatting --- src/Message/AIMRefundRequest.php | 2 +- tests/Message/AIMRefundRequestTest.php | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index b72092cd..7fcc883f 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -28,4 +28,4 @@ public function getData() return $data; } -} \ No newline at end of file +} diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index 5d6696af..bb21ce12 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -15,7 +15,7 @@ public function setUp() $this->request = new AIMRefundRequest($this->getHttpClient(), $this->getHttpRequest()); } - public function testGetData_MissingCardInfo() + public function testGetDataMissingCardInfo() { $this->request->initialize( array( @@ -26,10 +26,12 @@ public function testGetData_MissingCardInfo() try { $this->request->getData(); - } catch(InvalidRequestException $irex) { - return $this->assertEquals($irex->getMessage(), "The card parameter is required"); - } catch(\Exception $e) { - return $this->fail("Invalid exception was thrown: " . $e->getMessage()); + } catch (InvalidRequestException $irex) { + $this->assertEquals($irex->getMessage(), "The card parameter is required"); + return; + } catch (\Exception $e) { + $this->fail("Invalid exception was thrown: " . $e->getMessage()); + return; } $this->fail("InvalidRequestException should get thrown because card is missing"); @@ -48,11 +50,11 @@ public function testGetData() $data = $this->request->getData(); $this->assertEquals('refundTransaction', $data->transactionRequest->transactionType); - $this->assertEquals('12.12', (string) $data->transactionRequest->amount[0]); + $this->assertEquals('12.12', (string)$data->transactionRequest->amount[0]); $this->assertEquals('authnet-transaction-reference', $data->transactionRequest->refTransId); $setting = $data->transactionRequest->transactionSettings->setting[0]; $this->assertEquals('testRequest', $setting->settingName); $this->assertEquals('false', $setting->settingValue); } -} \ No newline at end of file +} From 881d9d4302f84d018e7ccab5975617cdcb48d4f5 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Thu, 14 Aug 2014 15:22:49 +0530 Subject: [PATCH 011/254] Code formatting --- src/AIMGateway.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 52b2508c..82cbb344 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -5,6 +5,7 @@ use Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest; use Omnipay\AuthorizeNet\Message\AIMCaptureRequest; use Omnipay\AuthorizeNet\Message\AIMPurchaseRequest; +use Omnipay\AuthorizeNet\Message\AIMRefundRequest; use Omnipay\AuthorizeNet\Message\AIMVoidRequest; use Omnipay\Common\AbstractGateway; @@ -102,5 +103,4 @@ public function refund(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMRefundRequest', $parameters); } - } From c12125074839abed6e1c179312e1e5b3dc3b6f94 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Mon, 18 Aug 2014 16:40:15 +0530 Subject: [PATCH 012/254] Do not validate credit card for Refund transactions because it is not valid CC info. AuthorizetNet only requires last 4 digits of the credit card for refund transactions --- src/Message/AIMRefundRequest.php | 1 - tests/Message/AIMRefundRequestTest.php | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index b72092cd..8ab144b3 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -17,7 +17,6 @@ public function getData() /** @var CreditCard $card */ $card = $this->getCard(); - $card->validate(); $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getParameter('amount'); diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index 5d6696af..401f2256 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -41,7 +41,11 @@ public function testGetData() array( 'transactionReference' => 'authnet-transaction-reference', 'amount' => 12.12, - 'card' => $this->getValidCard() + 'card' => array( + 'number' => 1111, // Refunds require only the last 4 digits of the credit card + 'expiryMonth' => 5, + 'expiryYear' => 2020 + ) ) ); From 4426ff1f2c560e2282804405276171e31c4908ff Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Mon, 18 Aug 2014 17:27:33 +0530 Subject: [PATCH 013/254] CC last 4 to string --- tests/Message/AIMRefundRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index 401f2256..f000f2c2 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -42,7 +42,7 @@ public function testGetData() 'transactionReference' => 'authnet-transaction-reference', 'amount' => 12.12, 'card' => array( - 'number' => 1111, // Refunds require only the last 4 digits of the credit card + 'number' => '1111', // Refunds require only the last 4 digits of the credit card 'expiryMonth' => 5, 'expiryYear' => 2020 ) From 7c2b2c04bebd6a4c104bfb5fb4b9d0db9ce2e3c3 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Mon, 18 Aug 2014 17:31:26 +0530 Subject: [PATCH 014/254] CC last 4 to string --- tests/Message/AIMRefundRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index f3950d12..1c90dcbb 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -44,7 +44,7 @@ public function testGetData() 'transactionReference' => 'authnet-transaction-reference', 'amount' => 12.12, 'card' => array( - 'number' => 1111, // Refunds require only the last 4 digits of the credit card + 'number' => '1111', // Refunds require only the last 4 digits of the credit card 'expiryMonth' => 5, 'expiryYear' => 2020 ) From 0f5f96d7d7c646e253b697c119bcd68fde59839c Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Tue, 16 Sep 2014 21:54:41 +0530 Subject: [PATCH 015/254] Create card implemented with integration test for Authorize.net CIM --- composer.json | 9 +- src/CIMGateway.php | 27 +++++ src/Message/CIMAbstractRequest.php | 31 ++++++ src/Message/CIMCreateCardRequest.php | 143 ++++++++++++++++++++++++++ src/Message/CIMCreateCardResponse.php | 104 +++++++++++++++++++ tests/CIMGatewayIntegrationTest.php | 74 +++++++++++++ 6 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 src/CIMGateway.php create mode 100644 src/Message/CIMAbstractRequest.php create mode 100644 src/Message/CIMCreateCardRequest.php create mode 100644 src/Message/CIMCreateCardResponse.php create mode 100644 tests/CIMGatewayIntegrationTest.php diff --git a/composer.json b/composer.json index 0dd8b4c3..9044136a 100644 --- a/composer.json +++ b/composer.json @@ -1,4 +1,4 @@ -{ + { "name": "omnipay/authorizenet", "type": "library", "description": "Authorize.Net gateway for the Omnipay payment processing library", @@ -31,7 +31,12 @@ "omnipay/common": "~2.0" }, "require-dev": { - "omnipay/tests": "~2.0" + "omnipay/tests": "~2.0", + "monolog/monolog": "dev-master", + "guzzle/http": "~3.7", + "guzzle/plugin": "~3.7", + "guzzle/log": "~3.7", + "psr/log": "1.0" }, "extra": { "branch-alias": { diff --git a/src/CIMGateway.php b/src/CIMGateway.php new file mode 100644 index 00000000..1bd9fbab --- /dev/null +++ b/src/CIMGateway.php @@ -0,0 +1,27 @@ +createRequest('\Omnipay\AuthorizeNet\Message\CIMCreateCardRequest', $parameters); + } + +} \ No newline at end of file diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php new file mode 100644 index 00000000..d2bf54f7 --- /dev/null +++ b/src/Message/CIMAbstractRequest.php @@ -0,0 +1,31 @@ +setParameter('email', $value); + } + + public function getEmail() + { + return $this->getParameter('email'); + } + + public function setName($value) + { + return $this->setParameter('name', $value); + } + + public function getName() + { + return $this->getParameter('name'); + } +} diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php new file mode 100644 index 00000000..929148b1 --- /dev/null +++ b/src/Message/CIMCreateCardRequest.php @@ -0,0 +1,143 @@ +validate('card'); + + /** @var CreditCard $card */ + $card = $this->getCard(); + $card->validate(); + + $data = $this->getBaseData(); + + $this->addBillingData($data); + $this->addPaymentData($data); + $this->addTestModeSetting($data); + + return $data; + } + + /** + * @throws InvalidRequestException + * @return mixed|\SimpleXMLElement + */ + public function getBaseData() + { + $data = new \SimpleXMLElement(''); + $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); + + // Credentials + $data->merchantAuthentication->name = $this->getApiLoginId(); + $data->merchantAuthentication->transactionKey = $this->getTransactionKey(); + + return $data; + } + + /** + * Adds billing data to a partially filled request data object. + * + * @param \SimpleXMLElement $data + * + * @return \SimpleXMLElement + */ + protected function addBillingData(\SimpleXMLElement $data) + { + // Merchant assigned customer ID + $customer = $this->getCustomerId(); + if (!empty($customer)) { + $data->profile->merchantCustomerId = $customer; + } + + $description = $this->getDescription(); + if (!empty($description)) { + $data->profile->description = $description; + } + + $email = $this->getEmail(); + if (!empty($email)) { + $data->profile->email = $email; + } + + // This order is important. Payment profiles should come in this order only + /** @var mixed $req */ + $data->profile->paymentProfiles = null; + $req = $data->profile->paymentProfiles; + + /** @var CreditCard $card */ + if ($card = $this->getCard()) { + // A card is present, so include billing details + $req->billTo->firstName = $card->getBillingFirstName(); + $req->billTo->lastName = $card->getBillingLastName(); + $req->billTo->company = $card->getBillingCompany(); + $req->billTo->address = trim($card->getBillingAddress1() . " \n" . $card->getBillingAddress2()); + $req->billTo->city = $card->getBillingCity(); + $req->billTo->state = $card->getBillingState(); + $req->billTo->zip = $card->getBillingPostcode(); + $req->billTo->country = $card->getBillingCountry(); + } + + return $data; + } + + /** + * Adds payment data to a partially filled request data object. + * + * @param \SimpleXMLElement $data + * + * @return \SimpleXMLElement + */ + protected function addPaymentData(\SimpleXMLElement $data) + { + /** @var CreditCard $card */ + if ($card = $this->getCard()) { + // A card is present, so include payment details + /** @var mixed $req */ + $data->profile->paymentProfiles->payment = null; + $req = $data->profile->paymentProfiles->payment; + + $req->creditCard->cardNumber = $card->getNumber(); + $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); + $req->creditCard->cardCode = $card->getCvv(); + + $req = $data->profile; + $req->shipToList->firstName = $card->getShippingLastName(); + $req->shipToList->lastName = $card->getShippingLastName(); + $req->shipToList->company = $card->getShippingCompany(); + $req->shipToList->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); + $req->shipToList->city = $card->getShippingCity(); + $req->shipToList->state = $card->getShippingState(); + $req->shipToList->zip = $card->getShippingPostcode(); + $req->shipToList->country = $card->getShippingCountry(); + } + + return $data; + } + + protected function addTestModeSetting(\SimpleXMLElement $data) + { + // Test mode setting + $data->validationMode = $this->getTestMode() ? 'testMode' : 'liveMode'; + + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMCreateCardResponse($this, $httpResponse->getBody()); + } + +} diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php new file mode 100644 index 00000000..cea4f915 --- /dev/null +++ b/src/Message/CIMCreateCardResponse.php @@ -0,0 +1,104 @@ +request = $request; + + // Strip out the xmlns junk so that PHP can parse the XML + $xml = preg_replace('/]+>/', '', (string)$data); + + try { + $xml = simplexml_load_string($xml); + } catch(\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + $this->data = $xml; + } + + public function isSuccessful() + { + return 1 === $this->getResultCode(); + } + + /** + * Overall status of the transaction. This field is also known as "Response Code" in Authorize.NET terminology. + * + * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review + */ + public function getResultCode() + { + $result = (string)$this->data->messages[0]->resultCode; + switch ($result) { + case 'Ok': + return 1; + case 'Error': + return 3; + default: + return 4; + + } + } + + /** + * A more detailed version of the Result/Response code. + * + * @return int|null + */ + public function getReasonCode() + { + $code = null; + + if (isset($this->data->messages)) { + // In case of a successful transaction, a "messages" element is present + $code = (string)$this->data->messages[0]->message[0]->code; + + } + + return $code; + } + + /** + * Text description of the status. + * + * @return string|null + */ + public function getMessage() + { + $message = null; + + if (isset($this->data->messages)) { + // In case of a successful transaction, a "messages" element is present + $message = (string)$this->data->messages[0]->message[0]->text; + + } + + return $message; + } + + public function getCardReference() + { + $cardRef = null; + if (isset($this->data->customerProfileId)) { + // In case of a successful transaction, a "customerPaymentProfileId" element is present + $cardRef = (string)$this->data->customerProfileId; + } + + return $cardRef; + } +} diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php new file mode 100644 index 00000000..8958acac --- /dev/null +++ b/tests/CIMGatewayIntegrationTest.php @@ -0,0 +1,74 @@ +pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); + $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); + $adapter = new PsrLogAdapter($logger); + $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); + + $client = new Client(); + $client->addSubscriber($logPlugin); + + $this->gateway = new CIMGateway($client, $this->getHttpRequest()); + $this->gateway->setDeveloperMode(true); + $this->gateway->setApiLoginId($apiLoginId); + $this->gateway->setTransactionKey($transactionKey); + } else { + // No credentials were found, so skip this test + $this->markTestSkipped(); + } + } + + public function testCreateCard() + { + $rand = rand(100000, 999999); + // Create card + $params = array( + 'card' => $this->getValidCard(), + 'name' => 'Kaywinnet Lee Frye', + 'email' => "kaylee$rand@serenity.com", + ); + $request = $this->gateway->createCard($params); + $request->setTestMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Profile should get created'); + $this->assertNotNull($response->getCardReference(), 'Card response should be returned'); + } +} From d1b65010f09ba77ef5b2b9dc0a4695a32b98628f Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Wed, 17 Sep 2014 15:41:21 +0530 Subject: [PATCH 016/254] Abstract out common method for CIM requests --- src/Message/CIMAbstractRequest.php | 21 ++++++++++++++++++++- src/Message/CIMCreateCardRequest.php | 17 ----------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index d2bf54f7..761e2dec 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -2,13 +2,16 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidRequestException; + /** * Authorize.Net CIM Abstract Request */ abstract class CIMAbstractRequest extends AIMAbstractRequest { - // Need the below setters and getters for accessing this data within createCardRequest.send + private $xmlRootElement = 'createCustomerProfileRequest'; + // Need the below setters and getters for accessing this data within createCardRequest.send public function setEmail($value) { return $this->setParameter('email', $value); @@ -28,4 +31,20 @@ public function getName() { return $this->getParameter('name'); } + + /** + * @throws InvalidRequestException + * @return mixed|\SimpleXMLElement + */ + public function getBaseData() + { + $data = new \SimpleXMLElement("<" . $this->xmlRootElement . "/>"); + $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); + + // Credentials + $data->merchantAuthentication->name = $this->getApiLoginId(); + $data->merchantAuthentication->transactionKey = $this->getTransactionKey(); + + return $data; + } } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 929148b1..ec8470ed 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -3,7 +3,6 @@ namespace Omnipay\AuthorizeNet\Message; use Omnipay\Common\CreditCard; -use Omnipay\Common\Exception\InvalidRequestException; /** * Create Credit Card Request. @@ -27,22 +26,6 @@ public function getData() return $data; } - /** - * @throws InvalidRequestException - * @return mixed|\SimpleXMLElement - */ - public function getBaseData() - { - $data = new \SimpleXMLElement(''); - $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); - - // Credentials - $data->merchantAuthentication->name = $this->getApiLoginId(); - $data->merchantAuthentication->transactionKey = $this->getTransactionKey(); - - return $data; - } - /** * Adds billing data to a partially filled request data object. * From f7abefc53a1af5cf9e68a9ee421149a91f18ecba Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Wed, 17 Sep 2014 19:54:35 +0530 Subject: [PATCH 017/254] Implement all transactions in CIM Gateway --- src/CIMGateway.php | 23 +++++- src/Message/CIMAbstractRequest.php | 2 +- src/Message/CIMAbstractResponse.php | 100 ++++++++++++++++++++++++++ src/Message/CIMAuthorizeRequest.php | 53 ++++++++++++++ src/Message/CIMCaptureRequest.php | 44 ++++++++++++ src/Message/CIMCreateCardRequest.php | 2 + src/Message/CIMCreateCardResponse.php | 99 ++++--------------------- src/Message/CIMPurchaseRequest.php | 11 +++ src/Message/CIMRefundRequest.php | 28 ++++++++ src/Message/CIMResponse.php | 31 ++++++++ tests/CIMGatewayIntegrationTest.php | 61 +++++++++++++++- 11 files changed, 363 insertions(+), 91 deletions(-) create mode 100644 src/Message/CIMAbstractResponse.php create mode 100644 src/Message/CIMAuthorizeRequest.php create mode 100644 src/Message/CIMCaptureRequest.php create mode 100644 src/Message/CIMPurchaseRequest.php create mode 100644 src/Message/CIMRefundRequest.php create mode 100644 src/Message/CIMResponse.php diff --git a/src/CIMGateway.php b/src/CIMGateway.php index 1bd9fbab..793210ca 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -2,7 +2,7 @@ namespace Omnipay\AuthorizeNet; -use Omnipay\Common\AbstractGateway; +use Omnipay\AuthorizeNet\Message\CIMCreateCardRequest; /** * Authorize.Net CIM Class @@ -17,11 +17,30 @@ public function getName() /** * @param array $parameters * - * @return AIMAuthorizeRequest + * @return CIMCreateCardRequest */ public function createCard(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMCreateCardRequest', $parameters); } + public function authorize(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMAuthorizeRequest', $parameters); + } + + public function capture(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMCaptureRequest', $parameters); + } + + public function purchase(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMPurchaseRequest', $parameters); + } + + public function refund(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMRefundRequest', $parameters); + } } \ No newline at end of file diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 761e2dec..b2c8955f 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -9,7 +9,7 @@ */ abstract class CIMAbstractRequest extends AIMAbstractRequest { - private $xmlRootElement = 'createCustomerProfileRequest'; + protected $xmlRootElement = null; // Need the below setters and getters for accessing this data within createCardRequest.send public function setEmail($value) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php new file mode 100644 index 00000000..f1a5b759 --- /dev/null +++ b/src/Message/CIMAbstractResponse.php @@ -0,0 +1,100 @@ +request = $request; + + // Strip out the xmlns junk so that PHP can parse the XML + $xml = preg_replace('/<' . $this->xmlRootElement . '[^>]+>/', '<' . $this->xmlRootElement . '>', (string)$data); + + try { + $xml = simplexml_load_string($xml); + } catch(\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + $this->data = $xml; + } + + public function isSuccessful() + { + return 1 === $this->getResultCode(); + } + + /** + * Overall status of the transaction. This field is also known as "Response Code" in Authorize.NET terminology. + * + * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review + */ + public function getResultCode() + { + $result = (string)$this->data->messages[0]->resultCode; + switch ($result) { + case 'Ok': + return 1; + case 'Error': + return 3; + default: + return null; + + } + } + + /** + * A more detailed version of the Result/Response code. + * + * @return int|null + */ + public function getReasonCode() + { + $code = null; + + if (isset($this->data->messages)) { + // In case of a successful transaction, a "messages" element is present + $code = (string)$this->data->messages[0]->message[0]->code; + + } + + return $code; + } + + /** + * Text description of the status. + * + * @return string|null + */ + public function getMessage() + { + $message = null; + + if (isset($this->data->messages)) { + // In case of a successful transaction, a "messages" element is present + $message = (string)$this->data->messages[0]->message[0]->text; + + } + + return $message; + } + + public function getCardReference() + { + return null; + } +} diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php new file mode 100644 index 00000000..f62f8d47 --- /dev/null +++ b/src/Message/CIMAuthorizeRequest.php @@ -0,0 +1,53 @@ +validate('cardReference', 'amount'); + + $data = $this->getBaseData(); + + $this->addTransactionData($data); + return $data; + } + + /** + * Adds transaction data + * + * @param \SimpleXMLElement $data + * + * @return \SimpleXMLElement + */ + protected function addTransactionData(\SimpleXMLElement $data) + { + $transaction = $data->addChild('transaction'); + $action = $transaction->addChild($this->action); + $action->amount = number_format($this->getAmount(), 2); + + $cardRef = json_decode($this->getCardReference(), true); + $action->customerProfileId = $cardRef['customerProfileId']; + $action->customerPaymentProfileId = $cardRef['customerPaymentProfileId']; + $action->customerShippingAddressId = $cardRef['customerShippingAddressId']; + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMResponse($this, $httpResponse->getBody()); + } + +} diff --git a/src/Message/CIMCaptureRequest.php b/src/Message/CIMCaptureRequest.php new file mode 100644 index 00000000..e406abf8 --- /dev/null +++ b/src/Message/CIMCaptureRequest.php @@ -0,0 +1,44 @@ +validate('transactionReference', 'amount'); + + // Get the card reference from the transaction reference and set it into the request. Card reference is required + // to make all the transactions + $transRef = json_decode($this->getTransactionReference(), true); + $this->setCardReference($transRef['cardReference']); + + $data = $this->getBaseData(); + + $this->addTransactionData($data); + $this->addTransactionReferenceData($data); + return $data; + } + + /** + * Adds references for original transaction to a partially filled request data object. + * + * @param \SimpleXMLElement $data + * + * @return \SimpleXMLElement + */ + protected function addTransactionReferenceData(\SimpleXMLElement $data) + { + $action = $data->transaction->profileTransCaptureOnly; + + $transRef = json_decode($this->getTransactionReference(), true); + + $action->approvalCode = $transRef['approvalCode']; + return $data; + } +} diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index ec8470ed..a55eecb7 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -9,6 +9,8 @@ */ class CIMCreateCardRequest extends CIMAbstractRequest { + protected $xmlRootElement = 'createCustomerProfileRequest'; + public function getData() { $this->validate('card'); diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index cea4f915..6c1441df 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -2,101 +2,30 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\Exception\InvalidResponseException; -use Omnipay\Common\Message\AbstractResponse; -use Omnipay\Common\Message\RequestInterface; - /** * Authorize.Net CIM Create card Response */ -class CIMCreateCardResponse extends AbstractResponse +class CIMCreateCardResponse extends CIMAbstractResponse { - public function __construct(RequestInterface $request, $data) - { - $this->request = $request; - - // Strip out the xmlns junk so that PHP can parse the XML - $xml = preg_replace('/]+>/', '', (string)$data); - - try { - $xml = simplexml_load_string($xml); - } catch(\Exception $e) { - throw new InvalidResponseException(); - } - - if (!$xml) { - throw new InvalidResponseException(); - } - - $this->data = $xml; - } - - public function isSuccessful() - { - return 1 === $this->getResultCode(); - } - - /** - * Overall status of the transaction. This field is also known as "Response Code" in Authorize.NET terminology. - * - * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review - */ - public function getResultCode() - { - $result = (string)$this->data->messages[0]->resultCode; - switch ($result) { - case 'Ok': - return 1; - case 'Error': - return 3; - default: - return 4; - - } - } - - /** - * A more detailed version of the Result/Response code. - * - * @return int|null - */ - public function getReasonCode() - { - $code = null; - - if (isset($this->data->messages)) { - // In case of a successful transaction, a "messages" element is present - $code = (string)$this->data->messages[0]->message[0]->code; - - } - - return $code; - } - - /** - * Text description of the status. - * - * @return string|null - */ - public function getMessage() - { - $message = null; - - if (isset($this->data->messages)) { - // In case of a successful transaction, a "messages" element is present - $message = (string)$this->data->messages[0]->message[0]->text; - - } - - return $message; - } + protected $xmlRootElement = 'createCustomerProfileResponse'; public function getCardReference() { $cardRef = null; + $data = array(); if (isset($this->data->customerProfileId)) { // In case of a successful transaction, a "customerPaymentProfileId" element is present - $cardRef = (string)$this->data->customerProfileId; + $data['customerProfileId'] = (string)$this->data->customerProfileId; + } + if (isset($this->data->customerPaymentProfileIdList)) { + $data['customerPaymentProfileId'] = (string)$this->data->customerPaymentProfileIdList->numericString; + } + if (isset($this->data->customerShippingAddressIdList)) { + $data['customerShippingAddressId'] = (string)$this->data->customerShippingAddressIdList->numericString; + } + + if (!empty($data)) { + $cardRef = json_encode($data); } return $cardRef; diff --git a/src/Message/CIMPurchaseRequest.php b/src/Message/CIMPurchaseRequest.php new file mode 100644 index 00000000..b359e959 --- /dev/null +++ b/src/Message/CIMPurchaseRequest.php @@ -0,0 +1,11 @@ +transaction->profileTransRefund; + + $transRef = json_decode($this->getTransactionReference(), true); + + $action->transId = $transRef['transId']; + return $data; + } +} diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php new file mode 100644 index 00000000..f6df5319 --- /dev/null +++ b/src/Message/CIMResponse.php @@ -0,0 +1,31 @@ +data->directResponse)) { + $transRef = array(); + // In case of a successful transaction, a "directResponse" element is present + $directResponse = explode(',', (string)$this->data->directResponse); + // Required for capturing an authorized transaction + $transRef['approvalCode'] = $directResponse[4]; + // Required for second and subsequent transactions related to a partial authorization transaction + $transRef['transId'] = $directResponse[6]; + + // Save the card reference also as it is needed for making further transactions + $transRef['cardReference'] = $this->request->getCardReference(); + $transRef = json_encode($transRef); + } + + return $transRef; + } +} diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 8958acac..aa1173ed 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -55,10 +55,10 @@ public function setUp() } } - public function testCreateCard() + public function testIntegration() { - $rand = rand(100000, 999999); // Create card + $rand = rand(100000, 999999); $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', @@ -69,6 +69,61 @@ public function testCreateCard() $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Profile should get created'); - $this->assertNotNull($response->getCardReference(), 'Card response should be returned'); + $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + + $cardRef = $response->getCardReference(); + + // Create Authorize only transaction + $params = array( + 'cardReference' => $cardRef, + 'amount' => 100.00, + ); + $request = $this->gateway->authorize($params); + $request->setTestMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Authorize transaction should get created'); + $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + + $transRef = $response->getTransactionReference(); + + // Capture the authorised transaction + $params = array( + 'transactionReference' => $transRef, + 'amount' => 100.00, + ); + $request = $this->gateway->capture($params); + $request->setTestMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Capture transaction should get created'); + $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + $captureTransRef = $response->getTransactionReference(); + + // Make a purchase using the saved card. i.e auth and capture + $params = array( + 'cardReference' => $cardRef, + 'amount' => 110.00, + ); + $request = $this->gateway->purchase($params); + $request->setTestMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Purchase transaction should get created'); + $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + $purchaseTransRef = $response->getTransactionReference(); + + // Make a refund on the purchase transaction + $params = array( + 'transactionReference' => $purchaseTransRef, + 'amount' => 110.00, + ); + $request = $this->gateway->refund($params); + $request->setTestMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); + $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + } } From 9d43913410bbdbae504f0f7aee0bf1fd9a7f6049 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Thu, 18 Sep 2014 14:55:34 +0530 Subject: [PATCH 018/254] Add unit tests using mocks. CIM response also checks and parses ErrorResponse --- src/Message/CIMAbstractResponse.php | 6 +- src/Message/CIMAuthorizeRequest.php | 6 + src/Message/CIMCreateCardRequest.php | 2 +- src/Message/CIMResponse.php | 8 +- tests/CIMGatewayIntegrationTest.php | 6 +- tests/CIMGatewayTest.php | 189 ++++++++++++++++++++ tests/Message/CIMAuthorizeRequestTest.php | 34 ++++ tests/Message/CIMCaptureRequestTest.php | 38 ++++ tests/Message/CIMCreateCardRequestTest.php | 32 ++++ tests/Message/CIMCreateCardResponseTest.php | 43 +++++ tests/Message/CIMPurchaseRequestTest.php | 30 ++++ tests/Message/CIMRefundRequestTest.php | 38 ++++ tests/Message/CIMResponseTest.php | 30 ++++ tests/Mock/CIMAuthorizeFailure.txt | 14 ++ tests/Mock/CIMAuthorizeSuccess.txt | 14 ++ tests/Mock/CIMCaptureFailure.txt | 14 ++ tests/Mock/CIMCaptureSuccess.txt | 14 ++ tests/Mock/CIMCreateCardFailure.txt | 14 ++ tests/Mock/CIMCreateCardSuccess.txt | 14 ++ tests/Mock/CIMPurchaseFailure.txt | 14 ++ tests/Mock/CIMPurchaseSuccess.txt | 14 ++ tests/Mock/CIMRefundFailure.txt | 14 ++ 22 files changed, 582 insertions(+), 6 deletions(-) create mode 100644 tests/CIMGatewayTest.php create mode 100644 tests/Message/CIMAuthorizeRequestTest.php create mode 100644 tests/Message/CIMCaptureRequestTest.php create mode 100644 tests/Message/CIMCreateCardRequestTest.php create mode 100644 tests/Message/CIMCreateCardResponseTest.php create mode 100644 tests/Message/CIMPurchaseRequestTest.php create mode 100644 tests/Message/CIMRefundRequestTest.php create mode 100644 tests/Message/CIMResponseTest.php create mode 100644 tests/Mock/CIMAuthorizeFailure.txt create mode 100644 tests/Mock/CIMAuthorizeSuccess.txt create mode 100644 tests/Mock/CIMCaptureFailure.txt create mode 100644 tests/Mock/CIMCaptureSuccess.txt create mode 100644 tests/Mock/CIMCreateCardFailure.txt create mode 100644 tests/Mock/CIMCreateCardSuccess.txt create mode 100644 tests/Mock/CIMPurchaseFailure.txt create mode 100644 tests/Mock/CIMPurchaseSuccess.txt create mode 100644 tests/Mock/CIMRefundFailure.txt diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index f1a5b759..9bc5d056 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -17,8 +17,12 @@ public function __construct(RequestInterface $request, $data) { $this->request = $request; + // Check if this is an error response + $isError = strpos((string)$data, 'xmlRootElement; // Strip out the xmlns junk so that PHP can parse the XML - $xml = preg_replace('/<' . $this->xmlRootElement . '[^>]+>/', '<' . $this->xmlRootElement . '>', (string)$data); + $xml = preg_replace('/<' . $xmlRootElement . '[^>]+>/', '<' . $xmlRootElement . '>', (string)$data); try { $xml = simplexml_load_string($xml); diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index f62f8d47..3f3e8880 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -38,6 +38,12 @@ protected function addTransactionData(\SimpleXMLElement $data) $action->customerProfileId = $cardRef['customerProfileId']; $action->customerPaymentProfileId = $cardRef['customerPaymentProfileId']; $action->customerShippingAddressId = $cardRef['customerShippingAddressId']; + + $desc = $this->getDescription(); + if (!empty($desc)) { + $action->order->description = $desc; + } + return $data; } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index a55eecb7..c2fec2a4 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -95,7 +95,7 @@ protected function addPaymentData(\SimpleXMLElement $data) $req->creditCard->cardCode = $card->getCvv(); $req = $data->profile; - $req->shipToList->firstName = $card->getShippingLastName(); + $req->shipToList->firstName = $card->getShippingFirstName(); $req->shipToList->lastName = $card->getShippingLastName(); $req->shipToList->company = $card->getShippingCompany(); $req->shipToList->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index f6df5319..12c7526f 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -11,6 +11,9 @@ class CIMResponse extends CIMAbstractResponse public function getTransactionReference() { + if (!$this->isSuccessful()) { + return null; + } $transRef = null; if (isset($this->data->directResponse)) { $transRef = array(); @@ -18,10 +21,11 @@ public function getTransactionReference() $directResponse = explode(',', (string)$this->data->directResponse); // Required for capturing an authorized transaction $transRef['approvalCode'] = $directResponse[4]; - // Required for second and subsequent transactions related to a partial authorization transaction + // Required for refund a transaction $transRef['transId'] = $directResponse[6]; - // Save the card reference also as it is needed for making further transactions + // Save the card reference also as it is needed for making further transactions. + // This card reference is got from the request. (transaction response does not have it) $transRef['cardReference'] = $this->request->getCardReference(); $transRef = json_encode($transRef); } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index aa1173ed..8e6e8136 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -77,6 +77,7 @@ public function testIntegration() $params = array( 'cardReference' => $cardRef, 'amount' => 100.00, + 'description' ); $request = $this->gateway->authorize($params); $request->setTestMode(true); @@ -122,8 +123,9 @@ public function testIntegration() $request->setTestMode(true); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); - $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + // todo: Fix refunds +// $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); +// $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); } } diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php new file mode 100644 index 00000000..36372dfa --- /dev/null +++ b/tests/CIMGatewayTest.php @@ -0,0 +1,189 @@ +gateway = new CIMGateway($this->getHttpClient(), $this->getHttpRequest()); + + $this->createCardOptions = array( + 'email' => "kaylee@serenity.com", + 'card' => $this->getValidCard(), + 'testMode' => true + ); + + $this->authorizeOptions = array( + 'cardReference' => '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', + 'amount' => 10.00, + 'description' => 'authorize' + ); + + $this->captureOptions = array( + 'amount' => '10.00', + 'description' => 'capture', + 'transactionReference' => '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', + ); + + $this->authorizeOptions = array( + 'cardReference' => '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', + 'amount' => 10.00, + 'description' => 'purchase' + ); + + $this->refundOptions = array( + 'amount' => '10.00', + 'transactionReference' => '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', + 'description' => 'refund' + ); + } + + public function testCreateCardSuccess() + { + $this->setMockHttpResponse('CIMCreateCardSuccess.txt'); + + $response = $this->gateway->createCard($this->createCardOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', + $response->getCardReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + + public function testCreateCardFailure() + { + $this->setMockHttpResponse('CIMCreateCardFailure.txt'); + + $response = $this->gateway->createCard($this->createCardOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getCardReference()); + $this->assertSame('One or more fields in the profile must contain a value.', $response->getMessage()); + } + + public function testAuthorizeSuccess() + { + $this->setMockHttpResponse('CIMAuthorizeSuccess.txt'); + + $response = $this->gateway->authorize($this->authorizeOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', + $response->getTransactionReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + + public function testAuthorizeFailure() + { + $this->setMockHttpResponse('CIMAuthorizeFailure.txt'); + + try { + $response = $this->gateway->authorize($this->authorizeOptions)->send(); + } catch(\Exception $e) { + + } + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getTransactionReference()); + $this->assertSame( + "The 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:amount' element is invalid - The value '-100.00' is invalid according to its datatype 'Decimal' - The MinInclusive constraint failed.", + $response->getMessage() + ); + } + + public function testCaptureSuccess() + { + $this->setMockHttpResponse('CIMCaptureSuccess.txt'); + + $response = $this->gateway->capture($this->captureOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"approvalCode":"DMK100","transId":"2220001903","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', + $response->getTransactionReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + + public function testCaptureFailure() + { + $this->setMockHttpResponse('CIMCaptureFailure.txt'); + + $response = $this->gateway->capture($this->captureOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getTransactionReference()); + $this->assertSame('Approval Code is required.', $response->getMessage()); + } + + public function testPurchaseSuccess() + { + $this->setMockHttpResponse('CIMPurchaseSuccess.txt'); + + $response = $this->gateway->purchase($this->authorizeOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"approvalCode":"MNLXJQ","transId":"2220001904","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', + $response->getTransactionReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + + public function testPurchaseFailure() + { + $this->setMockHttpResponse('CIMPurchaseFailure.txt'); + + $response = $this->gateway->purchase($this->authorizeOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull( + $response->getTransactionReference() + ); + $this->assertSame('This transaction has been declined.', $response->getMessage()); + } + + public function testRefundSuccess() + { +// $this->setMockHttpResponse('CIMRefundSuccess.txt'); +// +// $response = $this->gateway->refund($this->refundOptions)->send(); +// +// $this->assertTrue($response->isSuccessful()); +// $this->assertSame('', $response->getTransactionReference()); +// $this->assertSame('This transaction has been approved.', $response->getMessage()); + } + + public function testRefundFailure() + { + $this->setMockHttpResponse('CIMRefundFailure.txt'); + + $response = $this->gateway->refund($this->refundOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull( + $response->getTransactionReference() + ); + $this->assertSame( + 'The referenced transaction does not meet the criteria for issuing a credit.', + $response->getMessage() + ); + } +} diff --git a/tests/Message/CIMAuthorizeRequestTest.php b/tests/Message/CIMAuthorizeRequestTest.php new file mode 100644 index 00000000..dcfd2e56 --- /dev/null +++ b/tests/Message/CIMAuthorizeRequestTest.php @@ -0,0 +1,34 @@ +request = new CIMAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'cardReference' => '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}', + 'amount' => '12.00', + 'description' => 'Test authorize transaction' + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertEquals('12.00', $data->transaction->profileTransAuthOnly->amount); + $this->assertEquals('28972085', $data->transaction->profileTransAuthOnly->customerProfileId); + $this->assertEquals('26317841', $data->transaction->profileTransAuthOnly->customerPaymentProfileId); + $this->assertEquals('27057151', $data->transaction->profileTransAuthOnly->customerShippingAddressId); + $this->assertEquals('Test authorize transaction', $data->transaction->profileTransAuthOnly->order->description); + } +} diff --git a/tests/Message/CIMCaptureRequestTest.php b/tests/Message/CIMCaptureRequestTest.php new file mode 100644 index 00000000..3d34936b --- /dev/null +++ b/tests/Message/CIMCaptureRequestTest.php @@ -0,0 +1,38 @@ +request = new CIMCaptureRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'transactionReference' => '{"approvalCode":"V7DO8Q","transId":"2220001612","cardReference":"{\"customerProfileId\":\"28972085\",\"customerPaymentProfileId\":\"26317841\",\"customerShippingAddressId\":\"27057151\"}"}', + 'amount' => 12.00, + 'description' => 'Test capture only transaction' + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertEquals('12.00', $data->transaction->profileTransCaptureOnly->amount); + $this->assertEquals('28972085', $data->transaction->profileTransCaptureOnly->customerProfileId); + $this->assertEquals('26317841', $data->transaction->profileTransCaptureOnly->customerPaymentProfileId); + $this->assertEquals('27057151', $data->transaction->profileTransCaptureOnly->customerShippingAddressId); + $this->assertEquals( + 'Test capture only transaction', + $data->transaction->profileTransCaptureOnly->order->description + ); + $this->assertEquals('V7DO8Q', $data->transaction->profileTransCaptureOnly->approvalCode); + } +} \ No newline at end of file diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php new file mode 100644 index 00000000..542e0581 --- /dev/null +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -0,0 +1,32 @@ +request = new CIMCreateCardRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'email' => "kaylee@serenity.com", + 'card' => $this->getValidCard(), + 'testMode' => true + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertEquals('Example', $data->profile->paymentProfiles->billTo->firstName); + $this->assertEquals('4111111111111111', $data->profile->paymentProfiles->payment->creditCard->cardNumber); + $this->assertEquals('testMode', $data->validationMode); + } +} diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php new file mode 100644 index 00000000..d1eb8807 --- /dev/null +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -0,0 +1,43 @@ +getMockRequest(), ''); + } + + public function testCreateCardSuccess() + { + $httpResponse = $this->getMockHttpResponse('CIMCreateCardSuccess.txt'); + $response = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('I00001', $response->getReasonCode()); + $this->assertEquals("1", $response->getResultCode()); + $this->assertEquals("Successful.", $response->getMessage()); + $this->assertEquals( + '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', + $response->getCardReference() + ); + } + + public function testCreateCardFailure() + { + $httpResponse = $this->getMockHttpResponse('CIMCreateCardFailure.txt'); + $response = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertFalse($response->isSuccessful()); + $this->assertEquals('E00041', $response->getReasonCode()); + $this->assertEquals("3", $response->getResultCode()); + $this->assertEquals("One or more fields in the profile must contain a value.", $response->getMessage()); + $this->assertNull($response->getCardReference()); + } +} diff --git a/tests/Message/CIMPurchaseRequestTest.php b/tests/Message/CIMPurchaseRequestTest.php new file mode 100644 index 00000000..4cf76acc --- /dev/null +++ b/tests/Message/CIMPurchaseRequestTest.php @@ -0,0 +1,30 @@ +request = new CIMPurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'cardReference' => '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}', + 'amount' => '12.00', + 'description' => 'Test purchase transaction' + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertObjectHasAttribute('profileTransAuthCapture',$data->transaction); + } +} diff --git a/tests/Message/CIMRefundRequestTest.php b/tests/Message/CIMRefundRequestTest.php new file mode 100644 index 00000000..79c5cfe2 --- /dev/null +++ b/tests/Message/CIMRefundRequestTest.php @@ -0,0 +1,38 @@ +request = new CIMRefundRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'transactionReference' => '{"approvalCode":"V7DO8Q","transId":"2220001612","cardReference":"{\"customerProfileId\":\"28972085\",\"customerPaymentProfileId\":\"26317841\",\"customerShippingAddressId\":\"27057151\"}"}', + 'amount' => 12.00, + 'description' => 'Test refund transaction' + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertEquals('12.00', $data->transaction->profileTransRefund->amount); + $this->assertEquals('28972085', $data->transaction->profileTransRefund->customerProfileId); + $this->assertEquals('26317841', $data->transaction->profileTransRefund->customerPaymentProfileId); + $this->assertEquals('27057151', $data->transaction->profileTransRefund->customerShippingAddressId); + $this->assertEquals( + 'Test refund transaction', + $data->transaction->profileTransRefund->order->description + ); + $this->assertEquals('2220001612', $data->transaction->profileTransRefund->transId); + } +} \ No newline at end of file diff --git a/tests/Message/CIMResponseTest.php b/tests/Message/CIMResponseTest.php new file mode 100644 index 00000000..e04b3d8d --- /dev/null +++ b/tests/Message/CIMResponseTest.php @@ -0,0 +1,30 @@ +getMockRequest(), ''); + } + + public function testGetTransactionReference() + { + $httpResponse = $this->getMockHttpResponse('CIMAuthorizeSuccess.txt'); + $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); + $mockRequest->shouldReceive('getCardReference')->times(1)->andReturn('{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}'); + $response = new CIMResponse($mockRequest, $httpResponse->getBody()); + + $this->assertEquals( + '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972085\",\"customerPaymentProfileId\":\"26317841\",\"customerShippingAddressId\":\"27057151\"}"}', + $response->getTransactionReference() + ); + } +} diff --git a/tests/Mock/CIMAuthorizeFailure.txt b/tests/Mock/CIMAuthorizeFailure.txt new file mode 100644 index 00000000..8ff4d2f0 --- /dev/null +++ b/tests/Mock/CIMAuthorizeFailure.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 832 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:22 GMT + +ErrorE00003The 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:amount' element is invalid - The value '-100.00' is invalid according to its datatype 'Decimal' - The MinInclusive constraint failed. diff --git a/tests/Mock/CIMAuthorizeSuccess.txt b/tests/Mock/CIMAuthorizeSuccess.txt new file mode 100644 index 00000000..5bd792a3 --- /dev/null +++ b/tests/Mock/CIMAuthorizeSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 832 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:22 GMT + +OkI00001Successful.1,1,1,This transaction has been approved.,DMK100,Y,2220001902,,,100.00,CC,auth_only,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,F667DD4AF086CA3C1588D77F088C2E1B,,2,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMCaptureFailure.txt b/tests/Mock/CIMCaptureFailure.txt new file mode 100644 index 00000000..f15fbffe --- /dev/null +++ b/tests/Mock/CIMCaptureFailure.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 1027 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:23 GMT + +ErrorE00014Approval Code is required. diff --git a/tests/Mock/CIMCaptureSuccess.txt b/tests/Mock/CIMCaptureSuccess.txt new file mode 100644 index 00000000..713b7b81 --- /dev/null +++ b/tests/Mock/CIMCaptureSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 1027 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:23 GMT + +OkI00001Successful.1,1,1,This transaction has been approved.,DMK100,P,2220001903,,,100.00,CC,capture_only,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,28AF50C3CB7ED3D132E6BED4558CDE8F,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMCreateCardFailure.txt b/tests/Mock/CIMCreateCardFailure.txt new file mode 100644 index 00000000..fe7bdc5a --- /dev/null +++ b/tests/Mock/CIMCreateCardFailure.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +ErrorE00041One or more fields in the profile must contain a value. diff --git a/tests/Mock/CIMCreateCardSuccess.txt b/tests/Mock/CIMCreateCardSuccess.txt new file mode 100644 index 00000000..97e06ed2 --- /dev/null +++ b/tests/Mock/CIMCreateCardSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +OkI00001Successful.2897208426317840270571491,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee427330@serenity.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,, diff --git a/tests/Mock/CIMPurchaseFailure.txt b/tests/Mock/CIMPurchaseFailure.txt new file mode 100644 index 00000000..922df3b2 --- /dev/null +++ b/tests/Mock/CIMPurchaseFailure.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:24 GMT + +ErrorE00027This transaction has been declined.2,1,2,This transaction has been declined.,,Y,2220009663,,,110.00,CC,auth_capture,,Example,User,,123 Billing St Billsville,Billstown,CA,46282,US,,,kaylee729813@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,CE96C60797B394AF0BFFD6FEBEDE7C2A,,2,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27058978 diff --git a/tests/Mock/CIMPurchaseSuccess.txt b/tests/Mock/CIMPurchaseSuccess.txt new file mode 100644 index 00000000..61eb0ba3 --- /dev/null +++ b/tests/Mock/CIMPurchaseSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:24 GMT + +OkI00001Successful.1,1,1,This transaction has been approved.,MNLXJQ,Y,2220001904,,,110.00,CC,auth_capture,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,FE4AE98F3E5BD3AA01280DF8DC1EB640,,2,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMRefundFailure.txt b/tests/Mock/CIMRefundFailure.txt new file mode 100644 index 00000000..b33fd61f --- /dev/null +++ b/tests/Mock/CIMRefundFailure.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 832 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 04:15:24 GMT + +ErrorE00027The referenced transaction does not meet the criteria for issuing a credit.3,2,54,The referenced transaction does not meet the criteria for issuing a credit.,,P,0,,,110.00,CC,credit,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,C42AF83A6FF4CF347A06BFF79715849D,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 From 6ad83f6640139f547875d9c862750fd2f606fd02 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Thu, 18 Sep 2014 15:00:55 +0530 Subject: [PATCH 019/254] Clean up logging used during development --- composer.json | 7 +------ tests/CIMGatewayIntegrationTest.php | 21 ++++----------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/composer.json b/composer.json index 9044136a..d10e9352 100644 --- a/composer.json +++ b/composer.json @@ -31,12 +31,7 @@ "omnipay/common": "~2.0" }, "require-dev": { - "omnipay/tests": "~2.0", - "monolog/monolog": "dev-master", - "guzzle/http": "~3.7", - "guzzle/plugin": "~3.7", - "guzzle/log": "~3.7", - "psr/log": "1.0" + "omnipay/tests": "~2.0" }, "extra": { "branch-alias": { diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 8e6e8136..0cafc424 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -28,24 +28,11 @@ public function setUp() { parent::setUp(); -// $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); -// $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); - //todo: Remove this before final commit - $apiLoginId = '3wM8sJ9qR'; - $transactionKey = '4d3v32QJtB78tBTT'; + $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); + $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); if ($apiLoginId && $transactionKey) { - - $logger = new \Monolog\Logger('authorizenet_cim'); - $logger->pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); - $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); - $adapter = new PsrLogAdapter($logger); - $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); - - $client = new Client(); - $client->addSubscriber($logPlugin); - - $this->gateway = new CIMGateway($client, $this->getHttpRequest()); + $this->gateway = new CIMGateway($this->getHttpClient(), $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); $this->gateway->setApiLoginId($apiLoginId); $this->gateway->setTransactionKey($transactionKey); @@ -123,7 +110,7 @@ public function testIntegration() $request->setTestMode(true); $response = $request->send(); - // todo: Fix refunds + // todo: Fix refunds, and add unit tests using mocks // $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); // $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); From 58e4de324149c54a3f4f2333ea94fdfc6cfadd36 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Thu, 18 Sep 2014 22:02:30 +0530 Subject: [PATCH 020/254] Use Developer mode rather than test mode for setting the dev context before making the authorize net requests. --- src/Message/CIMCreateCardRequest.php | 34 ++++++++++++++++++++-------- tests/CIMGatewayIntegrationTest.php | 10 ++++---- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index c2fec2a4..f4fa34df 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -95,14 +95,30 @@ protected function addPaymentData(\SimpleXMLElement $data) $req->creditCard->cardCode = $card->getCvv(); $req = $data->profile; - $req->shipToList->firstName = $card->getShippingFirstName(); - $req->shipToList->lastName = $card->getShippingLastName(); - $req->shipToList->company = $card->getShippingCompany(); - $req->shipToList->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); - $req->shipToList->city = $card->getShippingCity(); - $req->shipToList->state = $card->getShippingState(); - $req->shipToList->zip = $card->getShippingPostcode(); - $req->shipToList->country = $card->getShippingCountry(); + if ($card->getShippingFirstName()) { + $req->shipToList->firstName = $card->getShippingFirstName(); + } + if ($card->getShippingLastName()) { + $req->shipToList->lastName = $card->getShippingLastName(); + } + if ($card->getShippingCompany()) { + $req->shipToList->company = $card->getShippingCompany(); + } + if ($card->getShippingAddress1() || $card->getShippingAddress2()) { + $req->shipToList->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); + } + if ($card->getShippingCity()) { + $req->shipToList->city = $card->getShippingCity(); + } + if ($card->getShippingState()) { + $req->shipToList->state = $card->getShippingState(); + } + if ($card->getShippingPostcode()) { + $req->shipToList->zip = $card->getShippingPostcode(); + } + if ($card->getShippingCountry()) { + $req->shipToList->country = $card->getShippingCountry(); + } } return $data; @@ -111,7 +127,7 @@ protected function addPaymentData(\SimpleXMLElement $data) protected function addTestModeSetting(\SimpleXMLElement $data) { // Test mode setting - $data->validationMode = $this->getTestMode() ? 'testMode' : 'liveMode'; + $data->validationMode = $this->getDeveloperMode() ? 'testMode' : 'liveMode'; return $data; } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 0cafc424..3ed5ee0e 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -52,7 +52,7 @@ public function testIntegration() 'email' => "kaylee$rand@serenity.com", ); $request = $this->gateway->createCard($params); - $request->setTestMode(true); + $request->setDeveloperMode(true); $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Profile should get created'); @@ -67,7 +67,7 @@ public function testIntegration() 'description' ); $request = $this->gateway->authorize($params); - $request->setTestMode(true); + $request->setDeveloperMode(true); $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Authorize transaction should get created'); @@ -81,7 +81,7 @@ public function testIntegration() 'amount' => 100.00, ); $request = $this->gateway->capture($params); - $request->setTestMode(true); + $request->setDeveloperMode(true); $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Capture transaction should get created'); @@ -94,7 +94,7 @@ public function testIntegration() 'amount' => 110.00, ); $request = $this->gateway->purchase($params); - $request->setTestMode(true); + $request->setDeveloperMode(true); $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Purchase transaction should get created'); @@ -107,7 +107,7 @@ public function testIntegration() 'amount' => 110.00, ); $request = $this->gateway->refund($params); - $request->setTestMode(true); + $request->setDeveloperMode(true); $response = $request->send(); // todo: Fix refunds, and add unit tests using mocks From de9ef9748df1f6e9e38ed14656cfe1e4b044142a Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Fri, 19 Sep 2014 00:53:02 +0530 Subject: [PATCH 021/254] Use customer shipping address id only if present while making a transaction --- src/Message/CIMAuthorizeRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index 3f3e8880..f5c2068e 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -37,7 +37,9 @@ protected function addTransactionData(\SimpleXMLElement $data) $cardRef = json_decode($this->getCardReference(), true); $action->customerProfileId = $cardRef['customerProfileId']; $action->customerPaymentProfileId = $cardRef['customerPaymentProfileId']; - $action->customerShippingAddressId = $cardRef['customerShippingAddressId']; + if (!empty($cardRef['customerShippingAddressId'])) { + $action->customerShippingAddressId = $cardRef['customerShippingAddressId']; + } $desc = $this->getDescription(); if (!empty($desc)) { From 87e594dcf26278af9367a5879af0ceaea6e6a5c9 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Fri, 19 Sep 2014 21:57:01 +0530 Subject: [PATCH 022/254] If create card fails due to duplicate profile error, then create a payment profile for a give customer profile. If that call also results in duplicate, then get the customer profile containing all its payment profiles. Then get the payment profile id matching the last4 in our original request. Once this is done, use the customer profile id, payment profile id, and update the card details. (It is possible that last4 matches but the expiry dates change). After updation of the payment profile, return the response. --- src/Message/CIMAbstractRequest.php | 20 ++ src/Message/CIMCreateCardRequest.php | 182 +++++++++++++----- .../CIMCreatePaymentProfileRequest.php | 50 +++++ .../CIMCreatePaymentProfileResponse.php | 25 +++ src/Message/CIMGetProfileRequest.php | 34 ++++ src/Message/CIMGetProfileResponse.php | 32 +++ .../CIMUpdatePaymentProfileRequest.php | 51 +++++ .../CIMUpdatePaymentProfileResponse.php | 23 +++ tests/CIMGatewayIntegrationTest.php | 21 +- tests/Message/CIMCreateCardRequestTest.php | 8 +- .../CIMCreatePaymentProfileRequestTest.php | 34 ++++ .../CIMCreatePaymentProfileResponseTest.php | 45 +++++ tests/Mock/CIMCreatePaymentProfileFailure.txt | 14 ++ tests/Mock/CIMCreatePaymentProfileSuccess.txt | 14 ++ 14 files changed, 495 insertions(+), 58 deletions(-) create mode 100644 src/Message/CIMCreatePaymentProfileRequest.php create mode 100644 src/Message/CIMCreatePaymentProfileResponse.php create mode 100644 src/Message/CIMGetProfileRequest.php create mode 100644 src/Message/CIMGetProfileResponse.php create mode 100644 src/Message/CIMUpdatePaymentProfileRequest.php create mode 100644 src/Message/CIMUpdatePaymentProfileResponse.php create mode 100644 tests/Message/CIMCreatePaymentProfileRequestTest.php create mode 100644 tests/Message/CIMCreatePaymentProfileResponseTest.php create mode 100644 tests/Mock/CIMCreatePaymentProfileFailure.txt create mode 100644 tests/Mock/CIMCreatePaymentProfileSuccess.txt diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index b2c8955f..9b6a2b62 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -32,6 +32,26 @@ public function getName() return $this->getParameter('name'); } + public function setCustomerProfileId($value) + { + return $this->setParameter('customerProfileId', $value); + } + + public function getCustomerProfileId() + { + return $this->getParameter('customerProfileId'); + } + + public function setCustomerPaymentProfileId($value) + { + return $this->setParameter('customerPaymentProfileId', $value); + } + + public function getCustomerPaymentProfileId() + { + return $this->getParameter('customerPaymentProfileId'); + } + /** * @throws InvalidRequestException * @return mixed|\SimpleXMLElement diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index f4fa34df..229acd62 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -20,116 +20,121 @@ public function getData() $card->validate(); $data = $this->getBaseData(); - - $this->addBillingData($data); - $this->addPaymentData($data); + $this->addProfileData($data); $this->addTestModeSetting($data); return $data; } /** - * Adds billing data to a partially filled request data object. + * Add customer profile data to the specified xml element * * @param \SimpleXMLElement $data - * - * @return \SimpleXMLElement */ - protected function addBillingData(\SimpleXMLElement $data) + protected function addProfileData(\SimpleXMLElement $data) { + $req = $data->addChild('profile'); // Merchant assigned customer ID $customer = $this->getCustomerId(); if (!empty($customer)) { - $data->profile->merchantCustomerId = $customer; + $req->merchantCustomerId = $customer; } $description = $this->getDescription(); if (!empty($description)) { - $data->profile->description = $description; + $req->description = $description; } $email = $this->getEmail(); if (!empty($email)) { - $data->profile->email = $email; + $req->email = $email; } - // This order is important. Payment profiles should come in this order only - /** @var mixed $req */ - $data->profile->paymentProfiles = null; - $req = $data->profile->paymentProfiles; - - /** @var CreditCard $card */ - if ($card = $this->getCard()) { - // A card is present, so include billing details - $req->billTo->firstName = $card->getBillingFirstName(); - $req->billTo->lastName = $card->getBillingLastName(); - $req->billTo->company = $card->getBillingCompany(); - $req->billTo->address = trim($card->getBillingAddress1() . " \n" . $card->getBillingAddress2()); - $req->billTo->city = $card->getBillingCity(); - $req->billTo->state = $card->getBillingState(); - $req->billTo->zip = $card->getBillingPostcode(); - $req->billTo->country = $card->getBillingCountry(); - } + $this->addPaymentProfileData($req); + $this->addShippingData($req); + } - return $data; + /** + * Adds payment profile to the specified xml element + * + * @param \SimpleXMLElement $data + */ + protected function addPaymentProfileData(\SimpleXMLElement $data) + { + // This order is important. Payment profiles should come in this order only + $req = $data->addChild('paymentProfiles'); + $this->addBillingData($req); } /** - * Adds payment data to a partially filled request data object. + * Adds billing/payment data to the specified xml element * * @param \SimpleXMLElement $data * - * @return \SimpleXMLElement + * @return \SimpleXMLElement|void */ - protected function addPaymentData(\SimpleXMLElement $data) + protected function addBillingData(\SimpleXMLElement $data) { /** @var CreditCard $card */ if ($card = $this->getCard()) { - // A card is present, so include payment details - /** @var mixed $req */ - $data->profile->paymentProfiles->payment = null; - $req = $data->profile->paymentProfiles->payment; - + $req = $data->addChild('billTo'); + // A card is present, so include billing details + $req->firstName = $card->getBillingFirstName(); + $req->lastName = $card->getBillingLastName(); + $req->company = $card->getBillingCompany(); + $req->address = trim($card->getBillingAddress1() . " \n" . $card->getBillingAddress2()); + $req->city = $card->getBillingCity(); + $req->state = $card->getBillingState(); + $req->zip = $card->getBillingPostcode(); + $req->country = $card->getBillingCountry(); + + $req = $data->addChild('payment'); $req->creditCard->cardNumber = $card->getNumber(); $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); $req->creditCard->cardCode = $card->getCvv(); + } + } - $req = $data->profile; + /** + * Adds shipping data to the specified xml element + * + * @param \SimpleXMLElement $data + */ + protected function addShippingData(\SimpleXMLElement $data) + { + /** @var CreditCard $card */ + if ($card = $this->getCard()) { if ($card->getShippingFirstName()) { - $req->shipToList->firstName = $card->getShippingFirstName(); + $data->shipToList->firstName = $card->getShippingFirstName(); } if ($card->getShippingLastName()) { - $req->shipToList->lastName = $card->getShippingLastName(); + $data->shipToList->lastName = $card->getShippingLastName(); } if ($card->getShippingCompany()) { - $req->shipToList->company = $card->getShippingCompany(); + $data->shipToList->company = $card->getShippingCompany(); } if ($card->getShippingAddress1() || $card->getShippingAddress2()) { - $req->shipToList->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); + $data->shipToList->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); } if ($card->getShippingCity()) { - $req->shipToList->city = $card->getShippingCity(); + $data->shipToList->city = $card->getShippingCity(); } if ($card->getShippingState()) { - $req->shipToList->state = $card->getShippingState(); + $data->shipToList->state = $card->getShippingState(); } if ($card->getShippingPostcode()) { - $req->shipToList->zip = $card->getShippingPostcode(); + $data->shipToList->zip = $card->getShippingPostcode(); } if ($card->getShippingCountry()) { - $req->shipToList->country = $card->getShippingCountry(); + $data->shipToList->country = $card->getShippingCountry(); } } - - return $data; } protected function addTestModeSetting(\SimpleXMLElement $data) { // Test mode setting $data->validationMode = $this->getDeveloperMode() ? 'testMode' : 'liveMode'; - - return $data; } public function sendData($data) @@ -138,7 +143,84 @@ public function sendData($data) $data = $data->saveXml(); $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); - return $this->response = new CIMCreateCardResponse($this, $httpResponse->getBody()); + $response = new CIMCreateCardResponse($this, $httpResponse->getBody()); + + if (!$response->isSuccessful() && $response->getReasonCode() == 'E00039') { + // Duplicate profile. Try adding a new payment profile for the same profile and get the response + $response = $this->createPaymentProfile($response); + + } + + return $this->response = $response; + } + + /** + * Attempts to add a payment profile to the existing customer profile. + * + * @param CIMCreateCardResponse $response Duplicate customer profile response + * + * @return CIMCreateCardResponse + */ + public function createPaymentProfile(CIMCreateCardResponse $response) + { + // Parse the customer profile Id from the message + $msg = $response->getMessage(); + preg_match("/ID (.+) already/i", $msg, $matches); + if (empty($matches[1])) { + // Duplicate profile id not found. Return current response + return $response; + } + + // Use the customerProfileId and create a payment profile for the customer + $parameters = array_replace($this->getParameters(), array('customerProfileId' => $matches[1])); + $obj = new CIMCreatePaymentProfileRequest($this->httpClient, $this->httpRequest); + $obj->initialize($parameters); + $paymentProfileResponse = $obj->send(); + if (!$paymentProfileResponse->isSuccessful() && + $paymentProfileResponse->getReasonCode() == 'E00039' + ) { + // Found a duplicate payment profile existing for the same card data. So get the complete profile of the user + // and find the payment profile id matching the credit card number + $card = $this->getCard(); + $last4 = substr($card->getNumber(), -4); + $getProfileResponse = $this->getProfile($parameters); + $customerPaymentProfileId = $getProfileResponse->getMatchingPaymentProfileId($last4); + if (!$customerPaymentProfileId) { + // Matching customer payment profile id not found. Return the original response + return $response; + } + + $parameters['customerPaymentProfileId'] = $customerPaymentProfileId; + return $this->updatePaymentProfile($parameters); + } + } + + /** + * Get the customer profile + * + * @param array $parameters + * + * @return CIMGetProfileResponse + */ + public function getProfile($parameters) + { + $obj = new CIMGetProfileRequest($this->httpClient, $this->httpRequest); + $obj->initialize(array_replace($this->getParameters(), $parameters)); + return $obj->send(); + } + + /** + * Makes an update profile request + * + * @param $parameters + * + * @return CIMCreateCardResponse + */ + public function updatePaymentProfile($parameters) + { + $obj = new CIMUpdatePaymentProfileRequest($this->httpClient, $this->httpRequest); + $obj->initialize(array_replace($this->getParameters(), $parameters)); + return $obj->send(); } } diff --git a/src/Message/CIMCreatePaymentProfileRequest.php b/src/Message/CIMCreatePaymentProfileRequest.php new file mode 100644 index 00000000..d7f3d556 --- /dev/null +++ b/src/Message/CIMCreatePaymentProfileRequest.php @@ -0,0 +1,50 @@ +validate('card', 'customerProfileId'); + + /** @var CreditCard $card */ + $card = $this->getCard(); + $card->validate(); + + $data = $this->getBaseData(); + $data->customerProfileId = $this->getCustomerProfileId(); + $this->addPaymentProfileData($data); + $this->addTestModeSetting($data); + + return $data; + } + + /** + * Adds payment profile to the specified xml element + * + * @param \SimpleXMLElement $data + */ + protected function addPaymentProfileData(\SimpleXMLElement $data) + { + // This order is important. Payment profiles should come in this order only + $req = $data->addChild('paymentProfile'); + $this->addBillingData($req); + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMCreatePaymentProfileResponse($this, $httpResponse->getBody()); + } +} diff --git a/src/Message/CIMCreatePaymentProfileResponse.php b/src/Message/CIMCreatePaymentProfileResponse.php new file mode 100644 index 00000000..14b3078c --- /dev/null +++ b/src/Message/CIMCreatePaymentProfileResponse.php @@ -0,0 +1,25 @@ +isSuccessful()) { + $data['customerProfileId'] = $this->request->getCustomerProfileId(); + if (isset($this->data->customerPaymentProfileId)) { + $data['customerPaymentProfileId'] = (string)$this->data->customerPaymentProfileId; + } + + $cardRef = json_encode($data); + } + return $cardRef; + } +} diff --git a/src/Message/CIMGetProfileRequest.php b/src/Message/CIMGetProfileRequest.php new file mode 100644 index 00000000..c74a9e74 --- /dev/null +++ b/src/Message/CIMGetProfileRequest.php @@ -0,0 +1,34 @@ +validate('customerProfileId'); + + $data = $this->getBaseData(); + + $data->customerProfileId = $this->getCustomerProfileId(); + + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMGetProfileResponse($this, $httpResponse->getBody()); + } + +} diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php new file mode 100644 index 00000000..09339429 --- /dev/null +++ b/src/Message/CIMGetProfileResponse.php @@ -0,0 +1,32 @@ +isSuccessful()) { + return null; + } + +// $card = $this->request->getCard(); +// if ($card && $card->getNumber()) { +// $last4 = substr($card->getNumber(), -4); + + foreach ($this->data->profile->paymentProfiles as $paymentProfile) { + // For every payment profile check if the last4 matches the last4 of the card in request. + $cardLast4 = substr((string)$paymentProfile->payment->creditCard->cardNumber, -4); + if ($last4 == $cardLast4) { + return (string)$paymentProfile->customerPaymentProfileId; + } + } + + return null; + } +} diff --git a/src/Message/CIMUpdatePaymentProfileRequest.php b/src/Message/CIMUpdatePaymentProfileRequest.php new file mode 100644 index 00000000..be273ce3 --- /dev/null +++ b/src/Message/CIMUpdatePaymentProfileRequest.php @@ -0,0 +1,51 @@ +validate('card', 'customerProfileId', 'customerPaymentProfileId'); + + /** @var CreditCard $card */ + $card = $this->getCard(); + $card->validate(); + + $data = $this->getBaseData(); + $data->customerProfileId = $this->getCustomerProfileId(); + $this->addPaymentProfileData($data); + $this->addTestModeSetting($data); + + return $data; + } + + /** + * Adds payment profile to the specified xml element + * + * @param \SimpleXMLElement $data + */ + protected function addPaymentProfileData(\SimpleXMLElement $data) + { + // This order is important. Payment profiles should come in this order only + $req = $data->addChild('paymentProfile'); + $this->addBillingData($req); + $req->customerPaymentProfileId = $this->getCustomerPaymentProfileId(); + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMUpdatePaymentProfileResponse($this, $httpResponse->getBody()); + } +} diff --git a/src/Message/CIMUpdatePaymentProfileResponse.php b/src/Message/CIMUpdatePaymentProfileResponse.php new file mode 100644 index 00000000..45b6953c --- /dev/null +++ b/src/Message/CIMUpdatePaymentProfileResponse.php @@ -0,0 +1,23 @@ +isSuccessful()) { + $data['customerProfileId'] = $this->request->getCustomerProfileId(); + $data['customerPaymentProfileId'] = $this->request->getCustomerPaymentProfileId(); + + $cardRef = json_encode($data); + } + return $cardRef; + } +} diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 3ed5ee0e..7bcd5c5f 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -28,11 +28,24 @@ public function setUp() { parent::setUp(); - $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); - $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); +// $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); +// $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); + //todo: Remove this before final commit + $apiLoginId = '3wM8sJ9qR'; + $transactionKey = '4u53d55me4NHTE9h'; if ($apiLoginId && $transactionKey) { - $this->gateway = new CIMGateway($this->getHttpClient(), $this->getHttpRequest()); + + $logger = new \Monolog\Logger('authorizenet_cim'); + $logger->pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); + $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); + $adapter = new PsrLogAdapter($logger); + $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); + + $client = new Client(); + $client->addSubscriber($logPlugin); + + $this->gateway = new CIMGateway($client, $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); $this->gateway->setApiLoginId($apiLoginId); $this->gateway->setTransactionKey($transactionKey); @@ -49,7 +62,7 @@ public function testIntegration() $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee$rand@serenity.com", + 'email' => "kaylee@serenity.com", ); $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index 542e0581..e8042c39 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -16,7 +16,7 @@ public function setUp() array( 'email' => "kaylee@serenity.com", 'card' => $this->getValidCard(), - 'testMode' => true + 'developerMode' => true ) ); } @@ -24,9 +24,9 @@ public function setUp() public function testGetData() { $data = $this->request->getData(); - - $this->assertEquals('Example', $data->profile->paymentProfiles->billTo->firstName); - $this->assertEquals('4111111111111111', $data->profile->paymentProfiles->payment->creditCard->cardNumber); + $card = $this->getValidCard(); + $this->assertEquals('12345', $data->profile->paymentProfiles->billTo->zip); + $this->assertEquals($card['number'], $data->profile->paymentProfiles->payment->creditCard->cardNumber); $this->assertEquals('testMode', $data->validationMode); } } diff --git a/tests/Message/CIMCreatePaymentProfileRequestTest.php b/tests/Message/CIMCreatePaymentProfileRequestTest.php new file mode 100644 index 00000000..cf407618 --- /dev/null +++ b/tests/Message/CIMCreatePaymentProfileRequestTest.php @@ -0,0 +1,34 @@ +request = new CIMCreatePaymentProfileRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'customerProfileId' => '28775801', + 'email' => "kaylee@serenity.com", + 'card' => $this->getValidCard(), + 'developerMode' => true + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $card = $this->getValidCard(); + $this->assertEquals('28775801', $data->customerProfileId); + $this->assertEquals($card['number'], $data->paymentProfile->payment->creditCard->cardNumber); + $this->assertEquals('testMode', $data->validationMode); + } +} diff --git a/tests/Message/CIMCreatePaymentProfileResponseTest.php b/tests/Message/CIMCreatePaymentProfileResponseTest.php new file mode 100644 index 00000000..927ac600 --- /dev/null +++ b/tests/Message/CIMCreatePaymentProfileResponseTest.php @@ -0,0 +1,45 @@ +getMockRequest(), ''); + } + + public function testCreateCardSuccess() + { + $httpResponse = $this->getMockHttpResponse('CIMCreatePaymentProfileSuccess.txt'); + $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); + $mockRequest->shouldReceive('getCustomerProfileId')->times(1)->andReturn('28775801'); + $response = new CIMCreatePaymentProfileResponse($mockRequest, $httpResponse->getBody()); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('I00001', $response->getReasonCode()); + $this->assertEquals("1", $response->getResultCode()); + $this->assertEquals("Successful.", $response->getMessage()); + $this->assertEquals( + '{"customerProfileId":"28775801","customerPaymentProfileId":"26455709"}', + $response->getCardReference() + ); + } + + public function testCreateCardFailure() + { + $httpResponse = $this->getMockHttpResponse('CIMCreatePaymentProfileFailure.txt'); + $response = new CIMCreatePaymentProfileResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertFalse($response->isSuccessful()); + $this->assertEquals('E00039', $response->getReasonCode()); + $this->assertEquals("3", $response->getResultCode()); + $this->assertEquals("A duplicate customer payment profile already exists.", $response->getMessage()); + $this->assertNull($response->getCardReference()); + } +} diff --git a/tests/Mock/CIMCreatePaymentProfileFailure.txt b/tests/Mock/CIMCreatePaymentProfileFailure.txt new file mode 100644 index 00000000..2d8a34a8 --- /dev/null +++ b/tests/Mock/CIMCreatePaymentProfileFailure.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +ErrorE00039A duplicate customer payment profile already exists.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,none,,,,,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,, diff --git a/tests/Mock/CIMCreatePaymentProfileSuccess.txt b/tests/Mock/CIMCreatePaymentProfileSuccess.txt new file mode 100644 index 00000000..40bdb247 --- /dev/null +++ b/tests/Mock/CIMCreatePaymentProfileSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +OkI00001Successful.264557091,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,none,,,,,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, From b076d75e0f33dc71c39fb2fc77d812ce1de76476 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Mon, 22 Sep 2014 13:36:01 +0530 Subject: [PATCH 023/254] Unit test using mocks for get profile, update payment profile --- src/Message/CIMGetProfileResponse.php | 12 ++++--- .../CIMUpdatePaymentProfileResponse.php | 2 ++ tests/CIMGatewayIntegrationTest.php | 19 ++-------- tests/Message/CIMGetProfileRequestTest.php | 27 ++++++++++++++ tests/Message/CIMGetProfileResponseTest.php | 26 ++++++++++++++ .../CIMUpdatePaymentProfileRequestTest.php | 35 +++++++++++++++++++ .../CIMUpdatePaymentProfileResponseTest.php | 34 ++++++++++++++++++ tests/Mock/CIMGetProfileSuccess.txt | 14 ++++++++ tests/Mock/CIMUpdatePaymentProfileSuccess.txt | 14 ++++++++ 9 files changed, 163 insertions(+), 20 deletions(-) create mode 100644 tests/Message/CIMGetProfileRequestTest.php create mode 100644 tests/Message/CIMGetProfileResponseTest.php create mode 100644 tests/Message/CIMUpdatePaymentProfileRequestTest.php create mode 100644 tests/Message/CIMUpdatePaymentProfileResponseTest.php create mode 100644 tests/Mock/CIMGetProfileSuccess.txt create mode 100644 tests/Mock/CIMUpdatePaymentProfileSuccess.txt diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index 09339429..54ccad7e 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -9,16 +9,20 @@ class CIMGetProfileResponse extends CIMAbstractResponse { protected $xmlRootElement = 'getCustomerProfileResponse'; + /** + * Get the payment profile id corresponding to the specified last4 by looking into the payment profiles + * of the customer + * + * @param $last4 + * + * @return null|string + */ public function getMatchingPaymentProfileId($last4) { if (!$this->isSuccessful()) { return null; } -// $card = $this->request->getCard(); -// if ($card && $card->getNumber()) { -// $last4 = substr($card->getNumber(), -4); - foreach ($this->data->profile->paymentProfiles as $paymentProfile) { // For every payment profile check if the last4 matches the last4 of the card in request. $cardLast4 = substr((string)$paymentProfile->payment->creditCard->cardNumber, -4); diff --git a/src/Message/CIMUpdatePaymentProfileResponse.php b/src/Message/CIMUpdatePaymentProfileResponse.php index 45b6953c..f337b480 100644 --- a/src/Message/CIMUpdatePaymentProfileResponse.php +++ b/src/Message/CIMUpdatePaymentProfileResponse.php @@ -13,6 +13,8 @@ public function getCardReference() { $cardRef = null; if ($this->isSuccessful()) { + // Update payment profile never returns customer profileId or payment profile Id. So use the request + // data to generate the card reference $data['customerProfileId'] = $this->request->getCustomerProfileId(); $data['customerPaymentProfileId'] = $this->request->getCustomerPaymentProfileId(); diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 7bcd5c5f..f107ee88 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -28,24 +28,11 @@ public function setUp() { parent::setUp(); -// $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); -// $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); - //todo: Remove this before final commit - $apiLoginId = '3wM8sJ9qR'; - $transactionKey = '4u53d55me4NHTE9h'; + $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); + $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); if ($apiLoginId && $transactionKey) { - - $logger = new \Monolog\Logger('authorizenet_cim'); - $logger->pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); - $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); - $adapter = new PsrLogAdapter($logger); - $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); - - $client = new Client(); - $client->addSubscriber($logPlugin); - - $this->gateway = new CIMGateway($client, $this->getHttpRequest()); + $this->gateway = new CIMGateway($this->getHttpClient(), $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); $this->gateway->setApiLoginId($apiLoginId); $this->gateway->setTransactionKey($transactionKey); diff --git a/tests/Message/CIMGetProfileRequestTest.php b/tests/Message/CIMGetProfileRequestTest.php new file mode 100644 index 00000000..f6669141 --- /dev/null +++ b/tests/Message/CIMGetProfileRequestTest.php @@ -0,0 +1,27 @@ +request = new CIMGetProfileRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'customerProfileId' => '28775801', + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + $this->assertEquals('28775801', $data->customerProfileId); + } +} \ No newline at end of file diff --git a/tests/Message/CIMGetProfileResponseTest.php b/tests/Message/CIMGetProfileResponseTest.php new file mode 100644 index 00000000..c1abda05 --- /dev/null +++ b/tests/Message/CIMGetProfileResponseTest.php @@ -0,0 +1,26 @@ +getMockRequest(), ''); + } + + public function testGetMatchingPaymentProfileId() + { + $httpResponse = $this->getMockHttpResponse('CIMGetProfileSuccess.txt'); + $response = new CIMGetProfileResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertEquals('26455656', $response->getMatchingPaymentProfileId('1111')); + $this->assertEquals('26455709', $response->getMatchingPaymentProfileId('8888')); + $this->assertNull($response->getMatchingPaymentProfileId('8889')); + } +} diff --git a/tests/Message/CIMUpdatePaymentProfileRequestTest.php b/tests/Message/CIMUpdatePaymentProfileRequestTest.php new file mode 100644 index 00000000..cff4d46c --- /dev/null +++ b/tests/Message/CIMUpdatePaymentProfileRequestTest.php @@ -0,0 +1,35 @@ +request = new CIMUpdatePaymentProfileRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'customerProfileId' => '28775801', + 'customerPaymentProfileId' => '26455709', + 'email' => "kaylee@serenity.com", + 'card' => $this->getValidCard(), + 'developerMode' => true + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $card = $this->getValidCard(); + $this->assertEquals('28775801', $data->customerProfileId); + $this->assertEquals($card['number'], $data->paymentProfile->payment->creditCard->cardNumber); + $this->assertEquals('testMode', $data->validationMode); + } +} \ No newline at end of file diff --git a/tests/Message/CIMUpdatePaymentProfileResponseTest.php b/tests/Message/CIMUpdatePaymentProfileResponseTest.php new file mode 100644 index 00000000..0e08ddcf --- /dev/null +++ b/tests/Message/CIMUpdatePaymentProfileResponseTest.php @@ -0,0 +1,34 @@ +getMockRequest(), ''); + } + + public function testCreateCardSuccess() + { + $httpResponse = $this->getMockHttpResponse('CIMUpdatePaymentProfileSuccess.txt'); + $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); + $mockRequest->shouldReceive('getCustomerProfileId')->times(1)->andReturn('28775801'); + $mockRequest->shouldReceive('getCustomerPaymentProfileId')->times(1)->andReturn('26455709'); + $response = new CIMUpdatePaymentProfileResponse($mockRequest, $httpResponse->getBody()); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('I00001', $response->getReasonCode()); + $this->assertEquals("1", $response->getResultCode()); + $this->assertEquals("Successful.", $response->getMessage()); + $this->assertEquals( + '{"customerProfileId":"28775801","customerPaymentProfileId":"26455709"}', + $response->getCardReference() + ); + } +} diff --git a/tests/Mock/CIMGetProfileSuccess.txt b/tests/Mock/CIMGetProfileSuccess.txt new file mode 100644 index 00000000..0c7f5fbe --- /dev/null +++ b/tests/Mock/CIMGetProfileSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +OkI00001Successful.kaylee@serenity.com28775801
1234526455656XXXX1111XXXX
1234526455709XXXX8888XXXX diff --git a/tests/Mock/CIMUpdatePaymentProfileSuccess.txt b/tests/Mock/CIMUpdatePaymentProfileSuccess.txt new file mode 100644 index 00000000..bb760503 --- /dev/null +++ b/tests/Mock/CIMUpdatePaymentProfileSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +OkI00001Successful.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,,,,,,,,12345,,,,kaylee@serenity.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, From 9967d32a9ffd308fbfe44e6eaba58f714d49aff4 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Tue, 23 Sep 2014 09:10:40 +0530 Subject: [PATCH 024/254] Add forceCardUpdate parameter to createCard. --- src/Message/CIMAbstractRequest.php | 17 +++++++++++++++++ src/Message/CIMCreateCardRequest.php | 7 ++++--- tests/CIMGatewayIntegrationTest.php | 16 +++++++++++++++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 9b6a2b62..35fd328f 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -52,6 +52,23 @@ public function getCustomerPaymentProfileId() return $this->getParameter('customerPaymentProfileId'); } + /** + * Flag to force update consumer payment profile if duplicate is found + * + * @param $value + * + * @return $this + */ + public function setForceCardUpdate($value) + { + return $this->setParameter('forceCardUpdate', $value); + } + + public function getForceCardUpdate() + { + return $this->getParameter('forceCardUpdate'); + } + /** * @throws InvalidRequestException * @return mixed|\SimpleXMLElement diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 229acd62..fb64aae9 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -177,10 +177,11 @@ public function createPaymentProfile(CIMCreateCardResponse $response) $obj->initialize($parameters); $paymentProfileResponse = $obj->send(); if (!$paymentProfileResponse->isSuccessful() && - $paymentProfileResponse->getReasonCode() == 'E00039' + $paymentProfileResponse->getReasonCode() == 'E00039' && $this->getForceCardUpdate() == true ) { - // Found a duplicate payment profile existing for the same card data. So get the complete profile of the user - // and find the payment profile id matching the credit card number + // Found a duplicate payment profile existing for the same card data. Force update is turned on, + // so get the complete profile of the user and find the payment profile id matching the credit card number + // and update the payment profile with the card details. $card = $this->getCard(); $last4 = substr($card->getNumber(), -4); $getProfileResponse = $this->getProfile($parameters); diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index f107ee88..0aa27299 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -45,7 +45,6 @@ public function setUp() public function testIntegration() { // Create card - $rand = rand(100000, 999999); $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', @@ -60,6 +59,21 @@ public function testIntegration() $cardRef = $response->getCardReference(); + // Try creating card for the same user. + $params = array( + 'card' => $this->getValidCard(), + 'name' => 'Kaywinnet Lee Frye', + 'email' => "kaylee@serenity.com", + ); + $request = $this->gateway->createCard($params); + $request->setDeveloperMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Profile should get created'); + $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + + $this->assertEquals($cardRef, $response->getCardReference(), 'Card reference should be same when creating card for already existing user'); + // Create Authorize only transaction $params = array( 'cardReference' => $cardRef, From d697e2ff81d4f6f350e5e060e86e5e3bce7120b7 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Tue, 23 Sep 2014 16:41:55 +0530 Subject: [PATCH 025/254] Create card will always return customer profile as response. Card reference will contain customer profile id and customer payment profile id, as these are enough for making a transaction --- src/Message/CIMCreateCardRequest.php | 70 ++++++++++++++----- src/Message/CIMCreateCardResponse.php | 5 +- .../CIMCreatePaymentProfileResponse.php | 15 +--- src/Message/CIMGetProfileResponse.php | 13 +++- tests/CIMGatewayIntegrationTest.php | 44 ++++++++++-- tests/CIMGatewayTest.php | 2 +- tests/Message/CIMCreateCardRequestTest.php | 10 +++ tests/Message/CIMCreateCardResponseTest.php | 2 +- .../CIMCreatePaymentProfileResponseTest.php | 6 +- .../CIMCreateCardFailureWithDuplicate.txt | 14 ++++ tests/Mock/CIMCreatePaymentProfileFailure.txt | 2 +- 11 files changed, 133 insertions(+), 50 deletions(-) create mode 100644 tests/Mock/CIMCreateCardFailureWithDuplicate.txt diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index fb64aae9..f03861fb 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -155,45 +155,79 @@ public function sendData($data) } /** - * Attempts to add a payment profile to the existing customer profile. + * Attempts to add a payment profile to the existing customer profile and return the updated customer profile * - * @param CIMCreateCardResponse $response Duplicate customer profile response + * @param CIMCreateCardResponse $createCardResponse Duplicate customer profile response * * @return CIMCreateCardResponse */ - public function createPaymentProfile(CIMCreateCardResponse $response) + public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) { // Parse the customer profile Id from the message - $msg = $response->getMessage(); + $msg = $createCardResponse->getMessage(); preg_match("/ID (.+) already/i", $msg, $matches); if (empty($matches[1])) { // Duplicate profile id not found. Return current response - return $response; + return $createCardResponse; } // Use the customerProfileId and create a payment profile for the customer $parameters = array_replace($this->getParameters(), array('customerProfileId' => $matches[1])); - $obj = new CIMCreatePaymentProfileRequest($this->httpClient, $this->httpRequest); - $obj->initialize($parameters); - $paymentProfileResponse = $obj->send(); - if (!$paymentProfileResponse->isSuccessful() && - $paymentProfileResponse->getReasonCode() == 'E00039' && $this->getForceCardUpdate() == true + $createPaymentProfileResponse = $this->makeCreatePaymentProfileRequest($parameters); + if ($createPaymentProfileResponse->isSuccessful()) { + $parameters['customerPaymentProfileId'] = $createPaymentProfileResponse->getCustomerPaymentProfileId(); + } elseif ($this->getForceCardUpdate() !== true) { + // force card update flag turned off. No need to further process. + return $createCardResponse; + } + + $getProfileResponse = $this->makeGetProfileRequest($parameters); + + if (!$createPaymentProfileResponse->isSuccessful() && + $createPaymentProfileResponse->getReasonCode() == 'E00039' ) { // Found a duplicate payment profile existing for the same card data. Force update is turned on, - // so get the complete profile of the user and find the payment profile id matching the credit card number - // and update the payment profile with the card details. + // So find matching payment profile id from the customer profile and update it. $card = $this->getCard(); $last4 = substr($card->getNumber(), -4); - $getProfileResponse = $this->getProfile($parameters); + $customerPaymentProfileId = $getProfileResponse->getMatchingPaymentProfileId($last4); + if (!$customerPaymentProfileId) { - // Matching customer payment profile id not found. Return the original response - return $response; + // Failed. Matching customer payment profile id not found. Return the original response + return $createCardResponse; } $parameters['customerPaymentProfileId'] = $customerPaymentProfileId; - return $this->updatePaymentProfile($parameters); + $updatePaymentProfileRequest = $this->makeUpdatePaymentProfileRequest($parameters); + if (!$updatePaymentProfileRequest->isSuccessful()) { + // Could not update payment profile. Return the original response + return $createCardResponse; + } + + // return the updated customer profile + $getProfileResponse = $this->makeGetProfileRequest($parameters); + if (!$getProfileResponse->isSuccessful()) { + // Could not get the updated customer profile. Return the original response + return $createCardResponse; + } } + + return $getProfileResponse; + } + + /** + * Make a request to add a payment profile to the current customer profile + * + * @param $parameters + * + * @return CIMCreatePaymentProfileResponse + */ + public function makeCreatePaymentProfileRequest($parameters) + { + $obj = new CIMCreatePaymentProfileRequest($this->httpClient, $this->httpRequest); + $obj->initialize($parameters); + return $obj->send(); } /** @@ -203,7 +237,7 @@ public function createPaymentProfile(CIMCreateCardResponse $response) * * @return CIMGetProfileResponse */ - public function getProfile($parameters) + public function makeGetProfileRequest($parameters) { $obj = new CIMGetProfileRequest($this->httpClient, $this->httpRequest); $obj->initialize(array_replace($this->getParameters(), $parameters)); @@ -217,7 +251,7 @@ public function getProfile($parameters) * * @return CIMCreateCardResponse */ - public function updatePaymentProfile($parameters) + public function makeUpdatePaymentProfileRequest($parameters) { $obj = new CIMUpdatePaymentProfileRequest($this->httpClient, $this->httpRequest); $obj->initialize(array_replace($this->getParameters(), $parameters)); diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index 6c1441df..162d04f0 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -17,12 +17,9 @@ public function getCardReference() // In case of a successful transaction, a "customerPaymentProfileId" element is present $data['customerProfileId'] = (string)$this->data->customerProfileId; } - if (isset($this->data->customerPaymentProfileIdList)) { + if (!empty($this->data->customerPaymentProfileIdList->numericString)) { $data['customerPaymentProfileId'] = (string)$this->data->customerPaymentProfileIdList->numericString; } - if (isset($this->data->customerShippingAddressIdList)) { - $data['customerShippingAddressId'] = (string)$this->data->customerShippingAddressIdList->numericString; - } if (!empty($data)) { $cardRef = json_encode($data); diff --git a/src/Message/CIMCreatePaymentProfileResponse.php b/src/Message/CIMCreatePaymentProfileResponse.php index 14b3078c..b69fc66c 100644 --- a/src/Message/CIMCreatePaymentProfileResponse.php +++ b/src/Message/CIMCreatePaymentProfileResponse.php @@ -5,21 +5,12 @@ /** * Authorize.Net CIM Create payment profile Response */ -class CIMCreatePaymentProfileResponse extends CIMCreateCardResponse +class CIMCreatePaymentProfileResponse extends CIMAbstractResponse { protected $xmlRootElement = 'createCustomerPaymentProfileResponse'; - public function getCardReference() + public function getCustomerPaymentProfileId() { - $cardRef = null; - if ($this->isSuccessful()) { - $data['customerProfileId'] = $this->request->getCustomerProfileId(); - if (isset($this->data->customerPaymentProfileId)) { - $data['customerPaymentProfileId'] = (string)$this->data->customerPaymentProfileId; - } - - $cardRef = json_encode($data); - } - return $cardRef; + return (string)$this->data->customerPaymentProfileId; } } diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index 54ccad7e..d1809237 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -5,7 +5,7 @@ /** * Authorize.Net CIM Get payment profiles Response */ -class CIMGetProfileResponse extends CIMAbstractResponse +class CIMGetProfileResponse extends CIMCreateCardResponse { protected $xmlRootElement = 'getCustomerProfileResponse'; @@ -33,4 +33,15 @@ public function getMatchingPaymentProfileId($last4) return null; } + + public function getCardReference() + { + $cardRef = null; + if ($this->isSuccessful() && $this->request->getCustomerPaymentProfileId()) { + $data['customerProfileId'] = $this->request->getCustomerProfileId(); + $data['customerPaymentProfileId'] = $this->request->getCustomerPaymentProfileId(); + $cardRef = json_encode($data); + } + return $cardRef; + } } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 0aa27299..643b315f 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -30,9 +30,22 @@ public function setUp() $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); +// //todo: Remove this before final commit +// $apiLoginId = '3wM8sJ9qR'; +// $transactionKey = '8V529R4p6sc8bY88'; if ($apiLoginId && $transactionKey) { - $this->gateway = new CIMGateway($this->getHttpClient(), $this->getHttpRequest()); + + $logger = new \Monolog\Logger('authorizenet_cim'); + $logger->pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); + $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); + $adapter = new PsrLogAdapter($logger); + $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); + + $client = new Client(); + $client->addSubscriber($logPlugin); + + $this->gateway = new CIMGateway($client, $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); $this->gateway->setApiLoginId($apiLoginId); $this->gateway->setTransactionKey($transactionKey); @@ -45,10 +58,11 @@ public function setUp() public function testIntegration() { // Create card + $rand = rand(100000, 999999); $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee@serenity.com", + 'email' => "kaylee$rand@serenity.com", ); $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); @@ -59,20 +73,36 @@ public function testIntegration() $cardRef = $response->getCardReference(); - // Try creating card for the same user. + // Try creating card for the same user again. $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee@serenity.com", + 'email' => "kaylee$rand@serenity.com", ); $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Profile should get created'); - $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + $this->assertFalse($response->isSuccessful(), 'Should not success as we tried creating duplicate profile'); + $this->assertNull($response->getCardReference(), 'Card reference should be returned'); + + // Try creating card for the same user again with force card update flag. + $params = array( + 'card' => $this->getValidCard(), + 'name' => 'Kaywinnet Lee Frye', + 'email' => "kaylee$rand@serenity.com", + 'forceCardUpdate' => true + ); + $request = $this->gateway->createCard($params); + $request->setDeveloperMode(true); - $this->assertEquals($cardRef, $response->getCardReference(), 'Card reference should be same when creating card for already existing user'); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Should succeed updating of the existing payment profile'); + $this->assertEquals( + $cardRef, + $response->getCardReference(), + 'Card reference should be same as with the one newly created' + ); // Create Authorize only transaction $params = array( diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 36372dfa..7009b068 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -59,7 +59,7 @@ public function testCreateCardSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame( - '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', + '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840"}', $response->getCardReference() ); $this->assertSame('Successful.', $response->getMessage()); diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index e8042c39..892e19e5 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -29,4 +29,14 @@ public function testGetData() $this->assertEquals($card['number'], $data->profile->paymentProfiles->payment->creditCard->cardNumber); $this->assertEquals('testMode', $data->validationMode); } + + public function testCreatePaymentProfile() + { + $httpResponse = $this->getMockHttpResponse('CIMCreateCardFailureWithDuplicate.txt'); + $duplicateProfileResponse = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody()); + $this->setMockHttpResponse(array('CIMCreatePaymentProfileFailure.txt')); + + $response = $this->request->createPaymentProfile($duplicateProfileResponse); + + } } diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php index d1eb8807..c770b2a2 100644 --- a/tests/Message/CIMCreateCardResponseTest.php +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -24,7 +24,7 @@ public function testCreateCardSuccess() $this->assertEquals("1", $response->getResultCode()); $this->assertEquals("Successful.", $response->getMessage()); $this->assertEquals( - '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', + '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840"}', $response->getCardReference() ); } diff --git a/tests/Message/CIMCreatePaymentProfileResponseTest.php b/tests/Message/CIMCreatePaymentProfileResponseTest.php index 927ac600..5ec5b68a 100644 --- a/tests/Message/CIMCreatePaymentProfileResponseTest.php +++ b/tests/Message/CIMCreatePaymentProfileResponseTest.php @@ -18,17 +18,13 @@ public function testCreateCardSuccess() { $httpResponse = $this->getMockHttpResponse('CIMCreatePaymentProfileSuccess.txt'); $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); - $mockRequest->shouldReceive('getCustomerProfileId')->times(1)->andReturn('28775801'); $response = new CIMCreatePaymentProfileResponse($mockRequest, $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); $this->assertEquals('I00001', $response->getReasonCode()); $this->assertEquals("1", $response->getResultCode()); $this->assertEquals("Successful.", $response->getMessage()); - $this->assertEquals( - '{"customerProfileId":"28775801","customerPaymentProfileId":"26455709"}', - $response->getCardReference() - ); + $this->assertEquals("26455709", $response->getCustomerPaymentProfileId()); } public function testCreateCardFailure() diff --git a/tests/Mock/CIMCreateCardFailureWithDuplicate.txt b/tests/Mock/CIMCreateCardFailureWithDuplicate.txt new file mode 100644 index 00000000..617eaaad --- /dev/null +++ b/tests/Mock/CIMCreateCardFailureWithDuplicate.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +ErrorE00039A duplicate record with ID 28775801 already exists.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,,,,,,,,12345,,,,kaylee@serenity.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, diff --git a/tests/Mock/CIMCreatePaymentProfileFailure.txt b/tests/Mock/CIMCreatePaymentProfileFailure.txt index 2d8a34a8..c7791c3c 100644 --- a/tests/Mock/CIMCreatePaymentProfileFailure.txt +++ b/tests/Mock/CIMCreatePaymentProfileFailure.txt @@ -11,4 +11,4 @@ Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET,POST,OPTIONS Date: Thu, 18 Sep 2014 03:59:27 GMT -ErrorE00039A duplicate customer payment profile already exists.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,none,,,,,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,, +ErrorE00039A duplicate customer payment profile already exists.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,none,,,,,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, From c7022a565d66cff2b4b97c1b8cc5961a1cbd5d7a Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Tue, 23 Sep 2014 19:43:22 +0530 Subject: [PATCH 026/254] Create card always returns response of a perticular payment profile --- src/Message/CIMCreateCardRequest.php | 40 ++++++++++++++----- src/Message/CIMCreateCardResponse.php | 23 +++++------ src/Message/CIMGetPaymentProfileRequest.php | 35 ++++++++++++++++ src/Message/CIMGetPaymentProfileResponse.php | 22 ++++++++++ tests/CIMGatewayIntegrationTest.php | 4 +- tests/CIMGatewayTest.php | 4 +- tests/Message/CIMCreateCardResponseTest.php | 4 -- .../CIMGetPaymentProfileRequestTest.php | 29 ++++++++++++++ .../CIMGetPaymentProfileResponseTest.php | 26 ++++++++++++ tests/Mock/CIMGetPaymentProfileSuccess.txt | 14 +++++++ 10 files changed, 170 insertions(+), 31 deletions(-) create mode 100644 src/Message/CIMGetPaymentProfileRequest.php create mode 100644 src/Message/CIMGetPaymentProfileResponse.php create mode 100644 tests/Message/CIMGetPaymentProfileRequestTest.php create mode 100644 tests/Message/CIMGetPaymentProfileResponseTest.php create mode 100644 tests/Mock/CIMGetPaymentProfileSuccess.txt diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index f03861fb..9fb0e7cf 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -148,7 +148,13 @@ public function sendData($data) if (!$response->isSuccessful() && $response->getReasonCode() == 'E00039') { // Duplicate profile. Try adding a new payment profile for the same profile and get the response $response = $this->createPaymentProfile($response); - + } elseif ($response->isSuccessful()) { + $parameters = array( + 'customerProfileId' => $response->getCustomerProfileId(), + 'customerPaymentProfileId' => $response->getCustomerPaymentProfileId() + ); + // Get the payment profile for the specified card. + $response = $this->makeGetPaymentProfileRequest($parameters); } return $this->response = $response; @@ -199,21 +205,21 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) } $parameters['customerPaymentProfileId'] = $customerPaymentProfileId; - $updatePaymentProfileRequest = $this->makeUpdatePaymentProfileRequest($parameters); - if (!$updatePaymentProfileRequest->isSuccessful()) { + $updatePaymentProfileResponse = $this->makeUpdatePaymentProfileRequest($parameters); + if (!$updatePaymentProfileResponse->isSuccessful()) { // Could not update payment profile. Return the original response return $createCardResponse; } + } - // return the updated customer profile - $getProfileResponse = $this->makeGetProfileRequest($parameters); - if (!$getProfileResponse->isSuccessful()) { - // Could not get the updated customer profile. Return the original response - return $createCardResponse; - } + // return the updated customer profile + $getPaymentProfileResponse = $this->makeGetPaymentProfileRequest($parameters); + if (!$getPaymentProfileResponse->isSuccessful()) { + // Could not get the updated customer profile. Return the original response + return $createCardResponse; } - return $getProfileResponse; + return $getPaymentProfileResponse; } /** @@ -244,6 +250,20 @@ public function makeGetProfileRequest($parameters) return $obj->send(); } + /** + * Get the customer payment profile + * + * @param array $parameters + * + * @return CIMGetPaymentProfileResponse + */ + public function makeGetPaymentProfileRequest($parameters) + { + $obj = new CIMGetPaymentProfileRequest($this->httpClient, $this->httpRequest); + $obj->initialize(array_replace($this->getParameters(), $parameters)); + return $obj->send(); + } + /** * Makes an update profile request * diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index 162d04f0..23d26b3a 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -9,22 +9,19 @@ class CIMCreateCardResponse extends CIMAbstractResponse { protected $xmlRootElement = 'createCustomerProfileResponse'; - public function getCardReference() + public function getCustomerProfileId() { - $cardRef = null; - $data = array(); - if (isset($this->data->customerProfileId)) { - // In case of a successful transaction, a "customerPaymentProfileId" element is present - $data['customerProfileId'] = (string)$this->data->customerProfileId; - } - if (!empty($this->data->customerPaymentProfileIdList->numericString)) { - $data['customerPaymentProfileId'] = (string)$this->data->customerPaymentProfileIdList->numericString; + if ($this->isSuccessful()) { + return (string)$this->data->customerProfileId; } + return null; + } - if (!empty($data)) { - $cardRef = json_encode($data); + public function getCustomerPaymentProfileId() + { + if ($this->isSuccessful()) { + return (string)$this->data->customerPaymentProfileIdList->numericString; } - - return $cardRef; + return null; } } diff --git a/src/Message/CIMGetPaymentProfileRequest.php b/src/Message/CIMGetPaymentProfileRequest.php new file mode 100644 index 00000000..bef74200 --- /dev/null +++ b/src/Message/CIMGetPaymentProfileRequest.php @@ -0,0 +1,35 @@ +validate('customerProfileId', 'customerPaymentProfileId'); + + $data = $this->getBaseData(); + + $data->customerProfileId = $this->getCustomerProfileId(); + $data->customerPaymentProfileId = $this->getCustomerPaymentProfileId(); + + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMGetPaymentProfileResponse($this, $httpResponse->getBody()); + } + +} diff --git a/src/Message/CIMGetPaymentProfileResponse.php b/src/Message/CIMGetPaymentProfileResponse.php new file mode 100644 index 00000000..242f87b1 --- /dev/null +++ b/src/Message/CIMGetPaymentProfileResponse.php @@ -0,0 +1,22 @@ +isSuccessful() && $this->request->getCustomerProfileId()) { + $data['customerProfileId'] = $this->request->getCustomerProfileId(); + $data['customerPaymentProfileId'] = (string)$this->data->paymentProfile->customerPaymentProfileId; + $cardRef = json_encode($data); + } + return $cardRef; + } +} diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 643b315f..8a24c947 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -31,8 +31,8 @@ public function setUp() $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); // //todo: Remove this before final commit -// $apiLoginId = '3wM8sJ9qR'; -// $transactionKey = '8V529R4p6sc8bY88'; + $apiLoginId = '3wM8sJ9qR'; + $transactionKey = '3K2e3z44EKz3g326'; if ($apiLoginId && $transactionKey) { diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 7009b068..a52e21ef 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -53,13 +53,13 @@ public function setUp() public function testCreateCardSuccess() { - $this->setMockHttpResponse('CIMCreateCardSuccess.txt'); + $this->setMockHttpResponse(array('CIMCreateCardSuccess.txt','CIMGetPaymentProfileSuccess.txt')); $response = $this->gateway->createCard($this->createCardOptions)->send(); $this->assertTrue($response->isSuccessful()); $this->assertSame( - '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840"}', + '{"customerProfileId":"28972084","customerPaymentProfileId":"26485433"}', $response->getCardReference() ); $this->assertSame('Successful.', $response->getMessage()); diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php index c770b2a2..7a22ff5c 100644 --- a/tests/Message/CIMCreateCardResponseTest.php +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -23,10 +23,6 @@ public function testCreateCardSuccess() $this->assertEquals('I00001', $response->getReasonCode()); $this->assertEquals("1", $response->getResultCode()); $this->assertEquals("Successful.", $response->getMessage()); - $this->assertEquals( - '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840"}', - $response->getCardReference() - ); } public function testCreateCardFailure() diff --git a/tests/Message/CIMGetPaymentProfileRequestTest.php b/tests/Message/CIMGetPaymentProfileRequestTest.php new file mode 100644 index 00000000..9c85e531 --- /dev/null +++ b/tests/Message/CIMGetPaymentProfileRequestTest.php @@ -0,0 +1,29 @@ +request = new CIMGetPaymentProfileRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'customerProfileId' => '28775801', + 'customerPaymentProfileId' => '28775803', + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + $this->assertEquals('28775801', $data->customerProfileId); + $this->assertEquals('28775803', $data->customerPaymentProfileId); + } +} \ No newline at end of file diff --git a/tests/Message/CIMGetPaymentProfileResponseTest.php b/tests/Message/CIMGetPaymentProfileResponseTest.php new file mode 100644 index 00000000..76576c65 --- /dev/null +++ b/tests/Message/CIMGetPaymentProfileResponseTest.php @@ -0,0 +1,26 @@ +getMockRequest(), ''); + } + + public function testGetMatchingPaymentProfileId() + { + $httpResponse = $this->getMockHttpResponse('CIMGetPaymentProfileSuccess.txt'); + $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); + $mockRequest->shouldReceive('getCustomerProfileId')->andReturn('28972085'); + $response = new CIMGetPaymentProfileResponse($mockRequest, $httpResponse->getBody()); + + $this->assertEquals('{"customerProfileId":"28972085","customerPaymentProfileId":"26485433"}', $response->getCardReference()); + } +} diff --git a/tests/Mock/CIMGetPaymentProfileSuccess.txt b/tests/Mock/CIMGetPaymentProfileSuccess.txt new file mode 100644 index 00000000..9c4c6782 --- /dev/null +++ b/tests/Mock/CIMGetPaymentProfileSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT4 + +OkI00001Successful.
1234526485433XXXX8888XXXX From d398f93e9a948a1d5b046e89886ab674d4fb5d68 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Fri, 26 Sep 2014 08:31:54 +0530 Subject: [PATCH 027/254] Response is always an array. Create card response is augmented with fingerprint and brand --- src/Message/CIMAbstractResponse.php | 56 +++++++++++++++++-- src/Message/CIMCreateCardRequest.php | 21 ++++++- src/Message/CIMCreateCardResponse.php | 4 +- .../CIMCreatePaymentProfileResponse.php | 13 ++++- src/Message/CIMGetPaymentProfileResponse.php | 13 ++--- src/Message/CIMGetProfileResponse.php | 19 +++---- src/Message/CIMResponse.php | 4 +- .../CIMUpdatePaymentProfileResponse.php | 13 +---- tests/CIMGatewayIntegrationTest.php | 18 +++++- tests/Message/CIMCreateCardRequestTest.php | 10 ---- tests/Message/CIMCreateCardResponseTest.php | 7 +++ .../CIMCreatePaymentProfileResponseTest.php | 2 + tests/Message/CIMResponseTest.php | 4 +- 13 files changed, 129 insertions(+), 55 deletions(-) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index 9bc5d056..d34d85b6 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -34,7 +34,7 @@ public function __construct(RequestInterface $request, $data) throw new InvalidResponseException(); } - $this->data = $xml; + $this->data = $this->xml2array($xml); } public function isSuccessful() @@ -49,7 +49,7 @@ public function isSuccessful() */ public function getResultCode() { - $result = (string)$this->data->messages[0]->resultCode; + $result = (string)$this->data['messages'][0]['resultCode'][0]; switch ($result) { case 'Ok': return 1; @@ -70,9 +70,9 @@ public function getReasonCode() { $code = null; - if (isset($this->data->messages)) { + if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present - $code = (string)$this->data->messages[0]->message[0]->code; + $code = (string)$this->data['messages'][0]['message'][0]['code'][0]; } @@ -88,9 +88,9 @@ public function getMessage() { $message = null; - if (isset($this->data->messages)) { + if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present - $message = (string)$this->data->messages[0]->message[0]->text; + $message = (string)$this->data['messages'][0]['message'][0]['text'][0]; } @@ -98,6 +98,50 @@ public function getMessage() } public function getCardReference() + { + $cardRef = null; + if ($this->isSuccessful()) { + $data['customerProfileId'] = $this->getCustomerProfileId(); + $data['customerPaymentProfileId'] = $this->getCustomerPaymentProfileId(); + if (!empty($data['customerProfileId']) && !empty($data['customerPaymentProfileId'])) { + // For card reference both profileId and payment profileId should exist + $cardRef = json_encode($data); + } + } + return $cardRef; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag][] = trim($element); + } + } + + return $arr; + } + + public function getCustomerProfileId() + { + return null; + } + + public function getCustomerPaymentProfileId() { return null; } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 9fb0e7cf..e37ad157 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -157,7 +157,26 @@ public function sendData($data) $response = $this->makeGetPaymentProfileRequest($parameters); } - return $this->response = $response; + return $this->response = $this->augmentResponse($response); + } + + /** + * Authorize net does not provide finger print and brand of the card hence we build the parameters from the + * request data + * + * @param $response + * + * @return mixed + */ + public function augmentResponse($response) + { + if ($response->isSuccessful()) { + $card = $this->getCard(); + $response->data['fingerPrint'] = md5($card['number'] . $card['expiryMonth'] . $card['expiryYear']); + $response->data['brand'] = $card->getBrand(); + } + + return $response; } /** diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index 23d26b3a..d13dd0c4 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -12,7 +12,7 @@ class CIMCreateCardResponse extends CIMAbstractResponse public function getCustomerProfileId() { if ($this->isSuccessful()) { - return (string)$this->data->customerProfileId; + return $this->data['customerProfileId'][0]; } return null; } @@ -20,7 +20,7 @@ public function getCustomerProfileId() public function getCustomerPaymentProfileId() { if ($this->isSuccessful()) { - return (string)$this->data->customerPaymentProfileIdList->numericString; + return $this->data['customerPaymentProfileIdList'][0]['numericString'][0]; } return null; } diff --git a/src/Message/CIMCreatePaymentProfileResponse.php b/src/Message/CIMCreatePaymentProfileResponse.php index b69fc66c..122c9dd0 100644 --- a/src/Message/CIMCreatePaymentProfileResponse.php +++ b/src/Message/CIMCreatePaymentProfileResponse.php @@ -9,8 +9,19 @@ class CIMCreatePaymentProfileResponse extends CIMAbstractResponse { protected $xmlRootElement = 'createCustomerPaymentProfileResponse'; + public function getCustomerProfileId() + { + if ($this->isSuccessful()) { + return $this->request->getCustomerProfileId(); + } + return null; + } + public function getCustomerPaymentProfileId() { - return (string)$this->data->customerPaymentProfileId; + if ($this->isSuccessful()) { + return $this->data['customerPaymentProfileId'][0]; + } + return null; } } diff --git a/src/Message/CIMGetPaymentProfileResponse.php b/src/Message/CIMGetPaymentProfileResponse.php index 242f87b1..b16bafa1 100644 --- a/src/Message/CIMGetPaymentProfileResponse.php +++ b/src/Message/CIMGetPaymentProfileResponse.php @@ -5,18 +5,15 @@ /** * Authorize.Net CIM Get payment profiles Response */ -class CIMGetPaymentProfileResponse extends CIMCreateCardResponse +class CIMGetPaymentProfileResponse extends CIMCreatePaymentProfileResponse { protected $xmlRootElement = 'getCustomerPaymentProfileResponse'; - public function getCardReference() + public function getCustomerPaymentProfileId() { - $cardRef = null; - if ($this->isSuccessful() && $this->request->getCustomerProfileId()) { - $data['customerProfileId'] = $this->request->getCustomerProfileId(); - $data['customerPaymentProfileId'] = (string)$this->data->paymentProfile->customerPaymentProfileId; - $cardRef = json_encode($data); + if ($this->isSuccessful()) { + return $this->data['paymentProfile'][0]['customerPaymentProfileId'][0]; } - return $cardRef; + return null; } } diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index d1809237..f5a43237 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -5,7 +5,7 @@ /** * Authorize.Net CIM Get payment profiles Response */ -class CIMGetProfileResponse extends CIMCreateCardResponse +class CIMGetProfileResponse extends CIMCreatePaymentProfileResponse { protected $xmlRootElement = 'getCustomerProfileResponse'; @@ -23,25 +23,22 @@ public function getMatchingPaymentProfileId($last4) return null; } - foreach ($this->data->profile->paymentProfiles as $paymentProfile) { + foreach ($this->data['profile'][0]['paymentProfiles'] as $paymentProfile) { // For every payment profile check if the last4 matches the last4 of the card in request. - $cardLast4 = substr((string)$paymentProfile->payment->creditCard->cardNumber, -4); + $cardLast4 = substr($paymentProfile['payment'][0]['creditCard'][0]['cardNumber'][0], -4); if ($last4 == $cardLast4) { - return (string)$paymentProfile->customerPaymentProfileId; + return (string)$paymentProfile['customerPaymentProfileId'][0]; } } return null; } - public function getCardReference() + public function getCustomerPaymentProfileId() { - $cardRef = null; - if ($this->isSuccessful() && $this->request->getCustomerPaymentProfileId()) { - $data['customerProfileId'] = $this->request->getCustomerProfileId(); - $data['customerPaymentProfileId'] = $this->request->getCustomerPaymentProfileId(); - $cardRef = json_encode($data); + if ($this->isSuccessful()) { + return $this->request->getCustomerPaymentProfileId(); } - return $cardRef; + return null; } } diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index 12c7526f..157ea1cd 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -15,10 +15,10 @@ public function getTransactionReference() return null; } $transRef = null; - if (isset($this->data->directResponse)) { + if (isset($this->data['directResponse'])) { $transRef = array(); // In case of a successful transaction, a "directResponse" element is present - $directResponse = explode(',', (string)$this->data->directResponse); + $directResponse = explode(',', (string)$this->data['directResponse'][0]); // Required for capturing an authorized transaction $transRef['approvalCode'] = $directResponse[4]; // Required for refund a transaction diff --git a/src/Message/CIMUpdatePaymentProfileResponse.php b/src/Message/CIMUpdatePaymentProfileResponse.php index f337b480..8b069970 100644 --- a/src/Message/CIMUpdatePaymentProfileResponse.php +++ b/src/Message/CIMUpdatePaymentProfileResponse.php @@ -9,17 +9,8 @@ class CIMUpdatePaymentProfileResponse extends CIMCreatePaymentProfileResponse { protected $xmlRootElement = 'updateCustomerPaymentProfileResponse'; - public function getCardReference() + public function getCustomerPaymentProfileId() { - $cardRef = null; - if ($this->isSuccessful()) { - // Update payment profile never returns customer profileId or payment profile Id. So use the request - // data to generate the card reference - $data['customerProfileId'] = $this->request->getCustomerProfileId(); - $data['customerPaymentProfileId'] = $this->request->getCustomerPaymentProfileId(); - - $cardRef = json_encode($data); - } - return $cardRef; + return $this->request->getCustomerPaymentProfileId(); } } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 8a24c947..5475a1cb 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -73,7 +73,21 @@ public function testIntegration() $cardRef = $response->getCardReference(); - // Try creating card for the same user again. + // Try different creating card for same user + $params = array( + 'card' => $this->getValidCard(), + 'name' => 'Kaywinnet Lee Frye', + 'email' => "kaylee$rand@serenity.com", + ); + $params['card']['number'] = '4007000000027'; + $request = $this->gateway->createCard($params); + $request->setDeveloperMode(true); + + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Should be a success as we create a payment profile'); + $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + + // Try creating same card for the same user without force card update flag. $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', @@ -86,7 +100,7 @@ public function testIntegration() $this->assertFalse($response->isSuccessful(), 'Should not success as we tried creating duplicate profile'); $this->assertNull($response->getCardReference(), 'Card reference should be returned'); - // Try creating card for the same user again with force card update flag. + // Try creating same card for the same user again with force card update flag. $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index 892e19e5..e8042c39 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -29,14 +29,4 @@ public function testGetData() $this->assertEquals($card['number'], $data->profile->paymentProfiles->payment->creditCard->cardNumber); $this->assertEquals('testMode', $data->validationMode); } - - public function testCreatePaymentProfile() - { - $httpResponse = $this->getMockHttpResponse('CIMCreateCardFailureWithDuplicate.txt'); - $duplicateProfileResponse = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody()); - $this->setMockHttpResponse(array('CIMCreatePaymentProfileFailure.txt')); - - $response = $this->request->createPaymentProfile($duplicateProfileResponse); - - } } diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php index 7a22ff5c..a68942cf 100644 --- a/tests/Message/CIMCreateCardResponseTest.php +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -23,6 +23,9 @@ public function testCreateCardSuccess() $this->assertEquals('I00001', $response->getReasonCode()); $this->assertEquals("1", $response->getResultCode()); $this->assertEquals("Successful.", $response->getMessage()); + + $this->assertEquals('28972084', $response->getCustomerProfileId()); + $this->assertEquals('26317840', $response->getCustomerPaymentProfileId()); } public function testCreateCardFailure() @@ -34,6 +37,10 @@ public function testCreateCardFailure() $this->assertEquals('E00041', $response->getReasonCode()); $this->assertEquals("3", $response->getResultCode()); $this->assertEquals("One or more fields in the profile must contain a value.", $response->getMessage()); + + $this->assertNull($response->getCustomerProfileId()); + $this->assertNull($response->getCustomerPaymentProfileId()); + $this->assertNull($response->getCardReference()); } } diff --git a/tests/Message/CIMCreatePaymentProfileResponseTest.php b/tests/Message/CIMCreatePaymentProfileResponseTest.php index 5ec5b68a..70b33914 100644 --- a/tests/Message/CIMCreatePaymentProfileResponseTest.php +++ b/tests/Message/CIMCreatePaymentProfileResponseTest.php @@ -18,6 +18,7 @@ public function testCreateCardSuccess() { $httpResponse = $this->getMockHttpResponse('CIMCreatePaymentProfileSuccess.txt'); $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); + $mockRequest->shouldReceive('getCustomerProfileId')->times(1)->andReturn('28775801'); $response = new CIMCreatePaymentProfileResponse($mockRequest, $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); @@ -25,6 +26,7 @@ public function testCreateCardSuccess() $this->assertEquals("1", $response->getResultCode()); $this->assertEquals("Successful.", $response->getMessage()); $this->assertEquals("26455709", $response->getCustomerPaymentProfileId()); + $this->assertEquals("28775801", $response->getCustomerProfileId()); } public function testCreateCardFailure() diff --git a/tests/Message/CIMResponseTest.php b/tests/Message/CIMResponseTest.php index e04b3d8d..bc587f95 100644 --- a/tests/Message/CIMResponseTest.php +++ b/tests/Message/CIMResponseTest.php @@ -19,7 +19,9 @@ public function testGetTransactionReference() { $httpResponse = $this->getMockHttpResponse('CIMAuthorizeSuccess.txt'); $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); - $mockRequest->shouldReceive('getCardReference')->times(1)->andReturn('{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}'); + $mockRequest->shouldReceive('getCardReference')->times(1)->andReturn( + '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}' + ); $response = new CIMResponse($mockRequest, $httpResponse->getBody()); $this->assertEquals( From 808e67395b2b1baf7b0a05280ec9b75189f947b5 Mon Sep 17 00:00:00 2001 From: Venkat Krishna Kotra Date: Fri, 26 Sep 2014 15:39:49 +0530 Subject: [PATCH 028/254] Add expiry month and expiry year to the CIM create card response. --- src/Message/CIMAbstractResponse.php | 21 +++++++++++++++++++++ src/Message/CIMCreateCardRequest.php | 22 ++-------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index d34d85b6..7793841a 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\CreditCard; use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractResponse; use Omnipay\Common\Message\RequestInterface; @@ -145,4 +146,24 @@ public function getCustomerPaymentProfileId() { return null; } + + /** + * Authorize net does not provide finger print and brand of the card hence we build the parameters from the + * requested card data + * + */ + public function augmentResponse() + { + if ($this->isSuccessful()) { + /** @var CreditCard $card */ + $card = $this->request->getCard(); + if ($card) { + $ccString = $card->getNumber() . $card->getExpiryMonth() . $card->getExpiryYear(); + $this->data['hash'] = md5($ccString); + $this->data['brand'] = $card->getBrand(); + $this->data['expiryYear'] = $card->getExpiryYear(); + $this->data['expiryMonth'] = $card->getExpiryMonth(); + } + } + } } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index e37ad157..31be07a4 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -157,26 +157,8 @@ public function sendData($data) $response = $this->makeGetPaymentProfileRequest($parameters); } - return $this->response = $this->augmentResponse($response); - } - - /** - * Authorize net does not provide finger print and brand of the card hence we build the parameters from the - * request data - * - * @param $response - * - * @return mixed - */ - public function augmentResponse($response) - { - if ($response->isSuccessful()) { - $card = $this->getCard(); - $response->data['fingerPrint'] = md5($card['number'] . $card['expiryMonth'] . $card['expiryYear']); - $response->data['brand'] = $card->getBrand(); - } - - return $response; + $response->augmentResponse(); + return $this->response = $response; } /** From 5efb7c2de21f0381c1a389f982264f9fbefc8a0a Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 13 Nov 2014 19:11:05 +0530 Subject: [PATCH 029/254] Cleanup code, fix failing unit tests --- composer.json | 7 +++++-- src/CIMGateway.php | 2 ++ src/Message/AIMAbstractRequest.php | 1 + src/Message/AIMResponse.php | 2 +- src/Message/CIMAbstractRequest.php | 5 ++--- src/Message/CIMGetPaymentProfileRequest.php | 2 -- src/Message/CIMGetProfileRequest.php | 2 -- tests/CIMGatewayIntegrationTest.php | 7 +++---- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index d10e9352..0cf87c13 100644 --- a/composer.json +++ b/composer.json @@ -1,4 +1,4 @@ - { +{ "name": "omnipay/authorizenet", "type": "library", "description": "Authorize.Net gateway for the Omnipay payment processing library", @@ -28,7 +28,10 @@ "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "~2.0" + "omnipay/common": "~2.0", + "monolog/monolog": "~1.11", + "guzzle/log": "~3.9", + "guzzle/plugin": "~3.9" }, "require-dev": { "omnipay/tests": "~2.0" diff --git a/src/CIMGateway.php b/src/CIMGateway.php index 793210ca..d7d06c88 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -15,6 +15,8 @@ public function getName() } /** + * Create a new debit or credit card + * * @param array $parameters * * @return CIMCreateCardRequest diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index ff7531c1..d99254c5 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -89,6 +89,7 @@ public function getBaseData() * Adds billing data to a partially filled request data object. * * @param \SimpleXMLElement $data + * * @return \SimpleXMLElement */ protected function addBillingData(\SimpleXMLElement $data) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 1de2b374..7145eac6 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -20,7 +20,7 @@ public function __construct(RequestInterface $request, $data) try { $xml = simplexml_load_string($xml); - } catch (\Exception $e) { + } catch(\Exception $e) { throw new InvalidResponseException(); } diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 35fd328f..b5169ccd 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\Exception\InvalidRequestException; - /** * Authorize.Net CIM Abstract Request */ @@ -70,7 +68,8 @@ public function getForceCardUpdate() } /** - * @throws InvalidRequestException + * Create and return the base XML data required to create a new request + * * @return mixed|\SimpleXMLElement */ public function getBaseData() diff --git a/src/Message/CIMGetPaymentProfileRequest.php b/src/Message/CIMGetPaymentProfileRequest.php index bef74200..fe5cec51 100644 --- a/src/Message/CIMGetPaymentProfileRequest.php +++ b/src/Message/CIMGetPaymentProfileRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\CreditCard; - /** * Create Request to get customer profile */ diff --git a/src/Message/CIMGetProfileRequest.php b/src/Message/CIMGetProfileRequest.php index c74a9e74..52000157 100644 --- a/src/Message/CIMGetProfileRequest.php +++ b/src/Message/CIMGetProfileRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\CreditCard; - /** * Create Request to get customer profile */ diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 5475a1cb..52a33e6e 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -30,20 +30,19 @@ public function setUp() $apiLoginId = getenv('AUTHORIZE_NET_API_LOGIN_ID'); $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); -// //todo: Remove this before final commit - $apiLoginId = '3wM8sJ9qR'; - $transactionKey = '3K2e3z44EKz3g326'; if ($apiLoginId && $transactionKey) { + /* $logger = new \Monolog\Logger('authorizenet_cim'); $logger->pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); $adapter = new PsrLogAdapter($logger); $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); + */ $client = new Client(); - $client->addSubscriber($logPlugin); + // $client->addSubscriber($logPlugin); $this->gateway = new CIMGateway($client, $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); From c6b1e3ff7759ede17f0fe4ca6746411fa7f4e114 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 13 Nov 2014 19:27:52 +0530 Subject: [PATCH 030/254] Move dependencies into require-dev --- composer.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 0cf87c13..201c9d65 100644 --- a/composer.json +++ b/composer.json @@ -28,13 +28,13 @@ "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "~2.0", - "monolog/monolog": "~1.11", - "guzzle/log": "~3.9", - "guzzle/plugin": "~3.9" + "omnipay/common": "~2.0" }, "require-dev": { - "omnipay/tests": "~2.0" + "omnipay/tests": "~2.0", + "guzzle/plugin": "~3.9", + "guzzle/log": "~3.9", + "monolog/monolog": "~1.3" }, "extra": { "branch-alias": { From a95b5cab6635e8e09c3cd360dd5bfceec74616fd Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Fri, 14 Nov 2014 17:37:46 +0530 Subject: [PATCH 031/254] Fix xml2array and issues that arise because of it. --- src/Message/CIMAbstractResponse.php | 8 ++++---- src/Message/CIMCreateCardResponse.php | 4 ++-- src/Message/CIMCreatePaymentProfileResponse.php | 2 +- src/Message/CIMGetPaymentProfileResponse.php | 2 +- src/Message/CIMGetProfileResponse.php | 2 +- src/Message/CIMResponse.php | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index 7793841a..cab6ce3f 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -50,7 +50,7 @@ public function isSuccessful() */ public function getResultCode() { - $result = (string)$this->data['messages'][0]['resultCode'][0]; + $result = (string)$this->data['messages'][0]['resultCode']; switch ($result) { case 'Ok': return 1; @@ -73,7 +73,7 @@ public function getReasonCode() if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present - $code = (string)$this->data['messages'][0]['message'][0]['code'][0]; + $code = (string)$this->data['messages'][0]['message'][0]['code']; } @@ -91,7 +91,7 @@ public function getMessage() if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present - $message = (string)$this->data['messages'][0]['message'][0]['text'][0]; + $message = (string)$this->data['messages'][0]['message'][0]['text']; } @@ -130,7 +130,7 @@ public function xml2array(\SimpleXMLElement $xml) if (!empty($e)) { $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; } else { - $arr[$tag][] = trim($element); + $arr[$tag] = trim($element); } } diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index d13dd0c4..ef50389d 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -12,7 +12,7 @@ class CIMCreateCardResponse extends CIMAbstractResponse public function getCustomerProfileId() { if ($this->isSuccessful()) { - return $this->data['customerProfileId'][0]; + return $this->data['customerProfileId']; } return null; } @@ -20,7 +20,7 @@ public function getCustomerProfileId() public function getCustomerPaymentProfileId() { if ($this->isSuccessful()) { - return $this->data['customerPaymentProfileIdList'][0]['numericString'][0]; + return $this->data['customerPaymentProfileIdList'][0]['numericString']; } return null; } diff --git a/src/Message/CIMCreatePaymentProfileResponse.php b/src/Message/CIMCreatePaymentProfileResponse.php index 122c9dd0..35335392 100644 --- a/src/Message/CIMCreatePaymentProfileResponse.php +++ b/src/Message/CIMCreatePaymentProfileResponse.php @@ -20,7 +20,7 @@ public function getCustomerProfileId() public function getCustomerPaymentProfileId() { if ($this->isSuccessful()) { - return $this->data['customerPaymentProfileId'][0]; + return $this->data['customerPaymentProfileId']; } return null; } diff --git a/src/Message/CIMGetPaymentProfileResponse.php b/src/Message/CIMGetPaymentProfileResponse.php index b16bafa1..c6953fd1 100644 --- a/src/Message/CIMGetPaymentProfileResponse.php +++ b/src/Message/CIMGetPaymentProfileResponse.php @@ -12,7 +12,7 @@ class CIMGetPaymentProfileResponse extends CIMCreatePaymentProfileResponse public function getCustomerPaymentProfileId() { if ($this->isSuccessful()) { - return $this->data['paymentProfile'][0]['customerPaymentProfileId'][0]; + return $this->data['paymentProfile'][0]['customerPaymentProfileId']; } return null; } diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index f5a43237..fb7add8c 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -27,7 +27,7 @@ public function getMatchingPaymentProfileId($last4) // For every payment profile check if the last4 matches the last4 of the card in request. $cardLast4 = substr($paymentProfile['payment'][0]['creditCard'][0]['cardNumber'][0], -4); if ($last4 == $cardLast4) { - return (string)$paymentProfile['customerPaymentProfileId'][0]; + return (string)$paymentProfile['customerPaymentProfileId']; } } diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index 157ea1cd..42e96f8a 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -18,7 +18,7 @@ public function getTransactionReference() if (isset($this->data['directResponse'])) { $transRef = array(); // In case of a successful transaction, a "directResponse" element is present - $directResponse = explode(',', (string)$this->data['directResponse'][0]); + $directResponse = explode(',', (string)$this->data['directResponse']); // Required for capturing an authorized transaction $transRef['approvalCode'] = $directResponse[4]; // Required for refund a transaction From 169edbd76cf1bcc710b0bd5919aedc25344f2ec9 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Fri, 14 Nov 2014 19:24:24 +0530 Subject: [PATCH 032/254] Do not format the amount as it voids the XML schema. --- src/Message/CIMAuthorizeRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index f5c2068e..e520bfca 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -32,7 +32,7 @@ protected function addTransactionData(\SimpleXMLElement $data) { $transaction = $data->addChild('transaction'); $action = $transaction->addChild($this->action); - $action->amount = number_format($this->getAmount(), 2); + $action->amount = $this->getAmount(); $cardRef = json_decode($this->getCardReference(), true); $action->customerProfileId = $cardRef['customerProfileId']; From e9e0c44484ccb8265d08e2b794debd01f5ae223b Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Mon, 17 Nov 2014 15:14:59 +0530 Subject: [PATCH 033/254] Fix duplicate payment profile handling --- src/Message/CIMGetProfileResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index fb7add8c..18a91232 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -25,7 +25,7 @@ public function getMatchingPaymentProfileId($last4) foreach ($this->data['profile'][0]['paymentProfiles'] as $paymentProfile) { // For every payment profile check if the last4 matches the last4 of the card in request. - $cardLast4 = substr($paymentProfile['payment'][0]['creditCard'][0]['cardNumber'][0], -4); + $cardLast4 = substr($paymentProfile['payment'][0]['creditCard'][0]['cardNumber'], -4); if ($last4 == $cardLast4) { return (string)$paymentProfile['customerPaymentProfileId']; } From 81343c3ae422111a6e479b06d7e07cff3a71bc15 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Mon, 17 Nov 2014 15:22:41 +0530 Subject: [PATCH 034/254] Update unit tests --- src/Message/CIMAbstractResponse.php | 26 +++++------ src/Message/CIMResponse.php | 1 + tests/CIMGatewayIntegrationTest.php | 67 +++++++++++++++-------------- 3 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index cab6ce3f..38db9c54 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -74,7 +74,6 @@ public function getReasonCode() if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present $code = (string)$this->data['messages'][0]['message'][0]['code']; - } return $code; @@ -148,22 +147,23 @@ public function getCustomerPaymentProfileId() } /** - * Authorize net does not provide finger print and brand of the card hence we build the parameters from the + * Authorize net does not provide fingerprint and brand of the card hence we build the parameters from the * requested card data - * */ public function augmentResponse() { - if ($this->isSuccessful()) { - /** @var CreditCard $card */ - $card = $this->request->getCard(); - if ($card) { - $ccString = $card->getNumber() . $card->getExpiryMonth() . $card->getExpiryYear(); - $this->data['hash'] = md5($ccString); - $this->data['brand'] = $card->getBrand(); - $this->data['expiryYear'] = $card->getExpiryYear(); - $this->data['expiryMonth'] = $card->getExpiryMonth(); - } + if (!$this->isSuccessful()) { + return; + } + + /** @var CreditCard $card */ + $card = $this->request->getCard(); + if ($card) { + $ccString = $card->getNumber() . $card->getExpiryMonth() . $card->getExpiryYear(); + $this->data['hash'] = md5($ccString); + $this->data['brand'] = $card->getBrand(); + $this->data['expiryYear'] = $card->getExpiryYear(); + $this->data['expiryMonth'] = $card->getExpiryMonth(); } } } diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index 42e96f8a..72ef4205 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -14,6 +14,7 @@ public function getTransactionReference() if (!$this->isSuccessful()) { return null; } + $transRef = null; if (isset($this->data['directResponse'])) { $transRef = array(); diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 52a33e6e..2b67de5b 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -2,11 +2,9 @@ namespace Omnipay\AuthorizeNet; -use Omnipay\Tests\TestCase; use Guzzle\Http\Client; -use Guzzle\Log\MessageFormatter; -use Guzzle\Log\PsrLogAdapter; -use Guzzle\Plugin\Log\LogPlugin; +use Omnipay\AuthorizeNet\Message\CIMResponse; +use Omnipay\Tests\TestCase; /** * Integration tests for the CIM Gateway. These tests make real requests to Authorize.NET sandbox environment. @@ -32,17 +30,7 @@ public function setUp() $transactionKey = getenv('AUTHORIZE_NET_TRANSACTION_KEY'); if ($apiLoginId && $transactionKey) { - - /* - $logger = new \Monolog\Logger('authorizenet_cim'); - $logger->pushHandler(new \Monolog\Handler\StreamHandler('/var/log/php/debug.log', \Monolog\Logger::DEBUG)); - $logger->pushHandler(new \Monolog\Handler\FirePHPHandler()); - $adapter = new PsrLogAdapter($logger); - $logPlugin = new LogPlugin($adapter, MessageFormatter::DEBUG_FORMAT); - */ - $client = new Client(); - // $client->addSubscriber($logPlugin); $this->gateway = new CIMGateway($client, $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); @@ -54,10 +42,10 @@ public function setUp() } } - public function testIntegration() + public function testCreateCustomerAndPaymentProfile() { // Create card - $rand = rand(100000, 999999); + $rand = uniqid(); $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', @@ -66,13 +54,14 @@ public function testIntegration() $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); + /* @var $response CIMResponse */ $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Profile should get created'); $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); $cardRef = $response->getCardReference(); - // Try different creating card for same user + // Try creating a different card for the same user $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', @@ -83,7 +72,7 @@ public function testIntegration() $request->setDeveloperMode(true); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Should be a success as we create a payment profile'); + $this->assertTrue($response->isSuccessful(), 'Should be successful as we have created a payment profile'); $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); // Try creating same card for the same user without force card update flag. @@ -96,7 +85,7 @@ public function testIntegration() $request->setDeveloperMode(true); $response = $request->send(); - $this->assertFalse($response->isSuccessful(), 'Should not success as we tried creating duplicate profile'); + $this->assertFalse($response->isSuccessful(), 'Should fail as we tried creating a duplicate profile'); $this->assertNull($response->getCardReference(), 'Card reference should be returned'); // Try creating same card for the same user again with force card update flag. @@ -110,18 +99,37 @@ public function testIntegration() $request->setDeveloperMode(true); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Should succeed updating of the existing payment profile'); + $this->assertTrue($response->isSuccessful(), 'Should succeed in updating the existing payment profile'); $this->assertEquals( $cardRef, $response->getCardReference(), 'Card reference should be same as with the one newly created' ); + } + + public function testAuthorizeAndVoid() + { + // Create card + $rand = uniqid(); + $params = array( + 'card' => $this->getValidCard(), + 'name' => 'Kaywinnet Lee Frye ' . $rand, + 'email' => "kaylee$rand@serenity.com", + ); + $request = $this->gateway->createCard($params); + $request->setDeveloperMode(true); + + /* @var $response CIMResponse */ + $response = $request->send(); + $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + + $cardRef = $response->getCardReference(); // Create Authorize only transaction $params = array( 'cardReference' => $cardRef, 'amount' => 100.00, - 'description' + 'description' => 'Hello World' ); $request = $this->gateway->authorize($params); $request->setDeveloperMode(true); @@ -143,7 +151,6 @@ public function testIntegration() $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Capture transaction should get created'); $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); - $captureTransRef = $response->getTransactionReference(); // Make a purchase using the saved card. i.e auth and capture $params = array( @@ -156,20 +163,16 @@ public function testIntegration() $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Purchase transaction should get created'); $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); - $purchaseTransRef = $response->getTransactionReference(); + + $transactionRef = json_decode($response->getTransactionReference(), true); // Make a refund on the purchase transaction - $params = array( - 'transactionReference' => $purchaseTransRef, - 'amount' => 110.00, - ); - $request = $this->gateway->refund($params); + $params = array('transactionReference' => $transactionRef['transId']); + $request = $this->gateway->void($params); $request->setDeveloperMode(true); $response = $request->send(); - // todo: Fix refunds, and add unit tests using mocks -// $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); -// $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); - + $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); + $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); } } From 36d7c3ad60992abc640981859f36860297fce699 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 19 Nov 2014 08:49:45 +0530 Subject: [PATCH 035/254] Remove dev dependencies that are no longer required --- composer.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 201c9d65..0dd8b4c3 100644 --- a/composer.json +++ b/composer.json @@ -31,10 +31,7 @@ "omnipay/common": "~2.0" }, "require-dev": { - "omnipay/tests": "~2.0", - "guzzle/plugin": "~3.9", - "guzzle/log": "~3.9", - "monolog/monolog": "~1.3" + "omnipay/tests": "~2.0" }, "extra": { "branch-alias": { From e1e590c8bd0b83cfebb587c154585b2bef522b49 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 27 Nov 2014 08:01:00 +0530 Subject: [PATCH 036/254] Fix PSR-2 issues --- src/CIMGateway.php | 2 +- src/Message/AIMResponse.php | 2 +- src/Message/CIMAbstractResponse.php | 2 +- src/Message/CIMAuthorizeRequest.php | 1 - src/Message/CIMCreateCardRequest.php | 1 - src/Message/CIMGetPaymentProfileRequest.php | 1 - src/Message/CIMGetProfileRequest.php | 1 - 7 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index d7d06c88..f664b85b 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -45,4 +45,4 @@ public function refund(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMRefundRequest', $parameters); } -} \ No newline at end of file +} diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 7145eac6..1de2b374 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -20,7 +20,7 @@ public function __construct(RequestInterface $request, $data) try { $xml = simplexml_load_string($xml); - } catch(\Exception $e) { + } catch (\Exception $e) { throw new InvalidResponseException(); } diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index 38db9c54..13be97c8 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -27,7 +27,7 @@ public function __construct(RequestInterface $request, $data) try { $xml = simplexml_load_string($xml); - } catch(\Exception $e) { + } catch (\Exception $e) { throw new InvalidResponseException(); } diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index e520bfca..b2bcecee 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -57,5 +57,4 @@ public function sendData($data) return $this->response = new CIMResponse($this, $httpResponse->getBody()); } - } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 31be07a4..9c62af7d 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -278,5 +278,4 @@ public function makeUpdatePaymentProfileRequest($parameters) $obj->initialize(array_replace($this->getParameters(), $parameters)); return $obj->send(); } - } diff --git a/src/Message/CIMGetPaymentProfileRequest.php b/src/Message/CIMGetPaymentProfileRequest.php index fe5cec51..f99298b3 100644 --- a/src/Message/CIMGetPaymentProfileRequest.php +++ b/src/Message/CIMGetPaymentProfileRequest.php @@ -29,5 +29,4 @@ public function sendData($data) return $this->response = new CIMGetPaymentProfileResponse($this, $httpResponse->getBody()); } - } diff --git a/src/Message/CIMGetProfileRequest.php b/src/Message/CIMGetProfileRequest.php index 52000157..70d85a8a 100644 --- a/src/Message/CIMGetProfileRequest.php +++ b/src/Message/CIMGetProfileRequest.php @@ -28,5 +28,4 @@ public function sendData($data) return $this->response = new CIMGetProfileResponse($this, $httpResponse->getBody()); } - } From e8e986e86d4d427811b09babd69f3a092e712b92 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 27 Nov 2014 08:11:50 +0530 Subject: [PATCH 037/254] Update README.md to include mention of AuthorizeNet_CIM --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ca3157bc..c3de917f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ And run composer to update your dependencies: The following gateways are provided by this package: * AuthorizeNet_AIM +* AuthorizeNet_CIM * AuthorizeNet_SIM For general usage instructions, please see the main [Omnipay](https://github.com/omnipay/omnipay) From 0c106c64f3658fcd9dde3967c19b09f59e1b4f45 Mon Sep 17 00:00:00 2001 From: Tristan Harris Date: Fri, 19 Dec 2014 15:09:32 +0000 Subject: [PATCH 038/254] Allow alternative endpoint urls --- src/AIMGateway.php | 8 ++++++++ src/Message/AbstractRequest.php | 15 +++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 990c5928..ff88e93c 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -24,6 +24,8 @@ public function getDefaultParameters() 'transactionKey' => '', 'testMode' => false, 'developerMode' => false, + 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll' ); } @@ -57,6 +59,12 @@ public function setDeveloperMode($value) return $this->setParameter('developerMode', $value); } + public function setEndpoints($endpoints) + { + $this->setParameter('liveEndpoint', $endpoints['live']); + return $this->setParameter('developerEndpoint', $endpoints['developer']); + } + public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest', $parameters); diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index a8d45f19..18d11a7f 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -7,9 +7,6 @@ */ abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest { - protected $liveEndpoint = 'https://secure.authorize.net/gateway/transact.dll'; - protected $developerEndpoint = 'https://test.authorize.net/gateway/transact.dll'; - public function getApiLoginId() { return $this->getParameter('apiLoginId'); @@ -60,6 +57,16 @@ public function setHashSecret($value) return $this->setParameter('hashSecret', $value); } + public function setLiveEndpoint($value) + { + return $this->setParameter('liveEndpoint', $value); + } + + public function setDeveloperEndpoint($value) + { + return $this->setParameter('developerEndpoint', $value); + } + protected function getBaseData() { $data = array(); @@ -124,6 +131,6 @@ public function sendData($data) public function getEndpoint() { - return $this->getDeveloperMode() ? $this->developerEndpoint : $this->liveEndpoint; + return $this->getDeveloperMode() ? $this->getParameter('developerEndpoint') : $this->getParameter('liveEndpoint'); } } From 0d27a9ca92f293ed44bfa28e847b5f55a0cba68d Mon Sep 17 00:00:00 2001 From: Aaron Cicali Date: Tue, 13 Jan 2015 19:02:43 +0000 Subject: [PATCH 039/254] returns AIM transaction data as an associative array --- src/Message/AIMResponse.php | 99 ++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 9fa0907e..7d57f868 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -14,7 +14,90 @@ class AIMResponse extends AbstractResponse public function __construct(RequestInterface $request, $data) { $this->request = $request; - $this->data = explode('|,|', substr($data, 1, -1)); + $temp = explode('|,|', substr($data, 1, -1)); + + $response_fields = array( + 'Response Code', + 'Response Subcode', + 'Response Reason Code', + 'Response Reason Text', + 'Authorization Code', + 'AVS Response', + 'Transaction ID', + 'Invoice Number', + 'Description', + 'Amount', + 'Method', + 'Transaction Type', + 'Customer ID', + 'First Name', + 'Last Name', + 'Company', + 'Address', + 'City', + 'State', + 'ZIP Code', + 'Country', + 'Phone', + 'Fax', + 'Email Address', + 'Ship To First Name', + 'Ship To Last Name', + 'Ship To Company', + 'Ship To Address', + 'Ship To City', + 'Ship To State', + 'Ship To ZIP Code', + 'Ship To Country', + 'Tax', + 'Duty', + 'Freight', + 'Tax Exempt', + 'Purchase Order Number', + 'MD5 Hash', + 'Card Code Response', + 'Cardholder Authentication Verification Response', + 'Account Number', + 'Card Type', + 'Split Tender ID', + 'Requested Amount', + 'Balance On Card' + ); + + $response = array(); + + foreach($response_fields as $field) + { + $response[$field] = array_shift($temp); + } + + $response_codes = array( + 1 => 'Approved', + 2 => 'Declined', + 3 => 'Error', + 4 => 'Held for Review' + ); + + $avs_response_codes = array( + 'A' => 'Address (Street) matches, ZIP does not', + 'B' => 'Address information not provided for AVS check', + 'E' => 'AVS error', + 'G' => 'Non-U.S. Card Issuing Bank', + 'N' => 'No Match on Address (Street) or ZIP', + 'P' => 'AVS not applicable for this transaction', + 'R' => 'Retry?System unavailable or timed out', + 'S' => 'Service not supported by issuer', + 'U' => 'Address information is unavailable', + 'W' => 'Nine digit ZIP matches, Address (Street) does not', + 'X' => 'Address (Street) and nine digit ZIP match', + 'Y' => 'Address (Street) and five digit ZIP match', + 'Z' => 'Five digit ZIP matches, Address (Street) does not' + ); + + $response['Response Code'] = $response_codes[$response['Response Code']]; + $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; + + $this->data = $response; if (count($this->data) < 10) { throw new InvalidResponseException(); @@ -23,36 +106,36 @@ public function __construct(RequestInterface $request, $data) public function isSuccessful() { - return '1' === $this->getCode(); + return $this->getCode() == 'Approved'; } public function getCode() { - return $this->data[0]; + return $this->data['Response Code']; } public function getReasonCode() { - return $this->data[2]; + return $this->data['Response Reason Code']; } public function getMessage() { - return $this->data[3]; + return $this->data['Response Reason Text']; } public function getAuthorizationCode() { - return $this->data[4]; + return $this->data['Authorization Code']; } public function getAVSCode() { - return $this->data[5]; + return $this->data['AVS Response']; } public function getTransactionReference() { - return $this->data[6]; + return $this->data['Transaction ID']; } } From e9087e921eceec48d0df006700a7b50e2ecd76bb Mon Sep 17 00:00:00 2001 From: Aaron Cicali Date: Tue, 13 Jan 2015 19:13:17 +0000 Subject: [PATCH 040/254] tabs to spaces --- src/Message/AIMResponse.php | 164 ++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 7d57f868..02e54c4b 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -16,88 +16,88 @@ public function __construct(RequestInterface $request, $data) $this->request = $request; $temp = explode('|,|', substr($data, 1, -1)); - $response_fields = array( - 'Response Code', - 'Response Subcode', - 'Response Reason Code', - 'Response Reason Text', - 'Authorization Code', - 'AVS Response', - 'Transaction ID', - 'Invoice Number', - 'Description', - 'Amount', - 'Method', - 'Transaction Type', - 'Customer ID', - 'First Name', - 'Last Name', - 'Company', - 'Address', - 'City', - 'State', - 'ZIP Code', - 'Country', - 'Phone', - 'Fax', - 'Email Address', - 'Ship To First Name', - 'Ship To Last Name', - 'Ship To Company', - 'Ship To Address', - 'Ship To City', - 'Ship To State', - 'Ship To ZIP Code', - 'Ship To Country', - 'Tax', - 'Duty', - 'Freight', - 'Tax Exempt', - 'Purchase Order Number', - 'MD5 Hash', - 'Card Code Response', - 'Cardholder Authentication Verification Response', - 'Account Number', - 'Card Type', - 'Split Tender ID', - 'Requested Amount', - 'Balance On Card' - ); - - $response = array(); - - foreach($response_fields as $field) - { - $response[$field] = array_shift($temp); - } - - $response_codes = array( - 1 => 'Approved', - 2 => 'Declined', - 3 => 'Error', - 4 => 'Held for Review' - ); - - $avs_response_codes = array( - 'A' => 'Address (Street) matches, ZIP does not', - 'B' => 'Address information not provided for AVS check', - 'E' => 'AVS error', - 'G' => 'Non-U.S. Card Issuing Bank', - 'N' => 'No Match on Address (Street) or ZIP', - 'P' => 'AVS not applicable for this transaction', - 'R' => 'Retry?System unavailable or timed out', - 'S' => 'Service not supported by issuer', - 'U' => 'Address information is unavailable', - 'W' => 'Nine digit ZIP matches, Address (Street) does not', - 'X' => 'Address (Street) and nine digit ZIP match', - 'Y' => 'Address (Street) and five digit ZIP match', - 'Z' => 'Five digit ZIP matches, Address (Street) does not' - ); - - $response['Response Code'] = $response_codes[$response['Response Code']]; - $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; - - $this->data = $response; + $response_fields = array( + 'Response Code', + 'Response Subcode', + 'Response Reason Code', + 'Response Reason Text', + 'Authorization Code', + 'AVS Response', + 'Transaction ID', + 'Invoice Number', + 'Description', + 'Amount', + 'Method', + 'Transaction Type', + 'Customer ID', + 'First Name', + 'Last Name', + 'Company', + 'Address', + 'City', + 'State', + 'ZIP Code', + 'Country', + 'Phone', + 'Fax', + 'Email Address', + 'Ship To First Name', + 'Ship To Last Name', + 'Ship To Company', + 'Ship To Address', + 'Ship To City', + 'Ship To State', + 'Ship To ZIP Code', + 'Ship To Country', + 'Tax', + 'Duty', + 'Freight', + 'Tax Exempt', + 'Purchase Order Number', + 'MD5 Hash', + 'Card Code Response', + 'Cardholder Authentication Verification Response', + 'Account Number', + 'Card Type', + 'Split Tender ID', + 'Requested Amount', + 'Balance On Card' + ); + + $response = array(); + + foreach($response_fields as $field) + { + $response[$field] = array_shift($temp); + } + + $response_codes = array( + 1 => 'Approved', + 2 => 'Declined', + 3 => 'Error', + 4 => 'Held for Review' + ); + + $avs_response_codes = array( + 'A' => 'Address (Street) matches, ZIP does not', + 'B' => 'Address information not provided for AVS check', + 'E' => 'AVS error', + 'G' => 'Non-U.S. Card Issuing Bank', + 'N' => 'No Match on Address (Street) or ZIP', + 'P' => 'AVS not applicable for this transaction', + 'R' => 'Retry?System unavailable or timed out', + 'S' => 'Service not supported by issuer', + 'U' => 'Address information is unavailable', + 'W' => 'Nine digit ZIP matches, Address (Street) does not', + 'X' => 'Address (Street) and nine digit ZIP match', + 'Y' => 'Address (Street) and five digit ZIP match', + 'Z' => 'Five digit ZIP matches, Address (Street) does not' + ); + + $response['Response Code'] = $response_codes[$response['Response Code']]; + $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; + + $this->data = $response; if (count($this->data) < 10) { throw new InvalidResponseException(); From ca032542dc5eb75c6582bff749033e8445952579 Mon Sep 17 00:00:00 2001 From: Aaron Cicali Date: Tue, 13 Jan 2015 19:20:42 +0000 Subject: [PATCH 041/254] PSR2 fixes --- src/Message/AIMResponse.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 02e54c4b..5dbaaf76 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -66,8 +66,7 @@ public function __construct(RequestInterface $request, $data) $response = array(); - foreach($response_fields as $field) - { + foreach ($response_fields as $field) { $response[$field] = array_shift($temp); } From 788222ad5851937b8efbb20a913f85d934240794 Mon Sep 17 00:00:00 2001 From: Aaron Cicali Date: Tue, 13 Jan 2015 19:32:41 +0000 Subject: [PATCH 042/254] updates unit tests to reflect this PR --- tests/Message/AIMResponseTest.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 98ed2b81..da5e0be0 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -22,10 +22,10 @@ public function testAuthorizeSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184493132', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCode()); $this->assertSame('1', $response->getReasonCode()); $this->assertSame('GA4OQP', $response->getAuthorizationCode()); - $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('Address (Street) and five digit ZIP match', $response->getAVSCode()); } public function testAuthorizeFailure() @@ -36,10 +36,10 @@ public function testAuthorizeFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCode()); $this->assertSame('5', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); } public function testCaptureSuccess() @@ -50,10 +50,10 @@ public function testCaptureSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184494531', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCode()); $this->assertSame('1', $response->getReasonCode()); $this->assertSame('F51OYG', $response->getAuthorizationCode()); - $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); } public function testCaptureFailure() @@ -64,10 +64,10 @@ public function testCaptureFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCode()); $this->assertSame('16', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); } public function testPurchaseSuccess() @@ -78,10 +78,10 @@ public function testPurchaseSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184492509', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCode()); $this->assertSame('1', $response->getReasonCode()); $this->assertSame('JE6JM1', $response->getAuthorizationCode()); - $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('Address (Street) and five digit ZIP match', $response->getAVSCode()); } public function testPurchaseFailure() @@ -92,9 +92,9 @@ public function testPurchaseFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCode()); $this->assertSame('5', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); } } From 6ca8e7599b0e82dcd33f449c587921ad5ab1d6a3 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 28 Jan 2015 14:31:08 +0530 Subject: [PATCH 043/254] Add ability to specify custom 'billTo' information Authorize.net CIM requires billTo address be present when creating a payment profile. Sometimes you don't have a billing address so this allows you to specify a default/custom billing address to be submitted with the create card request --- src/Message/CIMAbstractRequest.php | 10 +++++++++ src/Message/CIMCreateCardRequest.php | 12 +++++++++++ tests/CIMGatewayTest.php | 6 ------ tests/Message/CIMCreateCardRequestTest.php | 25 ++++++++++++++++++++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index b5169ccd..584f1430 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -67,6 +67,16 @@ public function getForceCardUpdate() return $this->getParameter('forceCardUpdate'); } + public function setPopulateBillTo($populateBillTo) + { + return $this->setParameter('populateBillTo', $populateBillTo); + } + + public function getPopulateBillTo() + { + return $this->getParameter('populateBillTo'); + } + /** * Create and return the base XML data required to create a new request * diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 9c62af7d..dee6fa2a 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -88,6 +88,18 @@ protected function addBillingData(\SimpleXMLElement $data) $req->zip = $card->getBillingPostcode(); $req->country = $card->getBillingCountry(); + $populateBillTo = $this->getParameter('populateBillTo'); + if (is_array($populateBillTo)) { + // A configuration parameter to populate billTo has been specified + foreach ($populateBillTo as $field => $value) { + if (empty($req->{$field}) && !empty($value)) { + // This particular field is empty and default value in populateBillTo has been specified + // so use it + $req->{$field} = $value; + } + } + } + $req = $data->addChild('payment'); $req->creditCard->cardNumber = $card->getNumber(); $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index a52e21ef..141d06f1 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -38,12 +38,6 @@ public function setUp() 'transactionReference' => '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', ); - $this->authorizeOptions = array( - 'cardReference' => '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', - 'amount' => 10.00, - 'description' => 'purchase' - ); - $this->refundOptions = array( 'amount' => '10.00', 'transactionReference' => '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index e8042c39..4a164f40 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -29,4 +29,29 @@ public function testGetData() $this->assertEquals($card['number'], $data->profile->paymentProfiles->payment->creditCard->cardNumber); $this->assertEquals('testMode', $data->validationMode); } + + public function testGetDataShouldHaveCustomBillTo() + { + $card = $this->getValidCard(); + unset($card['billingAddress1']); + unset($card['billingAddress2']); + unset($card['billingCity']); + $this->request->initialize( + array( + 'email' => "kaylee@serenity.com", + 'card' => $card, + 'developerMode' => true, + 'forceCardUpdate' => true, + 'populateBillTo' => [ + 'address' => '1234 Test Street', + 'city' => 'Blacksburg' + ] + ) + ); + + $data = $this->request->getData(); + $this->assertEquals('12345', $data->profile->paymentProfiles->billTo->zip); + $this->assertEquals('1234 Test Street', $data->profile->paymentProfiles->billTo->address); + $this->assertEquals('Blacksburg', $data->profile->paymentProfiles->billTo->city); + } } From 9a227ccdb033bfe55ca98340c1ade9e5f0233236 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 28 Jan 2015 16:34:11 +0530 Subject: [PATCH 044/254] Change populateBillTo to defaultBillTo. Set flags at a gateway level --- src/CIMGateway.php | 37 ++++++++++++++++++++++ src/Message/CIMAbstractRequest.php | 8 ++--- src/Message/CIMCreateCardRequest.php | 6 ++-- src/Message/CIMVoidRequest.php | 22 +++++++++++++ tests/Message/CIMCreateCardRequestTest.php | 2 +- 5 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 src/Message/CIMVoidRequest.php diff --git a/src/CIMGateway.php b/src/CIMGateway.php index f664b85b..d525bede 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -9,11 +9,43 @@ */ class CIMGateway extends AIMGateway { + public function getDefaultParameters() + { + return array( + 'apiLoginId' => '', + 'transactionKey' => '', + 'testMode' => false, + 'developerMode' => false, + 'forceCardUpdate' => false, + 'defaultBillTo' => [[]] + ); + } + public function getName() { return 'Authorize.Net CIM'; } + public function setForceCardUpdate($forceCardUpdate) + { + return $this->setParameter('forceCardUpdate', $forceCardUpdate); + } + + public function getForceCardUpdate() + { + return $this->getParameter('forceCardUpdate'); + } + + public function setDefaultBillTo($defaultBillTo) + { + return $this->setParameter('defaultBillTo', $defaultBillTo); + } + + public function getDefaultBillTo() + { + return $this->getParameter('defaultBillTo'); + } + /** * Create a new debit or credit card * @@ -45,4 +77,9 @@ public function refund(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMRefundRequest', $parameters); } + + public function void(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMVoidRequest', $parameters); + } } diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 584f1430..8886498e 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -67,14 +67,14 @@ public function getForceCardUpdate() return $this->getParameter('forceCardUpdate'); } - public function setPopulateBillTo($populateBillTo) + public function setDefaultBillTo($defaultBillTo) { - return $this->setParameter('populateBillTo', $populateBillTo); + return $this->setParameter('defaultBillTo', $defaultBillTo); } - public function getPopulateBillTo() + public function getDefaultBillTo() { - return $this->getParameter('populateBillTo'); + return $this->getParameter('defaultBillTo'); } /** diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index dee6fa2a..a059c85b 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -88,10 +88,10 @@ protected function addBillingData(\SimpleXMLElement $data) $req->zip = $card->getBillingPostcode(); $req->country = $card->getBillingCountry(); - $populateBillTo = $this->getParameter('populateBillTo'); - if (is_array($populateBillTo)) { + $defaultBillTo = $this->getParameter('defaultBillTo'); + if (is_array($defaultBillTo)) { // A configuration parameter to populate billTo has been specified - foreach ($populateBillTo as $field => $value) { + foreach ($defaultBillTo as $field => $value) { if (empty($req->{$field}) && !empty($value)) { // This particular field is empty and default value in populateBillTo has been specified // so use it diff --git a/src/Message/CIMVoidRequest.php b/src/Message/CIMVoidRequest.php new file mode 100644 index 00000000..0d153837 --- /dev/null +++ b/src/Message/CIMVoidRequest.php @@ -0,0 +1,22 @@ +validate('transactionReference'); + + $data = $this->getBaseData(); + $data->transactionRequest->refTransId = $this->getTransactionReference(); + $this->addTestModeSetting($data); + + return $data; + } +} diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index 4a164f40..8f94bab0 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -42,7 +42,7 @@ public function testGetDataShouldHaveCustomBillTo() 'card' => $card, 'developerMode' => true, 'forceCardUpdate' => true, - 'populateBillTo' => [ + 'defaultBillTo' => [ 'address' => '1234 Test Street', 'city' => 'Blacksburg' ] From 4423c883f692f2f2508b236866ddd3e05fe0db2f Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 3 Feb 2015 23:03:20 +0000 Subject: [PATCH 045/254] Started adding DPM gateway. --- src/DPMGateway.php | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/DPMGateway.php diff --git a/src/DPMGateway.php b/src/DPMGateway.php new file mode 100644 index 00000000..b3d4891e --- /dev/null +++ b/src/DPMGateway.php @@ -0,0 +1,10 @@ + Date: Wed, 4 Feb 2015 02:10:06 +0000 Subject: [PATCH 046/254] Dev snapshot. --- src/DPMGateway.php | 11 ++++- src/Message/DPMAuthorizeRequest.php | 72 ++++++++++++++++++++++++++++ src/Message/DPMAuthorizeResponse.php | 35 ++++++++++++++ src/Message/DPMPurchaseRequest.php | 11 +++++ 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/Message/DPMAuthorizeRequest.php create mode 100644 src/Message/DPMAuthorizeResponse.php create mode 100644 src/Message/DPMPurchaseRequest.php diff --git a/src/DPMGateway.php b/src/DPMGateway.php index b3d4891e..9867e261 100644 --- a/src/DPMGateway.php +++ b/src/DPMGateway.php @@ -5,6 +5,15 @@ /** * Authorize.Net DPM (Direct Post Method) Class */ -class DPMGateway extends AIMGateway +class DPMGateway extends SIMGateway { + public function getName() + { + return 'Authorize.Net DPM'; + } + + public function authorize(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMAuthorizeRequest', $parameters); + } } diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php new file mode 100644 index 00000000..e6858c66 --- /dev/null +++ b/src/Message/DPMAuthorizeRequest.php @@ -0,0 +1,72 @@ +getApiLoginId(), + $data['x_fp_sequence'], + $data['x_fp_timestamp'], + $data['x_amount'] + ) + ).'^'; + + // If x_currency_code is specified, then it must follow the final trailing carat. + // CHECKME: this may need to be back-ported to SIMAuthorizeRequest and AIMAuthorizeRequest + // in order to supprot multiple currencies. + + if ($this->getCurrency()) { + $fingerprint .= $this->getCurrency(); + } + + return hash_hmac('md5', $fingerprint, $this->getTransactionKey()); + } + + public function getData() + { + $data = parent::getData(); + + // This is the DPM trigger. + $data['x_show_form'] = 'PAYMENT_FORM'; + + // Support multiple currencies. + // CHECKME: should this be back-ported to SIMAuthorizeRequest and AIMAuthorizeRequest? + + if ($this->getCurrency()) { + $data['x_currency_code'] = $this->getCurrency(); + } + + // CHECKME: x_recurring_billing is (ambiguously) listed as mandatory in the DPM docs. + + // The customer ID is optional. + if ($this->getCustomerId()) { + $data['x_cust_id'] = $this->getCustomerId(); + } + + return $data; + } + + + /** + * Given the DPM data, we want to turn it into a form for the user to submit to Authorize.net + * The form may have most of the fields hidden, or may allow the user to change some details - + * that depends on the use-case. + * So this method will provide us with an object used to build the form. + */ + public function sendData($data) + { + return $this->response = new DPMAuthorizeResponse($this, $data, $this->getEndpoint()); + } +} diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php new file mode 100644 index 00000000..fa89ab62 --- /dev/null +++ b/src/Message/DPMAuthorizeResponse.php @@ -0,0 +1,35 @@ +request = $request; + $this->data = $data; + $this->postUrl = $postUrl; + } + + public function isSuccessful() + { + return true; + } + + public function getPostUrl() + { + return $this->postUrl; + } + + // Testing: use getData() to look at what we have. +} diff --git a/src/Message/DPMPurchaseRequest.php b/src/Message/DPMPurchaseRequest.php new file mode 100644 index 00000000..eeaf9373 --- /dev/null +++ b/src/Message/DPMPurchaseRequest.php @@ -0,0 +1,11 @@ + Date: Thu, 5 Feb 2015 01:28:06 +0000 Subject: [PATCH 047/254] Dev snapshot. --- README.md | 1 + src/Message/DPMAuthorizeRequest.php | 4 ++ src/Message/DPMAuthorizeResponse.php | 75 +++++++++++++++++++++++++++- src/Message/SIMAuthorizeRequest.php | 2 + 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2845c896..5f569648 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ The following gateways are provided by this package: * AuthorizeNet_AIM * AuthorizeNet_SIM +* AuthorizeNet_DPM For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) repository. diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index e6858c66..7d28a137 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -55,6 +55,10 @@ public function getData() $data['x_cust_id'] = $this->getCustomerId(); } + $data['x_card_num'] = $this->getCard()->getNumber(); + $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); + $data['x_card_code'] = $this->getCard()->getCvv(); + return $data; } diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php index fa89ab62..a8ad31f8 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMAuthorizeResponse.php @@ -14,6 +14,23 @@ class DPMAuthorizeResponse extends AbstractResponse { protected $postUrl; + protected $hiddenFields = array( + 'x_fp_hash', + 'x_amount', + 'x_test_request', + 'x_cancel_url', + 'x_relay_url', + 'x_relay_response', + 'x_show_form', + 'x_delim_data', + 'x_fp_timestamp', + 'x_fp_sequence', + 'x_type', + 'x_login', + 'x_invoice_num', + 'x_description', + ); + public function __construct(RequestInterface $request, $data, $postUrl) { $this->request = $request; @@ -21,15 +38,71 @@ public function __construct(RequestInterface $request, $data, $postUrl) $this->postUrl = $postUrl; } + /** + * Return false to indicate that more action is needed to complete + * the transaction, a transparent redirect form in this case. + */ public function isSuccessful() + { + return false; + } + + /** + * This is a transparent redirect transaction type, where a local form + * will POST direct to the remote gateway. + */ + public function isTransparentRedirect() { return true; } + // Helpers to build the form. + + /** + * The URL the form will be posted to. + */ public function getPostUrl() { return $this->postUrl; } - // Testing: use getData() to look at what we have. + /** + * Add a field to the list of hidden fields. + * The hidden fields are those we don't want to show the user, but + * must still be posted. + */ + public function setHiddenField($field_name) + { + if (!in_array($field_name, $this->hiddenFields)) { + $this->hiddenFields[] = $field_name; + } + } + + /** + * Remove a field from the list of hidden fields. + */ + public function unsetHiddenField($field_name) + { + if (($key = array_search($field_name, $this->hiddenFields)) !== false) { + unset($this->hiddenFields[$key]); + } + } + + /** + * Data that must be included as hidden fields, if they are available at all. + */ + public function getHiddenData() + { + return array_intersect_key($this->getData(), array_flip($this->hiddenFields)); + } + + /** + * Data not in the hidden fields list. + * These are not all mandatory, so you do not have to present all these + * to the user. + */ + public function getNonHiddenData() + { + return array_diff_key($this->getData(), array_flip($this->hiddenFields)); + } } diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index fc877eb0..292c099d 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -21,6 +21,8 @@ public function getData() $data['x_delim_data'] = 'FALSE'; $data['x_show_form'] = 'PAYMENT_FORM'; $data['x_relay_response'] = 'TRUE'; + // The returnUrl MUST be set in Authorize.net admin panel as a + // "Response/Receipt URLs" URL, but not necessarily the default. $data['x_relay_url'] = $this->getReturnUrl(); $data['x_cancel_url'] = $this->getCancelUrl(); From 1040f537f6af0f7c1f404562112e25942472d913 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Thu, 5 Feb 2015 20:03:48 +0000 Subject: [PATCH 048/254] Dev snapshot. --- src/DPMGateway.php | 9 +++ src/Message/DPMCompleteAuthorizeRequest.php | 64 ++++++++++++++++++++ src/Message/DPMCompleteAuthorizeResponse.php | 40 ++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 src/Message/DPMCompleteAuthorizeRequest.php create mode 100644 src/Message/DPMCompleteAuthorizeResponse.php diff --git a/src/DPMGateway.php b/src/DPMGateway.php index 9867e261..cc4278af 100644 --- a/src/DPMGateway.php +++ b/src/DPMGateway.php @@ -12,8 +12,17 @@ public function getName() return 'Authorize.Net DPM'; } +/* public function setHashSecret() + { + } */ + public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMAuthorizeRequest', $parameters); } + + public function completeAuthorize(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteAuthorizeRequest', $parameters); + } } diff --git a/src/Message/DPMCompleteAuthorizeRequest.php b/src/Message/DPMCompleteAuthorizeRequest.php new file mode 100644 index 00000000..49e0b83f --- /dev/null +++ b/src/Message/DPMCompleteAuthorizeRequest.php @@ -0,0 +1,64 @@ +httpRequest->request->get('x_MD5_Hash')); + $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); + $posted_amount = $this->httpRequest->request->get('x_amount'); + $hash_calculated = $this->getDpmHash($posted_transaction_reference, $posted_amount); + + if ($hash_posted !== $hash_calculated) { + // If the hash is incorrect, then we can't trust the source nor anything sent. + + throw new InvalidRequestException('Incorrect hash'); + } + + // The hashes have passed, but the amount should also be validated against the + // amount in the stored and retrieved transaction. If the application has the + // ability to retrieve the transaction (using the transaction_id sent as a custom + // form field, or perhaps as a GET parameter on the callback URL) then it will + // be checked here. + + $amount = $this->getAmount(); + + if (isset($amount) && $amount != $posted_amount) { + // The amounts don't match up. Someone may have been playing with the + // transaction references. + + throw new InvalidRequestException('Incorrect amount'); + } + + return $this->httpRequest->request->all(); + } + + /** + * This hash confirms the ransaction has come from the Authorize.Net gateway. + * It basically tests the shared hash secret is correct, but mixes in other details + * that will change for each transaction so the hash will be unique for each transaction. + * The hash secret and login ID are known to the merchent site, and the amount and transaction + * reference (x_amount and x_trans_id) are sent by the gatewa. + */ + public function getDpmHash($transaction_reference, $amount) + { + return md5( + $this->getHashSecret() + . $this->getApiLoginId() + . $transaction_reference + . $amount + ); + } + + public function sendData($data) + { + return $this->response = new DPMCompleteAuthorizeResponse($this, $data); + } +} diff --git a/src/Message/DPMCompleteAuthorizeResponse.php b/src/Message/DPMCompleteAuthorizeResponse.php new file mode 100644 index 00000000..0e288749 --- /dev/null +++ b/src/Message/DPMCompleteAuthorizeResponse.php @@ -0,0 +1,40 @@ +data['x_response_code']) && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; + } + + public function getTransactionReference() + { + return isset($this->data['x_trans_id']) ? $this->data['x_trans_id'] : null; + } + + // TODO: getCode()? + // TODO: redirect details (need "reptry" URL too). + + public function getMessage() + { + return isset($this->data['x_response_reason_text']) ? $this->data['x_response_reason_text'] : null; + } +} From ac397199d765b52654cf88722f278c5d1b9cf6ed Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Fri, 6 Feb 2015 13:46:51 +0000 Subject: [PATCH 049/254] Dev snapshot --- src/Message/DPMCompleteAuthorizeResponse.php | 67 ++++++++++++++++---- src/Message/SIMCompleteAuthorizeResponse.php | 10 +++ 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/Message/DPMCompleteAuthorizeResponse.php b/src/Message/DPMCompleteAuthorizeResponse.php index 0e288749..ea55bb27 100644 --- a/src/Message/DPMCompleteAuthorizeResponse.php +++ b/src/Message/DPMCompleteAuthorizeResponse.php @@ -3,6 +3,7 @@ namespace Omnipay\AuthorizeNet\Message; use Omnipay\Common\Message\AbstractResponse; +use Omnipay\Common\Message\RedirectResponseInterface; /** * Authorize.Net DPM Complete Authorize Response @@ -13,28 +14,72 @@ * We may want to return to the success page, the failed page or the retry * page (so the user can correct the form). */ -class DPMCompleteAuthorizeResponse extends SIMCompleteAuthorizeResponse // TOOD: redirect +class DPMCompleteAuthorizeResponse extends SIMCompleteAuthorizeResponse implements RedirectResponseInterface { - const RESPONSE_CODE_APPROVED = '1'; - const RESPONSE_CODE_DECLINED = '2'; - const RESPONSE_CODE_ERROR = '3'; - const RESPONSE_CODE_REVIEW = '4'; + const RESPONSE_CODE_APPROVED = '1'; + const RESPONSE_CODE_DECLINED = '2'; + const RESPONSE_CODE_ERROR = '3'; + const RESPONSE_CODE_REVIEW = '4'; public function isSuccessful() { return isset($this->data['x_response_code']) && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; } - public function getTransactionReference() + /** + * If there is an error in the form, then the user should be able to go back + * to the form and give it another shot. + */ + public function isError() { - return isset($this->data['x_trans_id']) ? $this->data['x_trans_id'] : null; + return isset($this->data['x_response_code']) && static::RESPONSE_CODE_ERROR === $this->data['x_response_code']; } - // TODO: getCode()? - // TODO: redirect details (need "reptry" URL too). - public function getMessage() { - return isset($this->data['x_response_reason_text']) ? $this->data['x_response_reason_text'] : null; + return parent::getReasonCode() . '|' . parent::getMessage(); + } + + /** + * We are in the callback, and we MUST return a HTML fragment to do a redirect. + * All headers we may return are discarded by the gateway, so we cannot use + * the "Location:" header. + */ + public function isRedirect() + { + return true; + } + + /** + * We default here to POST because the default redirect mechanism + * in Omnipay Common only generates a HTML snippet for POST and not + * GET. + * TODO: We could fix that here so both GET and POST can be supported. + * Our fix should also include the "form data" with the URL. + */ + public function getRedirectMethod() + { + return 'POST'; + } + + /** + * We probably do not require any redirect data, if the incomplete transaction + * is still in the user's session and we can inspect the results from the saved + * transaction in the database. We cannot send the result through the redirect + * unless it is hashed in some way so the authorisation result cannot be faked. + */ + public function getRedirectData() + { + return array(); + } + + /** + * The cancel URL is never handled here - that is a direct link from the gateway. + * The best approach is to have just one redirect URL, and once there, check the + * result of the authorisation in the database (assuming it has been saved in the + * callback) and take action from there. + */ + public function getRedirectUrl() + { } } diff --git a/src/Message/SIMCompleteAuthorizeResponse.php b/src/Message/SIMCompleteAuthorizeResponse.php index 1157121d..1908b0e8 100644 --- a/src/Message/SIMCompleteAuthorizeResponse.php +++ b/src/Message/SIMCompleteAuthorizeResponse.php @@ -23,4 +23,14 @@ public function getMessage() { return isset($this->data['x_response_reason_text']) ? $this->data['x_response_reason_text'] : null; } + + public function getReasonCode() + { + return isset($this->data['x_response_reason_code']) ? $this->data['x_response_reason_code'] : null; + } + + public function getCode() + { + return isset($this->data['x_response_code']) ? $this->data['x_response_code'] : null; + } } From 9e09dc181940ecfd186634baf0051beadfd91d69 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 8 Feb 2015 16:49:27 +0000 Subject: [PATCH 050/254] Added Payment service. --- src/DPMGateway.php | 16 +++++++++++----- src/Message/DPMAuthorizeRequest.php | 9 ++++++--- src/Message/DPMAuthorizeResponse.php | 16 ++++++++++++++-- ...thorizeRequest.php => DPMCompleteRequest.php} | 4 ++-- ...orizeResponse.php => DPMCompleteResponse.php} | 2 +- src/Message/DPMPaymentRequest.php | 13 +++++++++++++ 6 files changed, 47 insertions(+), 13 deletions(-) rename src/Message/{DPMCompleteAuthorizeRequest.php => DPMCompleteRequest.php} (93%) rename src/Message/{DPMCompleteAuthorizeResponse.php => DPMCompleteResponse.php} (96%) create mode 100644 src/Message/DPMPaymentRequest.php diff --git a/src/DPMGateway.php b/src/DPMGateway.php index cc4278af..ecf6f7dd 100644 --- a/src/DPMGateway.php +++ b/src/DPMGateway.php @@ -12,10 +12,6 @@ public function getName() return 'Authorize.Net DPM'; } -/* public function setHashSecret() - { - } */ - public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMAuthorizeRequest', $parameters); @@ -23,6 +19,16 @@ public function authorize(array $parameters = array()) public function completeAuthorize(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteAuthorizeRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteRequest', $parameters); + } + + public function payment(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMPaymentRequest', $parameters); + } + + public function completePayment(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteRequest', $parameters); } } diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 7d28a137..586c42b3 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -55,9 +55,12 @@ public function getData() $data['x_cust_id'] = $this->getCustomerId(); } - $data['x_card_num'] = $this->getCard()->getNumber(); - $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); - $data['x_card_code'] = $this->getCard()->getCvv(); + // The card details at this point are optional. + if ($this->getCard()) { + $data['x_card_num'] = $this->getCard()->getNumber(); + $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); + $data['x_card_code'] = $this->getCard()->getCvv(); + } return $data; } diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php index a8ad31f8..28716995 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMAuthorizeResponse.php @@ -4,13 +4,14 @@ use Omnipay\Common\Message\AbstractResponse; use Omnipay\Common\Message\RequestInterface; +use Omnipay\Common\Message\RedirectResponseInterface; /** * Authorize.Net DPM Authorize Response * Here we want the application to present a POST form to the user. This object will * provide the helper methods for doing so. */ -class DPMAuthorizeResponse extends AbstractResponse +class DPMAuthorizeResponse extends AbstractResponse implements RedirectResponseInterface { protected $postUrl; @@ -61,11 +62,22 @@ public function isTransparentRedirect() /** * The URL the form will be posted to. */ - public function getPostUrl() + public function getRedirectUrl() { return $this->postUrl; } + public function getRedirectMethod() + { + return "post"; + } + + // CHECKME: do we still need getHiddenData()? + public function getRedirectData() + { + return $this->getHiddenData(); + } + /** * Add a field to the list of hidden fields. * The hidden fields are those we don't want to show the user, but diff --git a/src/Message/DPMCompleteAuthorizeRequest.php b/src/Message/DPMCompleteRequest.php similarity index 93% rename from src/Message/DPMCompleteAuthorizeRequest.php rename to src/Message/DPMCompleteRequest.php index 49e0b83f..8b7007bd 100644 --- a/src/Message/DPMCompleteAuthorizeRequest.php +++ b/src/Message/DPMCompleteRequest.php @@ -7,7 +7,7 @@ /** * Authorize.Net DPM Complete Authorize Request */ -class DPMCompleteAuthorizeRequest extends SIMCompleteAuthorizeRequest +class DPMCompleteRequest extends SIMCompleteAuthorizeRequest { public function getData() { @@ -59,6 +59,6 @@ public function getDpmHash($transaction_reference, $amount) public function sendData($data) { - return $this->response = new DPMCompleteAuthorizeResponse($this, $data); + return $this->response = new DPMCompleteResponse($this, $data); } } diff --git a/src/Message/DPMCompleteAuthorizeResponse.php b/src/Message/DPMCompleteResponse.php similarity index 96% rename from src/Message/DPMCompleteAuthorizeResponse.php rename to src/Message/DPMCompleteResponse.php index ea55bb27..dda7164e 100644 --- a/src/Message/DPMCompleteAuthorizeResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -14,7 +14,7 @@ * We may want to return to the success page, the failed page or the retry * page (so the user can correct the form). */ -class DPMCompleteAuthorizeResponse extends SIMCompleteAuthorizeResponse implements RedirectResponseInterface +class DPMCompleteResponse extends SIMCompleteAuthorizeResponse implements RedirectResponseInterface { const RESPONSE_CODE_APPROVED = '1'; const RESPONSE_CODE_DECLINED = '2'; diff --git a/src/Message/DPMPaymentRequest.php b/src/Message/DPMPaymentRequest.php new file mode 100644 index 00000000..17e9b753 --- /dev/null +++ b/src/Message/DPMPaymentRequest.php @@ -0,0 +1,13 @@ + Date: Mon, 9 Feb 2015 15:32:05 +0000 Subject: [PATCH 051/254] Pass Customer Id as x_cust_id if provided --- src/Message/SIMAuthorizeRequest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index fc877eb0..91e2f727 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -23,6 +23,9 @@ public function getData() $data['x_relay_response'] = 'TRUE'; $data['x_relay_url'] = $this->getReturnUrl(); $data['x_cancel_url'] = $this->getCancelUrl(); + if ($this->getCustomerId() !== null) { + $data['x_cust_id'] = $this->getCustomerId(); + } if ($this->getTestMode()) { $data['x_test_request'] = 'TRUE'; From 5011207bcaaa5b6af24cad1a43786a6488b25552 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 10 Feb 2015 00:50:02 +0000 Subject: [PATCH 052/254] Dev snapshot. --- src/Message/DPMCompleteRequest.php | 11 +++++++---- src/Message/DPMCompleteResponse.php | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Message/DPMCompleteRequest.php b/src/Message/DPMCompleteRequest.php index 8b7007bd..836f3740 100644 --- a/src/Message/DPMCompleteRequest.php +++ b/src/Message/DPMCompleteRequest.php @@ -18,6 +18,9 @@ public function getData() if ($hash_posted !== $hash_calculated) { // If the hash is incorrect, then we can't trust the source nor anything sent. + // Throwing exceptions here is a *really* bad idea. We are trying to get the data, + // and if it is invalid, then we need to be able to log that data for analysis. + // Except we can't, baceuse the exception means we can't get to the data. throw new InvalidRequestException('Incorrect hash'); } @@ -49,12 +52,12 @@ public function getData() */ public function getDpmHash($transaction_reference, $amount) { - return md5( - $this->getHashSecret() + $key = $this->getHashSecret() . $this->getApiLoginId() . $transaction_reference - . $amount - ); + . $amount; + + return md5($key); } public function sendData($data) diff --git a/src/Message/DPMCompleteResponse.php b/src/Message/DPMCompleteResponse.php index dda7164e..cb077291 100644 --- a/src/Message/DPMCompleteResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -81,5 +81,7 @@ public function getRedirectData() */ public function getRedirectUrl() { + // Leave it for the applicatino to decide where to sent the user. + return; } } From 701f6fd53b07d88d90eae85f4c80edc97e5d3e3a Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 10 Feb 2015 16:39:44 +0000 Subject: [PATCH 053/254] Remove the x_show_form setting so no form is shown with DPM. --- src/Message/DPMAuthorizeRequest.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 586c42b3..355225f0 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -38,8 +38,14 @@ public function getData() { $data = parent::getData(); - // This is the DPM trigger. - $data['x_show_form'] = 'PAYMENT_FORM'; + // If x_show_form is swet, then the form will be displayed on the Authorize.Net + // gateway, which acts a bit like the SIM gateway. The documentation does NOT + // make this clear. + // TODO: revisit this - maybe much of what is in the DPM can be used to enhance + // the SIM gateway, with very little in the DPM messages. + + //$data['x_show_form'] = 'PAYMENT_FORM'; + unset($data['x_show_form']); // Support multiple currencies. // CHECKME: should this be back-ported to SIMAuthorizeRequest and AIMAuthorizeRequest? From 4a391cd6440d9310d34d2e9d9de3093c9fdfa0c9 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 15 Feb 2015 12:06:06 +0000 Subject: [PATCH 054/254] Remove "Payment" (should have been "Purchase") --- src/DPMGateway.php | 6 +++--- src/Message/DPMPaymentRequest.php | 13 ------------- src/Message/DPMPurchaseRequest.php | 2 +- 3 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 src/Message/DPMPaymentRequest.php diff --git a/src/DPMGateway.php b/src/DPMGateway.php index ecf6f7dd..85a3c72f 100644 --- a/src/DPMGateway.php +++ b/src/DPMGateway.php @@ -22,12 +22,12 @@ public function completeAuthorize(array $parameters = array()) return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteRequest', $parameters); } - public function payment(array $parameters = array()) + public function purchase(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMPaymentRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMPurchaseRequest', $parameters); } - public function completePayment(array $parameters = array()) + public function completePurchase(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteRequest', $parameters); } diff --git a/src/Message/DPMPaymentRequest.php b/src/Message/DPMPaymentRequest.php deleted file mode 100644 index 17e9b753..00000000 --- a/src/Message/DPMPaymentRequest.php +++ /dev/null @@ -1,13 +0,0 @@ - Date: Sun, 15 Feb 2015 12:54:01 +0000 Subject: [PATCH 055/254] Backported DPM getHash() to SIM getHash() to support a specified currency. --- src/DPMGateway.php | 12 ++++++++++++ src/Message/DPMAuthorizeRequest.php | 26 ++------------------------ src/Message/SIMAuthorizeRequest.php | 11 +++++++++++ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/DPMGateway.php b/src/DPMGateway.php index 85a3c72f..b5117ddf 100644 --- a/src/DPMGateway.php +++ b/src/DPMGateway.php @@ -12,21 +12,33 @@ public function getName() return 'Authorize.Net DPM'; } + /** + * Helper to generate the authorize direct-post form. + */ public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMAuthorizeRequest', $parameters); } + /** + * Get, validate, interpret and respond to the Authorize.Net callback. + */ public function completeAuthorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteRequest', $parameters); } + /** + * Helper to generate the purchase direct-post form. + */ public function purchase(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMPurchaseRequest', $parameters); } + /** + * Get, validate, interpret and respond to the Authorize.Net callback. + */ public function completePurchase(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\DPMCompleteRequest', $parameters); diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 355225f0..15331049 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -5,35 +5,13 @@ use Omnipay\AuthorizeNet\Message\SIMAbstractRequest; /** - * Authorize.Net DPM Authorize Request + * Authorize.Net DPM Authorize Request. + * Takes the data that will be used to create the direct-post form. */ class DPMAuthorizeRequest extends SIMAuthorizeRequest { protected $action = 'AUTH_ONLY'; - public function getHash($data) - { - $fingerprint = implode( - '^', - array( - $this->getApiLoginId(), - $data['x_fp_sequence'], - $data['x_fp_timestamp'], - $data['x_amount'] - ) - ).'^'; - - // If x_currency_code is specified, then it must follow the final trailing carat. - // CHECKME: this may need to be back-ported to SIMAuthorizeRequest and AIMAuthorizeRequest - // in order to supprot multiple currencies. - - if ($this->getCurrency()) { - $fingerprint .= $this->getCurrency(); - } - - return hash_hmac('md5', $fingerprint, $this->getTransactionKey()); - } - public function getData() { $data = parent::getData(); diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index 292c099d..73dab28b 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -36,6 +36,12 @@ public function getData() return $data; } + /** + * This hash is put into the form to confirm the amount has not been + * modified en-route. + * It uses the TransactionKey, which is a shared secret between the merchant + * and Authorize.Net The sequence and timestamp provide additional salt. + */ public function getHash($data) { $fingerprint = implode( @@ -48,6 +54,11 @@ public function getHash($data) ) ).'^'; + // If x_currency_code is specified, then it must follow the final trailing carat. + if ($this->getCurrency()) { + $fingerprint .= $this->getCurrency(); + } + return hash_hmac('md5', $fingerprint, $this->getTransactionKey()); } From f1b1e3ec013a80bccb1df461794bc0ff1d2791b9 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 15 Feb 2015 13:08:25 +0000 Subject: [PATCH 056/254] Clarify hidden/visible data a little with clearer method names. --- src/Message/DPMAuthorizeResponse.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php index 28716995..a492d08e 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMAuthorizeResponse.php @@ -15,6 +15,9 @@ class DPMAuthorizeResponse extends AbstractResponse implements RedirectResponseI { protected $postUrl; + /** + * These will be hidden fields in the direct-post form. + */ protected $hiddenFields = array( 'x_fp_hash', 'x_amount', @@ -30,6 +33,7 @@ class DPMAuthorizeResponse extends AbstractResponse implements RedirectResponseI 'x_login', 'x_invoice_num', 'x_description', + 'x_cust_id', ); public function __construct(RequestInterface $request, $data, $postUrl) @@ -79,11 +83,11 @@ public function getRedirectData() } /** - * Add a field to the list of hidden fields. + * Move a field to the list of hidden form fields. * The hidden fields are those we don't want to show the user, but * must still be posted. */ - public function setHiddenField($field_name) + public function hideField($field_name) { if (!in_array($field_name, $this->hiddenFields)) { $this->hiddenFields[] = $field_name; @@ -93,7 +97,7 @@ public function setHiddenField($field_name) /** * Remove a field from the list of hidden fields. */ - public function unsetHiddenField($field_name) + public function unhideField($field_name) { if (($key = array_search($field_name, $this->hiddenFields)) !== false) { unset($this->hiddenFields[$key]); @@ -113,7 +117,7 @@ public function getHiddenData() * These are not all mandatory, so you do not have to present all these * to the user. */ - public function getNonHiddenData() + public function getVisibleData() { return array_diff_key($this->getData(), array_flip($this->hiddenFields)); } From 730b7f58fbbea458b68d14495b1c4b967e6945dd Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 15 Feb 2015 16:36:55 +0000 Subject: [PATCH 057/254] Various tidy-up and TODOs comleted. DPM tests still needed. --- src/Message/DPMAuthorizeRequest.php | 31 ++++++++------------- src/Message/DPMAuthorizeResponse.php | 20 ++++++------- src/Message/DPMCompleteRequest.php | 21 ++++++++------ src/Message/DPMCompleteResponse.php | 25 ++++++----------- src/Message/SIMAuthorizeRequest.php | 6 ++++ src/Message/SIMCompleteAuthorizeRequest.php | 3 ++ 6 files changed, 49 insertions(+), 57 deletions(-) diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 15331049..f4451baf 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -16,34 +16,25 @@ public function getData() { $data = parent::getData(); - // If x_show_form is swet, then the form will be displayed on the Authorize.Net - // gateway, which acts a bit like the SIM gateway. The documentation does NOT - // make this clear. - // TODO: revisit this - maybe much of what is in the DPM can be used to enhance - // the SIM gateway, with very little in the DPM messages. + // If x_show_form is set, then the form will be displayed on the Authorize.Net + // gateway, in a similar way to the SIM gateway. The DPM documentation does NOT + // make this clear at all. + // Since x_show_form is set in the SIM gateway, make sure we unset it here. - //$data['x_show_form'] = 'PAYMENT_FORM'; unset($data['x_show_form']); - // Support multiple currencies. - // CHECKME: should this be back-ported to SIMAuthorizeRequest and AIMAuthorizeRequest? + // The card details are optional. + // They will most likely only be used for development and testing. + // The card fields are still needed in the direct-post form regardless. - if ($this->getCurrency()) { - $data['x_currency_code'] = $this->getCurrency(); - } - - // CHECKME: x_recurring_billing is (ambiguously) listed as mandatory in the DPM docs. - - // The customer ID is optional. - if ($this->getCustomerId()) { - $data['x_cust_id'] = $this->getCustomerId(); - } - - // The card details at this point are optional. if ($this->getCard()) { $data['x_card_num'] = $this->getCard()->getNumber(); $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); $data['x_card_code'] = $this->getCard()->getCvv(); + } else { + $data['x_card_num'] = ''; + $data['x_exp_date'] = ''; + $data['x_card_code'] = ''; } return $data; diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php index a492d08e..203d8101 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMAuthorizeResponse.php @@ -21,6 +21,7 @@ class DPMAuthorizeResponse extends AbstractResponse implements RedirectResponseI protected $hiddenFields = array( 'x_fp_hash', 'x_amount', + 'x_currency_code', 'x_test_request', 'x_cancel_url', 'x_relay_url', @@ -64,7 +65,7 @@ public function isTransparentRedirect() // Helpers to build the form. /** - * The URL the form will be posted to. + * The URL the form will POST to. */ public function getRedirectUrl() { @@ -76,10 +77,12 @@ public function getRedirectMethod() return "post"; } - // CHECKME: do we still need getHiddenData()? + /** + * Data that must be included as hidden fields. + */ public function getRedirectData() { - return $this->getHiddenData(); + return array_intersect_key($this->getData(), array_flip($this->hiddenFields)); } /** @@ -104,18 +107,11 @@ public function unhideField($field_name) } } - /** - * Data that must be included as hidden fields, if they are available at all. - */ - public function getHiddenData() - { - return array_intersect_key($this->getData(), array_flip($this->hiddenFields)); - } - /** * Data not in the hidden fields list. * These are not all mandatory, so you do not have to present all these - * to the user. + * to the user. You may also have custom fields you want to post, such + * as the merchant transactionId (if not using invoiceId for this purpose). */ public function getVisibleData() { diff --git a/src/Message/DPMCompleteRequest.php b/src/Message/DPMCompleteRequest.php index 836f3740..d9eddc3f 100644 --- a/src/Message/DPMCompleteRequest.php +++ b/src/Message/DPMCompleteRequest.php @@ -11,16 +11,24 @@ class DPMCompleteRequest extends SIMCompleteAuthorizeRequest { public function getData() { + // The hash sent in the callback from the Authorize.Net gateway. $hash_posted = strtolower($this->httpRequest->request->get('x_MD5_Hash')); + + // The transaction reference generated by the Authorize.Net gateway and sent in the callback. $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); + + // The amount that the callback has authorized. $posted_amount = $this->httpRequest->request->get('x_amount'); + + // Calculate the hash locally, using the shared "hash secret" and login ID. $hash_calculated = $this->getDpmHash($posted_transaction_reference, $posted_amount); if ($hash_posted !== $hash_calculated) { // If the hash is incorrect, then we can't trust the source nor anything sent. - // Throwing exceptions here is a *really* bad idea. We are trying to get the data, + // Throwing exceptions here is probably a bad idea. We are trying to get the data, // and if it is invalid, then we need to be able to log that data for analysis. // Except we can't, baceuse the exception means we can't get to the data. + // For now, this is consistent with other OmniPay gateway drivers. throw new InvalidRequestException('Incorrect hash'); } @@ -28,13 +36,12 @@ public function getData() // The hashes have passed, but the amount should also be validated against the // amount in the stored and retrieved transaction. If the application has the // ability to retrieve the transaction (using the transaction_id sent as a custom - // form field, or perhaps as a GET parameter on the callback URL) then it will - // be checked here. + // form field, or perhaps in an otherwise unused field such as x_invoice_id. $amount = $this->getAmount(); if (isset($amount) && $amount != $posted_amount) { - // The amounts don't match up. Someone may have been playing with the + // The amounts don't match. Someone may have been playing with the // transaction references. throw new InvalidRequestException('Incorrect amount'); @@ -45,10 +52,8 @@ public function getData() /** * This hash confirms the ransaction has come from the Authorize.Net gateway. - * It basically tests the shared hash secret is correct, but mixes in other details - * that will change for each transaction so the hash will be unique for each transaction. - * The hash secret and login ID are known to the merchent site, and the amount and transaction - * reference (x_amount and x_trans_id) are sent by the gatewa. + * It confirms the sender knows ther shared hash secret and that the amount and + * transaction reference has not been changed in transit. */ public function getDpmHash($transaction_reference, $amount) { diff --git a/src/Message/DPMCompleteResponse.php b/src/Message/DPMCompleteResponse.php index cb077291..0d21b680 100644 --- a/src/Message/DPMCompleteResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -9,10 +9,10 @@ * Authorize.Net DPM Complete Authorize Response * This is the result of handling the callback. * The result will always be a HTML redirect snippet. This gets - * returned to the gateway, displayed in the user's browser, and a GET - * redirect is performed using JavaScript and meta refresh (belt and braces). + * returned to the gateway, displayed in the user's browser, and a + * redirect is performed using JavaScript and meta refresh (for backup). * We may want to return to the success page, the failed page or the retry - * page (so the user can correct the form). + * page (so the user can correct the form to try again). */ class DPMCompleteResponse extends SIMCompleteAuthorizeResponse implements RedirectResponseInterface { @@ -35,11 +35,6 @@ public function isError() return isset($this->data['x_response_code']) && static::RESPONSE_CODE_ERROR === $this->data['x_response_code']; } - public function getMessage() - { - return parent::getReasonCode() . '|' . parent::getMessage(); - } - /** * We are in the callback, and we MUST return a HTML fragment to do a redirect. * All headers we may return are discarded by the gateway, so we cannot use @@ -51,11 +46,10 @@ public function isRedirect() } /** - * We default here to POST because the default redirect mechanism - * in Omnipay Common only generates a HTML snippet for POST and not - * GET. - * TODO: We could fix that here so both GET and POST can be supported. - * Our fix should also include the "form data" with the URL. + * We set POST because the default redirect mechanism in Omnipay Common only + * generates a HTML snippet for POST and not for the GET method. + * The redirect method is actually "HTML", where a HTML page is supplied + * to do a redirect using any method it likes. */ public function getRedirectMethod() { @@ -66,7 +60,7 @@ public function getRedirectMethod() * We probably do not require any redirect data, if the incomplete transaction * is still in the user's session and we can inspect the results from the saved * transaction in the database. We cannot send the result through the redirect - * unless it is hashed in some way so the authorisation result cannot be faked. + * unless it is hashed so the authorisation result cannot be faked. */ public function getRedirectData() { @@ -75,9 +69,6 @@ public function getRedirectData() /** * The cancel URL is never handled here - that is a direct link from the gateway. - * The best approach is to have just one redirect URL, and once there, check the - * result of the authorisation in the database (assuming it has been saved in the - * callback) and take action from there. */ public function getRedirectUrl() { diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index cad331f4..073293b8 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -21,14 +21,20 @@ public function getData() $data['x_delim_data'] = 'FALSE'; $data['x_show_form'] = 'PAYMENT_FORM'; $data['x_relay_response'] = 'TRUE'; + // The returnUrl MUST be set in Authorize.net admin panel as a // "Response/Receipt URLs" URL, but not necessarily the default. $data['x_relay_url'] = $this->getReturnUrl(); $data['x_cancel_url'] = $this->getCancelUrl(); + if ($this->getCustomerId() !== null) { $data['x_cust_id'] = $this->getCustomerId(); } + if ($this->getCurrency() !== null) { + $data['x_currency_code'] = $this->getCurrency(); + } + if ($this->getTestMode()) { $data['x_test_request'] = 'TRUE'; } diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index e3ecbb4a..274abc1e 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -18,6 +18,9 @@ public function getData() return $this->httpRequest->request->all(); } + /** + * CHECKME: DPM uses the transactionReference in the hash, not the transactionID. + */ public function getHash() { return md5($this->getHashSecret().$this->getApiLoginId().$this->getTransactionId().$this->getAmount()); From 1070058c058b6564e02b555409aee515a3394b96 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 15 Feb 2015 22:19:10 +0000 Subject: [PATCH 058/254] Workaround for https://github.com/thephpleague/omnipay-common/issues/29 --- src/Message/DPMAuthorizeRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index f4451baf..eff56260 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -29,7 +29,9 @@ public function getData() if ($this->getCard()) { $data['x_card_num'] = $this->getCard()->getNumber(); - $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); + // Workaround for https://github.com/thephpleague/omnipay-common/issues/29 + $expiry_date = $this->getCard()->getExpiryDate('my'); + $data['x_exp_date'] = ($expiry_date === '1299' ? '' : $expiry_date); $data['x_card_code'] = $this->getCard()->getCvv(); } else { $data['x_card_num'] = ''; From 35a3d583b7d7cc18457b52ce7107a3b44baa1d3a Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 15 Feb 2015 23:58:57 +0000 Subject: [PATCH 059/254] Started adding some tests. --- src/AIMGateway.php | 20 +++++++ src/Message/AbstractRequest.php | 10 ++++ src/Message/DPMAuthorizeRequest.php | 2 + src/Message/DPMAuthorizeResponse.php | 5 ++ src/Message/SIMAuthorizeRequest.php | 4 +- tests/DPMGatewayTest.php | 85 ++++++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 tests/DPMGatewayTest.php diff --git a/src/AIMGateway.php b/src/AIMGateway.php index ded28cc0..d7090963 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -62,6 +62,26 @@ public function setEndpoints($endpoints) return $this->setParameter('developerEndpoint', $endpoints['developer']); } + public function getLiveEndpoint() + { + return $this->getParameter('liveEndpoint'); + } + + public function setLiveEndpoint($value) + { + return $this->setParameter('liveEndpoint', $value); + } + + public function getDeveloperEndpoint() + { + return $this->getParameter('developerEndpoint'); + } + + public function setDeveloperEndpoint($value) + { + return $this->setParameter('developerEndpoint', $value); + } + public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest', $parameters); diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 18d11a7f..66998ec5 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -57,6 +57,11 @@ public function setHashSecret($value) return $this->setParameter('hashSecret', $value); } + public function getLiveEndpoint() + { + return $this->getParameter('liveEndpoint'); + } + public function setLiveEndpoint($value) { return $this->setParameter('liveEndpoint', $value); @@ -67,6 +72,11 @@ public function setDeveloperEndpoint($value) return $this->setParameter('developerEndpoint', $value); } + public function getDeveloperEndpoint() + { + return $this->getParameter('developerEndpoint'); + } + protected function getBaseData() { $data = array(); diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index eff56260..008e4013 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -29,9 +29,11 @@ public function getData() if ($this->getCard()) { $data['x_card_num'] = $this->getCard()->getNumber(); + // Workaround for https://github.com/thephpleague/omnipay-common/issues/29 $expiry_date = $this->getCard()->getExpiryDate('my'); $data['x_exp_date'] = ($expiry_date === '1299' ? '' : $expiry_date); + $data['x_card_code'] = $this->getCard()->getCvv(); } else { $data['x_card_num'] = ''; diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php index 203d8101..0ad21b80 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMAuthorizeResponse.php @@ -62,6 +62,11 @@ public function isTransparentRedirect() return true; } + public function isRedirect() + { + return true; + } + // Helpers to build the form. /** diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index 073293b8..f960e472 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -22,8 +22,8 @@ public function getData() $data['x_show_form'] = 'PAYMENT_FORM'; $data['x_relay_response'] = 'TRUE'; - // The returnUrl MUST be set in Authorize.net admin panel as a - // "Response/Receipt URLs" URL, but not necessarily the default. + // The returnUrl MUST be set in Authorize.net admin panel under + // "Response/Receipt URLs". $data['x_relay_url'] = $this->getReturnUrl(); $data['x_cancel_url'] = $this->getCancelUrl(); diff --git a/tests/DPMGatewayTest.php b/tests/DPMGatewayTest.php new file mode 100644 index 00000000..c9aa8460 --- /dev/null +++ b/tests/DPMGatewayTest.php @@ -0,0 +1,85 @@ +gateway = new DPMGateway($this->getHttpClient(), $this->getHttpRequest()); + $this->gateway->setApiLoginId('example'); + $this->gateway->setTransactionKey('keykey'); + $this->gateway->setHashSecret('elpmaxe'); + + $this->options = array( + 'amount' => '10.00', + 'transactionId' => '99', + 'returnUrl' => 'https://www.example.com/return', + ); + } + + public function testAuthorize() + { + $response = $this->gateway->authorize($this->options)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotEmpty($response->getRedirectUrl()); + + $redirectData = $response->getRedirectData(); + $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); + } + + public function testCompleteAuthorize() + { + $this->getHttpRequest()->request->replace( + array( + 'x_response_code' => '1', + 'x_trans_id' => '12345', + 'x_amount' => '10.00', + 'x_MD5_Hash' => md5('elpmaxe' . 'example' . '12345' . '10.00'), + ) + ); + + $response = $this->gateway->completeAuthorize($this->options)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('12345', $response->getTransactionReference()); + $this->assertNull($response->getMessage()); + } + + public function testPurchase() + { + $response = $this->gateway->purchase($this->options)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotEmpty($response->getRedirectUrl()); + + $redirectData = $response->getRedirectData(); + $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); + } + + public function testCompletePurchase() + { + $this->getHttpRequest()->request->replace( + array( + 'x_response_code' => '1', + 'x_trans_id' => '12345', + 'x_amount' => '10.00', + 'x_MD5_Hash' => md5('elpmaxe' . 'example' . '12345' . '10.00'), + ) + ); + + $response = $this->gateway->completePurchase($this->options)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('12345', $response->getTransactionReference()); + $this->assertNull($response->getMessage()); + } +} From 221f8df8ce04c91efd7bfb763466f57070120581 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 16 Feb 2015 00:15:13 +0000 Subject: [PATCH 060/254] Dev snapshot while working on tests (time for bed) --- tests/DPMGatewayTest.php | 28 +++++++++++++++++++++++ tests/Message/SIMAuthorizeRequestTest.php | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/DPMGatewayTest.php b/tests/DPMGatewayTest.php index c9aa8460..ae199225 100644 --- a/tests/DPMGatewayTest.php +++ b/tests/DPMGatewayTest.php @@ -35,6 +35,10 @@ public function testAuthorize() $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); } + /** + * The MD4 Hash consists of the shared secret, the login ID, the transaction *reference* (as + * generated on the remote gateway for the transaction) and the amount. + */ public function testCompleteAuthorize() { $this->getHttpRequest()->request->replace( @@ -53,6 +57,30 @@ public function testCompleteAuthorize() $this->assertNull($response->getMessage()); } + /** + * @expectedException Omnipay\Common\Exception\InvalidRequestException + * @expectedExceptionMessage Incorrect amount + * + * The hash is correct, so the sender knows the shared secret, but the amount + * is not what we expected, i.e. what we had requested to be authorized. + */ + public function testCompleteAuthorizeWrongAmount() + { + $this->getHttpRequest()->request->replace( + array( + 'x_response_code' => '1', + 'x_trans_id' => '12345', + 'x_amount' => '20.00', + 'x_MD5_Hash' => md5('elpmaxe' . 'example' . '12345' . '20.00'), + ) + ); + + $response = $this->gateway->completeAuthorize($this->options)->send(); + //$this->assertTrue($response->isSuccessful()); + //$this->assertSame('12345', $response->getTransactionReference()); + //$this->assertNull($response->getMessage()); + } + public function testPurchase() { $response = $this->gateway->purchase($this->options)->send(); diff --git a/tests/Message/SIMAuthorizeRequestTest.php b/tests/Message/SIMAuthorizeRequestTest.php index 559405fd..0e3c6aba 100644 --- a/tests/Message/SIMAuthorizeRequestTest.php +++ b/tests/Message/SIMAuthorizeRequestTest.php @@ -57,7 +57,7 @@ public function testSend() $this->assertFalse($response->isSuccessful()); $this->assertTrue($response->isRedirect()); - $this->assertNotEmpty($response->getRedirectUrl()); + $this->assertNotEmpty($response->getRedirectUrl()); // This test is failing; not sure why. $this->assertSame('POST', $response->getRedirectMethod()); $redirectData = $response->getRedirectData(); From e98c2e3004e7e4fffe75e5352fa169126408b04b Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 17 Feb 2015 01:17:38 +0000 Subject: [PATCH 061/254] Added x_relay_always as specified in new Authorize.Net API guide. Test needed for this. --- src/Message/DPMAuthorizeRequest.php | 5 +++++ tests/DPMGatewayTest.php | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 008e4013..8a9a6c5a 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -23,6 +23,11 @@ public function getData() unset($data['x_show_form']); + // Must be set for DPM. + // This directs all errors to the relay response. + + $data['x_relay_always'] = 'TRUE'; + // The card details are optional. // They will most likely only be used for development and testing. // The card fields are still needed in the direct-post form regardless. diff --git a/tests/DPMGatewayTest.php b/tests/DPMGatewayTest.php index ae199225..e9b3851d 100644 --- a/tests/DPMGatewayTest.php +++ b/tests/DPMGatewayTest.php @@ -76,9 +76,6 @@ public function testCompleteAuthorizeWrongAmount() ); $response = $this->gateway->completeAuthorize($this->options)->send(); - //$this->assertTrue($response->isSuccessful()); - //$this->assertSame('12345', $response->getTransactionReference()); - //$this->assertNull($response->getMessage()); } public function testPurchase() From c799cd278c72a57dc4ee329ca15696aa1816ad8e Mon Sep 17 00:00:00 2001 From: David Stockton Date: Fri, 20 Feb 2015 01:03:10 -0700 Subject: [PATCH 062/254] Fix for unit test, notices --- src/Message/AIMResponse.php | 25 +++++++++++++++++++++---- tests/Message/AIMResponseTest.php | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 5dbaaf76..fff4a5f5 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -14,7 +14,12 @@ class AIMResponse extends AbstractResponse public function __construct(RequestInterface $request, $data) { $this->request = $request; - $temp = explode('|,|', substr($data, 1, -1)); + $rawFields = substr($data, 1, - 1); + if ($rawFields !== false) { + $temp = explode('|,|', $rawFields); + } else { + $temp = []; + } $response_fields = array( 'Response Code', @@ -67,7 +72,10 @@ public function __construct(RequestInterface $request, $data) $response = array(); foreach ($response_fields as $field) { - $response[$field] = array_shift($temp); + $responseField = array_shift($temp); + if (!is_null($responseField)) { + $response[$field] = $responseField; + } } $response_codes = array( @@ -93,8 +101,17 @@ public function __construct(RequestInterface $request, $data) 'Z' => 'Five digit ZIP matches, Address (Street) does not' ); - $response['Response Code'] = $response_codes[$response['Response Code']]; - $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; + if (isset($response['Response Code']) && isset($response_codes[$response['Response Code']])) { + $response['Response Code'] = $response_codes[$response['Response Code']]; + } else { + $response['Response Code'] = null; + } + + if (isset($response['AVS Response']) && isset($avs_response_codes[$response['AVS Response']])) { + $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; + } else { + $response['AVS Response'] = null; + } $this->data = $response; diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index da5e0be0..da33633f 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -7,7 +7,7 @@ class AIMResponseTest extends TestCase { /** - * @expectedException Omnipay\Common\Exception\InvalidResponseException + * @expectedException \Omnipay\Common\Exception\InvalidResponseException */ public function testConstructEmpty() { From e9c3f8bf3ef71adddf2ac5b0775a74a5b3e1e93c Mon Sep 17 00:00:00 2001 From: David Stockton Date: Fri, 20 Feb 2015 01:41:43 -0700 Subject: [PATCH 063/254] Old style arrays --- src/Message/AIMResponse.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index fff4a5f5..2e5a08de 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -18,7 +18,7 @@ public function __construct(RequestInterface $request, $data) if ($rawFields !== false) { $temp = explode('|,|', $rawFields); } else { - $temp = []; + $temp = array(); } $response_fields = array( @@ -72,7 +72,7 @@ public function __construct(RequestInterface $request, $data) $response = array(); foreach ($response_fields as $field) { - $responseField = array_shift($temp); + $responseField = array_shift($temp); if (!is_null($responseField)) { $response[$field] = $responseField; } @@ -106,7 +106,7 @@ public function __construct(RequestInterface $request, $data) } else { $response['Response Code'] = null; } - + if (isset($response['AVS Response']) && isset($avs_response_codes[$response['AVS Response']])) { $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; } else { From 99327e193f7ae2451782aa1c869fcfa4e247945e Mon Sep 17 00:00:00 2001 From: David Stockton Date: Fri, 20 Feb 2015 01:54:38 -0700 Subject: [PATCH 064/254] Fix for new merged unit tests --- tests/Message/AIMResponseTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 58052406..88cb15a9 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -107,9 +107,9 @@ public function testRefundSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184492509', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCode()); $this->assertSame('1', $response->getReasonCode()); - $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); } public function testRefundFailure() @@ -120,9 +120,9 @@ public function testRefundFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('The credit card number is invalid.', $response->getMessage()); - $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCode()); $this->assertSame('6', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); } } From a8cb0c9cf7b58017ec7d2493d7bd4aa7cf9e1e56 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 24 Feb 2015 11:03:56 +0000 Subject: [PATCH 065/254] Support clientIp for advanced AFDS features. --- src/Message/DPMAuthorizeRequest.php | 2 -- src/Message/DPMAuthorizeResponse.php | 1 + src/Message/SIMAuthorizeRequest.php | 4 ++++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 8a9a6c5a..abef9483 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\AuthorizeNet\Message\SIMAbstractRequest; - /** * Authorize.Net DPM Authorize Request. * Takes the data that will be used to create the direct-post form. diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMAuthorizeResponse.php index 0ad21b80..1b3e1f6d 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMAuthorizeResponse.php @@ -35,6 +35,7 @@ class DPMAuthorizeResponse extends AbstractResponse implements RedirectResponseI 'x_invoice_num', 'x_description', 'x_cust_id', + 'x_customer_ip', ); public function __construct(RequestInterface $request, $data, $postUrl) diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index f960e472..7debc89f 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -22,6 +22,10 @@ public function getData() $data['x_show_form'] = 'PAYMENT_FORM'; $data['x_relay_response'] = 'TRUE'; + if ($this->getClientIp()) { + $data['x_customer_ip'] = $this->getClientIp(); + } + // The returnUrl MUST be set in Authorize.net admin panel under // "Response/Receipt URLs". $data['x_relay_url'] = $this->getReturnUrl(); From 6010b7abc59475075f6b47ab631a9a2626970d95 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 24 Feb 2015 21:09:00 +0000 Subject: [PATCH 066/254] Moved DPMAuthorizeResponse to DPMResponse as it serves as DPMPurchaseResponse too --- src/Message/DPMAuthorizeRequest.php | 2 +- src/Message/{DPMAuthorizeResponse.php => DPMResponse.php} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/Message/{DPMAuthorizeResponse.php => DPMResponse.php} (93%) diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index abef9483..62425e04 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -56,6 +56,6 @@ public function getData() */ public function sendData($data) { - return $this->response = new DPMAuthorizeResponse($this, $data, $this->getEndpoint()); + return $this->response = new DPMResponse($this, $data, $this->getEndpoint()); } } diff --git a/src/Message/DPMAuthorizeResponse.php b/src/Message/DPMResponse.php similarity index 93% rename from src/Message/DPMAuthorizeResponse.php rename to src/Message/DPMResponse.php index 1b3e1f6d..7ceeb7fc 100644 --- a/src/Message/DPMAuthorizeResponse.php +++ b/src/Message/DPMResponse.php @@ -7,11 +7,11 @@ use Omnipay\Common\Message\RedirectResponseInterface; /** - * Authorize.Net DPM Authorize Response - * Here we want the application to present a POST form to the user. This object will + * Authorize.Net DPM Authorize and Purchase Response + * We want the application to present a POST form to the user. This object will * provide the helper methods for doing so. */ -class DPMAuthorizeResponse extends AbstractResponse implements RedirectResponseInterface +class DPMResponse extends AbstractResponse implements RedirectResponseInterface { protected $postUrl; From cf12bd690480cc8706a5470a6de92e2ab368dd08 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 24 Feb 2015 23:32:35 +0000 Subject: [PATCH 067/254] Additional fields moved to hidden field list for DPM. --- src/Message/AbstractRequest.php | 3 ++ src/Message/DPMResponse.php | 49 +++++++++++++++++++++++------ src/Message/SIMAuthorizeRequest.php | 2 ++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 66998ec5..23b2717e 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -77,6 +77,9 @@ public function getDeveloperEndpoint() return $this->getParameter('developerEndpoint'); } + /** + * Base data used only for the AIM API. + */ protected function getBaseData() { $data = array(); diff --git a/src/Message/DPMResponse.php b/src/Message/DPMResponse.php index 7ceeb7fc..d5982ae1 100644 --- a/src/Message/DPMResponse.php +++ b/src/Message/DPMResponse.php @@ -17,25 +17,54 @@ class DPMResponse extends AbstractResponse implements RedirectResponseInterface /** * These will be hidden fields in the direct-post form. + * Not all are required */ protected $hiddenFields = array( + // Merchant + 'x_login', + + // Fingerprint 'x_fp_hash', + 'x_fp_sequence', + 'x_fp_timestamp', + + // Transaction + 'x_type', + 'x_version', + 'x_method', + + // Payment 'x_amount', 'x_currency_code', - 'x_test_request', - 'x_cancel_url', - 'x_relay_url', + 'x_tax', + 'x_freight', + 'x_duty', + 'x_tax_exempt', + + // Relay response 'x_relay_response', - 'x_show_form', - 'x_delim_data', - 'x_fp_timestamp', - 'x_fp_sequence', - 'x_type', - 'x_login', + 'x_relay_url', + 'x_relay_always', + 'x_cancel_url', + + // AFDS + 'x_customer_ip', + + // Testing + 'x_test_request', + 'x_invoice_num', 'x_description', 'x_cust_id', - 'x_customer_ip', + 'x_email_customer', + + 'x_delim_data', + ); + + /** + * Maps OmniPay field names to Authorize.Net field names. + */ + protected $fieldMapping = array( ); public function __construct(RequestInterface $request, $data, $postUrl) diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index 7debc89f..b0598e24 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -16,6 +16,8 @@ public function getData() $data = array(); $data['x_login'] = $this->getApiLoginId(); $data['x_type'] = $this->action; + $data['x_version'] = '3.1'; + $data['x_method'] = 'CC'; $data['x_fp_sequence'] = mt_rand(); $data['x_fp_timestamp'] = time(); $data['x_delim_data'] = 'FALSE'; From 4e49d8c87c1aa4440e6a9aabb6d2bb8120ee5073 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 25 Feb 2015 00:02:31 +0000 Subject: [PATCH 068/254] Created some test coverage for DPM. --- src/AIMGateway.php | 2 +- src/Message/DPMResponse.php | 2 +- tests/Message/DPMAuthorizeRequestTest.php | 68 +++++++++++++++++++++++ tests/Message/DPMPurchaseRequestTest.php | 34 ++++++++++++ tests/Message/SIMAuthorizeRequestTest.php | 4 +- 5 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 tests/Message/DPMAuthorizeRequestTest.php create mode 100644 tests/Message/DPMPurchaseRequestTest.php diff --git a/src/AIMGateway.php b/src/AIMGateway.php index d7090963..c4c354f7 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -22,7 +22,7 @@ public function getDefaultParameters() 'testMode' => false, 'developerMode' => false, 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', - 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll' + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', ); } diff --git a/src/Message/DPMResponse.php b/src/Message/DPMResponse.php index d5982ae1..2a1f59c9 100644 --- a/src/Message/DPMResponse.php +++ b/src/Message/DPMResponse.php @@ -109,7 +109,7 @@ public function getRedirectUrl() public function getRedirectMethod() { - return "post"; + return 'POST'; } /** diff --git a/tests/Message/DPMAuthorizeRequestTest.php b/tests/Message/DPMAuthorizeRequestTest.php new file mode 100644 index 00000000..5f8b96b6 --- /dev/null +++ b/tests/Message/DPMAuthorizeRequestTest.php @@ -0,0 +1,68 @@ +request = new DPMAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'clientIp' => '10.0.0.1', + 'amount' => '12.00', + 'returnUrl' => 'https://www.example.com/return', + 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertSame('AUTH_ONLY', $data['x_type']); + $this->assertArrayNotHasKey('x_show_form', $data); + $this->assertArrayNotHasKey('x_test_request', $data); + } + + public function testGetDataTestMode() + { + $this->request->setTestMode(true); + + $data = $this->request->getData(); + + $this->assertSame('TRUE', $data['x_test_request']); + } + + public function testGetHash() + { + $this->request->setApiLoginId('user'); + $this->request->setTransactionKey('key'); + $data = array( + 'x_fp_sequence' => 'a', + 'x_fp_timestamp' => 'b', + 'x_amount' => 'c', + ); + + $expected = hash_hmac('md5', 'user^a^b^c^', 'key'); + + $this->assertSame($expected, $this->request->getHash($data)); + } + + public function testSend() + { + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotEmpty($response->getRedirectUrl()); + $this->assertSame('POST', $response->getRedirectMethod()); + + $redirectData = $response->getRedirectData(); + $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); + } +} diff --git a/tests/Message/DPMPurchaseRequestTest.php b/tests/Message/DPMPurchaseRequestTest.php new file mode 100644 index 00000000..d0202dd5 --- /dev/null +++ b/tests/Message/DPMPurchaseRequestTest.php @@ -0,0 +1,34 @@ +request = new DPMPurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); + $this->request->initialize( + array( + 'clientIp' => '10.0.0.1', + 'amount' => '12.00', + 'customerId' => 'cust-id', + 'card' => $this->getValidCard(), + 'returnUrl' => 'https://www.example.com/return', + 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', + ) + ); + } + + public function testGetData() + { + $data = $this->request->getData(); + + $this->assertSame('AUTH_CAPTURE', $data['x_type']); + $this->assertSame('10.0.0.1', $data['x_customer_ip']); + $this->assertSame('cust-id', $data['x_cust_id']); + $this->assertArrayNotHasKey('x_test_request', $data); + } +} diff --git a/tests/Message/SIMAuthorizeRequestTest.php b/tests/Message/SIMAuthorizeRequestTest.php index 0e3c6aba..46c5ca17 100644 --- a/tests/Message/SIMAuthorizeRequestTest.php +++ b/tests/Message/SIMAuthorizeRequestTest.php @@ -14,6 +14,8 @@ public function setUp() 'clientIp' => '10.0.0.1', 'amount' => '12.00', 'returnUrl' => 'https://www.example.com/return', + 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', ) ); } @@ -57,7 +59,7 @@ public function testSend() $this->assertFalse($response->isSuccessful()); $this->assertTrue($response->isRedirect()); - $this->assertNotEmpty($response->getRedirectUrl()); // This test is failing; not sure why. + $this->assertNotEmpty($response->getRedirectUrl()); $this->assertSame('POST', $response->getRedirectMethod()); $redirectData = $response->getRedirectData(); From 801a674ef27d065e03ccdbdbf8048fdcd1784c8d Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Fri, 6 Mar 2015 22:34:18 +0000 Subject: [PATCH 069/254] Additional DPM tests, including check that CC expiry is empty. --- tests/Message/DPMCompleteRequestTest.php | 62 ++++++++++++++++++++++++ tests/Message/DPMPurchaseRequestTest.php | 56 ++++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests/Message/DPMCompleteRequestTest.php diff --git a/tests/Message/DPMCompleteRequestTest.php b/tests/Message/DPMCompleteRequestTest.php new file mode 100644 index 00000000..96ad814f --- /dev/null +++ b/tests/Message/DPMCompleteRequestTest.php @@ -0,0 +1,62 @@ +request = new DPMCompleteRequest($this->getHttpClient(), $this->getHttpRequest()); + } + + /** + * @expectedException \Omnipay\Common\Exception\InvalidRequestException + * @expectedExceptionMessage Incorrect hash + */ + public function testGetDataInvalid() + { + $this->getHttpRequest()->request->replace(array('x_MD5_Hash' => 'invalid')); + $this->request->getData(); + } + + public function testGetHash() + { + $this->assertSame(md5(''), $this->request->getHash()); + + $this->request->setHashSecret('hashsec'); + $this->request->setApiLoginId('apilogin'); + $this->request->setTransactionId('trnid'); + $this->request->setAmount('10.00'); + + $this->assertSame(md5('hashsecapilogintrnid10.00'), $this->request->getHash()); + } + + public function testSend() + { + // Note: the hash contains no data supplied by the merchant site, apart + // from the secret. This is the first point at which we see the transaction + // reference (x_trans_id), and this hash is to validate that the reference and + // the amount have not be tampered with en-route. + + $this->getHttpRequest()->request->replace( + array( + 'x_response_code' => '1', + 'x_trans_id' => '12345', + 'x_amount' => '10.00', + 'x_MD5_Hash' => strtolower(md5('shhh' . 'user' . '12345' . '10.00')), + ) + ); + $this->request->setApiLoginId('user'); + $this->request->setHashSecret('shhh'); + //$this->request->setAmount('10.00'); + //$this->request->setTransactionReference('12345'); + + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('12345', $response->getTransactionReference()); + $this->assertNull($response->getMessage()); + } +} \ No newline at end of file diff --git a/tests/Message/DPMPurchaseRequestTest.php b/tests/Message/DPMPurchaseRequestTest.php index d0202dd5..cceaf94f 100644 --- a/tests/Message/DPMPurchaseRequestTest.php +++ b/tests/Message/DPMPurchaseRequestTest.php @@ -8,13 +8,25 @@ class DPMPurchaseRequestTest extends TestCase { public function setUp() { + // The card for DPM will always start out blank, so remove the card details. + + $validCard = array_merge( + $this->getValidCard(), + array( + 'number' => '', + 'expiryMonth' => '', + 'expiryYear' => '', + 'cvv' => '', + ) + ); + $this->request = new DPMPurchaseRequest($this->getHttpClient(), $this->getHttpRequest()); $this->request->initialize( array( 'clientIp' => '10.0.0.1', 'amount' => '12.00', 'customerId' => 'cust-id', - 'card' => $this->getValidCard(), + 'card' => $validCard, 'returnUrl' => 'https://www.example.com/return', 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', @@ -29,6 +41,48 @@ public function testGetData() $this->assertSame('AUTH_CAPTURE', $data['x_type']); $this->assertSame('10.0.0.1', $data['x_customer_ip']); $this->assertSame('cust-id', $data['x_cust_id']); + + $this->assertSame('', $data['x_card_num']); + $this->assertSame('', $data['x_exp_date']); + $this->assertSame('', $data['x_card_code']); + $this->assertArrayNotHasKey('x_test_request', $data); } + + public function testGetDataTestMode() + { + $this->request->setTestMode(true); + + $data = $this->request->getData(); + + $this->assertSame('TRUE', $data['x_test_request']); + } + + public function testGetHash() + { + $this->request->setApiLoginId('user'); + $this->request->setTransactionKey('key'); + $data = array( + 'x_fp_sequence' => 'a', + 'x_fp_timestamp' => 'b', + 'x_amount' => 'c', + ); + + $expected = hash_hmac('md5', 'user^a^b^c^', 'key'); + + $this->assertSame($expected, $this->request->getHash($data)); + } + + public function testSend() + { + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotEmpty($response->getRedirectUrl()); + $this->assertSame('POST', $response->getRedirectMethod()); + + $redirectData = $response->getRedirectData(); + $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); + } } From f296cfc3c2fc18c16522c18fe80131fef057da18 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Mar 2015 12:18:36 +0000 Subject: [PATCH 070/254] More test coverage. --- tests/Message/DPMCompleteRequestTest.php | 42 +++++++++++++++++++---- tests/Message/DPMCompleteResponseTest.php | 26 ++++++++++++++ tests/Mock/DPMAuthorizeFailure.txt | 10 ++++++ tests/Mock/DPMAuthorizeSuccess.txt | 10 ++++++ 4 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 tests/Message/DPMCompleteResponseTest.php create mode 100644 tests/Mock/DPMAuthorizeFailure.txt create mode 100644 tests/Mock/DPMAuthorizeSuccess.txt diff --git a/tests/Message/DPMCompleteRequestTest.php b/tests/Message/DPMCompleteRequestTest.php index 96ad814f..77732220 100644 --- a/tests/Message/DPMCompleteRequestTest.php +++ b/tests/Message/DPMCompleteRequestTest.php @@ -2,6 +2,10 @@ namespace Omnipay\AuthorizeNet\Message; +/** + * The CompleteRequest object is invoked in the callback handler. + */ + use Omnipay\Tests\TestCase; class DPMCompleteAuthorizeRequestTest extends TestCase @@ -21,21 +25,19 @@ public function testGetDataInvalid() $this->request->getData(); } - public function testGetHash() + public function testGetDpmHash() { $this->assertSame(md5(''), $this->request->getHash()); $this->request->setHashSecret('hashsec'); $this->request->setApiLoginId('apilogin'); - $this->request->setTransactionId('trnid'); - $this->request->setAmount('10.00'); - $this->assertSame(md5('hashsecapilogintrnid10.00'), $this->request->getHash()); + $this->assertSame(md5('hashsec' . 'apilogin' . 'trnid' . '10.00'), $this->request->getDpmHash('trnid', '10.00')); } public function testSend() { - // Note: the hash contains no data supplied by the merchant site, apart + // The hash contains no data supplied by the merchant site, apart // from the secret. This is the first point at which we see the transaction // reference (x_trans_id), and this hash is to validate that the reference and // the amount have not be tampered with en-route. @@ -50,8 +52,8 @@ public function testSend() ); $this->request->setApiLoginId('user'); $this->request->setHashSecret('shhh'); - //$this->request->setAmount('10.00'); - //$this->request->setTransactionReference('12345'); + + $this->request->setAmount('10.00'); $response = $this->request->send(); @@ -59,4 +61,30 @@ public function testSend() $this->assertSame('12345', $response->getTransactionReference()); $this->assertNull($response->getMessage()); } + + /** + * @expectedException \Omnipay\Common\Exception\InvalidRequestException + * @expectedExceptionMessage Incorrect amount + */ + public function testSendWrongAmount() + { + $this->getHttpRequest()->request->replace( + array( + 'x_response_code' => '1', + 'x_trans_id' => '12345', + 'x_amount' => '10.00', + 'x_MD5_Hash' => strtolower(md5('shhh' . 'user' . '12345' . '10.00')), + ) + ); + $this->request->setApiLoginId('user'); + $this->request->setHashSecret('shhh'); + + // In the callback, the merchant application sets the amount that + // was expected to be authorised. We expected 20.00 but are being + // told it was 10.00. + + $this->request->setAmount('20.00'); + + $response = $this->request->send(); + } } \ No newline at end of file diff --git a/tests/Message/DPMCompleteResponseTest.php b/tests/Message/DPMCompleteResponseTest.php new file mode 100644 index 00000000..c4ed11f1 --- /dev/null +++ b/tests/Message/DPMCompleteResponseTest.php @@ -0,0 +1,26 @@ +getMockRequest(), array('x_response_code' => '1', 'x_trans_id' => '12345')); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('12345', $response->getTransactionReference()); + $this->assertNull($response->getMessage()); + } + + public function testFailure() + { + $response = new DPMCompleteResponse($this->getMockRequest(), array('x_response_code' => '0', 'x_response_reason_text' => 'Declined')); + + $this->assertFalse($response->isSuccessful()); + $this->assertNull($response->getTransactionReference()); + $this->assertSame('Declined', $response->getMessage()); + } +} diff --git a/tests/Mock/DPMAuthorizeFailure.txt b/tests/Mock/DPMAuthorizeFailure.txt new file mode 100644 index 00000000..ac21934f --- /dev/null +++ b/tests/Mock/DPMAuthorizeFailure.txt @@ -0,0 +1,10 @@ +HTTP/1.1 200 OK +CACHE-CONTROL: no-cache +CONNECTION: close +PRAGMA: no-cache +CONTENT-TYPE: application/x-www-form-urlencoded +ACCEPT: */* +CONTENT-LENGTH: 739 +HOST: example.com + +x_response_code=3&x_response_reason_code=98&x_response_reason_text=%28TESTMODE%29+This+transaction+cannot+be+accepted%2E&x_avs_code=P&x_auth_code=000000&x_trans_id=0&x_method=CC&x_card_type=&x_account_number=&x_first_name=&x_last_name=&x_company=&x_address=&x_city=&x_state=&x_zip=&x_country=&x_phone=&x_fax=&x_email=&x_invoice_num=&x_description=&x_type=auth%5Fonly&x_cust_id=&x_ship_to_first_name=&x_ship_to_last_name=&x_ship_to_company=&x_ship_to_address=&x_ship_to_city=&x_ship_to_state=&x_ship_to_zip=&x_ship_to_country=&x_amount=10%2E00&x_tax=0%2E00&x_duty=0%2E00&x_freight=0%2E00&x_tax_exempt=FALSE&x_po_num=&x_MD5_Hash=480AA04BE6E4BF0469B63D9E42BD568A&x_cvv2_resp_code=&x_cavv_response=&x_test_request=true diff --git a/tests/Mock/DPMAuthorizeSuccess.txt b/tests/Mock/DPMAuthorizeSuccess.txt new file mode 100644 index 00000000..81446cc1 --- /dev/null +++ b/tests/Mock/DPMAuthorizeSuccess.txt @@ -0,0 +1,10 @@ +HTTP/1.1 200 OK +CACHE-CONTROL: no-cache +CONNECTION: close +PRAGMA: no-cache +CONTENT-TYPE: application/x-www-form-urlencoded +ACCEPT: */* +CONTENT-LENGTH: 877 +HOST: example.com + +x_response_code=1&x_response_reason_code=1&x_response_reason_text=%28TESTMODE%29+This+transaction+has+been+approved%2E&x_avs_code=P&x_auth_code=000000&x_trans_id=2184493132&x_method=CC&x_card_type=Visa&x_account_number=XXXX4242&x_first_name=Joe&x_last_name=Bloggs&x_company=&x_address=88+Address+2&x_city=City&x_state=State&x_zip=412&x_country=GB&x_phone=01234+567+890&x_fax=&x_email=jason%40academe%2Eco%2Euk&x_invoice_num=975077375&x_description=&x_type=auth%5Fonly&x_cust_id=CUST123&x_ship_to_first_name=Joe&x_ship_to_last_name=Bloggs&x_ship_to_company=&x_ship_to_address=99+Address+2S&x_ship_to_city=CityS&x_ship_to_state=StateS&x_ship_to_zip=412S&x_ship_to_country=GB&x_amount=10%2E00&x_tax=0%2E00&x_duty=0%2E00&x_freight=0%2E00&x_tax_exempt=FALSE&x_po_num=&x_MD5_Hash=480AA04BE6E4BF0469B63D9E42BD568A&x_cvv2_resp_code=&x_cavv_response=&x_test_request=true From 6661d9b179a6c86ab512937918ee1bffb06c8727 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Mar 2015 12:30:16 +0000 Subject: [PATCH 071/254] Some notes. Will raise a ticket against this. --- src/Message/SIMCompleteAuthorizeRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index 274abc1e..585e268b 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -19,7 +19,9 @@ public function getData() } /** - * CHECKME: DPM uses the transactionReference in the hash, not the transactionID. + * CHECKME: should this be the transactionReference in the hash, not the transactionId? + * The transaction reference and the amount are both sent by the remote gateway (x_trans_id + * and x_amount) and it is those that should be checked against. */ public function getHash() { From 1f61b24f3c1700a72805c4d310e8ce300ce13a91 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Mar 2015 13:07:37 +0000 Subject: [PATCH 072/254] Wrap some lines to shorten them. --- src/Message/DPMCompleteResponse.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Message/DPMCompleteResponse.php b/src/Message/DPMCompleteResponse.php index 0d21b680..5ee71f05 100644 --- a/src/Message/DPMCompleteResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -23,7 +23,8 @@ class DPMCompleteResponse extends SIMCompleteAuthorizeResponse implements Redire public function isSuccessful() { - return isset($this->data['x_response_code']) && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; + return isset($this->data['x_response_code']) + && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; } /** @@ -32,7 +33,8 @@ public function isSuccessful() */ public function isError() { - return isset($this->data['x_response_code']) && static::RESPONSE_CODE_ERROR === $this->data['x_response_code']; + return isset($this->data['x_response_code']) + && static::RESPONSE_CODE_ERROR === $this->data['x_response_code']; } /** From f83008ef2bae5506225028e868f5848af64ea327 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Mar 2015 13:09:44 +0000 Subject: [PATCH 073/254] Shorten some more lines. --- src/Message/AbstractRequest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 23b2717e..3b85dd55 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -144,6 +144,10 @@ public function sendData($data) public function getEndpoint() { - return $this->getDeveloperMode() ? $this->getParameter('developerEndpoint') : $this->getParameter('liveEndpoint'); + if ($this->getDeveloperMode()) { + return $this->getParameter('developerEndpoint'); + } else { + return $this->getParameter('liveEndpoint'); + } } } From 8fb80873e237d326f9b690d6401e06d971af0fa1 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sun, 22 Mar 2015 23:14:01 +0530 Subject: [PATCH 074/254] PHP 5.3 compatible array style --- tests/Message/CIMCreateCardRequestTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index 8f94bab0..340b92b7 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -42,10 +42,10 @@ public function testGetDataShouldHaveCustomBillTo() 'card' => $card, 'developerMode' => true, 'forceCardUpdate' => true, - 'defaultBillTo' => [ + 'defaultBillTo' => array( 'address' => '1234 Test Street', 'city' => 'Blacksburg' - ] + ) ) ); From cf540fa8b2ef77929adc70a1afb7262efd5503a0 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sun, 22 Mar 2015 23:22:46 +0530 Subject: [PATCH 075/254] PHP 5.3 compatible array style --- src/CIMGateway.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index d525bede..385d10a3 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -17,7 +17,7 @@ public function getDefaultParameters() 'testMode' => false, 'developerMode' => false, 'forceCardUpdate' => false, - 'defaultBillTo' => [[]] + 'defaultBillTo' => array(array()) ); } From 7fa9d7e2fe82f33b931b69378712b235118f2aa2 Mon Sep 17 00:00:00 2001 From: David Stockton Date: Tue, 9 Jun 2015 22:22:38 -0600 Subject: [PATCH 076/254] Fix for BC break of returning messages when asking for codes Added new getCodeMessage and getAVSCodeMessage methods to AIMResponse class. Updated unit tests to correspond. --- src/Message/AIMResponse.php | 20 +++++++++---- tests/Message/AIMResponseTest.php | 48 ++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 2e5a08de..5fc1f4cc 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -102,15 +102,15 @@ public function __construct(RequestInterface $request, $data) ); if (isset($response['Response Code']) && isset($response_codes[$response['Response Code']])) { - $response['Response Code'] = $response_codes[$response['Response Code']]; + $response['Response Code Message'] = $response_codes[$response['Response Code']]; } else { - $response['Response Code'] = null; + $response['Response Code Message'] = null; } if (isset($response['AVS Response']) && isset($avs_response_codes[$response['AVS Response']])) { - $response['AVS Response'] = $avs_response_codes[$response['AVS Response']]; + $response['AVS Response Message'] = $avs_response_codes[$response['AVS Response']]; } else { - $response['AVS Response'] = null; + $response['AVS Response Message'] = null; } $this->data = $response; @@ -122,7 +122,7 @@ public function __construct(RequestInterface $request, $data) public function isSuccessful() { - return $this->getCode() == 'Approved'; + return $this->getCodeMessage() == 'Approved'; } public function getCode() @@ -130,6 +130,11 @@ public function getCode() return $this->data['Response Code']; } + public function getCodeMessage() + { + return $this->data['Response Code Message']; + } + public function getReasonCode() { return $this->data['Response Reason Code']; @@ -150,6 +155,11 @@ public function getAVSCode() return $this->data['AVS Response']; } + public function getAVSCodeMessage() + { + return $this->data['AVS Response Message']; + } + public function getTransactionReference() { return $this->data['Transaction ID']; diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 88cb15a9..57ecbd51 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -22,10 +22,12 @@ public function testAuthorizeSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184493132', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('Approved', $response->getCode()); + $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCodeMessage()); $this->assertSame('1', $response->getReasonCode()); $this->assertSame('GA4OQP', $response->getAuthorizationCode()); - $this->assertSame('Address (Street) and five digit ZIP match', $response->getAVSCode()); + $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('Address (Street) and five digit ZIP match', $response->getAVSCodeMessage()); } public function testAuthorizeFailure() @@ -36,10 +38,12 @@ public function testAuthorizeFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); - $this->assertSame('Error', $response->getCode()); + $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCodeMessage()); $this->assertSame('5', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); + $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCodeMessage()); } public function testCaptureSuccess() @@ -50,10 +54,12 @@ public function testCaptureSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184494531', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('Approved', $response->getCode()); + $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCodeMessage()); $this->assertSame('1', $response->getReasonCode()); $this->assertSame('F51OYG', $response->getAuthorizationCode()); - $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); + $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCodeMessage()); } public function testCaptureFailure() @@ -64,10 +70,12 @@ public function testCaptureFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); - $this->assertSame('Error', $response->getCode()); + $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCodeMessage()); $this->assertSame('16', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); + $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCodeMessage()); } public function testPurchaseSuccess() @@ -78,10 +86,12 @@ public function testPurchaseSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184492509', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('Approved', $response->getCode()); + $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCodeMessage()); $this->assertSame('1', $response->getReasonCode()); $this->assertSame('JE6JM1', $response->getAuthorizationCode()); - $this->assertSame('Address (Street) and five digit ZIP match', $response->getAVSCode()); + $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('Address (Street) and five digit ZIP match', $response->getAVSCodeMessage()); } public function testPurchaseFailure() @@ -92,10 +102,12 @@ public function testPurchaseFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); - $this->assertSame('Error', $response->getCode()); + $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCodeMessage()); $this->assertSame('5', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); + $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCodeMessage()); } public function testRefundSuccess() @@ -107,9 +119,11 @@ public function testRefundSuccess() $this->assertTrue($response->isSuccessful()); $this->assertSame('2184492509', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); - $this->assertSame('Approved', $response->getCode()); + $this->assertSame('1', $response->getCode()); + $this->assertSame('Approved', $response->getCodeMessage()); $this->assertSame('1', $response->getReasonCode()); - $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); + $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCodeMessage()); } public function testRefundFailure() @@ -120,9 +134,11 @@ public function testRefundFailure() $this->assertFalse($response->isSuccessful()); $this->assertSame('0', $response->getTransactionReference()); $this->assertSame('The credit card number is invalid.', $response->getMessage()); - $this->assertSame('Error', $response->getCode()); + $this->assertSame('3', $response->getCode()); + $this->assertSame('Error', $response->getCodeMessage()); $this->assertSame('6', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); - $this->assertSame('AVS not applicable for this transaction', $response->getAVSCode()); + $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('AVS not applicable for this transaction', $response->getAVSCodeMessage()); } } From 272b7b002665518d87152633159950e60b044489 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 5 Jul 2015 01:38:58 +0100 Subject: [PATCH 077/254] Issue #19 Main changes. --- src/Message/AbstractRequest.php | 16 +++++- src/Message/DPMCompleteRequest.php | 56 ------------------- src/Message/DPMCompleteResponse.php | 5 -- src/Message/SIMAuthorizeRequest.php | 2 +- src/Message/SIMCompleteAuthorizeRequest.php | 45 ++++++++++++++- src/Message/SIMCompleteAuthorizeResponse.php | 9 ++- tests/Message/DPMCompleteRequestTest.php | 6 +- .../SIMCompleteAuthorizeRequestTest.php | 18 +++--- tests/SIMGatewayTest.php | 6 +- 9 files changed, 83 insertions(+), 80 deletions(-) diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index 3b85dd55..c6b51328 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -5,8 +5,16 @@ /** * Authorize.Net Abstract Request */ -abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest + +use Omnipay\Common\Message\AbstractRequest as CommonAbstractRequest; + +abstract class AbstractRequest extends CommonAbstractRequest { + /** + * Recommended custom field name to send the transaction ID to the notify handler. + */ + const TRANSACTION_ID_PARAM = 'omnipay_transaction_id'; + public function getApiLoginId() { return $this->getParameter('apiLoginId'); @@ -99,7 +107,13 @@ protected function getBillingData() { $data = array(); $data['x_amount'] = $this->getAmount(); + + // This is deprecated. The invoice number field is reserved for the invoice number. $data['x_invoice_num'] = $this->getTransactionId(); + + // A custom field can be used to pass over the merchant site transaction ID. + $data[static::TRANSACTION_ID_PARAM] = $this->getTransactionId(); + $data['x_description'] = $this->getDescription(); if ($card = $this->getCard()) { diff --git a/src/Message/DPMCompleteRequest.php b/src/Message/DPMCompleteRequest.php index d9eddc3f..26ad0434 100644 --- a/src/Message/DPMCompleteRequest.php +++ b/src/Message/DPMCompleteRequest.php @@ -9,62 +9,6 @@ */ class DPMCompleteRequest extends SIMCompleteAuthorizeRequest { - public function getData() - { - // The hash sent in the callback from the Authorize.Net gateway. - $hash_posted = strtolower($this->httpRequest->request->get('x_MD5_Hash')); - - // The transaction reference generated by the Authorize.Net gateway and sent in the callback. - $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); - - // The amount that the callback has authorized. - $posted_amount = $this->httpRequest->request->get('x_amount'); - - // Calculate the hash locally, using the shared "hash secret" and login ID. - $hash_calculated = $this->getDpmHash($posted_transaction_reference, $posted_amount); - - if ($hash_posted !== $hash_calculated) { - // If the hash is incorrect, then we can't trust the source nor anything sent. - // Throwing exceptions here is probably a bad idea. We are trying to get the data, - // and if it is invalid, then we need to be able to log that data for analysis. - // Except we can't, baceuse the exception means we can't get to the data. - // For now, this is consistent with other OmniPay gateway drivers. - - throw new InvalidRequestException('Incorrect hash'); - } - - // The hashes have passed, but the amount should also be validated against the - // amount in the stored and retrieved transaction. If the application has the - // ability to retrieve the transaction (using the transaction_id sent as a custom - // form field, or perhaps in an otherwise unused field such as x_invoice_id. - - $amount = $this->getAmount(); - - if (isset($amount) && $amount != $posted_amount) { - // The amounts don't match. Someone may have been playing with the - // transaction references. - - throw new InvalidRequestException('Incorrect amount'); - } - - return $this->httpRequest->request->all(); - } - - /** - * This hash confirms the ransaction has come from the Authorize.Net gateway. - * It confirms the sender knows ther shared hash secret and that the amount and - * transaction reference has not been changed in transit. - */ - public function getDpmHash($transaction_reference, $amount) - { - $key = $this->getHashSecret() - . $this->getApiLoginId() - . $transaction_reference - . $amount; - - return md5($key); - } - public function sendData($data) { return $this->response = new DPMCompleteResponse($this, $data); diff --git a/src/Message/DPMCompleteResponse.php b/src/Message/DPMCompleteResponse.php index 5ee71f05..eeef08cf 100644 --- a/src/Message/DPMCompleteResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -16,11 +16,6 @@ */ class DPMCompleteResponse extends SIMCompleteAuthorizeResponse implements RedirectResponseInterface { - const RESPONSE_CODE_APPROVED = '1'; - const RESPONSE_CODE_DECLINED = '2'; - const RESPONSE_CODE_ERROR = '3'; - const RESPONSE_CODE_REVIEW = '4'; - public function isSuccessful() { return isset($this->data['x_response_code']) diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index b0598e24..bbcdfb7a 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -28,7 +28,7 @@ public function getData() $data['x_customer_ip'] = $this->getClientIp(); } - // The returnUrl MUST be set in Authorize.net admin panel under + // The returnUrl MUST be whitelisted in Authorize.net admin panel under // "Response/Receipt URLs". $data['x_relay_url'] = $this->getReturnUrl(); $data['x_cancel_url'] = $this->getCancelUrl(); diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index 585e268b..d3c5af03 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -11,10 +11,42 @@ class SIMCompleteAuthorizeRequest extends AbstractRequest { public function getData() { - if (strtolower($this->httpRequest->request->get('x_MD5_Hash')) !== $this->getHash()) { + // The hash sent in the callback from the Authorize.Net gateway. + $hash_posted = strtolower($this->httpRequest->request->get('x_MD5_Hash')); + + // The transaction reference generated by the Authorize.Net gateway and sent in the callback. + $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); + + // The amount that the callback has authorized. + $posted_amount = $this->httpRequest->request->get('x_amount'); + + // Calculate the hash locally, using the shared "hash secret" and login ID. + $hash_calculated = $this->getHash($posted_transaction_reference, $posted_amount); + + if ($hash_posted !== $hash_calculated) { + // If the hash is incorrect, then we can't trust the source nor anything sent. + // Throwing exceptions here is probably a bad idea. We are trying to get the data, + // and if it is invalid, then we need to be able to log that data for analysis. + // Except we can't, baceuse the exception means we can't get to the data. + // For now, this is consistent with other OmniPay gateway drivers. + throw new InvalidRequestException('Incorrect hash'); } + // The hashes have passed, but the amount should also be validated against the + // amount in the stored and retrieved transaction. If the application has the + // ability to retrieve the transaction (using the transaction_id sent as a custom + // form field, or perhaps in an otherwise unused field such as x_invoice_id. + + $amount = $this->getAmount(); + + if (isset($amount) && $amount != $posted_amount) { + // The amounts don't match. Someone may have been playing with the + // transaction references. + + throw new InvalidRequestException('Incorrect amount'); + } + return $this->httpRequest->request->all(); } @@ -23,9 +55,16 @@ public function getData() * The transaction reference and the amount are both sent by the remote gateway (x_trans_id * and x_amount) and it is those that should be checked against. */ - public function getHash() + public function getHash($transaction_reference, $amount) { - return md5($this->getHashSecret().$this->getApiLoginId().$this->getTransactionId().$this->getAmount()); + $key = array( + $this->getHashSecret(), + $this->getApiLoginId(), + $transaction_reference, + $amount, + ); + + return md5(implode('', $key)); } public function sendData($data) diff --git a/src/Message/SIMCompleteAuthorizeResponse.php b/src/Message/SIMCompleteAuthorizeResponse.php index 1908b0e8..de060079 100644 --- a/src/Message/SIMCompleteAuthorizeResponse.php +++ b/src/Message/SIMCompleteAuthorizeResponse.php @@ -9,9 +9,16 @@ */ class SIMCompleteAuthorizeResponse extends AbstractResponse { + // Response codes returned by Authorize.Net + + const RESPONSE_CODE_APPROVED = '1'; + const RESPONSE_CODE_DECLINED = '2'; + const RESPONSE_CODE_ERROR = '3'; + const RESPONSE_CODE_REVIEW = '4'; + public function isSuccessful() { - return isset($this->data['x_response_code']) && '1' === $this->data['x_response_code']; + return isset($this->data['x_response_code']) && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; } public function getTransactionReference() diff --git a/tests/Message/DPMCompleteRequestTest.php b/tests/Message/DPMCompleteRequestTest.php index 77732220..71c62b08 100644 --- a/tests/Message/DPMCompleteRequestTest.php +++ b/tests/Message/DPMCompleteRequestTest.php @@ -25,14 +25,14 @@ public function testGetDataInvalid() $this->request->getData(); } - public function testGetDpmHash() + public function testGetHash() { - $this->assertSame(md5(''), $this->request->getHash()); + $this->assertSame(md5(''), $this->request->getHash('', '')); $this->request->setHashSecret('hashsec'); $this->request->setApiLoginId('apilogin'); - $this->assertSame(md5('hashsec' . 'apilogin' . 'trnid' . '10.00'), $this->request->getDpmHash('trnid', '10.00')); + $this->assertSame(md5('hashsec' . 'apilogin' . 'trnid' . '10.00'), $this->request->getHash('trnid', '10.00')); } public function testSend() diff --git a/tests/Message/SIMCompleteAuthorizeRequestTest.php b/tests/Message/SIMCompleteAuthorizeRequestTest.php index 7a87cfc3..64af2144 100644 --- a/tests/Message/SIMCompleteAuthorizeRequestTest.php +++ b/tests/Message/SIMCompleteAuthorizeRequestTest.php @@ -23,34 +23,36 @@ public function testGetDataInvalid() public function testGetHash() { - $this->assertSame(md5(''), $this->request->getHash()); + $this->assertSame(md5(''), $this->request->getHash('', '')); $this->request->setHashSecret('hashsec'); $this->request->setApiLoginId('apilogin'); - $this->request->setTransactionId('trnid'); - $this->request->setAmount('10.00'); - $this->assertSame(md5('hashsecapilogintrnid10.00'), $this->request->getHash()); + $this->assertSame(md5('hashsec' . 'apilogin' . 'trnref ' . '10.00'), $this->request->getHash('trnref ', '10.00')); } public function testSend() { + $posted_trans_id = '12345'; // transactionReference in POST. + $posted_amount = '10.00'; // amount authothorised in POST. + $this->getHttpRequest()->request->replace( array( 'x_response_code' => '1', - 'x_trans_id' => '12345', - 'x_MD5_Hash' => md5('shhhuser9910.00'), + 'x_trans_id' => $posted_trans_id, + 'x_amount' => $posted_amount, + 'x_MD5_Hash' => md5('shhh' . 'user' . $posted_trans_id . $posted_amount), ) ); $this->request->setApiLoginId('user'); $this->request->setHashSecret('shhh'); $this->request->setAmount('10.00'); - $this->request->setTransactionId(99); + //$this->request->setTransactionId(99); $response = $this->request->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('12345', $response->getTransactionReference()); + $this->assertSame($posted_trans_id, $response->getTransactionReference()); $this->assertNull($response->getMessage()); } } diff --git a/tests/SIMGatewayTest.php b/tests/SIMGatewayTest.php index ad5bd2e6..61f19346 100644 --- a/tests/SIMGatewayTest.php +++ b/tests/SIMGatewayTest.php @@ -39,7 +39,8 @@ public function testCompleteAuthorize() array( 'x_response_code' => '1', 'x_trans_id' => '12345', - 'x_MD5_Hash' => md5('elpmaxeexample9910.00'), + 'x_amount' => '10.00', + 'x_MD5_Hash' => md5('elpmaxe' . 'example' . '12345' . '10.00'), ) ); @@ -68,7 +69,8 @@ public function testCompletePurchase() array( 'x_response_code' => '1', 'x_trans_id' => '12345', - 'x_MD5_Hash' => md5('elpmaxeexample9910.00'), + 'x_amount' => '10.00', + 'x_MD5_Hash' => md5('elpmaxe' . 'example' . '12345' . '10.00'), ) ); From 152959c2d92f935e40213947f958a9885ff76bd0 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 5 Jul 2015 23:18:59 +0100 Subject: [PATCH 078/254] Issue #19 Add getTransactionId() to SIMcompleteAuthorize.php for access to custom field. --- src/Message/AbstractRequest.php | 2 +- src/Message/SIMCompleteAuthorizeRequest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Message/AbstractRequest.php b/src/Message/AbstractRequest.php index c6b51328..a3b2280e 100644 --- a/src/Message/AbstractRequest.php +++ b/src/Message/AbstractRequest.php @@ -11,7 +11,7 @@ abstract class AbstractRequest extends CommonAbstractRequest { /** - * Recommended custom field name to send the transaction ID to the notify handler. + * Custom field name to send the transaction ID to the notify handler. */ const TRANSACTION_ID_PARAM = 'omnipay_transaction_id'; diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index d3c5af03..9b3b014d 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -9,6 +9,15 @@ */ class SIMCompleteAuthorizeRequest extends AbstractRequest { + /** + * Get the transaction ID passed in through the custom field. + * This is used to look up the transaction in storage. + */ + public function getTransactionId() + { + return $this->httpRequest->request->get(static::TRANSACTION_ID_PARAM); + } + public function getData() { // The hash sent in the callback from the Authorize.Net gateway. From 56e1cec7371c13a7b9a4fbe3133736c424149702 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 7 Jul 2015 16:11:51 +0100 Subject: [PATCH 079/254] Issue #22 and Issue #16 implementation --- src/Message/SIMAuthorizeRequest.php | 12 +++- src/Message/SIMCompleteAuthorizeResponse.php | 68 +++++++++++++++++++- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index bbcdfb7a..4d962924 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -11,7 +11,13 @@ class SIMAuthorizeRequest extends AbstractRequest public function getData() { - $this->validate('amount', 'returnUrl'); + $this->validate('amount'); + + // Either the nodifyUrl or the returnUrl can be provided. + // The returnUrl is deprecated, as strictly this is a notifyUrl. + if (!$this->getNotifyUrl()) { + $this->validate('returnUrl'); + } $data = array(); $data['x_login'] = $this->getApiLoginId(); @@ -30,7 +36,9 @@ public function getData() // The returnUrl MUST be whitelisted in Authorize.net admin panel under // "Response/Receipt URLs". - $data['x_relay_url'] = $this->getReturnUrl(); + // Use the notifyUrl if available, as that is strictly what this is. + // Fall back to returnUrl for BC support. + $data['x_relay_url'] = $this->getNotifyUrl() ?: $this->getReturnUrl(); $data['x_cancel_url'] = $this->getCancelUrl(); if ($this->getCustomerId() !== null) { diff --git a/src/Message/SIMCompleteAuthorizeResponse.php b/src/Message/SIMCompleteAuthorizeResponse.php index de060079..d1933fd7 100644 --- a/src/Message/SIMCompleteAuthorizeResponse.php +++ b/src/Message/SIMCompleteAuthorizeResponse.php @@ -3,11 +3,13 @@ namespace Omnipay\AuthorizeNet\Message; use Omnipay\Common\Message\AbstractResponse; +use Omnipay\Common\Message\RedirectResponseInterface; +use Symfony\Component\HttpFoundation\Response as HttpResponse; /** * Authorize.Net SIM Complete Authorize Response */ -class SIMCompleteAuthorizeResponse extends AbstractResponse +class SIMCompleteAuthorizeResponse extends AbstractResponse implements RedirectResponseInterface { // Response codes returned by Authorize.Net @@ -18,7 +20,7 @@ class SIMCompleteAuthorizeResponse extends AbstractResponse public function isSuccessful() { - return isset($this->data['x_response_code']) && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; + return static::RESPONSE_CODE_APPROVED === $this->getCode(); } public function getTransactionReference() @@ -40,4 +42,66 @@ public function getCode() { return isset($this->data['x_response_code']) ? $this->data['x_response_code'] : null; } + + /** + * This message is handled in a notify, where a HTML redirect must be performed. + */ + public function isRedirect() + { + return true; + } + + /** + * The merchant site notify handler needs to set the returnUrl in the complete request. + */ + public function getRedirectUrl() + { + return $this->request->getReturnUrl(); + } + + public function getRedirectMethod() + { + return 'GET'; + } + + /** + * There is no redirect data to send; the aim is just to get the user to a URL + * by delivering a HTML page. + */ + public function getRedirectData() + { + return array(); + } + + /** + * Authorize.Net requires a redirect in a HTML page. + * The OmniPay redirect helper will only provide a HTML page for the POST method + * and then implements that through a self-sbmitting form. This will generate + * browser warnings if returning to a non-SSL page. + */ + public function getRedirectResponse() + { + $output = << + + + Redirecting... + + + +

Redirecting to payment complete page...

+ + + +ENDHTML; + + $output = sprintf( + $output, + htmlentities($this->getRedirectUrl(), ENT_QUOTES, 'UTF-8', false) + ); + + return HttpResponse::create($output); + } } From 4a4da57e214975c8291dde0a5fc5e45da1d20f23 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 7 Jul 2015 16:33:49 +0100 Subject: [PATCH 080/254] Issue #16 Test for use of notifyUrl. --- tests/Message/SIMAuthorizeRequestTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/Message/SIMAuthorizeRequestTest.php b/tests/Message/SIMAuthorizeRequestTest.php index 46c5ca17..530e61bb 100644 --- a/tests/Message/SIMAuthorizeRequestTest.php +++ b/tests/Message/SIMAuthorizeRequestTest.php @@ -65,4 +65,21 @@ public function testSend() $redirectData = $response->getRedirectData(); $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); } + + // Issue #16 Support notifyUrl. + public function testSendNoifyUrl() + { + $this->request->setReturnUrl(null); + $this->request->setNotifyUrl('https://www.example.com/return'); + + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotEmpty($response->getRedirectUrl()); + $this->assertSame('POST', $response->getRedirectMethod()); + + $redirectData = $response->getRedirectData(); + $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); + } } From 1c6e4d6ed290dabb5bda17fda5102a6e5cf4c6c2 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 7 Jul 2015 16:37:28 +0100 Subject: [PATCH 081/254] Issue #16 Further test for DPM. --- tests/Message/DPMAuthorizeRequestTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/Message/DPMAuthorizeRequestTest.php b/tests/Message/DPMAuthorizeRequestTest.php index 5f8b96b6..472c1187 100644 --- a/tests/Message/DPMAuthorizeRequestTest.php +++ b/tests/Message/DPMAuthorizeRequestTest.php @@ -65,4 +65,20 @@ public function testSend() $redirectData = $response->getRedirectData(); $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); } + + public function testSendNotifyUrl() + { + $this->request->setReturnUrl(null); + $this->request->setNotifyUrl('https://www.example.com/return'); + + $response = $this->request->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertTrue($response->isRedirect()); + $this->assertNotEmpty($response->getRedirectUrl()); + $this->assertSame('POST', $response->getRedirectMethod()); + + $redirectData = $response->getRedirectData(); + $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); + } } From 21b39c686cf4ae00e8215e2ff6333d1a4aba888c Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 7 Jul 2015 19:01:18 +0100 Subject: [PATCH 082/254] Issue #22 test coverage, some fixes and simplification now much of DPM has moved up to SIM. --- src/Message/DPMCompleteResponse.php | 69 +------------------ src/Message/SIMCompleteAuthorizeResponse.php | 9 +++ tests/Message/DPMAuthorizeRequestTest.php | 1 + tests/Message/DPMCompleteRequestTest.php | 12 +++- .../SIMCompleteAuthorizeRequestTest.php | 10 ++- 5 files changed, 32 insertions(+), 69 deletions(-) diff --git a/src/Message/DPMCompleteResponse.php b/src/Message/DPMCompleteResponse.php index eeef08cf..92975509 100644 --- a/src/Message/DPMCompleteResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -2,74 +2,9 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\Message\AbstractResponse; -use Omnipay\Common\Message\RedirectResponseInterface; - /** - * Authorize.Net DPM Complete Authorize Response - * This is the result of handling the callback. - * The result will always be a HTML redirect snippet. This gets - * returned to the gateway, displayed in the user's browser, and a - * redirect is performed using JavaScript and meta refresh (for backup). - * We may want to return to the success page, the failed page or the retry - * page (so the user can correct the form to try again). + * SIM and DPM both have identical needs when handling the notify request. */ -class DPMCompleteResponse extends SIMCompleteAuthorizeResponse implements RedirectResponseInterface +class DPMCompleteResponse extends SIMCompleteAuthorizeResponse { - public function isSuccessful() - { - return isset($this->data['x_response_code']) - && static::RESPONSE_CODE_APPROVED === $this->data['x_response_code']; - } - - /** - * If there is an error in the form, then the user should be able to go back - * to the form and give it another shot. - */ - public function isError() - { - return isset($this->data['x_response_code']) - && static::RESPONSE_CODE_ERROR === $this->data['x_response_code']; - } - - /** - * We are in the callback, and we MUST return a HTML fragment to do a redirect. - * All headers we may return are discarded by the gateway, so we cannot use - * the "Location:" header. - */ - public function isRedirect() - { - return true; - } - - /** - * We set POST because the default redirect mechanism in Omnipay Common only - * generates a HTML snippet for POST and not for the GET method. - * The redirect method is actually "HTML", where a HTML page is supplied - * to do a redirect using any method it likes. - */ - public function getRedirectMethod() - { - return 'POST'; - } - - /** - * We probably do not require any redirect data, if the incomplete transaction - * is still in the user's session and we can inspect the results from the saved - * transaction in the database. We cannot send the result through the redirect - * unless it is hashed so the authorisation result cannot be faked. - */ - public function getRedirectData() - { - return array(); - } - - /** - * The cancel URL is never handled here - that is a direct link from the gateway. - */ - public function getRedirectUrl() - { - // Leave it for the applicatino to decide where to sent the user. - return; - } } diff --git a/src/Message/SIMCompleteAuthorizeResponse.php b/src/Message/SIMCompleteAuthorizeResponse.php index d1933fd7..b32cdd52 100644 --- a/src/Message/SIMCompleteAuthorizeResponse.php +++ b/src/Message/SIMCompleteAuthorizeResponse.php @@ -23,6 +23,15 @@ public function isSuccessful() return static::RESPONSE_CODE_APPROVED === $this->getCode(); } + /** + * If there is an error in the form, then the user should be able to go back + * to the form and give it another shot. + */ + public function isError() + { + return static::RESPONSE_CODE_ERROR === $this->getCode(); + } + public function getTransactionReference() { return isset($this->data['x_trans_id']) ? $this->data['x_trans_id'] : null; diff --git a/tests/Message/DPMAuthorizeRequestTest.php b/tests/Message/DPMAuthorizeRequestTest.php index 472c1187..1d4157d3 100644 --- a/tests/Message/DPMAuthorizeRequestTest.php +++ b/tests/Message/DPMAuthorizeRequestTest.php @@ -66,6 +66,7 @@ public function testSend() $this->assertSame('https://www.example.com/return', $redirectData['x_relay_url']); } + // Issue #16 Support notifyUrl public function testSendNotifyUrl() { $this->request->setReturnUrl(null); diff --git a/tests/Message/DPMCompleteRequestTest.php b/tests/Message/DPMCompleteRequestTest.php index 71c62b08..c22202b5 100644 --- a/tests/Message/DPMCompleteRequestTest.php +++ b/tests/Message/DPMCompleteRequestTest.php @@ -48,6 +48,7 @@ public function testSend() 'x_trans_id' => '12345', 'x_amount' => '10.00', 'x_MD5_Hash' => strtolower(md5('shhh' . 'user' . '12345' . '10.00')), + 'omnipay_transaction_id' => '99', ) ); $this->request->setApiLoginId('user'); @@ -55,10 +56,19 @@ public function testSend() $this->request->setAmount('10.00'); + $this->request->setReturnUrl('http://example.com/'); + + // Issue #22 Transaction ID in request is picked up from custom field. + $this->assertSame('99', $this->request->getTransactionId()); + $response = $this->request->send(); $this->assertTrue($response->isSuccessful()); $this->assertSame('12345', $response->getTransactionReference()); + $this->assertSame(true, $response->isRedirect()); + // CHECKME: does it matter what letter case the method is? + $this->assertSame('GET', $response->getRedirectMethod()); + $this->assertSame('http://example.com/', $response->getRedirectUrl()); $this->assertNull($response->getMessage()); } @@ -79,7 +89,7 @@ public function testSendWrongAmount() $this->request->setApiLoginId('user'); $this->request->setHashSecret('shhh'); - // In the callback, the merchant application sets the amount that + // In the notify, the merchant application sets the amount that // was expected to be authorised. We expected 20.00 but are being // told it was 10.00. diff --git a/tests/Message/SIMCompleteAuthorizeRequestTest.php b/tests/Message/SIMCompleteAuthorizeRequestTest.php index 64af2144..840e7424 100644 --- a/tests/Message/SIMCompleteAuthorizeRequestTest.php +++ b/tests/Message/SIMCompleteAuthorizeRequestTest.php @@ -42,17 +42,25 @@ public function testSend() 'x_trans_id' => $posted_trans_id, 'x_amount' => $posted_amount, 'x_MD5_Hash' => md5('shhh' . 'user' . $posted_trans_id . $posted_amount), + 'omnipay_transaction_id' => '99', ) ); $this->request->setApiLoginId('user'); $this->request->setHashSecret('shhh'); $this->request->setAmount('10.00'); - //$this->request->setTransactionId(99); + $this->request->setReturnUrl('http://example.com/'); + + // Issue #22 Transaction ID in request is picked up from custom field. + $this->assertSame('99', $this->request->getTransactionId()); $response = $this->request->send(); $this->assertTrue($response->isSuccessful()); $this->assertSame($posted_trans_id, $response->getTransactionReference()); + $this->assertSame(true, $response->isRedirect()); + // CHECKME: does it matter what letter case the method is? + $this->assertSame('GET', $response->getRedirectMethod()); + $this->assertSame('http://example.com/', $response->getRedirectUrl()); $this->assertNull($response->getMessage()); } } From e2c25ff083f905ef11c3df6b9cf992b1aec9c923 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 7 Jul 2015 19:18:12 +0100 Subject: [PATCH 083/254] Issue #22 Typo and additional comment. --- src/Message/SIMCompleteAuthorizeResponse.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Message/SIMCompleteAuthorizeResponse.php b/src/Message/SIMCompleteAuthorizeResponse.php index b32cdd52..b7270d34 100644 --- a/src/Message/SIMCompleteAuthorizeResponse.php +++ b/src/Message/SIMCompleteAuthorizeResponse.php @@ -85,8 +85,10 @@ public function getRedirectData() /** * Authorize.Net requires a redirect in a HTML page. * The OmniPay redirect helper will only provide a HTML page for the POST method - * and then implements that through a self-sbmitting form. This will generate - * browser warnings if returning to a non-SSL page. + * and then implements that through a self-submitting form, which will generate + * browser warnings if returning to a non-SSL page. This JavScript and meta refresh + * page avoids the security warning. No data is sent in this redirect, as that will + * have all been saved with the transaction in storage. */ public function getRedirectResponse() { From 1aad9da6999163c9680cc150baa9e6b52cbbba16 Mon Sep 17 00:00:00 2001 From: Kayla Daniels Date: Mon, 27 Jul 2015 11:20:48 -0400 Subject: [PATCH 084/254] Update Endpoint --- src/AIMGateway.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index c4c354f7..09cfdb39 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -21,7 +21,7 @@ public function getDefaultParameters() 'transactionKey' => '', 'testMode' => false, 'developerMode' => false, - 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', + 'liveEndpoint' => 'https://secure2.authorize.net/gateway/transact.dll', 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', ); } From 70e6c9c5f3de1a6a0b5d6b81ed8753d00bd09e90 Mon Sep 17 00:00:00 2001 From: Sachin Sudheendra Date: Thu, 27 Aug 2015 14:20:57 +0530 Subject: [PATCH 085/254] XOL-2533 Adding extraOptions payload to request XML extraOptions to set duplicate request window to 0 (in seconds), i.e. to disable the feature. --- src/Message/CIMAuthorizeRequest.php | 13 ++++++++++--- tests/Message/CIMAuthorizeRequestTest.php | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index b2bcecee..06e9896d 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -14,10 +14,18 @@ class CIMAuthorizeRequest extends CIMAbstractRequest public function getData() { $this->validate('cardReference', 'amount'); - $data = $this->getBaseData(); - $this->addTransactionData($data); + $this->addExtraOptions($data); + return $data; + } + + private function addExtraOptions(\SimpleXMLElement $data) + { + $extraOptions = $data->addChild('extraOptions'); + $node = dom_import_simplexml($extraOptions); + $nodeOwner = $node->ownerDocument; + $node->appendChild($nodeOwner->createCDATASection("x_duplicate_window=0")); return $data; } @@ -45,7 +53,6 @@ protected function addTransactionData(\SimpleXMLElement $data) if (!empty($desc)) { $action->order->description = $desc; } - return $data; } diff --git a/tests/Message/CIMAuthorizeRequestTest.php b/tests/Message/CIMAuthorizeRequestTest.php index dcfd2e56..c9b2b86a 100644 --- a/tests/Message/CIMAuthorizeRequestTest.php +++ b/tests/Message/CIMAuthorizeRequestTest.php @@ -31,4 +31,10 @@ public function testGetData() $this->assertEquals('27057151', $data->transaction->profileTransAuthOnly->customerShippingAddressId); $this->assertEquals('Test authorize transaction', $data->transaction->profileTransAuthOnly->order->description); } + + public function testShouldReturnExtraOptionsToDisableDuplicateWindowPeriod() + { + $data = $this->request->getData(); + $this->assertEquals('x_duplicate_window=0', strip_tags($data->extraOptions)); + } } From 23fbedcacc9c6eaaaebaa4ec09ee448870fdf758 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Thu, 27 Aug 2015 14:38:36 +0100 Subject: [PATCH 086/254] Include omnipay_transaction_id in hidden fields for the DPM form. --- src/Message/DPMResponse.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Message/DPMResponse.php b/src/Message/DPMResponse.php index 2a1f59c9..76298bb3 100644 --- a/src/Message/DPMResponse.php +++ b/src/Message/DPMResponse.php @@ -59,6 +59,9 @@ class DPMResponse extends AbstractResponse implements RedirectResponseInterface 'x_email_customer', 'x_delim_data', + + // Custom omnipay field. + 'omnipay_transaction_id', ); /** From 87a39f0c23ab9dc10584287cb2e5f168cb89d927 Mon Sep 17 00:00:00 2001 From: Sachin Sudheendra Date: Fri, 28 Aug 2015 15:58:47 +0530 Subject: [PATCH 087/254] XOL-2533 Parameterizing x_duplicate_window value and using it across AIM and CIM Application needs to pass parameter "duplicateWindow=x" which when not null will be sent as extra options with the request. --- .gitignore | 1 + src/Message/AIMAbstractRequest.php | 21 +++++++++++++++++++++ src/Message/AIMAuthorizeRequest.php | 1 + src/Message/CIMAuthorizeRequest.php | 9 --------- tests/Message/AIMAuthorizeRequestTest.php | 7 +++++++ tests/Message/CIMAuthorizeRequestTest.php | 3 ++- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 8a282a56..0d77fdb3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ composer.lock composer.phar phpunit.xml +.idea diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 4cd747ac..4031355d 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -53,6 +53,27 @@ public function setCustomerId($value) return $this->setParameter('customerId', $value); } + public function setDuplicateWindow($value) + { + $this->setParameter('duplicateWindow', $value); + } + + private function getDuplicateWindow() + { + return $this->getParameter('duplicateWindow'); // Maps x_duplicate_window + } + + protected function addExtraOptions(\SimpleXMLElement $data) + { + if (!is_null($this->getDuplicateWindow())) { + $extraOptions = $data->addChild('extraOptions'); + $node = dom_import_simplexml($extraOptions); + $nodeOwner = $node->ownerDocument; + $node->appendChild($nodeOwner->createCDATASection("x_duplicate_window=0")); + } + return $data; + } + /** * @return mixed|\SimpleXMLElement * @throws \Omnipay\Common\Exception\InvalidRequestException diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 915ce990..310bf0a5 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -31,6 +31,7 @@ public function getData() $this->addBillingData($data); $this->addTestModeSetting($data); + $this->addExtraOptions($data); return $data; } diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index 06e9896d..d8663014 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -20,15 +20,6 @@ public function getData() return $data; } - private function addExtraOptions(\SimpleXMLElement $data) - { - $extraOptions = $data->addChild('extraOptions'); - $node = dom_import_simplexml($extraOptions); - $nodeOwner = $node->ownerDocument; - $node->appendChild($nodeOwner->createCDATASection("x_duplicate_window=0")); - return $data; - } - /** * Adds transaction data * diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 92a6ac0f..63520b42 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -18,6 +18,7 @@ public function setUp() 'amount' => '12.00', 'customerId' => 'cust-id', 'card' => $this->getValidCard(), + 'duplicateWindow' => 0 ) ); } @@ -45,4 +46,10 @@ public function testGetDataTestMode() $this->assertEquals('testRequest', $setting->settingName); $this->assertEquals('true', $setting->settingValue); } + + public function testShouldReturnExtraOptionsToDisableDuplicateWindowPeriod() + { + $data = $this->request->getData(); + $this->assertEquals('x_duplicate_window=0', strip_tags($data->extraOptions)); + } } diff --git a/tests/Message/CIMAuthorizeRequestTest.php b/tests/Message/CIMAuthorizeRequestTest.php index c9b2b86a..c75aeed1 100644 --- a/tests/Message/CIMAuthorizeRequestTest.php +++ b/tests/Message/CIMAuthorizeRequestTest.php @@ -16,7 +16,8 @@ public function setUp() array( 'cardReference' => '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}', 'amount' => '12.00', - 'description' => 'Test authorize transaction' + 'description' => 'Test authorize transaction', + 'duplicateWindow' => '0' ) ); } From 6bfdef78c6627c476fabbb8ce6661d6afa6bdfc7 Mon Sep 17 00:00:00 2001 From: Sachin Sudheendra Date: Thu, 10 Sep 2015 16:51:35 +0530 Subject: [PATCH 088/254] XOL-2533 Using the value of the parameter passed in for x_duplicate_window --- src/Message/AIMAbstractRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 4031355d..016c705c 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -69,7 +69,7 @@ protected function addExtraOptions(\SimpleXMLElement $data) $extraOptions = $data->addChild('extraOptions'); $node = dom_import_simplexml($extraOptions); $nodeOwner = $node->ownerDocument; - $node->appendChild($nodeOwner->createCDATASection("x_duplicate_window=0")); + $node->appendChild($nodeOwner->createCDATASection(sprintf("x_duplicate_window=%s", $this->getDuplicateWindow()))); } return $data; } From 9af958e64c568d8a38685573710567ab0bb6471f Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Tue, 23 Feb 2016 13:40:17 +0530 Subject: [PATCH 089/254] Fix CodeSniffer issue. Line should be <= 120 chars --- src/Message/AIMAbstractRequest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 016c705c..86518d9f 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -69,7 +69,8 @@ protected function addExtraOptions(\SimpleXMLElement $data) $extraOptions = $data->addChild('extraOptions'); $node = dom_import_simplexml($extraOptions); $nodeOwner = $node->ownerDocument; - $node->appendChild($nodeOwner->createCDATASection(sprintf("x_duplicate_window=%s", $this->getDuplicateWindow()))); + $duplicateWindowStr = sprintf("x_duplicate_window=%s", $this->getDuplicateWindow()); + $node->appendChild($nodeOwner->createCDATASection($duplicateWindowStr)); } return $data; } From 131d7cfe9dac297ca8edfb89526124f78da001ae Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Tue, 23 Feb 2016 14:25:32 +0530 Subject: [PATCH 090/254] Fix test that failed due to change in SIMGateway's parent --- src/SIMGateway.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SIMGateway.php b/src/SIMGateway.php index 1e3281de..48619a30 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -21,7 +21,9 @@ public function getDefaultParameters() 'transactionKey' => '', 'testMode' => false, 'developerMode' => false, - 'hashSecret' => '' + 'hashSecret' => '', + 'liveEndpoint' => 'https://secure2.authorize.net/gateway/transact.dll', + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', ); } From 44e7a06afb666b67b3e0fc615ea9a13a7eee4375 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Tue, 23 Feb 2016 14:40:54 +0530 Subject: [PATCH 091/254] SIMGateway should inherit AIMGateway --- src/Message/AIMAbstractRequest.php | 9 +++++++++ src/SIMGateway.php | 16 ++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 86518d9f..19429034 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -53,6 +53,15 @@ public function setCustomerId($value) return $this->setParameter('customerId', $value); } + public function getHashSecret() + { + return $this->getParameter('hashSecret'); + } + public function setHashSecret($value) + { + return $this->setParameter('hashSecret', $value); + } + public function setDuplicateWindow($value) { $this->setParameter('duplicateWindow', $value); diff --git a/src/SIMGateway.php b/src/SIMGateway.php index 48619a30..23f1941e 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -2,12 +2,10 @@ namespace Omnipay\AuthorizeNet; -use Omnipay\Common\AbstractGateway; - /** * Authorize.Net SIM Class */ -class SIMGateway extends AbstractGateway +class SIMGateway extends AIMGateway { public function getName() { @@ -16,15 +14,9 @@ public function getName() public function getDefaultParameters() { - return array( - 'apiLoginId' => '', - 'transactionKey' => '', - 'testMode' => false, - 'developerMode' => false, - 'hashSecret' => '', - 'liveEndpoint' => 'https://secure2.authorize.net/gateway/transact.dll', - 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', - ); + $parameters = parent::getDefaultParameters(); + $parameters['hashSecret'] = ''; + return $parameters; } public function getApiLoginId() From 566cdddd0178599b66e91cf718e3adc1467f9977 Mon Sep 17 00:00:00 2001 From: Mike Almond Date: Thu, 25 Feb 2016 14:32:46 -0500 Subject: [PATCH 092/254] [AIMRefund] Pass credit card expiration date only when an expiration was set Authorize.Net does not require the expiration date when performing refunds. When no expiration is passed in and a refund request is made, the response comes back with an error saying the card has expired. This check makes it so the expiration date is only sent when a valid expiry date is passed in to the request parameters. > At least the last four digits of the credit card number (x_card_num) used for the original, successfully settled transaction are submitted. An expiration date is not required. --- src/Message/AIMRefundRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index 654c9c55..9223e6e7 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -17,7 +17,9 @@ public function getData() $data['x_trans_id'] = $this->getTransactionReference(); $data['x_card_num'] = $this->getCard()->getNumber(); - $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); + if (!empty($this->getCard()->getExpiryMonth())) { + $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); + } $data['x_amount'] = $this->getAmount(); return $data; From b24ebe8db37e8eb562a788deaef27c707868afbb Mon Sep 17 00:00:00 2001 From: Mike Almond Date: Thu, 25 Feb 2016 15:35:21 -0500 Subject: [PATCH 093/254] AIMRefund fix PHP < 5.5 bugs --- src/Message/AIMRefundRequest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index 9223e6e7..9b14a0b4 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -17,9 +17,12 @@ public function getData() $data['x_trans_id'] = $this->getTransactionReference(); $data['x_card_num'] = $this->getCard()->getNumber(); - if (!empty($this->getCard()->getExpiryMonth())) { + + $expiryMonth = $this->getCard()->getExpiryMonth(); + if (!empty($expiryMonth)) { $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); } + $data['x_amount'] = $this->getAmount(); return $data; From 84b2c3f4a1ce79232d5d7e0faa9b4267e3f0157c Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Mon, 29 Feb 2016 22:57:27 +0530 Subject: [PATCH 094/254] Make CVV optional --- composer.json | 8 +++++- .../CIMAbstractCustomerProfileRequest.php | 26 +++++++++++++++++++ src/Message/CIMCreateCardRequest.php | 10 ++++--- 3 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/Message/CIMAbstractCustomerProfileRequest.php diff --git a/composer.json b/composer.json index 70b4d099..59a25f1a 100644 --- a/composer.json +++ b/composer.json @@ -24,11 +24,17 @@ "homepage": "https://github.com/thephpleague/omnipay-authorizenet/contributors" } ], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/xola/omnipay-common" + } + ], "autoload": { "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "~2.0" + "omnipay/common": "~2.4.2" }, "require-dev": { "omnipay/tests": "~2.0" diff --git a/src/Message/CIMAbstractCustomerProfileRequest.php b/src/Message/CIMAbstractCustomerProfileRequest.php new file mode 100644 index 00000000..eb6ab6c6 --- /dev/null +++ b/src/Message/CIMAbstractCustomerProfileRequest.php @@ -0,0 +1,26 @@ +setParameter('validationMode', $value); + } + + public function getValidationMode() + { + $validationMode = $this->getParameter('validationMode'); + if($validationMode !== self::VALIDATION_MODE_NONE) { + $validationMode = $this->getDeveloperMode() ? self::VALIDATION_MODE_TEST : self::VALIDATION_MODE_LIVE; + } + return $validationMode; + } +} \ No newline at end of file diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index a059c85b..0eaa9e33 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -2,12 +2,13 @@ namespace Omnipay\AuthorizeNet\Message; +use Message\CIMAbstractCustomerProfileRequest; use Omnipay\Common\CreditCard; /** * Create Credit Card Request. */ -class CIMCreateCardRequest extends CIMAbstractRequest +class CIMCreateCardRequest extends CIMAbstractCustomerProfileRequest { protected $xmlRootElement = 'createCustomerProfileRequest'; @@ -103,7 +104,9 @@ protected function addBillingData(\SimpleXMLElement $data) $req = $data->addChild('payment'); $req->creditCard->cardNumber = $card->getNumber(); $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); - $req->creditCard->cardCode = $card->getCvv(); + if ($card->getCvv()) { + $req->creditCard->cardCode = $card->getCvv(); + } } } @@ -145,8 +148,7 @@ protected function addShippingData(\SimpleXMLElement $data) protected function addTestModeSetting(\SimpleXMLElement $data) { - // Test mode setting - $data->validationMode = $this->getDeveloperMode() ? 'testMode' : 'liveMode'; + $data->validationMode = $this->getValidationMode(); } public function sendData($data) From a0de700704eadcea33c42f06f2a6d4c523f6cb7b Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Tue, 1 Mar 2016 10:48:16 +0530 Subject: [PATCH 095/254] Fix codesniffer and namespace issues --- src/Message/CIMAbstractCustomerProfileRequest.php | 8 +++----- src/Message/CIMCreateCardRequest.php | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Message/CIMAbstractCustomerProfileRequest.php b/src/Message/CIMAbstractCustomerProfileRequest.php index eb6ab6c6..98676dd2 100644 --- a/src/Message/CIMAbstractCustomerProfileRequest.php +++ b/src/Message/CIMAbstractCustomerProfileRequest.php @@ -1,8 +1,6 @@ getParameter('validationMode'); - if($validationMode !== self::VALIDATION_MODE_NONE) { + if ($validationMode !== self::VALIDATION_MODE_NONE) { $validationMode = $this->getDeveloperMode() ? self::VALIDATION_MODE_TEST : self::VALIDATION_MODE_LIVE; } return $validationMode; } -} \ No newline at end of file +} diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 0eaa9e33..8dd742d7 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -2,7 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Message\CIMAbstractCustomerProfileRequest; use Omnipay\Common\CreditCard; /** From 35fc3a7f151db31dc5d5139534751fb625d94618 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Tue, 1 Mar 2016 19:44:10 +0530 Subject: [PATCH 096/254] Do not validate card if no cvv provided --- src/Message/CIMCreateCardRequest.php | 2 + tests/Message/CIMCreateCardRequestTest.php | 49 ++++++++++++---------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 8dd742d7..a456de34 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -105,6 +105,8 @@ protected function addBillingData(\SimpleXMLElement $data) $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); if ($card->getCvv()) { $req->creditCard->cardCode = $card->getCvv(); + } else { + $this->setValidationMode(self::VALIDATION_MODE_NONE); } } } diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index 340b92b7..92911b00 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -8,23 +8,23 @@ class CIMCreateCardRequestTest extends TestCase { /** @var CIMCreateCardRequest */ protected $request; + private $params; public function setUp() { $this->request = new CIMCreateCardRequest($this->getHttpClient(), $this->getHttpRequest()); - $this->request->initialize( - array( - 'email' => "kaylee@serenity.com", - 'card' => $this->getValidCard(), - 'developerMode' => true - ) + $this->params = array( + 'email' => "kaylee@serenity.com", + 'card' => $this->getValidCard(), + 'developerMode' => true ); + $this->request->initialize($this->params); } public function testGetData() { $data = $this->request->getData(); - $card = $this->getValidCard(); + $card = $this->params['card']; $this->assertEquals('12345', $data->profile->paymentProfiles->billTo->zip); $this->assertEquals($card['number'], $data->profile->paymentProfiles->payment->creditCard->cardNumber); $this->assertEquals('testMode', $data->validationMode); @@ -32,26 +32,31 @@ public function testGetData() public function testGetDataShouldHaveCustomBillTo() { - $card = $this->getValidCard(); - unset($card['billingAddress1']); - unset($card['billingAddress2']); - unset($card['billingCity']); - $this->request->initialize( - array( - 'email' => "kaylee@serenity.com", - 'card' => $card, - 'developerMode' => true, - 'forceCardUpdate' => true, - 'defaultBillTo' => array( - 'address' => '1234 Test Street', - 'city' => 'Blacksburg' - ) - ) + unset($this->params['card']['billingAddress1']); + unset($this->params['card']['billingAddress2']); + unset($this->params['card']['billingCity']); + $this->params['forceCardUpdate'] = true; + $this->params['defaultBillTo'] = array( + 'address' => '1234 Test Street', + 'city' => 'Blacksburg' ); + $this->request->initialize($this->params); $data = $this->request->getData(); + $this->assertEquals('12345', $data->profile->paymentProfiles->billTo->zip); $this->assertEquals('1234 Test Street', $data->profile->paymentProfiles->billTo->address); $this->assertEquals('Blacksburg', $data->profile->paymentProfiles->billTo->city); } + + public function testGetDataShouldSetValidationModeToNoneIfNoCvvProvided() + { + unset($this->params['card']['cvv']); + $this->request->initialize($this->params); + + $data = $this->request->getData(); + + $this->assertFalse(isset($data->profile->paymentProfiles->payment->creditCard->cardCode)); + $this->assertEquals(CIMCreatePaymentProfileRequest::VALIDATION_MODE_NONE, $this->request->getValidationMode()); + } } From 68d43820a393110a9e814b79a817af6666b59f8c Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 2 Mar 2016 12:49:26 +0530 Subject: [PATCH 097/254] CS-137 Look for duplicate payment profiles even if you reach maximum profile limit Normally if a duplicate payment profile exists, Authorize.net will return Error code E00039. But if the customer has the maximum number of payment profiles (10), then AUthorize.net will return E00042. So whenever we receive E00042 we need to check the existing payment profile list to see if there is a duplicate profile. --- src/Message/CIMCreateCardRequest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index a059c85b..ae608015 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -202,11 +202,13 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) $getProfileResponse = $this->makeGetProfileRequest($parameters); + // Check if there is a pre-existing profile for the given card numbers. + $otherErrorCodes = ['E00039', 'E00042']; // For these error codes we should check for duplicate payment profiles if (!$createPaymentProfileResponse->isSuccessful() && - $createPaymentProfileResponse->getReasonCode() == 'E00039' + in_array($createPaymentProfileResponse->getReasonCode(), $otherErrorCodes) ) { - // Found a duplicate payment profile existing for the same card data. Force update is turned on, - // So find matching payment profile id from the customer profile and update it. + // There is a possibility of a duplicate payment profile, so find matching payment profile id + // from the customer profile and update it. $card = $this->getCard(); $last4 = substr($card->getNumber(), -4); From 4d5c93a78ab045729f365e8b82dd2be301e8ede7 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 2 Mar 2016 13:23:37 +0530 Subject: [PATCH 098/254] CS-137 Use PHP 5.3 array() syntax so tests pass --- src/Message/CIMCreateCardRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index ae608015..10bef230 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -203,7 +203,7 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) $getProfileResponse = $this->makeGetProfileRequest($parameters); // Check if there is a pre-existing profile for the given card numbers. - $otherErrorCodes = ['E00039', 'E00042']; // For these error codes we should check for duplicate payment profiles + $otherErrorCodes = array('E00039', 'E00042'); // For these codes we should check for duplicate payment profiles if (!$createPaymentProfileResponse->isSuccessful() && in_array($createPaymentProfileResponse->getReasonCode(), $otherErrorCodes) ) { From d1e7f1053b38e267e01af0f1fd56fb8a8ee72236 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 2 Mar 2016 15:26:37 +0530 Subject: [PATCH 099/254] CS-137 Add tests for verification of duplicate payment profile logic --- tests/CIMGatewayTest.php | 50 ++++++++++++++++++- tests/Mock/CIMCreatePaymentProfileFailure.txt | 2 +- ...tePaymentProfileFailureMaxProfileLimit.txt | 14 ++++++ tests/Mock/CIMGetProfileSuccess.txt | 2 +- tests/Mock/CIMUpdatePaymentProfileSuccess.txt | 2 +- 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 141d06f1..74c9d8ef 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -23,7 +23,8 @@ public function setUp() $this->createCardOptions = array( 'email' => "kaylee@serenity.com", 'card' => $this->getValidCard(), - 'testMode' => true + 'testMode' => true, + 'forceCardUpdate' => true ); $this->authorizeOptions = array( @@ -59,6 +60,53 @@ public function testCreateCardSuccess() $this->assertSame('Successful.', $response->getMessage()); } + public function testShouldCreateCardIfDuplicateCustomerProfileExists() + { + $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt', + 'CIMGetProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + + $response = $this->gateway->createCard($this->createCardOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"customerProfileId":"28775801","customerPaymentProfileId":"26485433"}', + $response->getCardReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + + public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndForceCardUpdateIsSet() + { + // Duplicate **payment** profile + $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileFailure.txt', + 'CIMGetProfileSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + + $response = $this->gateway->createCard($this->createCardOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"customerProfileId":"28775801","customerPaymentProfileId":"26485433"}', + $response->getCardReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + + public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndMaxPaymentProfileLimitIsMet() + { + $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', + 'CIMCreatePaymentProfileFailureMaxProfileLimit.txt', 'CIMGetProfileSuccess.txt', + 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + + $response = $this->gateway->createCard($this->createCardOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"customerProfileId":"28775801","customerPaymentProfileId":"26485433"}', + $response->getCardReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + public function testCreateCardFailure() { $this->setMockHttpResponse('CIMCreateCardFailure.txt'); diff --git a/tests/Mock/CIMCreatePaymentProfileFailure.txt b/tests/Mock/CIMCreatePaymentProfileFailure.txt index c7791c3c..91b28e6c 100644 --- a/tests/Mock/CIMCreatePaymentProfileFailure.txt +++ b/tests/Mock/CIMCreatePaymentProfileFailure.txt @@ -11,4 +11,4 @@ Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET,POST,OPTIONS Date: Thu, 18 Sep 2014 03:59:27 GMT -ErrorE00039A duplicate customer payment profile already exists.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,none,,,,,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, +ErrorE00039A duplicate customer payment profile already exists.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,none,,,,,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, diff --git a/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt b/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt new file mode 100644 index 00000000..98b69db6 --- /dev/null +++ b/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +ErrorE00042You cannot add more than 10 payment profiles.1,1,1,This transaction has been approved.,03305Y,Z,9044060115,none,Test transaction for ValidateCustomerPaymentProfile.,0.00,CC,auth_only,none,John Doe,,,None provided,,,12345,,,,email@example.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,C01815A69AE1AC538B4F16A4C17DD88C,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,, diff --git a/tests/Mock/CIMGetProfileSuccess.txt b/tests/Mock/CIMGetProfileSuccess.txt index 0c7f5fbe..8fedf2f1 100644 --- a/tests/Mock/CIMGetProfileSuccess.txt +++ b/tests/Mock/CIMGetProfileSuccess.txt @@ -11,4 +11,4 @@ Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET,POST,OPTIONS Date: Thu, 18 Sep 2014 03:59:27 GMT -OkI00001Successful.kaylee@serenity.com28775801
1234526455656XXXX1111XXXX
1234526455709XXXX8888XXXX +OkI00001Successful.kaylee@serenity.com28775801
1234526455656XXXX1111XXXX
1234526455709XXXX8888XXXX diff --git a/tests/Mock/CIMUpdatePaymentProfileSuccess.txt b/tests/Mock/CIMUpdatePaymentProfileSuccess.txt index bb760503..348ab7e0 100644 --- a/tests/Mock/CIMUpdatePaymentProfileSuccess.txt +++ b/tests/Mock/CIMUpdatePaymentProfileSuccess.txt @@ -11,4 +11,4 @@ Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET,POST,OPTIONS Date: Thu, 18 Sep 2014 03:59:27 GMT -OkI00001Successful.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,,,,,,,,12345,,,,kaylee@serenity.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, +OkI00001Successful.1,1,1,(TESTMODE) This transaction has been approved.,000000,P,0,none,Test transaction for ValidateCustomerPaymentProfile.,1.00,CC,auth_only,,,,,,,,12345,,,,kaylee@serenity.com,,,,,,,,,0.00,0.00,0.00,FALSE,none,9ACE39F249AB996589D58E6FCCCFFFA3,,,,,,,,,,,,,XXXX8888,Visa,,,,,,,,,,,,,,,, From 10442c69e81c8999e64a9ce495edb678c4bf4018 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Wed, 2 Mar 2016 15:30:02 +0530 Subject: [PATCH 100/254] CS-137 Set constants for the profile response codes --- src/Message/CIMCreateCardRequest.php | 6 +++++- src/Message/CIMGetProfileResponse.php | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 10bef230..e46cb45b 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -203,7 +203,11 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) $getProfileResponse = $this->makeGetProfileRequest($parameters); // Check if there is a pre-existing profile for the given card numbers. - $otherErrorCodes = array('E00039', 'E00042'); // For these codes we should check for duplicate payment profiles + // For these codes we should check for duplicate payment profiles + $otherErrorCodes = array( + CIMGetProfileResponse::ERROR_DUPLICATE_PROFILE, + CIMGetProfileResponse::ERROR_MAX_PAYMENT_PROFILE_LIMIT_REACHED + ); if (!$createPaymentProfileResponse->isSuccessful() && in_array($createPaymentProfileResponse->getReasonCode(), $otherErrorCodes) ) { diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index 18a91232..a3a8f3e0 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -7,6 +7,9 @@ */ class CIMGetProfileResponse extends CIMCreatePaymentProfileResponse { + const ERROR_DUPLICATE_PROFILE = 'E00039'; + const ERROR_MAX_PAYMENT_PROFILE_LIMIT_REACHED = 'E00042'; + protected $xmlRootElement = 'getCustomerProfileResponse'; /** From 0d5b940e640c8d4195913ac92652619dba39e7ad Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 3 Mar 2016 14:44:19 +0530 Subject: [PATCH 101/254] XOL-2788 Ability to void a transaction and auto-void if refund fails --- src/Message/CIMAbstractRequest.php | 9 ++++++++ src/Message/CIMAbstractResponse.php | 17 +++++++++++++- src/Message/CIMRefundRequest.php | 35 +++++++++++++++++++++++++++++ src/Message/CIMResponse.php | 5 +++++ src/Message/CIMVoidRequest.php | 4 ++-- tests/CIMGatewayIntegrationTest.php | 1 + tests/CIMGatewayTest.php | 16 ++++++++++--- tests/Message/CIMResponseTest.php | 8 +++++++ tests/Mock/CIMVoidResponse.txt | 13 +++++++++++ 9 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 tests/Mock/CIMVoidResponse.txt diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 8886498e..8881449e 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -93,4 +93,13 @@ public function getBaseData() return $data; } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMResponse($this, $httpResponse->getBody()); + } } diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index 13be97c8..fc5e0ead 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -10,7 +10,7 @@ /** * Authorize.Net CIM Response */ -class CIMAbstractResponse extends AbstractResponse +abstract class CIMAbstractResponse extends AbstractResponse { protected $xmlRootElement = null; @@ -79,6 +79,21 @@ public function getReasonCode() return $code; } + /** + * A reason code is the a part of the "directResponse" attribute returned by Authorize.net. This is the third + * element within the "directResponse" attribute which is a CSV string. + */ + public function getResponseReasonCode() + { + $responseCode = null; + if (isset($this->data['directResponse'])) { + $directResponse = explode(',', (string)$this->data['directResponse']); + $responseCode = $directResponse[2]; + } + + return $responseCode; + } + /** * Text description of the status. * diff --git a/src/Message/CIMRefundRequest.php b/src/Message/CIMRefundRequest.php index 88b23649..4060467a 100644 --- a/src/Message/CIMRefundRequest.php +++ b/src/Message/CIMRefundRequest.php @@ -9,6 +9,24 @@ class CIMRefundRequest extends CIMCaptureRequest { protected $action = "profileTransRefund"; + protected $voidIfRefundFails = false; + + /** + * @return boolean + */ + public function isVoidIfRefundFails() + { + return $this->voidIfRefundFails; + } + + /** + * @param boolean $voidIfRefundFails + */ + public function setVoidIfRefundFails($voidIfRefundFails) + { + $this->voidIfRefundFails = $voidIfRefundFails; + } + /** * Adds reference for original transaction to a partially filled request data object. * @@ -25,4 +43,21 @@ protected function addTransactionReferenceData(\SimpleXMLElement $data) $action->transId = $transRef['transId']; return $data; } + + public function send() + { + /** @var CIMResponse $response */ + $response = parent::send(); + $parameters = $this->getParameters(); + + if (!$response->isSuccessful() && $this->voidIfRefundFails && + intval($response->getResponseReasonCode()) === CIMResponse::ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT) { + // An attempt to a refund a transaction that was not settled. We can just void the entire transaction + $voidRequest = new CIMVoidRequest($this->httpClient, $this->httpRequest); + $voidRequest->initialize($parameters); + $response = $voidRequest->send(); + } + + return $response; + } } diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index 72ef4205..f8fc8f49 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -7,6 +7,11 @@ */ class CIMResponse extends CIMAbstractResponse { + /** + * For Error codes: @see https://developer.authorize.net/api/reference/responseCodes.html + */ + const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = 54; + protected $xmlRootElement = 'createCustomerProfileTransactionResponse'; public function getTransactionReference() diff --git a/src/Message/CIMVoidRequest.php b/src/Message/CIMVoidRequest.php index 0d153837..9de7804b 100644 --- a/src/Message/CIMVoidRequest.php +++ b/src/Message/CIMVoidRequest.php @@ -7,6 +7,7 @@ */ class CIMVoidRequest extends CIMAbstractRequest { + protected $xmlRootElement = 'createCustomerProfileTransactionRequest'; protected $action = 'voidTransaction'; public function getData() @@ -14,8 +15,7 @@ public function getData() $this->validate('transactionReference'); $data = $this->getBaseData(); - $data->transactionRequest->refTransId = $this->getTransactionReference(); - $this->addTestModeSetting($data); + $data->transaction->profileTransVoid->transId = $this->getTransactionReference(); return $data; } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 2b67de5b..d37d5648 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -174,5 +174,6 @@ public function testAuthorizeAndVoid() $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + $this->assertEquals('Successful.', $response->getMessage()); } } diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 74c9d8ef..9c259779 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -220,12 +220,22 @@ public function testRefundFailure() $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull( - $response->getTransactionReference() - ); + $this->assertNull($response->getTransactionReference()); $this->assertSame( 'The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage() ); } + + public function testShouldVoidIfRefundFailedWithResponseError54() + { + $this->setMockHttpResponse(array('CIMRefundFailure.txt', 'CIMVoidResponse.txt')); + $this->refundOptions['voidIfRefundFails'] = true; + + $response = $this->gateway->refund($this->refundOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertNotNull($response->getTransactionReference()); + $this->assertEquals('Successful.', $response->getMessage()); + } } diff --git a/tests/Message/CIMResponseTest.php b/tests/Message/CIMResponseTest.php index bc587f95..429853ea 100644 --- a/tests/Message/CIMResponseTest.php +++ b/tests/Message/CIMResponseTest.php @@ -29,4 +29,12 @@ public function testGetTransactionReference() $response->getTransactionReference() ); } + + public function testShouldReturnResponseReasonCodeFromDirectResponse() + { + $httpResponse = $this->getMockHttpResponse('CIMRefundFailure.txt')->getBody(); + $response = new CIMResponse($this->getMockRequest(), $httpResponse); + + $this->assertEquals(54, $response->getResponseReasonCode()); + } } diff --git a/tests/Mock/CIMVoidResponse.txt b/tests/Mock/CIMVoidResponse.txt new file mode 100644 index 00000000..15d16ceb --- /dev/null +++ b/tests/Mock/CIMVoidResponse.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Sat, 02 Aug 2014 06:07:08 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 836 + +OkI00001Successful.1,1,1,This transaction has been approved.,4A6ZAK,P,2252208237,,,0.00,CC,void,,,,,,,,12345,,,,,,,,,,,,,,,,,,0E3D23E0BB8AD22BDFD412B205E42308,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,, From b6edd12cb8ca5c10fdeed48e095df2dd1e73087b Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 3 Mar 2016 15:12:34 +0530 Subject: [PATCH 102/254] XOL-2788 Fix transactionReference bug --- src/Message/CIMVoidRequest.php | 5 ++++- tests/CIMGatewayIntegrationTest.php | 5 +---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Message/CIMVoidRequest.php b/src/Message/CIMVoidRequest.php index 9de7804b..ab5d614d 100644 --- a/src/Message/CIMVoidRequest.php +++ b/src/Message/CIMVoidRequest.php @@ -15,7 +15,10 @@ public function getData() $this->validate('transactionReference'); $data = $this->getBaseData(); - $data->transaction->profileTransVoid->transId = $this->getTransactionReference(); + $transRef = json_decode($this->getTransactionReference(), true); + if (is_array($transRef) && isset($transRef['transId'])) { + $data->transaction->profileTransVoid->transId = $transRef["transId"]; + } return $data; } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index d37d5648..169f1378 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -164,11 +164,8 @@ public function testAuthorizeAndVoid() $this->assertTrue($response->isSuccessful(), 'Purchase transaction should get created'); $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); - $transactionRef = json_decode($response->getTransactionReference(), true); - // Make a refund on the purchase transaction - $params = array('transactionReference' => $transactionRef['transId']); - $request = $this->gateway->void($params); + $request = $this->gateway->void(['transactionReference' => $response->getTransactionReference()]); $request->setDeveloperMode(true); $response = $request->send(); From 599386ef6cd64981cafb774d7360732859a663f7 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 3 Mar 2016 15:32:46 +0530 Subject: [PATCH 103/254] XOL-2788 Fix array syntax for PHP 5.3 compatibility --- tests/CIMGatewayIntegrationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 169f1378..0b144953 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -165,7 +165,7 @@ public function testAuthorizeAndVoid() $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); // Make a refund on the purchase transaction - $request = $this->gateway->void(['transactionReference' => $response->getTransactionReference()]); + $request = $this->gateway->void(array('transactionReference' => $response->getTransactionReference())); $request->setDeveloperMode(true); $response = $request->send(); From f9f1397c388ed3185d9586f393eeda5387b559c5 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 3 Mar 2016 19:19:45 +0530 Subject: [PATCH 104/254] XOL-2788 Update test name --- tests/CIMGatewayTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 9c259779..b418898f 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -227,7 +227,7 @@ public function testRefundFailure() ); } - public function testShouldVoidIfRefundFailedWithResponseError54() + public function testShouldVoidTransactionIfTryingToRefundAnUnsettledTransaction() { $this->setMockHttpResponse(array('CIMRefundFailure.txt', 'CIMVoidResponse.txt')); $this->refundOptions['voidIfRefundFails'] = true; From c7d9a7197eb5bca40dec726ac6f3e1dd1486ff56 Mon Sep 17 00:00:00 2001 From: Rushi Vishavadia Date: Thu, 3 Mar 2016 20:49:01 +0530 Subject: [PATCH 105/254] XOL-2788 Address code review comment --- src/Message/CIMRefundRequest.php | 2 +- src/Message/CIMResponse.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Message/CIMRefundRequest.php b/src/Message/CIMRefundRequest.php index 4060467a..5a76cb8e 100644 --- a/src/Message/CIMRefundRequest.php +++ b/src/Message/CIMRefundRequest.php @@ -51,7 +51,7 @@ public function send() $parameters = $this->getParameters(); if (!$response->isSuccessful() && $this->voidIfRefundFails && - intval($response->getResponseReasonCode()) === CIMResponse::ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT) { + $response->getResponseReasonCode() === CIMResponse::ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT) { // An attempt to a refund a transaction that was not settled. We can just void the entire transaction $voidRequest = new CIMVoidRequest($this->httpClient, $this->httpRequest); $voidRequest->initialize($parameters); diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index f8fc8f49..85cf8cc7 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -10,7 +10,7 @@ class CIMResponse extends CIMAbstractResponse /** * For Error codes: @see https://developer.authorize.net/api/reference/responseCodes.html */ - const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = 54; + const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = '54'; protected $xmlRootElement = 'createCustomerProfileTransactionResponse'; From e54383a28afb4df46220b3b42ff35926f0e88ee8 Mon Sep 17 00:00:00 2001 From: Mike Almond Date: Mon, 7 Mar 2016 10:31:39 -0500 Subject: [PATCH 106/254] [AIMRefundRequest] Add test when no credit card expiry dates are set --- tests/Message/AIMRefundRequestTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index 7f4671d6..a35f3a52 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -29,5 +29,24 @@ public function testGetData() $this->assertSame('60O2UZ', $data['x_trans_id']); $this->assertSame($card['number'], $data['x_card_num']); $this->assertSame('12.00', $data['x_amount']); + + $this->assertArrayHasKey('x_exp_date', $data); + } + + public function testRefundWithSimplifiedCard() + { + $simplifiedCard = array( + 'firstName' => 'Example', + 'lastName' => 'User', + 'number' => '1111', + ); + + $this->request->setCard($simplifiedCard); + + $data = $this->request->getData(); + + $this->assertSame($simplifiedCard['number'], $data['x_card_num']); + + $this->assertArrayNotHasKey('x_exp_date', $data); } } From b4d3d0935be6c08d8dd72d24b95cae3888caacaf Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 12 Mar 2016 22:19:32 +0530 Subject: [PATCH 107/254] Consolidate common functionality between AIM and CIM --- src/CIMGateway.php | 8 - src/Message/AIMAbstractRequest.php | 147 ++++++++++++------ src/Message/AIMAuthorizeRequest.php | 28 ++-- src/Message/AIMCaptureRequest.php | 2 +- src/Message/AIMRefundRequest.php | 54 +++++-- src/Message/AIMResponse.php | 47 ++++-- src/Message/AIMVoidRequest.php | 2 +- .../CIMAbstractCustomerProfileRequest.php | 24 --- src/Message/CIMAbstractRequest.php | 41 ++--- src/Message/CIMAbstractResponse.php | 10 +- src/Message/CIMAuthorizeRequest.php | 59 +++---- src/Message/CIMCaptureRequest.php | 39 +---- src/Message/CIMCreateCardRequest.php | 8 +- src/Message/CIMCreateCardResponse.php | 2 +- .../CIMCreatePaymentProfileRequest.php | 2 +- .../CIMCreatePaymentProfileResponse.php | 2 +- src/Message/CIMGetPaymentProfileRequest.php | 2 +- src/Message/CIMGetPaymentProfileResponse.php | 2 +- src/Message/CIMGetProfileRequest.php | 2 +- src/Message/CIMGetProfileResponse.php | 2 +- src/Message/CIMPurchaseRequest.php | 2 +- src/Message/CIMRefundRequest.php | 54 +------ src/Message/CIMResponse.php | 31 ---- .../CIMUpdatePaymentProfileRequest.php | 2 +- .../CIMUpdatePaymentProfileResponse.php | 2 +- src/Message/CIMVoidRequest.php | 17 +- src/Model/CardReference.php | 80 ++++++++++ src/Model/TransactionReference.php | 124 +++++++++++++++ tests/AIMGatewayIntegrationTest.php | 45 ++++-- tests/AIMGatewayTest.php | 35 +++-- tests/CIMGatewayIntegrationTest.php | 98 ++++++------ tests/CIMGatewayTest.php | 64 +++----- tests/Message/AIMAbstractRequestTest.php | 37 +++++ tests/Message/AIMRefundRequestTest.php | 40 ++--- tests/Message/AIMResponseTest.php | 30 ++-- tests/Message/CIMAuthorizeRequestTest.php | 10 +- tests/Message/CIMCaptureRequestTest.php | 12 +- tests/Message/CIMPurchaseRequestTest.php | 7 +- tests/Message/CIMRefundRequestTest.php | 14 +- tests/Message/CIMResponseTest.php | 40 ----- tests/Mock/AIMVoidFailure.txt | 4 +- tests/Mock/AIMVoidSuccess.txt | 4 +- tests/Mock/CIMAuthorizeFailure.txt | 14 -- tests/Mock/CIMAuthorizeSuccess.txt | 14 -- tests/Mock/CIMCaptureFailure.txt | 14 -- tests/Mock/CIMCaptureSuccess.txt | 14 -- tests/Mock/CIMPurchaseFailure.txt | 14 -- tests/Mock/CIMPurchaseSuccess.txt | 14 -- tests/Mock/CIMRefundFailure.txt | 14 -- tests/Mock/CIMVoidResponse.txt | 13 -- tests/Model/CardReferenceTest.php | 29 ++++ tests/Model/TransactionReferenceTest.php | 31 ++++ 52 files changed, 757 insertions(+), 649 deletions(-) delete mode 100644 src/Message/CIMAbstractCustomerProfileRequest.php create mode 100644 src/Model/CardReference.php create mode 100644 src/Model/TransactionReference.php create mode 100644 tests/Message/AIMAbstractRequestTest.php delete mode 100644 tests/Message/CIMResponseTest.php delete mode 100644 tests/Mock/CIMAuthorizeFailure.txt delete mode 100644 tests/Mock/CIMAuthorizeSuccess.txt delete mode 100644 tests/Mock/CIMCaptureFailure.txt delete mode 100644 tests/Mock/CIMCaptureSuccess.txt delete mode 100644 tests/Mock/CIMPurchaseFailure.txt delete mode 100644 tests/Mock/CIMPurchaseSuccess.txt delete mode 100644 tests/Mock/CIMRefundFailure.txt delete mode 100644 tests/Mock/CIMVoidResponse.txt create mode 100644 tests/Model/CardReferenceTest.php create mode 100644 tests/Model/TransactionReferenceTest.php diff --git a/src/CIMGateway.php b/src/CIMGateway.php index 1fafc411..bf0d0cba 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -9,14 +9,6 @@ */ class CIMGateway extends AIMGateway { - public function getDefaultParameters() - { - $params = parent::getDefaultParameters(); - $params['forceCardUpdate'] = false; - $params['defaultBillTo'] = array(array()); - return $params; - } - public function getName() { return 'Authorize.Net CIM'; diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 19429034..438bfb5c 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -2,6 +2,8 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\AuthorizeNet\Model\CardReference; +use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\CreditCard; use Omnipay\Common\Exception\InvalidRequestException; use Omnipay\Common\Message\AbstractRequest; @@ -11,6 +13,7 @@ */ abstract class AIMAbstractRequest extends AbstractRequest { + protected $requestType = 'createTransactionRequest'; protected $action = null; public function getApiLoginId() @@ -72,16 +75,84 @@ private function getDuplicateWindow() return $this->getParameter('duplicateWindow'); // Maps x_duplicate_window } - protected function addExtraOptions(\SimpleXMLElement $data) + public function getLiveEndpoint() { - if (!is_null($this->getDuplicateWindow())) { - $extraOptions = $data->addChild('extraOptions'); - $node = dom_import_simplexml($extraOptions); - $nodeOwner = $node->ownerDocument; - $duplicateWindowStr = sprintf("x_duplicate_window=%s", $this->getDuplicateWindow()); - $node->appendChild($nodeOwner->createCDATASection($duplicateWindowStr)); + return $this->getParameter('liveEndpoint'); + } + + public function setLiveEndpoint($value) + { + return $this->setParameter('liveEndpoint', $value); + } + + public function getDeveloperEndpoint() + { + return $this->getParameter('developerEndpoint'); + } + + public function setDeveloperEndpoint($value) + { + return $this->setParameter('developerEndpoint', $value); + } + + public function getEndpoint() + { + return $this->getDeveloperMode() ? $this->getDeveloperEndpoint() : $this->getLiveEndpoint(); + } + + /** + * @return TransactionReference + */ + public function getTransactionReference() + { + return $this->getParameter('transactionReference'); + } + + public function setTransactionReference($value) + { + if (substr($value, 0, 1) === '{') { + // Value is a complex key containing the transaction ID and other properties + $transactionRef = new TransactionReference($value); + } else { + // Value just contains the transaction ID + $transactionRef = new TransactionReference(); + $transactionRef->setTransId($value); } - return $data; + return $this->setParameter('transactionReference', $transactionRef); + } + + /** + * @param string|CardReference $value + * @return AbstractRequest + */ + public function setCardReference($value) + { + if (!($value instanceof CardReference)) { + $value = new CardReference($value); + } + return parent::setCardReference($value); + } + + /** + * @param bool $serialize Determines whether the return value will be a string or object + * @return string|CardReference + */ + public function getCardReference($serialize = true) + { + $value = parent::getCardReference(); + if ($serialize) { + $value = (string)$value; + } + return $value; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new AIMResponse($this, $httpResponse->getBody()); } /** @@ -90,27 +161,35 @@ protected function addExtraOptions(\SimpleXMLElement $data) */ public function getBaseData() { - $data = new \SimpleXMLElement(''); + $data = new \SimpleXMLElement('<' . $this->requestType . '/>'); $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); + $this->addAuthentication($data); + $this->addReferenceId($data); + $this->addTransactionType($data); + return $data; + } - // Credentials + protected function addAuthentication(\SimpleXMLElement $data) + { $data->merchantAuthentication->name = $this->getApiLoginId(); $data->merchantAuthentication->transactionKey = $this->getTransactionKey(); + } - // User-assigned transaction ID + protected function addReferenceId(\SimpleXMLElement $data) + { $txnId = $this->getTransactionId(); if (!empty($txnId)) { $data->refId = $this->getTransactionId(); } + } - // Transaction type + protected function addTransactionType(\SimpleXMLElement $data) + { if (!$this->action) { // The extending class probably hasn't specified an "action" throw new InvalidRequestException(); } $data->transactionRequest->transactionType = $this->action; - - return $data; } /** @@ -165,37 +244,15 @@ protected function addTestModeSetting(\SimpleXMLElement $data) return $data; } - public function sendData($data) - { - $headers = array('Content-Type' => 'text/xml; charset=utf-8'); - $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); - - return $this->response = new AIMResponse($this, $httpResponse->getBody()); - } - - public function getLiveEndpoint() - { - return $this->getParameter('liveEndpoint'); - } - - public function setLiveEndpoint($value) - { - return $this->setParameter('liveEndpoint', $value); - } - - public function getDeveloperEndpoint() - { - return $this->getParameter('developerEndpoint'); - } - - public function setDeveloperEndpoint($value) - { - return $this->setParameter('developerEndpoint', $value); - } - - public function getEndpoint() + protected function addExtraOptions(\SimpleXMLElement $data) { - return $this->getDeveloperMode() ? $this->getDeveloperEndpoint() : $this->getLiveEndpoint(); + if (!is_null($this->getDuplicateWindow())) { + $extraOptions = $data->addChild('extraOptions'); + $node = dom_import_simplexml($extraOptions); + $nodeOwner = $node->ownerDocument; + $duplicateWindowStr = sprintf("x_duplicate_window=%s", $this->getDuplicateWindow()); + $node->appendChild($nodeOwner->createCDATASection($duplicateWindowStr)); + } + return $data; } } diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 310bf0a5..f6dbbb48 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -13,26 +13,34 @@ class AIMAuthorizeRequest extends AIMAbstractRequest public function getData() { - $this->validate('amount', 'card'); + $this->validate('amount'); + $data = $this->getBaseData(); + $data->transactionRequest->amount = $this->getAmount(); + $this->addPayment($data); + $this->addCustomerIP($data); + $this->addBillingData($data); + $this->addTestModeSetting($data); + $this->addExtraOptions($data); + return $data; + } + + protected function addPayment(\SimpleXMLElement $data) + { + $this->validate('card'); /** @var CreditCard $card */ $card = $this->getCard(); $card->validate(); - - $data = $this->getBaseData(); - $data->transactionRequest->amount = $this->getAmount(); $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) + { $ip = $this->getClientIp(); if (!empty($ip)) { $data->transactionRequest->customerIP = $ip; } - - $this->addBillingData($data); - $this->addTestModeSetting($data); - $this->addExtraOptions($data); - - return $data; } } diff --git a/src/Message/AIMCaptureRequest.php b/src/Message/AIMCaptureRequest.php index ea021d3d..a364870f 100644 --- a/src/Message/AIMCaptureRequest.php +++ b/src/Message/AIMCaptureRequest.php @@ -15,7 +15,7 @@ public function getData() $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getAmount(); - $data->transactionRequest->refTransId = $this->getTransactionReference(); + $data->transactionRequest->refTransId = $this->getTransactionReference()->getTransId(); $this->addTestModeSetting($data); return $data; diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index becdfd6e..3e73f067 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\CreditCard; - /** * Authorize.net AIM Refund Request */ @@ -11,20 +9,58 @@ class AIMRefundRequest extends AIMAbstractRequest { protected $action = 'refundTransaction'; - public function getData() + public function shouldVoidIfRefundFails() + { + return !!$this->getParameter('voidIfRefundFails'); + } + + public function setVoidIfRefundFails($value) { - $this->validate('transactionReference', 'amount', 'card'); + $this->setParameter('voidIfRefundFails', $value); + } - /** @var CreditCard $card */ - $card = $this->getCard(); + public function getData() + { + $this->validate('transactionReference', 'amount'); $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getParameter('amount'); - $data->transactionRequest->payment->creditCard->cardNumber = $card->getNumber(); - $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); - $data->transactionRequest->refTransId = $this->getTransactionReference(); + + $transactionRef = $this->getTransactionReference(); + if ($card = $transactionRef->getCard()) { + $data->transactionRequest->payment->creditCard->cardNumber = $card->number; + $data->transactionRequest->payment->creditCard->expirationDate = $card->expiry; + } elseif ($cardReference = $transactionRef->getCardReference()) { + $data->transactionRequest->profile->customerProfileId = $cardReference->getCustomerProfileId(); + $data->transactionRequest->profile->paymentProfile->paymentProfileId = $cardReference->getPaymentProfileId(); + } else { + // Transaction reference only contains the transaction ID, so a card is required + $this->validate('card'); + $card = $this->getCard(); + $data->transactionRequest->payment->creditCard->cardNumber = $card->getNumberLastFour(); + $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); + } + $data->transactionRequest->refTransId = $transactionRef->getTransId(); + $this->addTestModeSetting($data); return $data; } + + public function send() + { + /** @var AIMResponse $response */ + $response = parent::send(); + + if (!$response->isSuccessful() && $this->shouldVoidIfRefundFails() && + $response->getReasonCode() == AIMResponse::ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT + ) { + // This transaction has not yet been settled, hence cannot be refunded. But a void is possible. + $voidRequest = new CIMVoidRequest($this->httpClient, $this->httpRequest); + $voidRequest->initialize($this->getParameters()); + $response = $voidRequest->send(); + } + + return $response; + } } diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 1de2b374..4c99215e 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -2,19 +2,24 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\AuthorizeNet\Model\CardReference; +use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; +use Omnipay\Common\Message\AbstractRequest; use Omnipay\Common\Message\AbstractResponse; -use Omnipay\Common\Message\RequestInterface; /** * Authorize.Net AIM Response */ class AIMResponse extends AbstractResponse { - public function __construct(RequestInterface $request, $data) - { - $this->request = $request; + /** + * For Error codes: @see https://developer.authorize.net/api/reference/responseCodes.html + */ + const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = 54; + public function __construct(AbstractRequest $request, $data) + { // Strip out the xmlns junk so that PHP can parse the XML $xml = preg_replace('/]+>/', '', (string)$data); @@ -28,7 +33,7 @@ public function __construct(RequestInterface $request, $data) throw new InvalidResponseException(); } - $this->data = $xml; + parent::__construct($request, $xml); } public function isSuccessful() @@ -104,12 +109,36 @@ public function getAVSCode() } /** - * The payment gateway assigned identification number for transaction. + * A composite key containing the gateway provided transaction reference as well as other data points that may be + * required for subsequent transactions that may need to modify this one. * - * @return string + * @param bool $serialize Determines whether a string or object is returned + * @return TransactionReference|string */ - public function getTransactionReference() + public function getTransactionReference($serialize = true) { - return (string)$this->data->transactionResponse[0]->transId; + if ($this->isSuccessful()) { + $body = $this->data->transactionResponse[0]; + $transactionRef = new TransactionReference(); + $transactionRef->setApprovalCode((string)$body->authCode); + $transactionRef->setTransId((string)$body->transId); + + try { + // Need to store card details in the transaction reference since it is required when doing a refund + if ($card = $this->request->getCard()) { + $transactionRef->setCard(array( + 'number' => $card->getNumberLastFour(), + 'expiry' => $card->getExpiryDate('mY') + )); + } elseif ($cardReference = $this->request->getCardReference()) { + $transactionRef->setCardReference(new CardReference($cardReference)); + } + } catch (\Exception $e) { + } + + return $serialize ? (string)$transactionRef : $transactionRef; + } + + return null; } } diff --git a/src/Message/AIMVoidRequest.php b/src/Message/AIMVoidRequest.php index 78f0f3b1..dba99681 100644 --- a/src/Message/AIMVoidRequest.php +++ b/src/Message/AIMVoidRequest.php @@ -14,7 +14,7 @@ public function getData() $this->validate('transactionReference'); $data = $this->getBaseData(); - $data->transactionRequest->refTransId = $this->getTransactionReference(); + $data->transactionRequest->refTransId = $this->getTransactionReference()->getTransId(); $this->addTestModeSetting($data); return $data; diff --git a/src/Message/CIMAbstractCustomerProfileRequest.php b/src/Message/CIMAbstractCustomerProfileRequest.php deleted file mode 100644 index 98676dd2..00000000 --- a/src/Message/CIMAbstractCustomerProfileRequest.php +++ /dev/null @@ -1,24 +0,0 @@ -setParameter('validationMode', $value); - } - - public function getValidationMode() - { - $validationMode = $this->getParameter('validationMode'); - if ($validationMode !== self::VALIDATION_MODE_NONE) { - $validationMode = $this->getDeveloperMode() ? self::VALIDATION_MODE_TEST : self::VALIDATION_MODE_LIVE; - } - return $validationMode; - } -} diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 8881449e..171f0340 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -7,9 +7,29 @@ */ abstract class CIMAbstractRequest extends AIMAbstractRequest { - protected $xmlRootElement = null; + const VALIDATION_MODE_TEST = 'testMode'; + const VALIDATION_MODE_LIVE = 'liveMode'; + const VALIDATION_MODE_NONE = 'none'; + + protected function addTransactionType(\SimpleXMLElement $data) + { + // Do nothing since customer profile requests have no transaction type + } + + public function setValidationMode($value) + { + return $this->setParameter('validationMode', $value); + } + + public function getValidationMode() + { + $validationMode = $this->getParameter('validationMode'); + if ($validationMode !== self::VALIDATION_MODE_NONE) { + $validationMode = $this->getDeveloperMode() ? self::VALIDATION_MODE_TEST : self::VALIDATION_MODE_LIVE; + } + return $validationMode; + } - // Need the below setters and getters for accessing this data within createCardRequest.send public function setEmail($value) { return $this->setParameter('email', $value); @@ -77,23 +97,6 @@ public function getDefaultBillTo() return $this->getParameter('defaultBillTo'); } - /** - * Create and return the base XML data required to create a new request - * - * @return mixed|\SimpleXMLElement - */ - public function getBaseData() - { - $data = new \SimpleXMLElement("<" . $this->xmlRootElement . "/>"); - $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); - - // Credentials - $data->merchantAuthentication->name = $this->getApiLoginId(); - $data->merchantAuthentication->transactionKey = $this->getTransactionKey(); - - return $data; - } - public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index fc5e0ead..637cd613 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -12,16 +12,14 @@ */ abstract class CIMAbstractResponse extends AbstractResponse { - protected $xmlRootElement = null; + protected $responseType = null; public function __construct(RequestInterface $request, $data) { - $this->request = $request; - // Check if this is an error response $isError = strpos((string)$data, 'xmlRootElement; + $xmlRootElement = $isError !== false ? 'ErrorResponse' : $this->responseType; // Strip out the xmlns junk so that PHP can parse the XML $xml = preg_replace('/<' . $xmlRootElement . '[^>]+>/', '<' . $xmlRootElement . '>', (string)$data); @@ -35,7 +33,9 @@ public function __construct(RequestInterface $request, $data) throw new InvalidResponseException(); } - $this->data = $this->xml2array($xml); + $data = $this->xml2array($xml); + + parent::__construct($request, $data); } public function isSuccessful() diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index d8663014..7729eb21 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -2,57 +2,38 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\AuthorizeNet\Model\CardReference; + /** - * Creates a Authorize only transaction request for the specified card + * Creates a Authorize only transaction request for the specified customer profile */ -class CIMAuthorizeRequest extends CIMAbstractRequest +class CIMAuthorizeRequest extends AIMAuthorizeRequest { - protected $xmlRootElement = 'createCustomerProfileTransactionRequest'; - - protected $action = "profileTransAuthOnly"; - - public function getData() + protected function addPayment(\SimpleXMLElement $data) { - $this->validate('cardReference', 'amount'); - $data = $this->getBaseData(); - $this->addTransactionData($data); - $this->addExtraOptions($data); - return $data; - } - - /** - * Adds transaction data - * - * @param \SimpleXMLElement $data - * - * @return \SimpleXMLElement - */ - protected function addTransactionData(\SimpleXMLElement $data) - { - $transaction = $data->addChild('transaction'); - $action = $transaction->addChild($this->action); - $action->amount = $this->getAmount(); - - $cardRef = json_decode($this->getCardReference(), true); - $action->customerProfileId = $cardRef['customerProfileId']; - $action->customerPaymentProfileId = $cardRef['customerPaymentProfileId']; - if (!empty($cardRef['customerShippingAddressId'])) { - $action->customerShippingAddressId = $cardRef['customerShippingAddressId']; + $this->validate('cardReference'); + + /** @var mixed $req */ + $req = $data->transactionRequest; + /** @var CardReference $cardRef */ + $cardRef = $this->getCardReference(false); + $req->profile->customerProfileId = $cardRef->getCustomerProfileId(); + $req->profile->paymentProfile->paymentProfileId = $cardRef->getPaymentProfileId(); + if ($shippingProfileId = $cardRef->getShippingProfileId()) { + $req->profile->shippingProfileId = $shippingProfileId; } $desc = $this->getDescription(); if (!empty($desc)) { - $action->order->description = $desc; + $req->order->description = $desc; } + return $data; } - public function sendData($data) + protected function addBillingData(\SimpleXMLElement $data) { - $headers = array('Content-Type' => 'text/xml; charset=utf-8'); - $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); - - return $this->response = new CIMResponse($this, $httpResponse->getBody()); + // Do nothing since billing information is already part of the customer profile + return $data; } } diff --git a/src/Message/CIMCaptureRequest.php b/src/Message/CIMCaptureRequest.php index e406abf8..08e069e4 100644 --- a/src/Message/CIMCaptureRequest.php +++ b/src/Message/CIMCaptureRequest.php @@ -2,43 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -/** - * Creates a Authorize only transaction request for the specified card - */ -class CIMCaptureRequest extends CIMAuthorizeRequest +class CIMCaptureRequest extends AIMCaptureRequest { - protected $action = "profileTransCaptureOnly"; - - public function getData() - { - $this->validate('transactionReference', 'amount'); - - // Get the card reference from the transaction reference and set it into the request. Card reference is required - // to make all the transactions - $transRef = json_decode($this->getTransactionReference(), true); - $this->setCardReference($transRef['cardReference']); - - $data = $this->getBaseData(); - - $this->addTransactionData($data); - $this->addTransactionReferenceData($data); - return $data; - } - - /** - * Adds references for original transaction to a partially filled request data object. - * - * @param \SimpleXMLElement $data - * - * @return \SimpleXMLElement - */ - protected function addTransactionReferenceData(\SimpleXMLElement $data) - { - $action = $data->transaction->profileTransCaptureOnly; - - $transRef = json_decode($this->getTransactionReference(), true); - - $action->approvalCode = $transRef['approvalCode']; - return $data; - } } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 86e0a784..22f6b3e2 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -7,9 +7,9 @@ /** * Create Credit Card Request. */ -class CIMCreateCardRequest extends CIMAbstractCustomerProfileRequest +class CIMCreateCardRequest extends CIMAbstractRequest { - protected $xmlRootElement = 'createCustomerProfileRequest'; + protected $requestType = 'createCustomerProfileRequest'; public function getData() { @@ -39,17 +39,14 @@ protected function addProfileData(\SimpleXMLElement $data) if (!empty($customer)) { $req->merchantCustomerId = $customer; } - $description = $this->getDescription(); if (!empty($description)) { $req->description = $description; } - $email = $this->getEmail(); if (!empty($email)) { $req->email = $email; } - $this->addPaymentProfileData($req); $this->addShippingData($req); } @@ -61,7 +58,6 @@ protected function addProfileData(\SimpleXMLElement $data) */ protected function addPaymentProfileData(\SimpleXMLElement $data) { - // This order is important. Payment profiles should come in this order only $req = $data->addChild('paymentProfiles'); $this->addBillingData($req); } diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index ef50389d..8139b4fd 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -7,7 +7,7 @@ */ class CIMCreateCardResponse extends CIMAbstractResponse { - protected $xmlRootElement = 'createCustomerProfileResponse'; + protected $responseType = 'createCustomerProfileResponse'; public function getCustomerProfileId() { diff --git a/src/Message/CIMCreatePaymentProfileRequest.php b/src/Message/CIMCreatePaymentProfileRequest.php index d7f3d556..066464a8 100644 --- a/src/Message/CIMCreatePaymentProfileRequest.php +++ b/src/Message/CIMCreatePaymentProfileRequest.php @@ -9,7 +9,7 @@ */ class CIMCreatePaymentProfileRequest extends CIMCreateCardRequest { - protected $xmlRootElement = 'createCustomerPaymentProfileRequest'; + protected $requestType = 'createCustomerPaymentProfileRequest'; public function getData() { diff --git a/src/Message/CIMCreatePaymentProfileResponse.php b/src/Message/CIMCreatePaymentProfileResponse.php index 35335392..56c357c7 100644 --- a/src/Message/CIMCreatePaymentProfileResponse.php +++ b/src/Message/CIMCreatePaymentProfileResponse.php @@ -7,7 +7,7 @@ */ class CIMCreatePaymentProfileResponse extends CIMAbstractResponse { - protected $xmlRootElement = 'createCustomerPaymentProfileResponse'; + protected $responseType = 'createCustomerPaymentProfileResponse'; public function getCustomerProfileId() { diff --git a/src/Message/CIMGetPaymentProfileRequest.php b/src/Message/CIMGetPaymentProfileRequest.php index f99298b3..a8da6cf6 100644 --- a/src/Message/CIMGetPaymentProfileRequest.php +++ b/src/Message/CIMGetPaymentProfileRequest.php @@ -7,7 +7,7 @@ */ class CIMGetPaymentProfileRequest extends CIMAbstractRequest { - protected $xmlRootElement = 'getCustomerPaymentProfileRequest'; + protected $requestType = 'getCustomerPaymentProfileRequest'; public function getData() { diff --git a/src/Message/CIMGetPaymentProfileResponse.php b/src/Message/CIMGetPaymentProfileResponse.php index c6953fd1..f97f2292 100644 --- a/src/Message/CIMGetPaymentProfileResponse.php +++ b/src/Message/CIMGetPaymentProfileResponse.php @@ -7,7 +7,7 @@ */ class CIMGetPaymentProfileResponse extends CIMCreatePaymentProfileResponse { - protected $xmlRootElement = 'getCustomerPaymentProfileResponse'; + protected $responseType = 'getCustomerPaymentProfileResponse'; public function getCustomerPaymentProfileId() { diff --git a/src/Message/CIMGetProfileRequest.php b/src/Message/CIMGetProfileRequest.php index 70d85a8a..5f755475 100644 --- a/src/Message/CIMGetProfileRequest.php +++ b/src/Message/CIMGetProfileRequest.php @@ -7,7 +7,7 @@ */ class CIMGetProfileRequest extends CIMAbstractRequest { - protected $xmlRootElement = 'getCustomerProfileRequest'; + protected $requestType = 'getCustomerProfileRequest'; public function getData() { diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index a3a8f3e0..41fc503b 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -10,7 +10,7 @@ class CIMGetProfileResponse extends CIMCreatePaymentProfileResponse const ERROR_DUPLICATE_PROFILE = 'E00039'; const ERROR_MAX_PAYMENT_PROFILE_LIMIT_REACHED = 'E00042'; - protected $xmlRootElement = 'getCustomerProfileResponse'; + protected $responseType = 'getCustomerProfileResponse'; /** * Get the payment profile id corresponding to the specified last4 by looking into the payment profiles diff --git a/src/Message/CIMPurchaseRequest.php b/src/Message/CIMPurchaseRequest.php index b359e959..65c2b0f2 100644 --- a/src/Message/CIMPurchaseRequest.php +++ b/src/Message/CIMPurchaseRequest.php @@ -7,5 +7,5 @@ */ class CIMPurchaseRequest extends CIMAuthorizeRequest { - protected $action = "profileTransAuthCapture"; + protected $action = "authCaptureTransaction"; } diff --git a/src/Message/CIMRefundRequest.php b/src/Message/CIMRefundRequest.php index 5a76cb8e..7a7a9df8 100644 --- a/src/Message/CIMRefundRequest.php +++ b/src/Message/CIMRefundRequest.php @@ -5,59 +5,7 @@ /** * Creates a refund transaction request for the specified card, transaction */ -class CIMRefundRequest extends CIMCaptureRequest +class CIMRefundRequest extends AIMRefundRequest { - protected $action = "profileTransRefund"; - protected $voidIfRefundFails = false; - - /** - * @return boolean - */ - public function isVoidIfRefundFails() - { - return $this->voidIfRefundFails; - } - - /** - * @param boolean $voidIfRefundFails - */ - public function setVoidIfRefundFails($voidIfRefundFails) - { - $this->voidIfRefundFails = $voidIfRefundFails; - } - - /** - * Adds reference for original transaction to a partially filled request data object. - * - * @param \SimpleXMLElement $data - * - * @return \SimpleXMLElement - */ - protected function addTransactionReferenceData(\SimpleXMLElement $data) - { - $action = $data->transaction->profileTransRefund; - - $transRef = json_decode($this->getTransactionReference(), true); - - $action->transId = $transRef['transId']; - return $data; - } - - public function send() - { - /** @var CIMResponse $response */ - $response = parent::send(); - $parameters = $this->getParameters(); - - if (!$response->isSuccessful() && $this->voidIfRefundFails && - $response->getResponseReasonCode() === CIMResponse::ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT) { - // An attempt to a refund a transaction that was not settled. We can just void the entire transaction - $voidRequest = new CIMVoidRequest($this->httpClient, $this->httpRequest); - $voidRequest->initialize($parameters); - $response = $voidRequest->send(); - } - - return $response; - } } diff --git a/src/Message/CIMResponse.php b/src/Message/CIMResponse.php index 85cf8cc7..907953d9 100644 --- a/src/Message/CIMResponse.php +++ b/src/Message/CIMResponse.php @@ -7,35 +7,4 @@ */ class CIMResponse extends CIMAbstractResponse { - /** - * For Error codes: @see https://developer.authorize.net/api/reference/responseCodes.html - */ - const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = '54'; - - protected $xmlRootElement = 'createCustomerProfileTransactionResponse'; - - public function getTransactionReference() - { - if (!$this->isSuccessful()) { - return null; - } - - $transRef = null; - if (isset($this->data['directResponse'])) { - $transRef = array(); - // In case of a successful transaction, a "directResponse" element is present - $directResponse = explode(',', (string)$this->data['directResponse']); - // Required for capturing an authorized transaction - $transRef['approvalCode'] = $directResponse[4]; - // Required for refund a transaction - $transRef['transId'] = $directResponse[6]; - - // Save the card reference also as it is needed for making further transactions. - // This card reference is got from the request. (transaction response does not have it) - $transRef['cardReference'] = $this->request->getCardReference(); - $transRef = json_encode($transRef); - } - - return $transRef; - } } diff --git a/src/Message/CIMUpdatePaymentProfileRequest.php b/src/Message/CIMUpdatePaymentProfileRequest.php index be273ce3..cda87a03 100644 --- a/src/Message/CIMUpdatePaymentProfileRequest.php +++ b/src/Message/CIMUpdatePaymentProfileRequest.php @@ -9,7 +9,7 @@ */ class CIMUpdatePaymentProfileRequest extends CIMCreatePaymentProfileRequest { - protected $xmlRootElement = 'updateCustomerPaymentProfileRequest'; + protected $requestType = 'updateCustomerPaymentProfileRequest'; public function getData() { diff --git a/src/Message/CIMUpdatePaymentProfileResponse.php b/src/Message/CIMUpdatePaymentProfileResponse.php index 8b069970..5741d5c9 100644 --- a/src/Message/CIMUpdatePaymentProfileResponse.php +++ b/src/Message/CIMUpdatePaymentProfileResponse.php @@ -7,7 +7,7 @@ */ class CIMUpdatePaymentProfileResponse extends CIMCreatePaymentProfileResponse { - protected $xmlRootElement = 'updateCustomerPaymentProfileResponse'; + protected $responseType = 'updateCustomerPaymentProfileResponse'; public function getCustomerPaymentProfileId() { diff --git a/src/Message/CIMVoidRequest.php b/src/Message/CIMVoidRequest.php index ab5d614d..42afd6be 100644 --- a/src/Message/CIMVoidRequest.php +++ b/src/Message/CIMVoidRequest.php @@ -5,21 +5,6 @@ /** * Authorize.Net CIM Void Request */ -class CIMVoidRequest extends CIMAbstractRequest +class CIMVoidRequest extends AIMVoidRequest { - protected $xmlRootElement = 'createCustomerProfileTransactionRequest'; - protected $action = 'voidTransaction'; - - public function getData() - { - $this->validate('transactionReference'); - - $data = $this->getBaseData(); - $transRef = json_decode($this->getTransactionReference(), true); - if (is_array($transRef) && isset($transRef['transId'])) { - $data->transaction->profileTransVoid->transId = $transRef["transId"]; - } - - return $data; - } } diff --git a/src/Model/CardReference.php b/src/Model/CardReference.php new file mode 100644 index 00000000..5ffd8def --- /dev/null +++ b/src/Model/CardReference.php @@ -0,0 +1,80 @@ +customerProfileId)) { + $this->customerProfileId = $data->customerProfileId; + } + if (isset($data->customerPaymentProfileId)) { + $this->paymentProfileId = $data->customerPaymentProfileId; + } + if (isset($data->customerShippingAddressId)) { + $this->shippingProfileId = $data->customerShippingAddressId; + } + } + } + + public function __toString() + { + $data = array( + 'customerProfileId' => $this->customerProfileId, + 'customerPaymentProfileId' => $this->paymentProfileId + ); + if ($this->shippingProfileId) { + $data['customerShippingAddressId'] = $this->shippingProfileId; + } + return json_encode($data); + } + + public function getCustomerProfileId() + { + return $this->customerProfileId; + } + + public function setCustomerProfileId($customerProfileId) + { + $this->customerProfileId = $customerProfileId; + } + + public function getPaymentProfileId() + { + return $this->paymentProfileId; + } + + public function setPaymentProfileId($paymentProfileId) + { + $this->paymentProfileId = $paymentProfileId; + } + + public function getShippingProfileId() + { + return $this->shippingProfileId; + } + + public function setShippingProfileId($shippingProfileId) + { + $this->shippingProfileId = $shippingProfileId; + } + + +} \ No newline at end of file diff --git a/src/Model/TransactionReference.php b/src/Model/TransactionReference.php new file mode 100644 index 00000000..721fb556 --- /dev/null +++ b/src/Model/TransactionReference.php @@ -0,0 +1,124 @@ +transId)) { + $this->transId = $data->transId; + } + if (isset($data->approvalCode)) { + $this->approvalCode = $data->approvalCode; + } + if (isset($data->card)) { + $this->card = $data->card; + } + if (isset($data->cardReference)) { + $this->cardReference = new CardReference($data->cardReference); + } + } + } + + public function __toString() + { + $data = array(); + if (isset($this->approvalCode)) { + $data['approvalCode'] = $this->approvalCode; + } + if (isset($this->transId)) { + $data['transId'] = $this->transId; + } + if (isset($this->card)) { + $data['card'] = $this->card; + } + if (isset($this->cardReference)) { + $data['cardReference'] = (string)$this->cardReference; + } + return json_encode($data); + } + + /** + * @return string + */ + public function getTransId() + { + return $this->transId; + } + + /** + * @param string $transId + */ + public function setTransId($transId) + { + $this->transId = $transId; + } + + /** + * @return string + */ + public function getApprovalCode() + { + return $this->approvalCode; + } + + /** + * @param string $approvalCode + */ + public function setApprovalCode($approvalCode) + { + $this->approvalCode = $approvalCode; + } + + /** + * @return object + */ + public function getCard() + { + return $this->card; + } + + /** + * @param array $card + */ + public function setCard($card) + { + $this->card = $card; + } + + /** + * @return CardReference + */ + public function getCardReference() + { + return $this->cardReference; + } + + /** + * @param string|CardReference $cardReference + */ + public function setCardReference($cardReference) + { + $this->cardReference = $cardReference; + } + + +} \ No newline at end of file diff --git a/tests/AIMGatewayIntegrationTest.php b/tests/AIMGatewayIntegrationTest.php index c5157b9d..299161d8 100644 --- a/tests/AIMGatewayIntegrationTest.php +++ b/tests/AIMGatewayIntegrationTest.php @@ -38,16 +38,26 @@ public function setUp() } } - public function testPurchaseAndVoid() + public function testAuthCaptureVoid() { - $request = $this->gateway->purchase(array( - 'amount' => '10.01', + // Authorize + $request = $this->gateway->authorize(array( + 'amount' => '42.42', 'card' => $this->getValidCard() )); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Purchase should succeed'); + $this->assertTrue($response->isSuccessful(), 'Authorization should succeed'); $transactionRef = $response->getTransactionReference(); + // Capture + $request = $this->gateway->capture(array( + 'amount' => '42.42', + 'transactionReference' => $transactionRef + )); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Capture should succeed'); + + // Void $request = $this->gateway->void(array( 'transactionReference' => $transactionRef )); @@ -55,21 +65,32 @@ public function testPurchaseAndVoid() $this->assertTrue($response->isSuccessful(), 'Void should succeed'); } - public function testHoldAndCapture() + public function testPurchaseRefundAutoVoid() { - $request = $this->gateway->authorize(array( - 'amount' => '42.42', + // Purchase + $request = $this->gateway->purchase(array( + 'amount' => 10.01, 'card' => $this->getValidCard() )); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Authorization should succeed'); + $this->assertTrue($response->isSuccessful(), 'Purchase should succeed'); $transactionRef = $response->getTransactionReference(); - $request = $this->gateway->capture(array( - 'amount' => '42.42', - 'transactionReference' => $transactionRef + // Refund (should fail) + $request = $this->gateway->refund(array( + 'transactionReference' => $transactionRef, + 'amount' => 10.01 )); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Capture should succeed'); + $this->assertFalse($response->isSuccessful(), 'Refund should fail since the transaction has not been settled'); + + // Refund with auto-void + $request = $this->gateway->refund(array( + 'transactionReference' => $transactionRef, + 'amount' => 10.01, + 'voidIfRefundFails' => true + )); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Automatic void should succeed'); } } diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 4b7ca928..f45478b0 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -40,6 +40,11 @@ public function setUp() ); } + private function getExpiry($card) + { + return str_pad($card['expiryMonth'] . $card['expiryYear'], 6, '0', STR_PAD_LEFT); + } + public function testAuthorizeSuccess() { $this->setMockHttpResponse('AIMAuthorizeSuccess.txt'); @@ -47,7 +52,11 @@ public function testAuthorizeSuccess() $response = $this->gateway->authorize($this->purchaseOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2184493132', $response->getTransactionReference()); + $expiry = $this->getExpiry($this->purchaseOptions['card']); + $this->assertSame( + '{"approvalCode":"GA4OQP","transId":"2184493132","card":{"number":"1111","expiry":"' . $expiry . '"}}', + $response->getTransactionReference(), + 'should return complex key as transaction reference'); $this->assertSame('This transaction has been approved.', $response->getMessage()); } @@ -58,7 +67,7 @@ public function testAuthorizeFailure() $response = $this->gateway->authorize($this->purchaseOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); } @@ -69,7 +78,7 @@ public function testCaptureSuccess() $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2184494531', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"F51OYG","transId":"2184494531"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); } @@ -80,7 +89,7 @@ public function testCaptureFailure() $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); } @@ -91,7 +100,8 @@ public function testPurchaseSuccess() $response = $this->gateway->purchase($this->purchaseOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2184492509', $response->getTransactionReference()); + $expiry = $this->getExpiry($this->purchaseOptions['card']); + $this->assertSame('{"approvalCode":"JE6JM1","transId":"2184492509","card":{"number":"1111","expiry":"' . $expiry . '"}}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); } @@ -102,7 +112,7 @@ public function testPurchaseFailure() $response = $this->gateway->purchase($this->purchaseOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); } @@ -113,8 +123,8 @@ public function testVoidSuccess() $response = $this->gateway->void($this->voidOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); - $this->assertSame('This transaction has already been voided.', $response->getMessage()); + $this->assertSame('{"approvalCode":"ZJ5XAB","transId":"2252805912"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); } public function testVoidFailure() @@ -124,8 +134,8 @@ public function testVoidFailure() $response = $this->gateway->void($this->voidOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); - $this->assertSame('A valid referenced transaction ID is required.', $response->getMessage()); + $this->assertNull($response->getTransactionReference()); + $this->assertSame('The transaction cannot be found.', $response->getMessage()); } public function testRefundSuccess() @@ -135,7 +145,8 @@ public function testRefundSuccess() $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2217770693', $response->getTransactionReference()); + $expiry = $this->getExpiry($this->refundOptions['card']); + $this->assertSame('{"approvalCode":"","transId":"2217770693","card":{"number":"1111","expiry":"' . $expiry . '"}}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); } @@ -146,7 +157,7 @@ public function testRefundFailure() $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage()); } } diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 0b144953..59bf1049 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -31,7 +31,6 @@ public function setUp() if ($apiLoginId && $transactionKey) { $client = new Client(); - $this->gateway = new CIMGateway($client, $this->getHttpRequest()); $this->gateway->setDeveloperMode(true); $this->gateway->setApiLoginId($apiLoginId); @@ -42,62 +41,68 @@ public function setUp() } } - public function testCreateCustomerAndPaymentProfile() + /** + * Helper method to create a card on CIM. + * + * @param array $params + * @return string + */ + private function createCard($params = array()) { - // Create card - $rand = uniqid(); - $params = array( + $rand = uniqid('', true); + $defaults = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee$rand@serenity.com", + 'email' => "$rand@serenity.com", ); + $params = array_merge($defaults, $params); $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); - /* @var $response CIMResponse */ $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Profile should get created'); - $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + return $response->getCardReference(); + } - $cardRef = $response->getCardReference(); + public function testCustomerAndPaymentProfile() + { + // Create a customer profile with the specified email (email is the identifier) + $email = uniqid('', true) . '@example.com'; + $cardRef = $this->createCard(array('email' => $email)); - // Try creating a different card for the same user + // Create a new card in an existing customer profile $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee$rand@serenity.com", + 'email' => $email, ); $params['card']['number'] = '4007000000027'; $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); - $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Should be successful as we have created a payment profile'); $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); - // Try creating same card for the same user without force card update flag. + // Create a card with same number in an existing customer profile (should fail) $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee$rand@serenity.com", + 'email' => $email, ); $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); - $response = $request->send(); $this->assertFalse($response->isSuccessful(), 'Should fail as we tried creating a duplicate profile'); $this->assertNull($response->getCardReference(), 'Card reference should be returned'); - // Try creating same card for the same user again with force card update flag. + // Create a card with the same number in an existing customer profile with auto-update enabled $params = array( 'card' => $this->getValidCard(), 'name' => 'Kaywinnet Lee Frye', - 'email' => "kaylee$rand@serenity.com", + 'email' => $email, 'forceCardUpdate' => true ); $request = $this->gateway->createCard($params); $request->setDeveloperMode(true); - $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Should succeed in updating the existing payment profile'); $this->assertEquals( @@ -107,25 +112,11 @@ public function testCreateCustomerAndPaymentProfile() ); } - public function testAuthorizeAndVoid() + public function testAuthorizeCapture() { - // Create card - $rand = uniqid(); - $params = array( - 'card' => $this->getValidCard(), - 'name' => 'Kaywinnet Lee Frye ' . $rand, - 'email' => "kaylee$rand@serenity.com", - ); - $request = $this->gateway->createCard($params); - $request->setDeveloperMode(true); - - /* @var $response CIMResponse */ - $response = $request->send(); - $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + $cardRef = $this->createCard(); - $cardRef = $response->getCardReference(); - - // Create Authorize only transaction + // Authorize $params = array( 'cardReference' => $cardRef, 'amount' => 100.00, @@ -133,44 +124,55 @@ public function testAuthorizeAndVoid() ); $request = $this->gateway->authorize($params); $request->setDeveloperMode(true); - $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Authorize transaction should get created'); - $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); - $transRef = $response->getTransactionReference(); + $this->assertNotNull($transRef, 'Transaction reference should exist'); - // Capture the authorised transaction + // Capture $params = array( 'transactionReference' => $transRef, 'amount' => 100.00, ); $request = $this->gateway->capture($params); $request->setDeveloperMode(true); - $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Capture transaction should get created'); $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + } - // Make a purchase using the saved card. i.e auth and capture + public function testPurchaseRefundAutoVoid() + { + $cardRef = $this->createCard(); + + // Purchase $params = array( 'cardReference' => $cardRef, 'amount' => 110.00, ); $request = $this->gateway->purchase($params); $request->setDeveloperMode(true); - $response = $request->send(); $this->assertTrue($response->isSuccessful(), 'Purchase transaction should get created'); - $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); + $transactionReference = $response->getTransactionReference(); + $this->assertNotNull($transactionReference, 'Transaction reference should exist'); - // Make a refund on the purchase transaction - $request = $this->gateway->void(array('transactionReference' => $response->getTransactionReference())); + // Refund (should fail) + $request = $this->gateway->refund(array( + 'amount' => 110.00, + 'transactionReference' => $transactionReference)); $request->setDeveloperMode(true); + $response = $request->send(); + $this->assertFalse($response->isSuccessful(), 'Refund should fail since the transaction has not been settled'); + // Refund with auto-void + $request = $this->gateway->refund(array( + 'amount' => 110.00, + 'transactionReference' => $transactionReference, + 'voidIfRefundFails' => true)); + $request->setDeveloperMode(true); $response = $request->send(); - $this->assertTrue($response->isSuccessful(), 'Refund transaction should get created'); + $this->assertTrue($response->isSuccessful(), 'Refund should succeed as a void transaction'); $this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist'); - $this->assertEquals('Successful.', $response->getMessage()); } } diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index b418898f..b76e1048 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -120,86 +120,66 @@ public function testCreateCardFailure() public function testAuthorizeSuccess() { - $this->setMockHttpResponse('CIMAuthorizeSuccess.txt'); + $this->setMockHttpResponse('AIMAuthorizeSuccess.txt'); $response = $this->gateway->authorize($this->authorizeOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame( - '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', - $response->getTransactionReference() - ); - $this->assertSame('Successful.', $response->getMessage()); + $this->assertEquals('{"approvalCode":"GA4OQP","transId":"2184493132","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); } public function testAuthorizeFailure() { - $this->setMockHttpResponse('CIMAuthorizeFailure.txt'); - - try { - $response = $this->gateway->authorize($this->authorizeOptions)->send(); - } catch(\Exception $e) { - - } - + $this->setMockHttpResponse('AIMAuthorizeFailure.txt'); + $response = $this->gateway->authorize($this->authorizeOptions)->send(); $this->assertFalse($response->isSuccessful()); $this->assertNull($response->getTransactionReference()); - $this->assertSame( - "The 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:amount' element is invalid - The value '-100.00' is invalid according to its datatype 'Decimal' - The MinInclusive constraint failed.", - $response->getMessage() - ); + $this->assertEquals("A valid amount is required.", $response->getMessage()); } public function testCaptureSuccess() { - $this->setMockHttpResponse('CIMCaptureSuccess.txt'); + $this->setMockHttpResponse('AIMCaptureSuccess.txt'); $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame( - '{"approvalCode":"DMK100","transId":"2220001903","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', - $response->getTransactionReference() - ); - $this->assertSame('Successful.', $response->getMessage()); + $this->assertSame('{"approvalCode":"F51OYG","transId":"2184494531"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); } public function testCaptureFailure() { - $this->setMockHttpResponse('CIMCaptureFailure.txt'); + $this->setMockHttpResponse('AIMCaptureFailure.txt'); $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); - $this->assertSame('Approval Code is required.', $response->getMessage()); + $this->assertEquals(0, $response->getTransactionReference()); + $this->assertSame('The transaction cannot be found.', $response->getMessage()); } public function testPurchaseSuccess() { - $this->setMockHttpResponse('CIMPurchaseSuccess.txt'); + $this->setMockHttpResponse('AIMPurchaseSuccess.txt'); $response = $this->gateway->purchase($this->authorizeOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame( - '{"approvalCode":"MNLXJQ","transId":"2220001904","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', - $response->getTransactionReference() - ); - $this->assertSame('Successful.', $response->getMessage()); + $this->assertSame('{"approvalCode":"JE6JM1","transId":"2184492509","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); } public function testPurchaseFailure() { - $this->setMockHttpResponse('CIMPurchaseFailure.txt'); + $this->setMockHttpResponse('AIMPurchaseFailure.txt'); $response = $this->gateway->purchase($this->authorizeOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull( - $response->getTransactionReference() - ); - $this->assertSame('This transaction has been declined.', $response->getMessage()); + $this->assertNull($response->getTransactionReference()); + $this->assertSame('A valid amount is required.', $response->getMessage()); } public function testRefundSuccess() @@ -215,12 +195,12 @@ public function testRefundSuccess() public function testRefundFailure() { - $this->setMockHttpResponse('CIMRefundFailure.txt'); + $this->setMockHttpResponse('AIMRefundFailure.txt'); $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertEquals(0, $response->getTransactionReference()); $this->assertSame( 'The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage() @@ -229,13 +209,13 @@ public function testRefundFailure() public function testShouldVoidTransactionIfTryingToRefundAnUnsettledTransaction() { - $this->setMockHttpResponse(array('CIMRefundFailure.txt', 'CIMVoidResponse.txt')); + $this->setMockHttpResponse(array('AIMRefundFailure.txt', 'AIMVoidSuccess.txt')); $this->refundOptions['voidIfRefundFails'] = true; $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertTrue($response->isSuccessful()); $this->assertNotNull($response->getTransactionReference()); - $this->assertEquals('Successful.', $response->getMessage()); + $this->assertEquals('This transaction has been approved.', $response->getMessage()); } } diff --git a/tests/Message/AIMAbstractRequestTest.php b/tests/Message/AIMAbstractRequestTest.php new file mode 100644 index 00000000..04d01400 --- /dev/null +++ b/tests/Message/AIMAbstractRequestTest.php @@ -0,0 +1,37 @@ +request = $this->getMockForAbstractClass( + '\Omnipay\AuthorizeNet\Message\AIMAbstractRequest', + array( + $this->getMock('\Guzzle\Http\ClientInterface'), + $this->getMock('\Symfony\Component\HttpFoundation\Request') + ) + ); + } + + public function testShouldReturnTransactionReference() + { + $complexKey = json_encode(array('transId' => 'TRANS_ID', 'cardReference' => 'CARD_REF')); + $this->request->setTransactionReference($complexKey); + $this->assertEquals('TRANS_ID', $this->request->getTransactionReference()->getTransId()); + } + + public function testShouldReturnBackwardCompatibleTransactionReference() + { + $this->request->setTransactionReference('TRANS_ID'); + $this->assertEquals('TRANS_ID', $this->request->getTransactionReference()->getTransId()); + } +} diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index e401b872..15c3317b 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -13,24 +13,6 @@ class AIMRefundRequestTest extends TestCase public function setUp() { $this->request = new AIMRefundRequest($this->getHttpClient(), $this->getHttpRequest()); - $this->request->initialize( - array( - 'transactionReference' => '123', - 'amount' => '12.00' - ) - ); - - try { - $this->request->getData(); - } catch (InvalidRequestException $irex) { - $this->assertEquals($irex->getMessage(), "The card parameter is required"); - return; - } catch (\Exception $e) { - $this->fail("Invalid exception was thrown: " . $e->getMessage()); - return; - } - - $this->fail("InvalidRequestException should get thrown because card is missing"); } public function testGetData() @@ -57,4 +39,26 @@ public function testGetData() $this->assertEquals('testRequest', $setting->settingName); $this->assertEquals('false', $setting->settingValue); } + + public function testGetDataShouldFail() + { + $this->request->initialize( + array( + 'transactionReference' => '123', + 'amount' => '12.00' + ) + ); + + try { + $this->request->getData(); + } catch (InvalidRequestException $irex) { + $this->assertEquals($irex->getMessage(), "The card parameter is required"); + return; + } catch (\Exception $e) { + $this->fail("Invalid exception was thrown: " . $e->getMessage()); + return; + } + + $this->fail("InvalidRequestException should get thrown because card is missing"); + } } diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 76cfadc9..e0950474 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -6,11 +6,19 @@ class AIMResponseTest extends TestCase { - /** - * @expectedException Omnipay\Common\Exception\InvalidResponseException - */ + private $mockRequest; + + public function getMockRequest($className = '\Omnipay\AuthorizeNet\Message\AIMAbstractRequest') + { + if (null === $this->mockRequest) { + $this->mockRequest = \Mockery::mock($className); + } + return $this->mockRequest; + } + public function testConstructEmpty() { + $this->setExpectedException('\Omnipay\Common\Exception\InvalidResponseException'); new AIMResponse($this->getMockRequest(), ''); } @@ -20,7 +28,7 @@ public function testAuthorizeSuccess() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2184493132', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"GA4OQP","transId":"2184493132"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); @@ -34,7 +42,7 @@ public function testAuthorizeFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(5, $response->getReasonCode()); @@ -48,7 +56,7 @@ public function testCaptureSuccess() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2184494531', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"F51OYG","transId":"2184494531"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); @@ -62,7 +70,7 @@ public function testCaptureFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(16, $response->getReasonCode()); @@ -76,7 +84,7 @@ public function testPurchaseSuccess() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2184492509', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"JE6JM1","transId":"2184492509"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); @@ -90,7 +98,7 @@ public function testPurchaseFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(5, $response->getReasonCode()); @@ -105,7 +113,7 @@ public function testRefundSuccess() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); - $this->assertSame('2217770693', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"2217770693"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); @@ -118,7 +126,7 @@ public function testRefundFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertSame('0', $response->getTransactionReference()); + $this->assertNull($response->getTransactionReference()); $this->assertSame('The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(54, $response->getReasonCode()); diff --git a/tests/Message/CIMAuthorizeRequestTest.php b/tests/Message/CIMAuthorizeRequestTest.php index c75aeed1..2d3f998f 100644 --- a/tests/Message/CIMAuthorizeRequestTest.php +++ b/tests/Message/CIMAuthorizeRequestTest.php @@ -26,11 +26,11 @@ public function testGetData() { $data = $this->request->getData(); - $this->assertEquals('12.00', $data->transaction->profileTransAuthOnly->amount); - $this->assertEquals('28972085', $data->transaction->profileTransAuthOnly->customerProfileId); - $this->assertEquals('26317841', $data->transaction->profileTransAuthOnly->customerPaymentProfileId); - $this->assertEquals('27057151', $data->transaction->profileTransAuthOnly->customerShippingAddressId); - $this->assertEquals('Test authorize transaction', $data->transaction->profileTransAuthOnly->order->description); + $this->assertEquals('12.00', $data->transactionRequest->amount); + $this->assertEquals('28972085', $data->transactionRequest->profile->customerProfileId); + $this->assertEquals('26317841', $data->transactionRequest->profile->paymentProfile->paymentProfileId); + $this->assertEquals('27057151', $data->transactionRequest->profile->shippingProfileId); + $this->assertEquals('Test authorize transaction', $data->transactionRequest->order->description); } public function testShouldReturnExtraOptionsToDisableDuplicateWindowPeriod() diff --git a/tests/Message/CIMCaptureRequestTest.php b/tests/Message/CIMCaptureRequestTest.php index 3d34936b..b4daee99 100644 --- a/tests/Message/CIMCaptureRequestTest.php +++ b/tests/Message/CIMCaptureRequestTest.php @@ -24,15 +24,7 @@ public function setUp() public function testGetData() { $data = $this->request->getData(); - - $this->assertEquals('12.00', $data->transaction->profileTransCaptureOnly->amount); - $this->assertEquals('28972085', $data->transaction->profileTransCaptureOnly->customerProfileId); - $this->assertEquals('26317841', $data->transaction->profileTransCaptureOnly->customerPaymentProfileId); - $this->assertEquals('27057151', $data->transaction->profileTransCaptureOnly->customerShippingAddressId); - $this->assertEquals( - 'Test capture only transaction', - $data->transaction->profileTransCaptureOnly->order->description - ); - $this->assertEquals('V7DO8Q', $data->transaction->profileTransCaptureOnly->approvalCode); + $this->assertEquals('12.00', $data->transactionRequest->amount); + $this->assertEquals('2220001612', $data->transactionRequest->refTransId); } } \ No newline at end of file diff --git a/tests/Message/CIMPurchaseRequestTest.php b/tests/Message/CIMPurchaseRequestTest.php index 4cf76acc..aa90610e 100644 --- a/tests/Message/CIMPurchaseRequestTest.php +++ b/tests/Message/CIMPurchaseRequestTest.php @@ -24,7 +24,10 @@ public function setUp() public function testGetData() { $data = $this->request->getData(); - - $this->assertObjectHasAttribute('profileTransAuthCapture',$data->transaction); + $this->assertEquals('12.00', $data->transactionRequest->amount); + $this->assertEquals('28972085', $data->transactionRequest->profile->customerProfileId); + $this->assertEquals('26317841', $data->transactionRequest->profile->paymentProfile->paymentProfileId); + $this->assertEquals('27057151', $data->transactionRequest->profile->shippingProfileId); + $this->assertEquals('Test purchase transaction', $data->transactionRequest->order->description); } } diff --git a/tests/Message/CIMRefundRequestTest.php b/tests/Message/CIMRefundRequestTest.php index 79c5cfe2..6564869e 100644 --- a/tests/Message/CIMRefundRequestTest.php +++ b/tests/Message/CIMRefundRequestTest.php @@ -24,15 +24,9 @@ public function setUp() public function testGetData() { $data = $this->request->getData(); - - $this->assertEquals('12.00', $data->transaction->profileTransRefund->amount); - $this->assertEquals('28972085', $data->transaction->profileTransRefund->customerProfileId); - $this->assertEquals('26317841', $data->transaction->profileTransRefund->customerPaymentProfileId); - $this->assertEquals('27057151', $data->transaction->profileTransRefund->customerShippingAddressId); - $this->assertEquals( - 'Test refund transaction', - $data->transaction->profileTransRefund->order->description - ); - $this->assertEquals('2220001612', $data->transaction->profileTransRefund->transId); + $this->assertEquals('12.00', $data->transactionRequest->amount); + $this->assertEquals('28972085', $data->transactionRequest->profile->customerProfileId); + $this->assertEquals('26317841', $data->transactionRequest->profile->paymentProfile->paymentProfileId); + $this->assertEquals('2220001612', $data->transactionRequest->refTransId); } } \ No newline at end of file diff --git a/tests/Message/CIMResponseTest.php b/tests/Message/CIMResponseTest.php deleted file mode 100644 index 429853ea..00000000 --- a/tests/Message/CIMResponseTest.php +++ /dev/null @@ -1,40 +0,0 @@ -getMockRequest(), ''); - } - - public function testGetTransactionReference() - { - $httpResponse = $this->getMockHttpResponse('CIMAuthorizeSuccess.txt'); - $mockRequest = \Mockery::mock('\Omnipay\Common\Message\RequestInterface'); - $mockRequest->shouldReceive('getCardReference')->times(1)->andReturn( - '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}' - ); - $response = new CIMResponse($mockRequest, $httpResponse->getBody()); - - $this->assertEquals( - '{"approvalCode":"DMK100","transId":"2220001902","cardReference":"{\"customerProfileId\":\"28972085\",\"customerPaymentProfileId\":\"26317841\",\"customerShippingAddressId\":\"27057151\"}"}', - $response->getTransactionReference() - ); - } - - public function testShouldReturnResponseReasonCodeFromDirectResponse() - { - $httpResponse = $this->getMockHttpResponse('CIMRefundFailure.txt')->getBody(); - $response = new CIMResponse($this->getMockRequest(), $httpResponse); - - $this->assertEquals(54, $response->getResponseReasonCode()); - } -} diff --git a/tests/Mock/AIMVoidFailure.txt b/tests/Mock/AIMVoidFailure.txt index 6ad40059..bc64bcdc 100644 --- a/tests/Mock/AIMVoidFailure.txt +++ b/tests/Mock/AIMVoidFailure.txt @@ -8,6 +8,6 @@ X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private Content-Type: text/xml; charset=utf-8 -Content-Length: 826 +Content-Length: 839 -123456ErrorE00027The transaction was unsuccessful.3P0A6E047D5E58293477044C2F7EC8DF728033A valid referenced transaction ID is required. +123456ErrorE00027The transaction was unsuccessful.3P022434566A6E047D5E58293477044C2F7EC8DF728016The transaction cannot be found. diff --git a/tests/Mock/AIMVoidSuccess.txt b/tests/Mock/AIMVoidSuccess.txt index 7d02fb4d..75ecd07d 100644 --- a/tests/Mock/AIMVoidSuccess.txt +++ b/tests/Mock/AIMVoidSuccess.txt @@ -8,6 +8,6 @@ X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private Content-Type: text/xml; charset=utf-8 -Content-Length: 836 +Content-Length: 857 -123456OkI00001Successful.1P02217228520A6E047D5E58293477044C2F7EC8DF7280Visa310This transaction has already been voided. +OkI00001Successful.1ZJ5XABP2252805912225280591219BD707AFD6E0D2C27FA280FEF2181050XXXX0015MasterCard1This transaction has been approved. \ No newline at end of file diff --git a/tests/Mock/CIMAuthorizeFailure.txt b/tests/Mock/CIMAuthorizeFailure.txt deleted file mode 100644 index 8ff4d2f0..00000000 --- a/tests/Mock/CIMAuthorizeFailure.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 832 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:22 GMT - -ErrorE00003The 'AnetApi/xml/v1/schema/AnetApiSchema.xsd:amount' element is invalid - The value '-100.00' is invalid according to its datatype 'Decimal' - The MinInclusive constraint failed. diff --git a/tests/Mock/CIMAuthorizeSuccess.txt b/tests/Mock/CIMAuthorizeSuccess.txt deleted file mode 100644 index 5bd792a3..00000000 --- a/tests/Mock/CIMAuthorizeSuccess.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 832 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:22 GMT - -OkI00001Successful.1,1,1,This transaction has been approved.,DMK100,Y,2220001902,,,100.00,CC,auth_only,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,F667DD4AF086CA3C1588D77F088C2E1B,,2,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMCaptureFailure.txt b/tests/Mock/CIMCaptureFailure.txt deleted file mode 100644 index f15fbffe..00000000 --- a/tests/Mock/CIMCaptureFailure.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 1027 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:23 GMT - -ErrorE00014Approval Code is required. diff --git a/tests/Mock/CIMCaptureSuccess.txt b/tests/Mock/CIMCaptureSuccess.txt deleted file mode 100644 index 713b7b81..00000000 --- a/tests/Mock/CIMCaptureSuccess.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 1027 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:23 GMT - -OkI00001Successful.1,1,1,This transaction has been approved.,DMK100,P,2220001903,,,100.00,CC,capture_only,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,28AF50C3CB7ED3D132E6BED4558CDE8F,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMPurchaseFailure.txt b/tests/Mock/CIMPurchaseFailure.txt deleted file mode 100644 index 922df3b2..00000000 --- a/tests/Mock/CIMPurchaseFailure.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:24 GMT - -ErrorE00027This transaction has been declined.2,1,2,This transaction has been declined.,,Y,2220009663,,,110.00,CC,auth_capture,,Example,User,,123 Billing St Billsville,Billstown,CA,46282,US,,,kaylee729813@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,CE96C60797B394AF0BFFD6FEBEDE7C2A,,2,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27058978 diff --git a/tests/Mock/CIMPurchaseSuccess.txt b/tests/Mock/CIMPurchaseSuccess.txt deleted file mode 100644 index 61eb0ba3..00000000 --- a/tests/Mock/CIMPurchaseSuccess.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:24 GMT - -OkI00001Successful.1,1,1,This transaction has been approved.,MNLXJQ,Y,2220001904,,,110.00,CC,auth_capture,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,FE4AE98F3E5BD3AA01280DF8DC1EB640,,2,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMRefundFailure.txt b/tests/Mock/CIMRefundFailure.txt deleted file mode 100644 index b33fd61f..00000000 --- a/tests/Mock/CIMRefundFailure.txt +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.1 200 OK -Cache-Control: private -Content-Length: 832 -Content-Type: text/xml; -charset=utf-8 -Server: Microsoft-IIS/7.5 -X-AspNet-Version: 2.0.50727 -X-Powered-By: ASP.NET -Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET,POST,OPTIONS -Date: Thu, 18 Sep 2014 04:15:24 GMT - -ErrorE00027The referenced transaction does not meet the criteria for issuing a credit.3,2,54,The referenced transaction does not meet the criteria for issuing a credit.,,P,0,,,110.00,CC,credit,,Example,User,,123 Billing St Billsville,Billstown,CA,12345,US,,,kaylee346183@serenity.com,Example,User,,123 Shipping St Shipsville,Shipstown,NY,54321,US,,,,,,C42AF83A6FF4CF347A06BFF79715849D,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,,27057177 diff --git a/tests/Mock/CIMVoidResponse.txt b/tests/Mock/CIMVoidResponse.txt deleted file mode 100644 index 15d16ceb..00000000 --- a/tests/Mock/CIMVoidResponse.txt +++ /dev/null @@ -1,13 +0,0 @@ -HTTP/1.1 200 OK -Date: Sat, 02 Aug 2014 06:07:08 GMT -Server: Microsoft-IIS/6.0 -Access-Control-Allow-Origin: * -Access-Control-Allow-Methods: GET, POST, OPTIONS -Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method -X-Powered-By: ASP.NET -X-AspNet-Version: 2.0.50727 -Cache-Control: private -Content-Type: text/xml; charset=utf-8 -Content-Length: 836 - -OkI00001Successful.1,1,1,This transaction has been approved.,4A6ZAK,P,2252208237,,,0.00,CC,void,,,,,,,,12345,,,,,,,,,,,,,,,,,,0E3D23E0BB8AD22BDFD412B205E42308,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,, diff --git a/tests/Model/CardReferenceTest.php b/tests/Model/CardReferenceTest.php new file mode 100644 index 00000000..d471d2a4 --- /dev/null +++ b/tests/Model/CardReferenceTest.php @@ -0,0 +1,29 @@ +data = '{"customerProfileId":"203830614","customerPaymentProfileId":"197483796","customerShippingAddressId":"768245213"}'; + $this->cardReference = new CardReference($this->data); + } + + public function testShouldParseData() + { + $this->assertEquals('203830614', $this->cardReference->getCustomerProfileId()); + $this->assertEquals('197483796', $this->cardReference->getPaymentProfileId()); + $this->assertEquals('768245213', $this->cardReference->getShippingProfileId()); + } + + public function testShouldSerializeModel() + { + $actual = (string)$this->cardReference; + $this->assertEquals($this->data, $actual); + } +} diff --git a/tests/Model/TransactionReferenceTest.php b/tests/Model/TransactionReferenceTest.php new file mode 100644 index 00000000..b0cf0c80 --- /dev/null +++ b/tests/Model/TransactionReferenceTest.php @@ -0,0 +1,31 @@ +data = '{"approvalCode":"GA4OQP","transId":"2184493132","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}'; + $this->transactionReference = new TransactionReference($this->data); + } + + public function testShouldParseData() + { + $this->assertEquals('GA4OQP', $this->transactionReference->getApprovalCode()); + $this->assertEquals('2184493132', $this->transactionReference->getTransId()); + $cardReference = $this->transactionReference->getCardReference(); + $this->assertEquals('28972084', $cardReference->getCustomerProfileId()); + $this->assertEquals('26317840', $cardReference->getPaymentProfileId()); + $this->assertEquals('27057149', $cardReference->getShippingProfileId()); + } + + public function testShouldSerializeModel() + { + $this->assertEquals($this->data, (string)$this->transactionReference); + } +} From a5c0a9211546a6a803dcf5e3b36eedffbd6301d2 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 12 Mar 2016 23:14:40 +0530 Subject: [PATCH 108/254] Fix merge - make expiry optional for refund --- src/Message/AIMRefundRequest.php | 4 +++- tests/Message/AIMRefundRequestTest.php | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index 3e73f067..3d867c4a 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -38,7 +38,9 @@ public function getData() $this->validate('card'); $card = $this->getCard(); $data->transactionRequest->payment->creditCard->cardNumber = $card->getNumberLastFour(); - $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); + if ($card->getExpiryMonth()) { + $data->transactionRequest->payment->creditCard->expirationDate = $card->getExpiryDate('my'); + } } $data->transactionRequest->refTransId = $transactionRef->getTransId(); diff --git a/tests/Message/AIMRefundRequestTest.php b/tests/Message/AIMRefundRequestTest.php index 15c3317b..8bc5166e 100644 --- a/tests/Message/AIMRefundRequestTest.php +++ b/tests/Message/AIMRefundRequestTest.php @@ -32,7 +32,7 @@ public function testGetData() $data = $this->request->getData(); $this->assertEquals('refundTransaction', $data->transactionRequest->transactionType); - $this->assertEquals('12.12', (string)$data->transactionRequest->amount[0]); + $this->assertEquals('12.12', $data->transactionRequest->amount); $this->assertEquals('authnet-transaction-reference', $data->transactionRequest->refTransId); $setting = $data->transactionRequest->transactionSettings->setting[0]; @@ -40,6 +40,24 @@ public function testGetData() $this->assertEquals('false', $setting->settingValue); } + public function testGetDataWithoutExpiry() + { + $this->request->initialize(array( + 'transactionReference' => 'TRANS_ID', + 'amount' => 23.32, + 'card' => array( + 'number' => '1111' + ) + )); + + $data = $this->request->getData(); + + $this->assertEquals('TRANS_ID', $data->transactionRequest->refTransId); + $this->assertEquals('23.32', $data->transactionRequest->amount); + $this->assertEquals('1111', $data->transactionRequest->payment->creditCard->cardNumber); + $this->assertObjectNotHasAttribute('expirationDate', $data->transactionRequest->payment->creditCard); + } + public function testGetDataShouldFail() { $this->request->initialize( From 9b1a2256efa301f053c5b6519f34d5275e1f660d Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 12 Mar 2016 23:28:54 +0530 Subject: [PATCH 109/254] Fixed code style failures --- src/Message/AIMRefundRequest.php | 6 +++--- src/Model/CardReference.php | 4 +--- src/Model/TransactionReference.php | 4 +--- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index 3e73f067..5dcd748f 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -30,9 +30,9 @@ public function getData() if ($card = $transactionRef->getCard()) { $data->transactionRequest->payment->creditCard->cardNumber = $card->number; $data->transactionRequest->payment->creditCard->expirationDate = $card->expiry; - } elseif ($cardReference = $transactionRef->getCardReference()) { - $data->transactionRequest->profile->customerProfileId = $cardReference->getCustomerProfileId(); - $data->transactionRequest->profile->paymentProfile->paymentProfileId = $cardReference->getPaymentProfileId(); + } elseif ($cardRef = $transactionRef->getCardReference()) { + $data->transactionRequest->profile->customerProfileId = $cardRef->getCustomerProfileId(); + $data->transactionRequest->profile->paymentProfile->paymentProfileId = $cardRef->getPaymentProfileId(); } else { // Transaction reference only contains the transaction ID, so a card is required $this->validate('card'); diff --git a/src/Model/CardReference.php b/src/Model/CardReference.php index 5ffd8def..72925272 100644 --- a/src/Model/CardReference.php +++ b/src/Model/CardReference.php @@ -75,6 +75,4 @@ public function setShippingProfileId($shippingProfileId) { $this->shippingProfileId = $shippingProfileId; } - - -} \ No newline at end of file +} diff --git a/src/Model/TransactionReference.php b/src/Model/TransactionReference.php index 721fb556..76f62a6c 100644 --- a/src/Model/TransactionReference.php +++ b/src/Model/TransactionReference.php @@ -119,6 +119,4 @@ public function setCardReference($cardReference) { $this->cardReference = $cardReference; } - - -} \ No newline at end of file +} From 8ace4bfb773c779ccc7da2ca9519c93e5b8288e1 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Mon, 14 Mar 2016 18:23:48 +0530 Subject: [PATCH 110/254] Fix duplicate window setting --- src/AIMGateway.php | 10 ++++++++ src/Message/AIMAbstractRequest.php | 25 ++++++++----------- src/Message/AIMAuthorizeRequest.php | 3 +-- src/Message/AIMCaptureRequest.php | 2 +- src/Message/AIMRefundRequest.php | 2 +- src/Message/AIMVoidRequest.php | 2 +- src/Message/CIMCreateCardRequest.php | 4 +-- .../CIMCreatePaymentProfileRequest.php | 2 +- .../CIMUpdatePaymentProfileRequest.php | 2 +- tests/Message/AIMAuthorizeRequestTest.php | 6 +++-- tests/Message/CIMAuthorizeRequestTest.php | 9 +------ 11 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 16f8a5b8..fabfd05f 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -87,6 +87,16 @@ public function setDeveloperEndpoint($value) return $this->setParameter('developerEndpoint', $value); } + public function getDuplicateWindow() + { + return $this->getParameter('duplicateWindow'); + } + + public function setDuplicateWindow($value) + { + return $this->setParameter('duplicateWindow', $value); + } + /** * @param array $parameters * @return AIMAuthorizeRequest diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 438bfb5c..7e5fcaf9 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -72,7 +72,7 @@ public function setDuplicateWindow($value) private function getDuplicateWindow() { - return $this->getParameter('duplicateWindow'); // Maps x_duplicate_window + return $this->getParameter('duplicateWindow'); } public function getLiveEndpoint() @@ -235,24 +235,21 @@ protected function addBillingData(\SimpleXMLElement $data) return $data; } - protected function addTestModeSetting(\SimpleXMLElement $data) + protected function addTransactionSettings(\SimpleXMLElement $data) { - // Test mode setting - $data->transactionRequest->transactionSettings->setting->settingName = 'testRequest'; - $data->transactionRequest->transactionSettings->setting->settingValue = $this->getTestMode() ? 'true' : 'false'; + $i = 0; - return $data; - } + // 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'; - protected function addExtraOptions(\SimpleXMLElement $data) - { + // The duplicate window setting specifies the threshold for AuthorizeNet's duplicate transaction detection logic if (!is_null($this->getDuplicateWindow())) { - $extraOptions = $data->addChild('extraOptions'); - $node = dom_import_simplexml($extraOptions); - $nodeOwner = $node->ownerDocument; - $duplicateWindowStr = sprintf("x_duplicate_window=%s", $this->getDuplicateWindow()); - $node->appendChild($nodeOwner->createCDATASection($duplicateWindowStr)); + $i++; + $data->transactionRequest->transactionSettings->setting[$i]->settingName = 'duplicateWindow'; + $data->transactionRequest->transactionSettings->setting[$i]->settingValue = $this->getDuplicateWindow(); } + return $data; } } diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index f6dbbb48..919638e2 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -19,8 +19,7 @@ public function getData() $this->addPayment($data); $this->addCustomerIP($data); $this->addBillingData($data); - $this->addTestModeSetting($data); - $this->addExtraOptions($data); + $this->addTransactionSettings($data); return $data; } diff --git a/src/Message/AIMCaptureRequest.php b/src/Message/AIMCaptureRequest.php index a364870f..27ede287 100644 --- a/src/Message/AIMCaptureRequest.php +++ b/src/Message/AIMCaptureRequest.php @@ -16,7 +16,7 @@ public function getData() $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getAmount(); $data->transactionRequest->refTransId = $this->getTransactionReference()->getTransId(); - $this->addTestModeSetting($data); + $this->addTransactionSettings($data); return $data; } diff --git a/src/Message/AIMRefundRequest.php b/src/Message/AIMRefundRequest.php index 5264b763..90e65222 100644 --- a/src/Message/AIMRefundRequest.php +++ b/src/Message/AIMRefundRequest.php @@ -44,7 +44,7 @@ public function getData() } $data->transactionRequest->refTransId = $transactionRef->getTransId(); - $this->addTestModeSetting($data); + $this->addTransactionSettings($data); return $data; } diff --git a/src/Message/AIMVoidRequest.php b/src/Message/AIMVoidRequest.php index dba99681..39abb6d8 100644 --- a/src/Message/AIMVoidRequest.php +++ b/src/Message/AIMVoidRequest.php @@ -15,7 +15,7 @@ public function getData() $data = $this->getBaseData(); $data->transactionRequest->refTransId = $this->getTransactionReference()->getTransId(); - $this->addTestModeSetting($data); + $this->addTransactionSettings($data); return $data; } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 22f6b3e2..09ac180a 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -21,7 +21,7 @@ public function getData() $data = $this->getBaseData(); $this->addProfileData($data); - $this->addTestModeSetting($data); + $this->addTransactionSettings($data); return $data; } @@ -143,7 +143,7 @@ protected function addShippingData(\SimpleXMLElement $data) } } - protected function addTestModeSetting(\SimpleXMLElement $data) + protected function addTransactionSettings(\SimpleXMLElement $data) { $data->validationMode = $this->getValidationMode(); } diff --git a/src/Message/CIMCreatePaymentProfileRequest.php b/src/Message/CIMCreatePaymentProfileRequest.php index 066464a8..5948165b 100644 --- a/src/Message/CIMCreatePaymentProfileRequest.php +++ b/src/Message/CIMCreatePaymentProfileRequest.php @@ -22,7 +22,7 @@ public function getData() $data = $this->getBaseData(); $data->customerProfileId = $this->getCustomerProfileId(); $this->addPaymentProfileData($data); - $this->addTestModeSetting($data); + $this->addTransactionSettings($data); return $data; } diff --git a/src/Message/CIMUpdatePaymentProfileRequest.php b/src/Message/CIMUpdatePaymentProfileRequest.php index cda87a03..37a7e1a9 100644 --- a/src/Message/CIMUpdatePaymentProfileRequest.php +++ b/src/Message/CIMUpdatePaymentProfileRequest.php @@ -22,7 +22,7 @@ public function getData() $data = $this->getBaseData(); $data->customerProfileId = $this->getCustomerProfileId(); $this->addPaymentProfileData($data); - $this->addTestModeSetting($data); + $this->addTransactionSettings($data); return $data; } diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 63520b42..73788561 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -47,9 +47,11 @@ public function testGetDataTestMode() $this->assertEquals('true', $setting->settingValue); } - public function testShouldReturnExtraOptionsToDisableDuplicateWindowPeriod() + public function testShouldIncludeDuplicateWindowSetting() { $data = $this->request->getData(); - $this->assertEquals('x_duplicate_window=0', strip_tags($data->extraOptions)); + $setting = $data->transactionRequest->transactionSettings->setting[1]; + $this->assertEquals('duplicateWindow', $setting->settingName); + $this->assertEquals('0', $setting->settingValue); } } diff --git a/tests/Message/CIMAuthorizeRequestTest.php b/tests/Message/CIMAuthorizeRequestTest.php index 2d3f998f..04d6e90e 100644 --- a/tests/Message/CIMAuthorizeRequestTest.php +++ b/tests/Message/CIMAuthorizeRequestTest.php @@ -16,8 +16,7 @@ public function setUp() array( 'cardReference' => '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}', 'amount' => '12.00', - 'description' => 'Test authorize transaction', - 'duplicateWindow' => '0' + 'description' => 'Test authorize transaction' ) ); } @@ -32,10 +31,4 @@ public function testGetData() $this->assertEquals('27057151', $data->transactionRequest->profile->shippingProfileId); $this->assertEquals('Test authorize transaction', $data->transactionRequest->order->description); } - - public function testShouldReturnExtraOptionsToDisableDuplicateWindowPeriod() - { - $data = $this->request->getData(); - $this->assertEquals('x_duplicate_window=0', strip_tags($data->extraOptions)); - } } From cfe0227f76ad4b7cb167093d55375b2e116e15bf Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Fri, 18 Mar 2016 19:27:34 +0530 Subject: [PATCH 111/254] Point to the origin omnipay-common --- composer.json | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/composer.json b/composer.json index 59a25f1a..4f746f84 100644 --- a/composer.json +++ b/composer.json @@ -24,17 +24,11 @@ "homepage": "https://github.com/thephpleague/omnipay-authorizenet/contributors" } ], - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/xola/omnipay-common" - } - ], "autoload": { "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "~2.4.2" + "omnipay/common": "dev-master" }, "require-dev": { "omnipay/tests": "~2.0" From 95f2899409ccbde6e6831fe54622ae03d8976bc3 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Fri, 18 Mar 2016 19:52:07 +0530 Subject: [PATCH 112/254] Fix code style --- src/Message/AIMAbstractRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 7e5fcaf9..207502bf 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -241,7 +241,9 @@ protected function addTransactionSettings(\SimpleXMLElement $data) // 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'; + $data->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())) { From 39542c38e316d0760cf1e8b1ca939b1cd659339b Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Fri, 18 Mar 2016 20:36:00 +0530 Subject: [PATCH 113/254] Peg to a proper omnipay-common version dependency --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4f746f84..402d88fb 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "dev-master" + "omnipay/common": "~2.2" }, "require-dev": { "omnipay/tests": "~2.0" From e35e61557fab09a7754861a9361bdaad10b5088d Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Sat, 2 Apr 2016 08:34:06 +0530 Subject: [PATCH 114/254] Use correct endpoints form DPM and SIM --- src/SIMGateway.php | 6 +++++- tests/AIMGatewayTest.php | 16 ++++++++++++++++ tests/CIMGatewayTest.php | 16 ++++++++++++++++ tests/DPMGatewayTest.php | 24 ++++++++++++++++++++++-- tests/SIMGatewayTest.php | 16 ++++++++++++++++ 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/SIMGateway.php b/src/SIMGateway.php index 23f1941e..c5ccbe5c 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -15,7 +15,11 @@ public function getName() public function getDefaultParameters() { $parameters = parent::getDefaultParameters(); - $parameters['hashSecret'] = ''; + $parameters = array_merge($parameters, array( + 'hashSecret' => '', + 'liveEndpoint' => 'https://secure2.authorize.net/gateway/transact.dll', + 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll' + )); return $parameters; } diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index f45478b0..81a51537 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -40,6 +40,22 @@ public function setUp() ); } + public function testLiveEndpoint() + { + $this->assertEquals( + 'https://api.authorize.net/xml/v1/request.api', + $this->gateway->getLiveEndpoint() + ); + } + + public function testDeveloperEndpoint() + { + $this->assertEquals( + 'https://apitest.authorize.net/xml/v1/request.api', + $this->gateway->getDeveloperEndpoint() + ); + } + private function getExpiry($card) { return str_pad($card['expiryMonth'] . $card['expiryYear'], 6, '0', STR_PAD_LEFT); diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index b76e1048..8c785f25 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -46,6 +46,22 @@ public function setUp() ); } + public function testLiveEndpoint() + { + $this->assertEquals( + 'https://api.authorize.net/xml/v1/request.api', + $this->gateway->getLiveEndpoint() + ); + } + + public function testDeveloperEndpoint() + { + $this->assertEquals( + 'https://apitest.authorize.net/xml/v1/request.api', + $this->gateway->getDeveloperEndpoint() + ); + } + public function testCreateCardSuccess() { $this->setMockHttpResponse(array('CIMCreateCardSuccess.txt','CIMGetPaymentProfileSuccess.txt')); diff --git a/tests/DPMGatewayTest.php b/tests/DPMGatewayTest.php index e9b3851d..3140ef62 100644 --- a/tests/DPMGatewayTest.php +++ b/tests/DPMGatewayTest.php @@ -3,10 +3,14 @@ namespace Omnipay\AuthorizeNet; use Omnipay\Tests\GatewayTestCase; -//use Omnipay\AuthorizeNet\SIMGatewayTest; -class DPMGatewayTest extends GatewayTestCase //SIMGatewayTest +class DPMGatewayTest extends GatewayTestCase { + /** @var DPMGateway */ + protected $gateway; + /** @var array */ + private $options; + public function setUp() { parent::setUp(); @@ -23,6 +27,22 @@ public function setUp() ); } + public function testLiveEndpoint() + { + $this->assertEquals( + 'https://secure2.authorize.net/gateway/transact.dll', + $this->gateway->getLiveEndpoint() + ); + } + + public function testDeveloperEndpoint() + { + $this->assertEquals( + 'https://test.authorize.net/gateway/transact.dll', + $this->gateway->getDeveloperEndpoint() + ); + } + public function testAuthorize() { $response = $this->gateway->authorize($this->options)->send(); diff --git a/tests/SIMGatewayTest.php b/tests/SIMGatewayTest.php index 5ff89c69..7765eda9 100644 --- a/tests/SIMGatewayTest.php +++ b/tests/SIMGatewayTest.php @@ -24,6 +24,22 @@ public function setUp() ); } + public function testLiveEndpoint() + { + $this->assertEquals( + 'https://secure2.authorize.net/gateway/transact.dll', + $this->gateway->getLiveEndpoint() + ); + } + + public function testDeveloperEndpoint() + { + $this->assertEquals( + 'https://test.authorize.net/gateway/transact.dll', + $this->gateway->getDeveloperEndpoint() + ); + } + public function testAuthorize() { $response = $this->gateway->authorize($this->options)->send(); From bcb4369cc49bab830445195b96e52ca18a2a343f Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 28 May 2016 10:44:22 +0100 Subject: [PATCH 115/254] Issue 38 move order of billTo and customerIp elements in AIM authorisation. --- src/Message/AIMAuthorizeRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 919638e2..ab363d53 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -17,8 +17,10 @@ public function getData() $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getAmount(); $this->addPayment($data); - $this->addCustomerIP($data); $this->addBillingData($data); + // CHECKME: is shipping data useful here? + //$this->addShippingData($data); + $this->addCustomerIP($data); $this->addTransactionSettings($data); return $data; From 77729dcff733f708154d4a0afb009b90520189f7 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 28 May 2016 16:39:43 +0100 Subject: [PATCH 116/254] Forgot to save file before last commit. --- src/Message/AIMResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 4c99215e..624b2e6c 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -24,7 +24,7 @@ public function __construct(AbstractRequest $request, $data) $xml = preg_replace('/]+>/', '', (string)$data); try { - $xml = simplexml_load_string($xml); + $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); } catch (\Exception $e) { throw new InvalidResponseException(); } From 45c85fcd3a0095d20f610478ccf72c375f313d8a Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 28 May 2016 17:17:35 +0100 Subject: [PATCH 117/254] Issue #38 new test to confirm order of transactionRequest elements. --- src/Message/AIMAuthorizeRequest.php | 2 -- tests/Message/AIMAuthorizeRequestTest.php | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index ab363d53..21cb991a 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -18,8 +18,6 @@ public function getData() $data->transactionRequest->amount = $this->getAmount(); $this->addPayment($data); $this->addBillingData($data); - // CHECKME: is shipping data useful here? - //$this->addShippingData($data); $this->addCustomerIP($data); $this->addTransactionSettings($data); diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 73788561..245d7098 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -31,6 +31,23 @@ public function testGetData() $this->assertEquals('10.0.0.1', $data->transactionRequest->customerIP); $this->assertEquals('cust-id', $data->transactionRequest->customer->id); + // Issue #38 Make sure the transactionRequest properties are correctly ordered. + // This feels messy, but works. + $transactionRequestProperties = array_keys(get_object_vars($data->transactionRequest)); + // The names of the properies of the $data->transactionRequest object, in the order in + // which they must be defined for Authorize.Net to accept the transaction. + $keys = array( + "transactionType", + "amount", + "payment", + "customer", + "billTo", + "shipTo", + "customerIP", + "transactionSettings" + ); + $this->assertEquals($keys, $transactionRequestProperties); + $setting = $data->transactionRequest->transactionSettings->setting[0]; $this->assertEquals('testRequest', $setting->settingName); $this->assertEquals('false', $setting->settingValue); From a8cafa899a0bdd22dfd1fc10ca179bcc796be847 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 2 Jul 2016 12:51:05 -0700 Subject: [PATCH 118/254] DeleteCustomerPaymentProfile Request Adds the deleteCustomerPaymentProfileRequest to remove a previously saved customer profile. --- src/CIMGateway.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index bf0d0cba..5e4123b2 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -45,6 +45,17 @@ public function createCard(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMCreateCardRequest', $parameters); } + /** + * Removes a customer payment profile + * + * @param array $parameters + * + * @return CIMDeletePaymentProfileRequest + */ + public function deleteCard(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMDeletePaymentProfileRequest', $parameters); + } public function authorize(array $parameters = array()) { From 2cf352e522d65b42f5e71de7f66cdd862c11ed70 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 2 Jul 2016 12:52:50 -0700 Subject: [PATCH 119/254] Create CIMDeletePaymentProfileResponse.php --- src/Message/CIMDeletePaymentProfileResponse.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/Message/CIMDeletePaymentProfileResponse.php diff --git a/src/Message/CIMDeletePaymentProfileResponse.php b/src/Message/CIMDeletePaymentProfileResponse.php new file mode 100644 index 00000000..aa54c462 --- /dev/null +++ b/src/Message/CIMDeletePaymentProfileResponse.php @@ -0,0 +1,16 @@ +request->getCustomerPaymentProfileId(); + } +} From b81954dce12b6dc51132c3c2138f59028411b9d4 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 2 Jul 2016 12:53:09 -0700 Subject: [PATCH 120/254] Create CIMDeletePaymentProfileRequest.php --- .../CIMDeletePaymentProfileRequest.php | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/Message/CIMDeletePaymentProfileRequest.php diff --git a/src/Message/CIMDeletePaymentProfileRequest.php b/src/Message/CIMDeletePaymentProfileRequest.php new file mode 100644 index 00000000..91b8fc13 --- /dev/null +++ b/src/Message/CIMDeletePaymentProfileRequest.php @@ -0,0 +1,31 @@ +validate('customerProfileId', 'customerPaymentProfileId'); + + $data = $this->getBaseData(); + $data->customerProfileId = $this->getCustomerProfileId(); + $data->customerPaymentProfileId = $this->getCustomerPaymentProfileId(); + + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new CIMDeletePaymentProfileResponse($this, $httpResponse->getBody()); + } +} From 75128466a86244cde8203a93bb7cbbffff20efec Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 7 Jul 2016 10:24:48 -0700 Subject: [PATCH 121/254] Update CIMDeletePaymentProfileRequest.php Changed the parent class to the abstract request, since there is no need for additional methods --- src/Message/CIMDeletePaymentProfileRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMDeletePaymentProfileRequest.php b/src/Message/CIMDeletePaymentProfileRequest.php index 91b8fc13..4b30ac10 100644 --- a/src/Message/CIMDeletePaymentProfileRequest.php +++ b/src/Message/CIMDeletePaymentProfileRequest.php @@ -5,7 +5,7 @@ /** * Request to delete a customer payment profile for an existing customer and existing payment profile. */ -class CIMDeletePaymentProfileRequest extends CIMCreatePaymentProfileRequest +class CIMDeletePaymentProfileRequest extends CIMAbstractRequest { protected $requestType = 'deleteCustomerPaymentProfileRequest'; From bfd7b848ff7d5556a66ee81ced575e414624a52e Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 7 Jul 2016 10:26:23 -0700 Subject: [PATCH 122/254] Update CIMDeletePaymentProfileResponse.php Changed the parent class, since there is no need for additional methods --- src/Message/CIMDeletePaymentProfileResponse.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Message/CIMDeletePaymentProfileResponse.php b/src/Message/CIMDeletePaymentProfileResponse.php index aa54c462..afbe4715 100644 --- a/src/Message/CIMDeletePaymentProfileResponse.php +++ b/src/Message/CIMDeletePaymentProfileResponse.php @@ -5,12 +5,8 @@ /** * Authorize.Net CIM Delete payment profile Response */ -class CIMDeletePaymentProfileResponse extends CIMCreatePaymentProfileResponse +class CIMDeletePaymentProfileResponse extends CIMAbstractResponse { protected $responseType = 'deleteCustomerPaymentProfileResponse'; - public function getCustomerPaymentProfileId() - { - return $this->request->getCustomerPaymentProfileId(); - } } From d1efeadf4975f4ab1e85112b89fd8af2105a2380 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 7 Jul 2016 11:33:20 -0700 Subject: [PATCH 123/254] Update CIMGateway.php Adds getPaymentProfile method --- src/CIMGateway.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index 5e4123b2..b515f5b2 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -45,13 +45,12 @@ public function createCard(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMCreateCardRequest', $parameters); } - /** - * Removes a customer payment profile - * - * @param array $parameters - * - * @return CIMDeletePaymentProfileRequest - */ + + public function getPaymentProfile(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMGetPaymentProfileRequest', $parameters); + } + public function deleteCard(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMDeletePaymentProfileRequest', $parameters); From 9f62df561ae896e28f8c7b62c52304a632665ac4 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 7 Jul 2016 11:34:03 -0700 Subject: [PATCH 124/254] Update CIMGatewayIntegrationTest.php Adds deletePaymentProfileRequest integration test --- tests/CIMGatewayIntegrationTest.php | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 59bf1049..7b4a9087 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -112,6 +112,41 @@ public function testCustomerAndPaymentProfile() ); } + public function testPaymentProfileDelete() + { + + // Create a customer profile with the specified email (email is the identifier) (to have a deletable payment profile) + $email = uniqid('', true) . '@example.com'; + $cardRef = $this->createCard(array('email' => $email)); + $cardRef = json_decode($cardRef,true); + + //Delete the recently created payment profile (deletes the payment profile only, not the customer profile) + $params = array( + 'customerProfileId' => $cardRef['customerProfileId'], + 'customerPaymentProfileId' => $cardRef['customerPaymentProfileId'] + ); + $defaults = array( ); + $params = array_merge($defaults, $params); + $request = $this->gateway->deleteCard($params); + $request->setDeveloperMode(true); + /* @var $response CIMResponse */ + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Should be successful as we have deleted a payment profile'); + + /* retrieve the recently deleted payment profile for the customer profile from authorize.net (returns NULL) */ + $params = array( + 'customerProfileId' => $cardRef['customerProfileId'], + 'customerPaymentProfileId' => $cardRef['customerPaymentProfileId'] + ); + $defaults = array( ); + $params = array_merge($defaults, $params); + $request = $this->gateway->getPaymentProfile($params); + $request->setDeveloperMode(true); + /* @var $response CIMResponse */ + $response = $request->send(); + $this->assertNull($response->getCustomerPaymentProfileId(), 'Should be null as we have deleted that payment profile'); + } + public function testAuthorizeCapture() { $cardRef = $this->createCard(); From 17d1a908b787f7841cc2c0d2053205d2b6fc3801 Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 7 Jul 2016 11:42:54 -0700 Subject: [PATCH 125/254] Update CIMDeletePaymentProfileResponse.php Fix PSR2: The closing brace for the class must go on the next line after the body --- src/Message/CIMDeletePaymentProfileResponse.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Message/CIMDeletePaymentProfileResponse.php b/src/Message/CIMDeletePaymentProfileResponse.php index afbe4715..475fdf7a 100644 --- a/src/Message/CIMDeletePaymentProfileResponse.php +++ b/src/Message/CIMDeletePaymentProfileResponse.php @@ -8,5 +8,4 @@ class CIMDeletePaymentProfileResponse extends CIMAbstractResponse { protected $responseType = 'deleteCustomerPaymentProfileResponse'; - } From 07e5af2a537bd9637743b030e0fb7bb9b17eeae3 Mon Sep 17 00:00:00 2001 From: Ryan Sexton Date: Sat, 16 Jul 2016 16:07:41 -0400 Subject: [PATCH 126/254] Fixed getShippingLastName() was being used to seed shipTo->firstName. --- src/Message/AIMAbstractRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 207502bf..de0fc16b 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -222,7 +222,7 @@ protected function addBillingData(\SimpleXMLElement $data) $req->billTo->zip = $card->getBillingPostcode(); $req->billTo->country = $card->getBillingCountry(); - $req->shipTo->firstName = $card->getShippingLastName(); + $req->shipTo->firstName = $card->getShippingFirstName(); $req->shipTo->lastName = $card->getShippingLastName(); $req->shipTo->company = $card->getShippingCompany(); $req->shipTo->address = trim($card->getShippingAddress1() . " \n" . $card->getShippingAddress2()); From 5863e57c3f2e53b1351f2f70d2d1372f24756bd0 Mon Sep 17 00:00:00 2001 From: Matt Wisner Date: Tue, 30 Aug 2016 17:11:03 -0400 Subject: [PATCH 127/254] Set phoneNumber billTo and phoneNumber shipTo on AIM requests. --- src/Message/AIMAbstractRequest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index de0fc16b..c66e84b4 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -221,6 +221,7 @@ protected function addBillingData(\SimpleXMLElement $data) $req->billTo->state = $card->getBillingState(); $req->billTo->zip = $card->getBillingPostcode(); $req->billTo->country = $card->getBillingCountry(); + $req->billTo->phoneNumber = $card->getBillingPhone(); $req->shipTo->firstName = $card->getShippingFirstName(); $req->shipTo->lastName = $card->getShippingLastName(); @@ -230,6 +231,7 @@ protected function addBillingData(\SimpleXMLElement $data) $req->shipTo->state = $card->getShippingState(); $req->shipTo->zip = $card->getShippingPostcode(); $req->shipTo->country = $card->getShippingCountry(); + $req->shipTo->phoneNumber = $card->getShippingPhone(); } return $data; From c0b361df3a75f604fd45c4633610e2b0e07cec18 Mon Sep 17 00:00:00 2001 From: Matt Wisner Date: Wed, 31 Aug 2016 14:25:53 -0400 Subject: [PATCH 128/254] Remove phoneNumber from shipTo --- src/Message/AIMAbstractRequest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index c66e84b4..6da15696 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -231,7 +231,6 @@ protected function addBillingData(\SimpleXMLElement $data) $req->shipTo->state = $card->getShippingState(); $req->shipTo->zip = $card->getShippingPostcode(); $req->shipTo->country = $card->getShippingCountry(); - $req->shipTo->phoneNumber = $card->getShippingPhone(); } return $data; From fd15aea3090321927ff69a4d846cea8a0670c385 Mon Sep 17 00:00:00 2001 From: Vincent Gabriel Date: Thu, 13 Oct 2016 07:47:46 -0700 Subject: [PATCH 129/254] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 402d88fb..681a1dec 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "omnipay/authorizenet", + "name": "avninc/authorizenet", "type": "library", "description": "Authorize.Net gateway for the Omnipay payment processing library", "keywords": [ From d0b51eb20c15237176e2e7be55ef59617ca4e35e Mon Sep 17 00:00:00 2001 From: Vincent Gabriel Date: Thu, 13 Oct 2016 07:57:36 -0700 Subject: [PATCH 130/254] #50 - AIMResponse->getTransactionReference --- src/Message/AIMResponse.php | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 624b2e6c..4be1117f 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -117,28 +117,24 @@ public function getAVSCode() */ public function getTransactionReference($serialize = true) { - if ($this->isSuccessful()) { - $body = $this->data->transactionResponse[0]; - $transactionRef = new TransactionReference(); - $transactionRef->setApprovalCode((string)$body->authCode); - $transactionRef->setTransId((string)$body->transId); - - try { - // Need to store card details in the transaction reference since it is required when doing a refund - if ($card = $this->request->getCard()) { - $transactionRef->setCard(array( - 'number' => $card->getNumberLastFour(), - 'expiry' => $card->getExpiryDate('mY') - )); - } elseif ($cardReference = $this->request->getCardReference()) { - $transactionRef->setCardReference(new CardReference($cardReference)); - } - } catch (\Exception $e) { - } + $body = $this->data->transactionResponse[0]; + $transactionRef = new TransactionReference(); + $transactionRef->setApprovalCode((string)$body->authCode); + $transactionRef->setTransId((string)$body->transId); - return $serialize ? (string)$transactionRef : $transactionRef; + try { + // Need to store card details in the transaction reference since it is required when doing a refund + if ($card = $this->request->getCard()) { + $transactionRef->setCard(array( + 'number' => $card->getNumberLastFour(), + 'expiry' => $card->getExpiryDate('mY') + )); + } elseif ($cardReference = $this->request->getCardReference()) { + $transactionRef->setCardReference(new CardReference($cardReference)); + } + } catch (\Exception $e) { } - return null; + return $serialize ? (string)$transactionRef : $transactionRef; } } From 96358aba236b0f6c13daad8e0927a09d159d26be Mon Sep 17 00:00:00 2001 From: Vincent Gabriel Date: Thu, 13 Oct 2016 07:59:30 -0700 Subject: [PATCH 131/254] #50 - AIMResponse->getTransactionReference --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 681a1dec..402d88fb 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "avninc/authorizenet", + "name": "omnipay/authorizenet", "type": "library", "description": "Authorize.Net gateway for the Omnipay payment processing library", "keywords": [ From bd0851d7d792b4c05ead6457b6fe196eb21b6ddc Mon Sep 17 00:00:00 2001 From: Ryan Herriman Date: Tue, 18 Oct 2016 15:25:02 -0600 Subject: [PATCH 132/254] Use new Akamai SureRoute endpoint for AIM and CIM --- src/AIMGateway.php | 2 +- tests/AIMGatewayTest.php | 2 +- tests/CIMGatewayTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index fabfd05f..683ed160 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -26,7 +26,7 @@ public function getDefaultParameters() 'transactionKey' => '', 'testMode' => false, 'developerMode' => false, - 'liveEndpoint' => 'https://api.authorize.net/xml/v1/request.api', + 'liveEndpoint' => 'https://api2.authorize.net/xml/v1/request.api', 'developerEndpoint' => 'https://apitest.authorize.net/xml/v1/request.api', ); } diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 81a51537..33020033 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -43,7 +43,7 @@ public function setUp() public function testLiveEndpoint() { $this->assertEquals( - 'https://api.authorize.net/xml/v1/request.api', + 'https://api2.authorize.net/xml/v1/request.api', $this->gateway->getLiveEndpoint() ); } diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 8c785f25..f2851737 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -49,7 +49,7 @@ public function setUp() public function testLiveEndpoint() { $this->assertEquals( - 'https://api.authorize.net/xml/v1/request.api', + 'https://api2.authorize.net/xml/v1/request.api', $this->gateway->getLiveEndpoint() ); } From fa4fce23bfb3516bb6b64c2fa017e85f1cdc5174 Mon Sep 17 00:00:00 2001 From: Vincent Gabriel Date: Wed, 19 Oct 2016 10:16:30 -0700 Subject: [PATCH 133/254] fixed tests and added php 7.0 to travis yaml file --- .travis.yml | 1 + tests/AIMGatewayTest.php | 13 ++++++++----- tests/CIMGatewayTest.php | 9 +++++---- tests/Message/AIMResponseTest.php | 8 ++++---- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index b8d4825c..4893becf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 - hhvm matrix: diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 81a51537..6a6a6f51 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -81,9 +81,10 @@ public function testAuthorizeFailure() $this->setMockHttpResponse('AIMAuthorizeFailure.txt'); $response = $this->gateway->authorize($this->purchaseOptions)->send(); + $expiry = $this->getExpiry($this->purchaseOptions['card']); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0","card":{"number":"1111","expiry":"' . $expiry . '"}}', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); } @@ -105,7 +106,7 @@ public function testCaptureFailure() $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); } @@ -128,7 +129,8 @@ public function testPurchaseFailure() $response = $this->gateway->purchase($this->purchaseOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $expiry = $this->getExpiry($this->purchaseOptions['card']); + $this->assertSame('{"approvalCode":"","transId":"0","card":{"number":"1111","expiry":"' . $expiry . '"}}', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); } @@ -150,7 +152,7 @@ public function testVoidFailure() $response = $this->gateway->void($this->voidOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); } @@ -173,7 +175,8 @@ public function testRefundFailure() $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $expiry = $this->getExpiry($this->refundOptions['card']); + $this->assertSame('{"approvalCode":"","transId":"0","card":{"number":"1111","expiry":"' . $expiry . '"}}', $response->getTransactionReference()); $this->assertSame('The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage()); } } diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 8c785f25..8c0f1b8c 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -150,7 +150,8 @@ public function testAuthorizeFailure() $this->setMockHttpResponse('AIMAuthorizeFailure.txt'); $response = $this->gateway->authorize($this->authorizeOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + + $this->assertSame('{"approvalCode":"","transId":"0","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', $response->getTransactionReference()); $this->assertEquals("A valid amount is required.", $response->getMessage()); } @@ -172,7 +173,7 @@ public function testCaptureFailure() $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertEquals(0, $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); } @@ -194,7 +195,7 @@ public function testPurchaseFailure() $response = $this->gateway->purchase($this->authorizeOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0","cardReference":"{\"customerProfileId\":\"28972084\",\"customerPaymentProfileId\":\"26317840\",\"customerShippingAddressId\":\"27057149\"}"}', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); } @@ -216,7 +217,7 @@ public function testRefundFailure() $response = $this->gateway->refund($this->refundOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertEquals(0, $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame( 'The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage() diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index e0950474..6c966cd0 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -42,7 +42,7 @@ public function testAuthorizeFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(5, $response->getReasonCode()); @@ -70,7 +70,7 @@ public function testCaptureFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(16, $response->getReasonCode()); @@ -98,7 +98,7 @@ public function testPurchaseFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(5, $response->getReasonCode()); @@ -126,7 +126,7 @@ public function testRefundFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertNull($response->getTransactionReference()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The referenced transaction does not meet the criteria for issuing a credit.', $response->getMessage()); $this->assertSame(3, $response->getResultCode()); $this->assertSame(54, $response->getReasonCode()); From 564da01ab1395260c2af65149b248409a3689c43 Mon Sep 17 00:00:00 2001 From: Brendan Date: Fri, 21 Oct 2016 10:26:50 -0400 Subject: [PATCH 134/254] Add description to AIM request and update related tests --- src/Message/AIMAbstractRequest.php | 2 ++ tests/AIMGatewayTest.php | 6 +++++- tests/Message/AIMAuthorizeRequestTest.php | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 6da15696..17468a34 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -210,6 +210,8 @@ protected function addBillingData(\SimpleXMLElement $data) $req->customer->id = $customer; } + $req->order->description = $this->getDescription(); + /** @var CreditCard $card */ if ($card = $this->getCard()) { // A card is present, so include billing and shipping details diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 81a51537..595862ab 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -22,21 +22,25 @@ public function setUp() $this->purchaseOptions = array( 'amount' => '10.00', 'card' => $this->getValidCard(), + 'description' => 'purchase', ); $this->captureOptions = array( 'amount' => '10.00', 'transactionReference' => '12345', + 'description' => 'capture', ); $this->voidOptions = array( 'transactionReference' => '12345', + 'description' => 'void', ); $this->refundOptions = array( 'amount' => '10.00', 'transactionReference' => '12345', - 'card' => $this->getValidCard() + 'card' => $this->getValidCard(), + 'description' => 'refund', ); } diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 245d7098..852a1b3b 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -41,6 +41,7 @@ public function testGetData() "amount", "payment", "customer", + "order", "billTo", "shipTo", "customerIP", From 650182569ec5ff1f325edd4b96de28abd4ecd7ad Mon Sep 17 00:00:00 2001 From: Nate Emmons Date: Tue, 1 Nov 2016 11:02:11 -0400 Subject: [PATCH 135/254] set customer email in AIMAbstractRequest --- src/Message/AIMAbstractRequest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 6da15696..ded98f07 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -213,6 +213,8 @@ protected function addBillingData(\SimpleXMLElement $data) /** @var CreditCard $card */ if ($card = $this->getCard()) { // A card is present, so include billing and shipping details + $req->customer->email = $card->getEmail(); + $req->billTo->firstName = $card->getBillingFirstName(); $req->billTo->lastName = $card->getBillingLastName(); $req->billTo->company = $card->getBillingCompany(); From 536972544a0cc54fa4b745e2d96ba9826490c1f6 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 9 Nov 2016 23:09:12 +0000 Subject: [PATCH 136/254] Small code tidy-up. --- src/Message/AIMAbstractRequest.php | 11 ++++++++++- src/Message/CIMAbstractRequest.php | 3 +++ src/Message/CIMAuthorizeRequest.php | 4 ++++ tests/Message/AIMAbstractRequestTest.php | 4 ++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index ded98f07..34d7fec9 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -118,6 +118,7 @@ public function setTransactionReference($value) $transactionRef = new TransactionReference(); $transactionRef->setTransId($value); } + return $this->setParameter('transactionReference', $transactionRef); } @@ -130,6 +131,7 @@ public function setCardReference($value) if (!($value instanceof CardReference)) { $value = new CardReference($value); } + return parent::setCardReference($value); } @@ -140,15 +142,18 @@ public function setCardReference($value) public function getCardReference($serialize = true) { $value = parent::getCardReference(); + if ($serialize) { $value = (string)$value; } + return $value; } public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); @@ -162,10 +167,12 @@ public function sendData($data) public function getBaseData() { $data = new \SimpleXMLElement('<' . $this->requestType . '/>'); + $data->addAttribute('xmlns', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'); $this->addAuthentication($data); $this->addReferenceId($data); $this->addTransactionType($data); + return $data; } @@ -178,6 +185,7 @@ protected function addAuthentication(\SimpleXMLElement $data) protected function addReferenceId(\SimpleXMLElement $data) { $txnId = $this->getTransactionId(); + if (!empty($txnId)) { $data->refId = $this->getTransactionId(); } @@ -189,6 +197,7 @@ protected function addTransactionType(\SimpleXMLElement $data) // The extending class probably hasn't specified an "action" throw new InvalidRequestException(); } + $data->transactionRequest->transactionType = $this->action; } @@ -214,7 +223,7 @@ protected function addBillingData(\SimpleXMLElement $data) if ($card = $this->getCard()) { // A card is present, so include billing and shipping details $req->customer->email = $card->getEmail(); - + $req->billTo->firstName = $card->getBillingFirstName(); $req->billTo->lastName = $card->getBillingLastName(); $req->billTo->company = $card->getBillingCompany(); diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 171f0340..74d057bd 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -24,9 +24,11 @@ public function setValidationMode($value) public function getValidationMode() { $validationMode = $this->getParameter('validationMode'); + if ($validationMode !== self::VALIDATION_MODE_NONE) { $validationMode = $this->getDeveloperMode() ? self::VALIDATION_MODE_TEST : self::VALIDATION_MODE_LIVE; } + return $validationMode; } @@ -100,6 +102,7 @@ public function getDefaultBillTo() public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index 7729eb21..827e84da 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -15,10 +15,14 @@ protected function addPayment(\SimpleXMLElement $data) /** @var mixed $req */ $req = $data->transactionRequest; + /** @var CardReference $cardRef */ $cardRef = $this->getCardReference(false); + $req->profile->customerProfileId = $cardRef->getCustomerProfileId(); + $req->profile->paymentProfile->paymentProfileId = $cardRef->getPaymentProfileId(); + if ($shippingProfileId = $cardRef->getShippingProfileId()) { $req->profile->shippingProfileId = $shippingProfileId; } diff --git a/tests/Message/AIMAbstractRequestTest.php b/tests/Message/AIMAbstractRequestTest.php index 04d01400..f48ea78f 100644 --- a/tests/Message/AIMAbstractRequestTest.php +++ b/tests/Message/AIMAbstractRequestTest.php @@ -16,8 +16,8 @@ public function setUp() $this->request = $this->getMockForAbstractClass( '\Omnipay\AuthorizeNet\Message\AIMAbstractRequest', array( - $this->getMock('\Guzzle\Http\ClientInterface'), - $this->getMock('\Symfony\Component\HttpFoundation\Request') + $this->createMock('\Guzzle\Http\ClientInterface'), + $this->createMock('\Symfony\Component\HttpFoundation\Request') ) ); } From 497ea0259903cc5e0d0844a4d8e4074fe6f5e750 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 9 Nov 2016 23:23:04 +0000 Subject: [PATCH 137/254] Added test for AIM XML customer email. --- tests/Message/AIMAuthorizeRequestTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 245d7098..d4a4261d 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -12,12 +12,14 @@ class AIMAuthorizeRequestTest extends TestCase public function setUp() { $this->request = new AIMAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest()); + $card = $this->getValidCard(); + $card['email'] = 'example@example.net'; $this->request->initialize( array( 'clientIp' => '10.0.0.1', 'amount' => '12.00', 'customerId' => 'cust-id', - 'card' => $this->getValidCard(), + 'card' => $card, 'duplicateWindow' => 0 ) ); @@ -30,6 +32,7 @@ public function testGetData() $this->assertEquals('authOnlyTransaction', $data->transactionRequest->transactionType); $this->assertEquals('10.0.0.1', $data->transactionRequest->customerIP); $this->assertEquals('cust-id', $data->transactionRequest->customer->id); + $this->assertEquals('example@example.net', $data->transactionRequest->customer->email); // Issue #38 Make sure the transactionRequest properties are correctly ordered. // This feels messy, but works. From 587d5fa487f733a226847841f6731f8723686ba6 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 9 Nov 2016 23:30:51 +0000 Subject: [PATCH 138/254] Restored "createMock" back to deprecated "getMock". It worked for me, but not on Travis. No time to argue with Travis, so it gets what works for it, for mow. --- tests/Message/AIMAbstractRequestTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Message/AIMAbstractRequestTest.php b/tests/Message/AIMAbstractRequestTest.php index f48ea78f..04d01400 100644 --- a/tests/Message/AIMAbstractRequestTest.php +++ b/tests/Message/AIMAbstractRequestTest.php @@ -16,8 +16,8 @@ public function setUp() $this->request = $this->getMockForAbstractClass( '\Omnipay\AuthorizeNet\Message\AIMAbstractRequest', array( - $this->createMock('\Guzzle\Http\ClientInterface'), - $this->createMock('\Symfony\Component\HttpFoundation\Request') + $this->getMock('\Guzzle\Http\ClientInterface'), + $this->getMock('\Symfony\Component\HttpFoundation\Request') ) ); } From ef3667060b2d8350aa6c19341866e8dc42b0c4ea Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Thu, 10 Nov 2016 00:07:48 +0000 Subject: [PATCH 139/254] Change postion of the AIM "order" element in the request. The "order" element must come before the "customer" element. Authorize.Net is very fussy about the order in which the XML elements are put together. --- src/Message/AIMAbstractRequest.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 96d8c90f..98dacb2d 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -150,6 +150,16 @@ public function getCardReference($serialize = true) return $value; } + public function getInvoiceNumber() + { + return $this->getParameter('invoiceNumber'); + } + + public function setInvoiceNumber($value) + { + return $this->setParameter('invoiceNumber', $value); + } + public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); @@ -213,13 +223,17 @@ protected function addBillingData(\SimpleXMLElement $data) /** @var mixed $req */ $req = $data->transactionRequest; + // The order must come before the customer ID. + $req->order->invoiceNumber = $this->getInvoiceNumber(); + $req->order->description = $this->getDescription(); + // Merchant assigned customer ID $customer = $this->getCustomerId(); if (!empty($customer)) { $req->customer->id = $customer; } - $req->order->description = $this->getDescription(); + //$req->order->description = $this->getDescription(); /** @var CreditCard $card */ if ($card = $this->getCard()) { From e719a3a377b371453d0ba862d83b5b7065c18c07 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Thu, 10 Nov 2016 00:14:41 +0000 Subject: [PATCH 140/254] Position of "order" in tests in relation to "customer". --- tests/Message/AIMAuthorizeRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index ceb09878..5448905e 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -43,8 +43,8 @@ public function testGetData() "transactionType", "amount", "payment", - "customer", "order", + "customer", "billTo", "shipTo", "customerIP", From 1a3cdb88101f92c0e347b4d2fe5cf451e39544c4 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Thu, 10 Nov 2016 01:00:22 +0000 Subject: [PATCH 141/254] Issue 16: support invoiceNumber for both CIM and DPM. --- src/Message/SIMAbstractRequest.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Message/SIMAbstractRequest.php b/src/Message/SIMAbstractRequest.php index 6fb01c68..4167e1fe 100644 --- a/src/Message/SIMAbstractRequest.php +++ b/src/Message/SIMAbstractRequest.php @@ -84,6 +84,16 @@ public function getDeveloperEndpoint() return $this->getParameter('developerEndpoint'); } + public function setInvoiceNumber($value) + { + return $this->setParameter('invoiceNumber', $value); + } + + public function getInvoiceNumber() + { + return $this->getParameter('invoiceNumber'); + } + /** * Base data used only for the AIM API. */ @@ -107,8 +117,8 @@ protected function getBillingData() $data = array(); $data['x_amount'] = $this->getAmount(); - // This is deprecated. The invoice number field is reserved for the invoice number. - $data['x_invoice_num'] = $this->getTransactionId(); + // The invoice number field is properly supported. + $data['x_invoice_num'] = $this->getInvoiceNumber(); // A custom field can be used to pass over the merchant site transaction ID. $data[static::TRANSACTION_ID_PARAM] = $this->getTransactionId(); From 485b3f55abfefca3dc79ba09c9c1de99c754d4f4 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Thu, 10 Nov 2016 01:06:48 +0000 Subject: [PATCH 142/254] Issue #16 Test for correct setting of invoice number. --- tests/Message/SIMAuthorizeRequestTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Message/SIMAuthorizeRequestTest.php b/tests/Message/SIMAuthorizeRequestTest.php index 530e61bb..497f9ecd 100644 --- a/tests/Message/SIMAuthorizeRequestTest.php +++ b/tests/Message/SIMAuthorizeRequestTest.php @@ -16,6 +16,7 @@ public function setUp() 'returnUrl' => 'https://www.example.com/return', 'liveEndpoint' => 'https://secure.authorize.net/gateway/transact.dll', 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll', + 'invoiceNumber' => 'INVOICE_NUM', ) ); } @@ -36,6 +37,7 @@ public function testGetDataTestMode() $data = $this->request->getData(); $this->assertSame('TRUE', $data['x_test_request']); + $this->assertSame('INVOICE_NUM', $data['x_invoice_num']); } public function testGetHash() From 60213099ebf9407f9b9d69177243efbc36cb056f Mon Sep 17 00:00:00 2001 From: Zach Wilson Date: Sun, 5 Feb 2017 16:21:10 -0600 Subject: [PATCH 143/254] Getting malformed guzzle URL The makeCreatePaymentProfileRequest was not init params the same as everything else. As a result guzzle was throwing a malformed url error. --- src/Message/CIMCreateCardRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 09ac180a..81fa4b37 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -250,7 +250,7 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) public function makeCreatePaymentProfileRequest($parameters) { $obj = new CIMCreatePaymentProfileRequest($this->httpClient, $this->httpRequest); - $obj->initialize($parameters); + $obj->initialize(array_replace($this->getParameters(), $parameters)); return $obj->send(); } From 645a25b13a1806a2206329a6bcea2d297b4b77e4 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 5 Feb 2017 23:06:57 +0000 Subject: [PATCH 144/254] Revert "Issue69" From 36c567c5a5c51912789753e72453252213a9722a Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 5 Feb 2017 23:22:00 +0000 Subject: [PATCH 145/254] Issue #69 Include invoiceNumber if supplied in CIM Authorize. --- src/Message/CIMAuthorizeRequest.php | 11 ++++++++--- tests/Message/CIMAuthorizeRequestTest.php | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Message/CIMAuthorizeRequest.php b/src/Message/CIMAuthorizeRequest.php index 827e84da..d39fb972 100644 --- a/src/Message/CIMAuthorizeRequest.php +++ b/src/Message/CIMAuthorizeRequest.php @@ -27,9 +27,14 @@ protected function addPayment(\SimpleXMLElement $data) $req->profile->shippingProfileId = $shippingProfileId; } - $desc = $this->getDescription(); - if (!empty($desc)) { - $req->order->description = $desc; + $invoiceNumber = $this->getInvoiceNumber(); + if (!empty($invoiceNumber)) { + $req->order->invoiceNumber = $invoiceNumber; + } + + $description = $this->getDescription(); + if (!empty($description)) { + $req->order->description = $description; } return $data; diff --git a/tests/Message/CIMAuthorizeRequestTest.php b/tests/Message/CIMAuthorizeRequestTest.php index 04d6e90e..819d855e 100644 --- a/tests/Message/CIMAuthorizeRequestTest.php +++ b/tests/Message/CIMAuthorizeRequestTest.php @@ -16,6 +16,7 @@ public function setUp() array( 'cardReference' => '{"customerProfileId":"28972085","customerPaymentProfileId":"26317841","customerShippingAddressId":"27057151"}', 'amount' => '12.00', + 'invoiceNumber' => '00001234', 'description' => 'Test authorize transaction' ) ); @@ -29,6 +30,7 @@ public function testGetData() $this->assertEquals('28972085', $data->transactionRequest->profile->customerProfileId); $this->assertEquals('26317841', $data->transactionRequest->profile->paymentProfile->paymentProfileId); $this->assertEquals('27057151', $data->transactionRequest->profile->shippingProfileId); + $this->assertEquals('00001234', $data->transactionRequest->order->invoiceNumber); $this->assertEquals('Test authorize transaction', $data->transactionRequest->order->description); } } From 48eb3a791e233100c4947e5a9eb53895784b5e8f Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 6 Feb 2017 11:51:57 +0000 Subject: [PATCH 146/254] Issue #40 Collect result code, reason code and reason message from the correct places. --- src/Message/AIMResponse.php | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 4be1117f..ef8a038a 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -42,13 +42,22 @@ public function isSuccessful() } /** - * Overall status of the transaction. This field is also known as "Response Code" in Authorize.NET terminology. + * Status of the transaction. This field is also known as "Response Code" in Authorize.NET terminology. + * A result of 0 is returned if there is no transaction response returned, e.g. a validation error in + * some data, or invalid login credentials. * - * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review + * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review, 0 = Validation Error */ public function getResultCode() { - return intval((string)$this->data->transactionResponse[0]->responseCode); + // If there is a transaction response, then we get the code from that. + if (isset($this->data->transactionResponse[0])) { + return intval((string)$this->data->transactionResponse[0]->responseCode); + } + + // No transaction response, so no transaction was attempted, hence no + // transaction response code that we can return. + return 0; } /** @@ -62,11 +71,15 @@ public function getReasonCode() if (isset($this->data->transactionResponse[0]->messages)) { // In case of a successful transaction, a "messages" element is present - $code = intval((string)$this->data->transactionResponse[0]->messages[0]->message[0]->code); + $code = intval((string)$this->data->transactionResponse[0]->messages[0]->message->code); } elseif (isset($this->data->transactionResponse[0]->errors)) { // In case of an unsuccessful transaction, an "errors" element is present - $code = intval((string)$this->data->transactionResponse[0]->errors[0]->error[0]->errorCode); + $code = intval((string)$this->data->transactionResponse[0]->errors[0]->error->errorCode); + + } elseif (isset($this->data->messages[0]->message)) { + // In case of invalid request, the top-level message provides details. + $code = (string)$this->data->messages[0]->message->code; } return $code; @@ -83,11 +96,15 @@ public function getMessage() if (isset($this->data->transactionResponse[0]->messages)) { // In case of a successful transaction, a "messages" element is present - $message = (string)$this->data->transactionResponse[0]->messages[0]->message[0]->description; + $message = (string)$this->data->transactionResponse[0]->messages[0]->message->description; } elseif (isset($this->data->transactionResponse[0]->errors)) { // In case of an unsuccessful transaction, an "errors" element is present - $message = (string)$this->data->transactionResponse[0]->errors[0]->error[0]->errorText; + $message = (string)$this->data->transactionResponse[0]->errors[0]->error->errorText; + + } elseif (isset($this->data->messages[0]->message)) { + // In case of invalid request, the top-level message provides details. + $message = (string)$this->data->messages[0]->message->text; } return $message; From b195c82191929897cfe52d9a4ec4b86b657316ad Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 6 Feb 2017 11:53:35 +0000 Subject: [PATCH 147/254] Issue #40 switch the "0" result code to "3" (error). --- src/Message/AIMResponse.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index ef8a038a..6dcc5dbc 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -46,7 +46,7 @@ public function isSuccessful() * A result of 0 is returned if there is no transaction response returned, e.g. a validation error in * some data, or invalid login credentials. * - * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review, 0 = Validation Error + * @return int 1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review */ public function getResultCode() { @@ -55,9 +55,8 @@ public function getResultCode() return intval((string)$this->data->transactionResponse[0]->responseCode); } - // No transaction response, so no transaction was attempted, hence no - // transaction response code that we can return. - return 0; + // No transaction response, so return 3 aka "error". + return 3; } /** From 2db9dd5dc993caabf83099bc2da92be8ff0508ab Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 6 Feb 2017 23:02:34 +0000 Subject: [PATCH 148/254] Issue #40 Test for AIM Authorize with invalid request data. --- src/Message/AIMResponse.php | 66 ++++++++++++++++++++---------- tests/Message/AIMResponseTest.php | 14 +++++++ tests/Mock/AIMAuthorizeInvalid.txt | 13 ++++++ 3 files changed, 72 insertions(+), 21 deletions(-) create mode 100644 tests/Mock/AIMAuthorizeInvalid.txt diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 6dcc5dbc..020b51d8 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -18,6 +18,14 @@ class AIMResponse extends AbstractResponse */ const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = 54; + /** + * The overall transaction result code. + */ + const TRANSACTION_RESULT_CODE_APPROVED = 1; + const TRANSACTION_RESULT_CODE_DECLINED = 2; + const TRANSACTION_RESULT_CODE_ERROR = 3; + const TRANSACTION_RESULT_CODE_REVIEW = 4; + public function __construct(AbstractRequest $request, $data) { // Strip out the xmlns junk so that PHP can parse the XML @@ -38,7 +46,7 @@ public function __construct(AbstractRequest $request, $data) public function isSuccessful() { - return 1 === $this->getResultCode(); + return static::TRANSACTION_RESULT_CODE_APPROVED === $this->getResultCode(); } /** @@ -56,7 +64,7 @@ public function getResultCode() } // No transaction response, so return 3 aka "error". - return 3; + return static::TRANSACTION_RESULT_CODE_ERROR; } /** @@ -111,7 +119,11 @@ public function getMessage() public function getAuthorizationCode() { - return (string)$this->data->transactionResponse[0]->authCode; + if (isset($this->data->transactionResponse[0])) { + return (string)$this->data->transactionResponse[0]->authCode; + } else { + return ''; + } } /** @@ -121,36 +133,48 @@ public function getAuthorizationCode() */ public function getAVSCode() { - return (string)$this->data->transactionResponse[0]->avsResultCode; + if (isset($this->data->transactionResponse[0])) { + return (string)$this->data->transactionResponse[0]->avsResultCode; + } else { + return ''; + } } /** - * A composite key containing the gateway provided transaction reference as well as other data points that may be - * required for subsequent transactions that may need to modify this one. + * A composite key containing the gateway provided transaction reference as + * well as other data points that may be required for subsequent transactions + * that may need to modify this one. * * @param bool $serialize Determines whether a string or object is returned * @return TransactionReference|string */ public function getTransactionReference($serialize = true) { - $body = $this->data->transactionResponse[0]; - $transactionRef = new TransactionReference(); - $transactionRef->setApprovalCode((string)$body->authCode); - $transactionRef->setTransId((string)$body->transId); + // The transactionResponse is only returned if succesful or declined + // for some reason, so don't assume it will always be there. - try { - // Need to store card details in the transaction reference since it is required when doing a refund - if ($card = $this->request->getCard()) { - $transactionRef->setCard(array( - 'number' => $card->getNumberLastFour(), - 'expiry' => $card->getExpiryDate('mY') - )); - } elseif ($cardReference = $this->request->getCardReference()) { - $transactionRef->setCardReference(new CardReference($cardReference)); + if (isset($this->data->transactionResponse[0])) { + $body = $this->data->transactionResponse[0]; + $transactionRef = new TransactionReference(); + $transactionRef->setApprovalCode((string)$body->authCode); + $transactionRef->setTransId((string)$body->transId); + + try { + // Need to store card details in the transaction reference since it is required when doing a refund + if ($card = $this->request->getCard()) { + $transactionRef->setCard(array( + 'number' => $card->getNumberLastFour(), + 'expiry' => $card->getExpiryDate('mY') + )); + } elseif ($cardReference = $this->request->getCardReference()) { + $transactionRef->setCardReference(new CardReference($cardReference)); + } + } catch (\Exception $e) { } - } catch (\Exception $e) { + + return $serialize ? (string)$transactionRef : $transactionRef; } - return $serialize ? (string)$transactionRef : $transactionRef; + return ''; } } diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 6c966cd0..d5613b09 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -50,6 +50,20 @@ public function testAuthorizeFailure() $this->assertSame('P', $response->getAVSCode()); } + public function testAuthorizeInvalid() + { + $httpResponse = $this->getMockHttpResponse('AIMAuthorizeInvalid.txt'); + $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertFalse($response->isSuccessful()); + $this->assertSame('', $response->getTransactionReference()); + $this->assertSame('User authentication failed due to invalid authentication values.', $response->getMessage()); + $this->assertSame(3, $response->getResultCode()); + $this->assertSame('E00007', $response->getReasonCode()); + $this->assertSame('', $response->getAuthorizationCode()); + $this->assertSame('', $response->getAVSCode()); + } + public function testCaptureSuccess() { $httpResponse = $this->getMockHttpResponse('AIMCaptureSuccess.txt'); diff --git a/tests/Mock/AIMAuthorizeInvalid.txt b/tests/Mock/AIMAuthorizeInvalid.txt new file mode 100644 index 00000000..408eda40 --- /dev/null +++ b/tests/Mock/AIMAuthorizeInvalid.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Sat, 02 Aug 2014 05:20:38 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 844 + +123456ErrorE00007User authentication failed due to invalid authentication values. From d22c49396283f0a20a357d0d57c95f4b2d4d479f Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 21 Feb 2017 23:37:27 +0000 Subject: [PATCH 149/254] Small tidy-up of a few scripts. --- src/Message/CIMAbstractResponse.php | 30 +++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index 637cd613..e02d7a7a 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -12,6 +12,14 @@ */ abstract class CIMAbstractResponse extends AbstractResponse { + /** + * The overall transaction result code. + */ + const TRANSACTION_RESULT_CODE_APPROVED = 1; + const TRANSACTION_RESULT_CODE_DECLINED = 2; + const TRANSACTION_RESULT_CODE_ERROR = 3; + const TRANSACTION_RESULT_CODE_REVIEW = 4; + protected $responseType = null; public function __construct(RequestInterface $request, $data) @@ -40,7 +48,7 @@ public function __construct(RequestInterface $request, $data) public function isSuccessful() { - return 1 === $this->getResultCode(); + return $this->getResultCode() === static::TRANSACTION_RESULT_CODE_APPROVED; } /** @@ -51,11 +59,12 @@ public function isSuccessful() public function getResultCode() { $result = (string)$this->data['messages'][0]['resultCode']; + switch ($result) { case 'Ok': - return 1; + return static::TRANSACTION_RESULT_CODE_APPROVED; case 'Error': - return 3; + return static::TRANSACTION_RESULT_CODE_ERROR; default: return null; @@ -112,24 +121,33 @@ public function getMessage() return $message; } + /** + * Get the reusable card reference from the response. + * Used in conjuction with CIMGateway::createCard() + * + * @return string|null + */ public function getCardReference() { $cardRef = null; + if ($this->isSuccessful()) { $data['customerProfileId'] = $this->getCustomerProfileId(); $data['customerPaymentProfileId'] = $this->getCustomerPaymentProfileId(); + if (!empty($data['customerProfileId']) && !empty($data['customerPaymentProfileId'])) { // For card reference both profileId and payment profileId should exist $cardRef = json_encode($data); } } + return $cardRef; } /** * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ * - * Convert a simpleXMLElement in to an array + * Convert a simpleXMLElement into an array * * @param \SimpleXMLElement $xml * @@ -138,9 +156,11 @@ public function getCardReference() public function xml2array(\SimpleXMLElement $xml) { $arr = array(); + foreach ($xml as $element) { $tag = $element->getName(); $e = get_object_vars($element); + if (!empty($e)) { $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; } else { @@ -173,8 +193,10 @@ public function augmentResponse() /** @var CreditCard $card */ $card = $this->request->getCard(); + if ($card) { $ccString = $card->getNumber() . $card->getExpiryMonth() . $card->getExpiryYear(); + $this->data['hash'] = md5($ccString); $this->data['brand'] = $card->getBrand(); $this->data['expiryYear'] = $card->getExpiryYear(); From f8711495e918c1a4adb5e80c183a7f6ab8390103 Mon Sep 17 00:00:00 2001 From: felixmaier1989 Date: Thu, 2 Mar 2017 13:11:48 +0700 Subject: [PATCH 150/254] Unit test for fetching error message --- tests/Message/AIMResponseTest.php | 10 ++++++++++ tests/Mock/AIMAuthorizeInvalidOTSToken.txt | 13 +++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/Mock/AIMAuthorizeInvalidOTSToken.txt diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index d5613b09..275fdfd8 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -64,6 +64,16 @@ public function testAuthorizeInvalid() $this->assertSame('', $response->getAVSCode()); } + public function testAuthorizeInvalidOTSToken() + { + $httpResponse = $this->getMockHttpResponse('AIMAuthorizeInvalidOTSToken.txt'); + $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertFalse($response->isSuccessful()); + $this->assertSame('E00114', $response->getReasonCode()); + $this->assertSame('Invalid OTS Token.', $response->getMessage()); + } + public function testCaptureSuccess() { $httpResponse = $this->getMockHttpResponse('AIMCaptureSuccess.txt'); diff --git a/tests/Mock/AIMAuthorizeInvalidOTSToken.txt b/tests/Mock/AIMAuthorizeInvalidOTSToken.txt new file mode 100644 index 00000000..943227fa --- /dev/null +++ b/tests/Mock/AIMAuthorizeInvalidOTSToken.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Sat, 02 Aug 2014 05:20:38 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 844 + +ErrorE00114Invalid OTS Token. From 66d7b4a845f562a96ccd17db1bdc3cf0c6775396 Mon Sep 17 00:00:00 2001 From: felixmaier1989 Date: Thu, 2 Mar 2017 13:15:04 +0700 Subject: [PATCH 151/254] Support for tokenized credit card (Accept.js) --- src/Message/AIMAbstractRequest.php | 24 ++++++++++++++++++++++++ src/Message/AIMAuthorizeRequest.php | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 98dacb2d..adbb9034 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -160,6 +160,30 @@ public function setInvoiceNumber($value) return $this->setParameter('invoiceNumber', $value); } + public function getOpaqueDataDescriptor() + { + return $this->getParameter('opaqueDataDescriptor') + ? $this->getParameter('opaqueDataDescriptor') + : $this->httpRequest->request->get('opaqueDataDescriptor'); + } + + public function getOpaqueDataValue() + { + return $this->getParameter('opaqueDataValue') + ? $this->getParameter('opaqueDataValue') + : $this->httpRequest->request->get('opaqueDataValue'); + } + + public function setOpaqueDataDescriptor($value) + { + return $this->setParameter('opaqueDataDescriptor', $value); + } + + public function setOpaqueDataValue($value) + { + return $this->setParameter('opaqueDataValue', $value); + } + public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 21cb991a..794038f7 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -26,6 +26,12 @@ public function getData() protected function addPayment(\SimpleXMLElement $data) { + if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { + $data->transactionRequest->payment->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor(); + $data->transactionRequest->payment->opaqueData->dataValue = $this->getOpaqueDataValue(); + return; + } + $this->validate('card'); /** @var CreditCard $card */ $card = $this->getCard(); From a41d069b65344b1ad66004a4b859d9dce8956cef Mon Sep 17 00:00:00 2001 From: felixmaier1989 Date: Thu, 2 Mar 2017 15:12:27 +0700 Subject: [PATCH 152/254] Support for tokenized credit card (Accept.js) - unit test --- tests/Message/AIMAuthorizeRequestTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 5448905e..611a5f2c 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -68,6 +68,17 @@ public function testGetDataTestMode() $this->assertEquals('true', $setting->settingValue); } + public function testGetDataOpaqueData() + { + $this->request->setOpaqueDataDescriptor('COMMON.ACCEPT.INAPP.PAYMENT'); + $this->request->setOpaqueDataValue('jb2RlIjoiNTB'); + + $data = $this->request->getData(); + + $this->assertEquals('COMMON.ACCEPT.INAPP.PAYMENT', $data->transactionRequest->payment->opaqueData->dataDescriptor); + $this->assertEquals('jb2RlIjoiNTB', $data->transactionRequest->payment->opaqueData->dataValue); + } + public function testShouldIncludeDuplicateWindowSetting() { $data = $this->request->getData(); From 1676edd6c8f0d3cbd0c613a88d3314024c2fc5b2 Mon Sep 17 00:00:00 2001 From: felixmaier1989 Date: Thu, 2 Mar 2017 15:16:03 +0700 Subject: [PATCH 153/254] Support for tokenized credit card (Accept.js) - PHP doc --- src/Message/AIMAbstractRequest.php | 18 ++++++++++++++++++ src/Message/AIMAuthorizeRequest.php | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index adbb9034..05dffb85 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -160,6 +160,10 @@ public function setInvoiceNumber($value) return $this->setParameter('invoiceNumber', $value); } + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @return string + */ public function getOpaqueDataDescriptor() { return $this->getParameter('opaqueDataDescriptor') @@ -167,6 +171,10 @@ public function getOpaqueDataDescriptor() : $this->httpRequest->request->get('opaqueDataDescriptor'); } + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @return string + */ public function getOpaqueDataValue() { return $this->getParameter('opaqueDataValue') @@ -174,11 +182,21 @@ public function getOpaqueDataValue() : $this->httpRequest->request->get('opaqueDataValue'); } + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @param string + * @return string + */ public function setOpaqueDataDescriptor($value) { return $this->setParameter('opaqueDataDescriptor', $value); } + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @param string + * @return string + */ public function setOpaqueDataValue($value) { return $this->setParameter('opaqueDataValue', $value); diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 794038f7..cdaed951 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -26,6 +26,9 @@ public function getData() protected function addPayment(\SimpleXMLElement $data) { + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + */ if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { $data->transactionRequest->payment->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor(); $data->transactionRequest->payment->opaqueData->dataValue = $this->getOpaqueDataValue(); From e090a1332f2a396505b379690c4ae703bd8d21ce Mon Sep 17 00:00:00 2001 From: felixmaier1989 Date: Thu, 2 Mar 2017 18:33:47 +0700 Subject: [PATCH 154/254] Do not take opaque data from $_GET --- src/Message/AIMAbstractRequest.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 05dffb85..d769f73d 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -166,9 +166,7 @@ public function setInvoiceNumber($value) */ public function getOpaqueDataDescriptor() { - return $this->getParameter('opaqueDataDescriptor') - ? $this->getParameter('opaqueDataDescriptor') - : $this->httpRequest->request->get('opaqueDataDescriptor'); + return $this->getParameter('opaqueDataDescriptor'); } /** @@ -177,9 +175,7 @@ public function getOpaqueDataDescriptor() */ public function getOpaqueDataValue() { - return $this->getParameter('opaqueDataValue') - ? $this->getParameter('opaqueDataValue') - : $this->httpRequest->request->get('opaqueDataValue'); + return $this->getParameter('opaqueDataValue'); } /** From 24763d9a9f8b61e3b853fdb82225bc4412b8ac7e Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Fri, 3 Mar 2017 12:41:00 +0000 Subject: [PATCH 155/254] Issue #41 Some simple notes on Accept.JS --- README.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/README.md b/README.md index 62a69a36..301adb7e 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,46 @@ The following gateways are provided by this package: * AuthorizeNet_SIM * AuthorizeNet_DPM +In addition, `Accept.JS` is supported by the AIM driver. More details are provided below. + For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) repository. +## Accept.JS + +This gateway uses a JacaScript script to tokenize credit card details at the front end, +i.e. in the payment form. +Just the tokenized version of the credit card is then sent back to the merchant site, +where it is used as a proxy for the credit card. + +The card is tokenized into two values returned in `opaqueData` object from Accept.JS: + +* dataDescriptor - the type of opaque data, e.g. "COMMON.ACCEPT.INAPP.PAYMENT" +* dataValue - the value for the opaque data, e.g. "eyJjb2RlIjoiNT... {256 characters} ...idiI6IjEuMSJ9" + +These two values must be POSTed back to the merchant application, usually as a part of the payment form. +Make sure the raw credit card details are NOT posted back to your site. +How this is handled is beyond this short note, but examples are always welcome in the documentation. + +On the server, the tokenized detailt are passed into the `payment` or `authorize` request object. +You will still need to pass in the `CreditCard` object, as that contains details of the payee and +recipient, but just leave the credit card details of that object blank. For example: + +```php +// $gateway is an instantiation of the AIM driver. +// $dataDescriptor and $dataValue come from the paymentr form at the front end. + +$request = $gateway->purchase( + [ + 'notifyUrl' => '...', + 'amount' => $amount, + 'opaqueDataDescriptor' => $dataDescriptor, + 'opaqueDataValue' => $dataValue, + ... + ] +); +``` + ## Support If you are having general issues with Omnipay, we suggest posting on From 902287afe0ff27fdeb0844189e79e88cd0109aaa Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 6 Mar 2017 23:20:29 +1300 Subject: [PATCH 156/254] Add getters and setters for hashSecret, an optional authorization parameter --- src/AIMGateway.php | 11 +++++++++++ src/SIMGateway.php | 10 ---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 683ed160..6955017e 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -26,6 +26,7 @@ public function getDefaultParameters() 'transactionKey' => '', 'testMode' => false, 'developerMode' => false, + 'hashSecret' => '', 'liveEndpoint' => 'https://api2.authorize.net/xml/v1/request.api', 'developerEndpoint' => 'https://apitest.authorize.net/xml/v1/request.api', ); @@ -61,6 +62,16 @@ public function setDeveloperMode($value) return $this->setParameter('developerMode', $value); } + public function setHashSecret($value) + { + return $this->setParameter('hashSecret', $value); + } + + public function getHashSecret() + { + return $this->getParameter('hashSecret'); + } + public function setEndpoints($endpoints) { $this->setParameter('liveEndpoint', $endpoints['live']); diff --git a/src/SIMGateway.php b/src/SIMGateway.php index c5ccbe5c..67b47b4d 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -53,16 +53,6 @@ public function setDeveloperMode($value) return $this->setParameter('developerMode', $value); } - public function getHashSecret() - { - return $this->getParameter('hashSecret'); - } - - public function setHashSecret($value) - { - return $this->setParameter('hashSecret', $value); - } - public function authorize(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMAuthorizeRequest', $parameters); From 5b9fde9599265101a5f18ef753a5f39846e50c59 Mon Sep 17 00:00:00 2001 From: Mark Hamstra Date: Tue, 7 Mar 2017 14:22:08 +0100 Subject: [PATCH 157/254] Typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 301adb7e..daad684c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ repository. ## Accept.JS -This gateway uses a JacaScript script to tokenize credit card details at the front end, +This gateway uses a JavaScript script to tokenize credit card details at the front end, i.e. in the payment form. Just the tokenized version of the credit card is then sent back to the merchant site, where it is used as a proxy for the credit card. From 90bceafa5a23bf86a668a2c5064a1148e7646ce9 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 3 Oct 2017 21:03:36 +0300 Subject: [PATCH 158/254] Added solution id --- src/Message/AIMAbstractRequest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index d769f73d..167d71bb 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -100,6 +100,16 @@ public function getEndpoint() return $this->getDeveloperMode() ? $this->getDeveloperEndpoint() : $this->getLiveEndpoint(); } + public function getSolutionId() + { + return $this->getParameter('solutionId'); + } + + public function setSolutionId($value) + { + return $this->getSolutionId('solutionId', $value); + } + /** * @return TransactionReference */ @@ -220,6 +230,7 @@ public function getBaseData() $this->addAuthentication($data); $this->addReferenceId($data); $this->addTransactionType($data); + $this->addSolutiuonId($data); return $data; } @@ -249,6 +260,15 @@ protected function addTransactionType(\SimpleXMLElement $data) $data->transactionRequest->transactionType = $this->action; } + protected function addSolutiuonId(\SimpleXMLElement $data) + { + $solutionId = $this->getSolutionId(); + + if (!empty($solutionId)) { + $data->solution->id = $solutionId; + } + } + /** * Adds billing data to a partially filled request data object. * From 28503534e07642fb666e90e294d1b89ae600ddbd Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Tue, 3 Oct 2017 22:37:01 +0300 Subject: [PATCH 159/254] Added solution id --- src/Message/AIMAbstractRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 167d71bb..5f7c8010 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -107,7 +107,7 @@ public function getSolutionId() public function setSolutionId($value) { - return $this->getSolutionId('solutionId', $value); + return $this->setParameter('solutionId', $value); } /** From ab2ff86231e91164f51a2b3cb290333b2a417488 Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 4 Oct 2017 12:31:56 +0300 Subject: [PATCH 160/254] Add solution id --- src/Message/AIMAbstractRequest.php | 3 +-- src/Message/AIMAuthorizeRequest.php | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 5f7c8010..34cf79af 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -230,7 +230,6 @@ public function getBaseData() $this->addAuthentication($data); $this->addReferenceId($data); $this->addTransactionType($data); - $this->addSolutiuonId($data); return $data; } @@ -260,7 +259,7 @@ protected function addTransactionType(\SimpleXMLElement $data) $data->transactionRequest->transactionType = $this->action; } - protected function addSolutiuonId(\SimpleXMLElement $data) + protected function addSolutionId(\SimpleXMLElement $data) { $solutionId = $this->getSolutionId(); diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index cdaed951..a4f0a58e 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -17,6 +17,7 @@ public function getData() $data = $this->getBaseData(); $data->transactionRequest->amount = $this->getAmount(); $this->addPayment($data); + $this->addSolutionId($data); $this->addBillingData($data); $this->addCustomerIP($data); $this->addTransactionSettings($data); From 7211453cade09d9fe50bbac8a7616f053ab10c5b Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 4 Oct 2017 12:52:08 +0300 Subject: [PATCH 161/254] Add solution id --- src/Message/AIMAbstractRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 34cf79af..660714f7 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -264,7 +264,7 @@ protected function addSolutionId(\SimpleXMLElement $data) $solutionId = $this->getSolutionId(); if (!empty($solutionId)) { - $data->solution->id = $solutionId; + $data->transactionRequest->solution->id = $solutionId; } } From b36d3c1d87fd67f0d5c5232f8b68bd6547a25019 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 4 Oct 2017 11:43:08 +0100 Subject: [PATCH 162/254] Remove PHP5.3 from failing travis tests. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4893becf..88558d85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: php php: - - 5.3 - 5.4 - 5.5 - 5.6 From af76ebd43254ee67f15c54de067648e2f5062a62 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Oct 2017 11:41:16 +0100 Subject: [PATCH 163/254] Test solutionId for PR #87 --- tests/Message/AIMAbstractRequestTest.php | 15 +++++---------- tests/Message/AIMAuthorizeRequestTest.php | 5 ++++- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/Message/AIMAbstractRequestTest.php b/tests/Message/AIMAbstractRequestTest.php index 04d01400..03d47d32 100644 --- a/tests/Message/AIMAbstractRequestTest.php +++ b/tests/Message/AIMAbstractRequestTest.php @@ -1,25 +1,20 @@ request = $this->getMockForAbstractClass( - '\Omnipay\AuthorizeNet\Message\AIMAbstractRequest', - array( - $this->getMock('\Guzzle\Http\ClientInterface'), - $this->getMock('\Symfony\Component\HttpFoundation\Request') - ) - ); + $this->request = Mockery::mock('\Omnipay\AuthorizeNet\Message\AIMAbstractRequest')->makePartial(); + $this->request->initialize(); } public function testShouldReturnTransactionReference() diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 611a5f2c..e410a8f5 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -20,7 +20,8 @@ public function setUp() 'amount' => '12.00', 'customerId' => 'cust-id', 'card' => $card, - 'duplicateWindow' => 0 + 'duplicateWindow' => 0, + 'solutionId' => 'SOL12345ID', ) ); } @@ -33,6 +34,7 @@ public function testGetData() $this->assertEquals('10.0.0.1', $data->transactionRequest->customerIP); $this->assertEquals('cust-id', $data->transactionRequest->customer->id); $this->assertEquals('example@example.net', $data->transactionRequest->customer->email); + $this->assertEquals('SOL12345ID', $data->transactionRequest->solution->id); // Issue #38 Make sure the transactionRequest properties are correctly ordered. // This feels messy, but works. @@ -43,6 +45,7 @@ public function testGetData() "transactionType", "amount", "payment", + "solution", "order", "customer", "billTo", From 235a0d5e8b42b65c3446ec0a1cbf8dcdfbf19161 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Oct 2017 11:51:46 +0100 Subject: [PATCH 164/254] Add PHP 7.1 to the automated tests. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 88558d85..a910d105 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 5.5 - 5.6 - 7.0 + - 7.1 - hhvm matrix: From 821607495a2b72a4d412d6972ee8cf3efbba3e1d Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Oct 2017 14:36:31 +0100 Subject: [PATCH 165/254] Test for PR #78 hashSecret set at AIM gateway level --- tests/AIMGatewayTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index e50a3823..827ccac0 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -19,6 +19,10 @@ public function setUp() $this->gateway = new AIMGateway($this->getHttpClient(), $this->getHttpRequest()); + $this->gateway->initialize([ + 'hashSecret' => 'HASHYsecretyThang', + ]); + $this->purchaseOptions = array( 'amount' => '10.00', 'card' => $this->getValidCard(), @@ -60,6 +64,15 @@ public function testDeveloperEndpoint() ); } + // Added for PR #78 + public function testHashSecret() + { + $this->assertEquals( + 'HASHYsecretyThang', + $this->gateway->getHashSecret() + ); + } + private function getExpiry($card) { return str_pad($card['expiryMonth'] . $card['expiryYear'], 6, '0', STR_PAD_LEFT); From ff9dc9d076ab44600a72d0669d7bd1ca90c649c7 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 7 Oct 2017 14:39:13 +0100 Subject: [PATCH 166/254] Extended PR #78 test to CIM gateway. --- tests/CIMGatewayTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 9b3f9bfb..604f4707 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -20,6 +20,10 @@ public function setUp() $this->gateway = new CIMGateway($this->getHttpClient(), $this->getHttpRequest()); + $this->gateway->initialize([ + 'hashSecret' => 'HASHYsecretyThang', + ]); + $this->createCardOptions = array( 'email' => "kaylee@serenity.com", 'card' => $this->getValidCard(), @@ -62,6 +66,15 @@ public function testDeveloperEndpoint() ); } + // Added for PR #78 + public function testHashSecret() + { + $this->assertEquals( + 'HASHYsecretyThang', + $this->gateway->getHashSecret() + ); + } + public function testCreateCardSuccess() { $this->setMockHttpResponse(array('CIMCreateCardSuccess.txt','CIMGetPaymentProfileSuccess.txt')); From 30d1d1dd757f31526f6e47a547d0a3a055319a64 Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 7 Mar 2017 00:06:23 +1300 Subject: [PATCH 167/254] Add actions for querying Authorize.net. These actions are intended to be generic & usable on other processors. The main ones are >$gateway = Omnipay::crete('AIMGateway'); >$gateway->query(array('startTimestamp' => strtotime('yesterday'), 'endTimeStamp' => 'strtotime('now'))); or for subscription plans: >$gateway->paymentPlansQuery(); The others are more internal. The response object for query() supports >$response->getFirstName(); >$response->getLastName(); >$response->getTransactionId(); // this is a standard transactionReference string, not the object >$response->getTransactionReference(); >$response->getBillingAddress1(); >$response->getBillingAddress2(); >$response->getBillingPostcode(); >$response->getBillingState(); >$response->getBillingCountry(); >$response->getBillingCity(); >$response->getAmount(); >$response->getEmail(); >$response->getDescription(); >$response->getCurrency(); // masked credit card number >$response->getNumber(); // Get card type >$response->getType(); >$response->getTransactionDate(); >$response->getTransactionDate(); >$response->getSettlementDate(); // Customer reference is a reference string for a contact created in the system. >$response->getCustomerReference(); // The recurring reference is a reference for the payment plan. >$response->getRecurringReference(); --- src/AIMGateway.php | 56 ++++ src/Message/AIMAbstractRequest.php | 1 + src/Message/AIMPaymentPlanQueryRequest.php | 94 +++++++ src/Message/AIMPaymentPlanQueryResponse.php | 136 ++++++++++ src/Message/AIMPaymentPlansQueryRequest.php | 83 ++++++ src/Message/AIMPaymentPlansQueryResponse.php | 71 +++++ src/Message/QueryBatchDetailRequest.php | 86 ++++++ src/Message/QueryBatchDetailResponse.php | 71 +++++ src/Message/QueryBatchRequest.php | 78 ++++++ src/Message/QueryBatchResponse.php | 82 ++++++ src/Message/QueryDetailRequest.php | 86 ++++++ src/Message/QueryDetailResponse.php | 271 +++++++++++++++++++ src/Message/QueryRequest.php | 73 +++++ src/Message/QueryResponse.php | 69 +++++ 14 files changed, 1257 insertions(+) create mode 100644 src/Message/AIMPaymentPlanQueryRequest.php create mode 100644 src/Message/AIMPaymentPlanQueryResponse.php create mode 100644 src/Message/AIMPaymentPlansQueryRequest.php create mode 100644 src/Message/AIMPaymentPlansQueryResponse.php create mode 100644 src/Message/QueryBatchDetailRequest.php create mode 100644 src/Message/QueryBatchDetailResponse.php create mode 100644 src/Message/QueryBatchRequest.php create mode 100644 src/Message/QueryBatchResponse.php create mode 100644 src/Message/QueryDetailRequest.php create mode 100644 src/Message/QueryDetailResponse.php create mode 100644 src/Message/QueryRequest.php create mode 100644 src/Message/QueryResponse.php diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 6955017e..8f373d56 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -4,7 +4,9 @@ use Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest; use Omnipay\AuthorizeNet\Message\AIMCaptureRequest; +use Omnipay\AuthorizeNet\Message\AIMPaymentPlanQueryResponse; use Omnipay\AuthorizeNet\Message\AIMPurchaseRequest; +use Omnipay\AuthorizeNet\Message\QueryRequest; use Omnipay\AuthorizeNet\Message\AIMRefundRequest; use Omnipay\AuthorizeNet\Message\AIMVoidRequest; use Omnipay\Common\AbstractGateway; @@ -152,4 +154,58 @@ public function refund(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMRefundRequest', $parameters); } + + /** + * @param array $parameters + * @return AIMPaymentPlansQueryRequest + */ + public function paymentPlansQuery(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMPaymentPlansQueryRequest', $parameters); + } + + /** + * @param array $parameters + * @return AIMPaymentPlanQueryResponse + */ + public function paymentPlanQuery(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMPaymentPlanQueryRequest', $parameters); + } + + /** + * @param array $parameters + * @return QueryResponse + */ + public function query(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryRequest', $parameters); + } + + /** + * @param array $parameters + * @return QueryBatchResponse + */ + public function queryBatch(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryBatchRequest', $parameters); + } + + /** + * @param array $parameters + * @return QueryBatchDetailResponse + */ + public function queryBatchDetail(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryBatchDetailRequest', $parameters); + } + + /** + * @param array $parameters + * @return QueryDetailResponse + */ + public function queryDetail(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryDetailRequest', $parameters); + } } diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 660714f7..2282e254 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -60,6 +60,7 @@ public function getHashSecret() { return $this->getParameter('hashSecret'); } + public function setHashSecret($value) { return $this->setParameter('hashSecret', $value); diff --git a/src/Message/AIMPaymentPlanQueryRequest.php b/src/Message/AIMPaymentPlanQueryRequest.php new file mode 100644 index 00000000..776dd0c1 --- /dev/null +++ b/src/Message/AIMPaymentPlanQueryRequest.php @@ -0,0 +1,94 @@ +recurringReference; + } + + /** + * @param string $recurringReference + */ + public function setRecurringReference($recurringReference) + { + $this->recurringReference = $recurringReference; + } + + /** + * Get Limit. + * + * @return int + */ + public function getLimit() + { + return $this->limit; + } + + /** + * Set Limit. + * + * @param int $limit + */ + public function setLimit($limit) + { + $this->limit = $limit; + } + + /** + * Get offset. + * + * @return int + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Set offset. + * + * @param int $offset + */ + public function setOffset($offset) + { + $this->offset = $offset; + } + + /** + * Get data to send. + */ + public function getData() + { + $data = $this->getBaseData(); + $data->subscriptionId = $this->getRecurringReference(); + return $data; + } + + protected function addTransactionType(\SimpleXMLElement $data) + { + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new AIMPaymentPlanQueryResponse($this, $httpResponse->getBody()); + } +} diff --git a/src/Message/AIMPaymentPlanQueryResponse.php b/src/Message/AIMPaymentPlanQueryResponse.php new file mode 100644 index 00000000..4915ffe2 --- /dev/null +++ b/src/Message/AIMPaymentPlanQueryResponse.php @@ -0,0 +1,136 @@ +]+>/', '', (string)$data); + try { + $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); + } catch (\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + parent::__construct($request, $xml); + $result = $this->xml2array($this->data->subscription, true); + $this->subscription = $result['subscription'][0]; + } + + public function isSuccessful() + { + return 1 === $this->getResultCode(); + } + + public function getData() + { + return $this->subscription; + } + + public function getRecurStartDate() + { + return $this->subscription['paymentSchedule']['interval']['startDate']; + } + + public function getRecurInstallmentLimit() + { + return $this->subscription['paymentSchedule']['interval']['totalOccurrences']; + } + + public function getRecurrenceInterval() + { + return $this->subscription['paymentSchedule']['interval'][0]['length']; + } + + public function getRecurAmount() + { + return $this->subscription['amount']; + } + + public function getRecurReference() + { + echo "he"; + print_r($this->subscription); + } + + public function getContactReference() + { + $profileID = $this->subscription['profile'][0]['customerProfileId']; + $gateway = $gateway = Omnipay::create('AuthorizeNet_CIM'); + $gateway->setApiLoginId($this->request->getApiLoginId()); + $gateway->setHashSecret($this->request->getHashSecret()); + $gateway->setTransactionKey($this->request->getTransactionKey()); + $data = array( + 'customerProfileId' => $profileID, + 'customerPaymentProfileId' => + $this->subscription['profile'][0]['paymentProfile'][0]['customerPaymentProfileId'], + ); + $dataResponse = $gateway->getProfile($data)->send(); + return $dataResponse->getCustomerId(); + } + + /** + * @todo formalise options. + * + * @return mixed + */ + public function getRecurStatus() + { + return $this->subscription['paymentSchedule']['interval'][0]['status']; + } + + public function getRecurrenceUnit() + { + $interval = $this->subscription['paymentSchedule']['interval'][0]['unit']; + $options = array( + 'months' => 'month', + ); + return $options[$interval]; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} diff --git a/src/Message/AIMPaymentPlansQueryRequest.php b/src/Message/AIMPaymentPlansQueryRequest.php new file mode 100644 index 00000000..abdca244 --- /dev/null +++ b/src/Message/AIMPaymentPlansQueryRequest.php @@ -0,0 +1,83 @@ +limit; + } + + /** + * Set Limit. + * + * @param int $limit + */ + public function setLimit($limit) + { + $this->limit = $limit; + } + + /** + * Get offset. + * + * @return int + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Set offset. + * + * @param int $offset + */ + public function setOffset($offset) + { + $this->offset = $offset; + } + + /** + * Get data to send. + */ + public function getData() + { + $data = $this->getBaseData(); + $data->searchType = 'subscriptionActive'; + $data->sorting->orderBy = 'id'; + $data->sorting->orderDescending = true; + $data->paging->limit = $this->getLimit(); + $data->paging->offset = $this->getOffset(); + return $data; + } + + protected function addTransactionType(\SimpleXMLElement $data) + { + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new AIMPaymentPlansQueryResponse($this, $httpResponse->getBody()); + } +} diff --git a/src/Message/AIMPaymentPlansQueryResponse.php b/src/Message/AIMPaymentPlansQueryResponse.php new file mode 100644 index 00000000..857479f5 --- /dev/null +++ b/src/Message/AIMPaymentPlansQueryResponse.php @@ -0,0 +1,71 @@ +]+>/', '', (string)$data); + + try { + $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); + } catch (\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + parent::__construct($request, $xml); + } + + public function isSuccessful() + { + return 1 === $this->getResultCode(); + } + + public function getPlanData() + { + $result = $this->xml2array($this->data->subscriptionDetails, true); + return $result['subscriptionDetails'][0]['subscriptionDetail']; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} diff --git a/src/Message/QueryBatchDetailRequest.php b/src/Message/QueryBatchDetailRequest.php new file mode 100644 index 00000000..aeb7e5e0 --- /dev/null +++ b/src/Message/QueryBatchDetailRequest.php @@ -0,0 +1,86 @@ +limit; + } + + /** + * Set Limit. + * + * @param int $limit + */ + public function setLimit($limit) + { + $this->limit = $limit; + } + + /** + * Get offset. + * + * @return int + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Set offset. + * + * @param int $offset + */ + public function setOffset($offset) + { + $this->offset = $offset; + } + + /** + * Get data to send. + */ + public function getData() + { + $data = $this->getBaseData(); + $data->batchId = $this->getBatchID(); + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new QueryBatchDetailResponse($this, $httpResponse->getBody()); + } + + public function setBatchID($batchID) + { + $this->batchID = $batchID; + } + + public function getBatchID() + { + return $this->batchID; + } +} diff --git a/src/Message/QueryBatchDetailResponse.php b/src/Message/QueryBatchDetailResponse.php new file mode 100644 index 00000000..e8eaa726 --- /dev/null +++ b/src/Message/QueryBatchDetailResponse.php @@ -0,0 +1,71 @@ +]+>/', '', (string)$data); + try { + $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); + } catch (\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + parent::__construct($request, $xml); + } + + public function isSuccessful() + { + return 1 === $this->getResultCode(); + } + + public function getData() + { + $result = $this->xml2array($this->data->transactions, true); + return $result['transactions'][0]['transaction']; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} diff --git a/src/Message/QueryBatchRequest.php b/src/Message/QueryBatchRequest.php new file mode 100644 index 00000000..14e8a6f5 --- /dev/null +++ b/src/Message/QueryBatchRequest.php @@ -0,0 +1,78 @@ +limit; + } + + /** + * Set Limit. + * + * @param int $limit + */ + public function setLimit($limit) + { + $this->limit = $limit; + } + + /** + * Get offset. + * + * @return int + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Set offset. + * + * @param int $offset + */ + public function setOffset($offset) + { + $this->offset = $offset; + } + + /** + * Get data to send. + */ + public function getData() + { + $data = $this->getBaseData(); + return $data; + } + + protected function addTransactionType(\SimpleXMLElement $data) + { + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new QueryBatchResponse($this, $httpResponse->getBody()); + } +} diff --git a/src/Message/QueryBatchResponse.php b/src/Message/QueryBatchResponse.php new file mode 100644 index 00000000..41a6881b --- /dev/null +++ b/src/Message/QueryBatchResponse.php @@ -0,0 +1,82 @@ +]+>/', '', (string)$data); + + try { + $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); + } catch (\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + parent::__construct($request, $xml); + } + + public function isSuccessful() + { + return 'Ok' === $this->getResultCode(); + } + + public function getResultCode() + { + $result = $this->xml2array($this->data->messages, true); + return $result['messages'][0]['resultCode']; + } + + public function getData() + { + $result = $this->xml2array($this->data->batchList, true); + return $result['batchList'][0]['batch']; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} diff --git a/src/Message/QueryDetailRequest.php b/src/Message/QueryDetailRequest.php new file mode 100644 index 00000000..132e3524 --- /dev/null +++ b/src/Message/QueryDetailRequest.php @@ -0,0 +1,86 @@ +limit; + } + + /** + * Set Limit. + * + * @param int $limit + */ + public function setLimit($limit) + { + $this->limit = $limit; + } + + /** + * Get offset. + * + * @return int + */ + public function getOffset() + { + return $this->offset; + } + + /** + * Set offset. + * + * @param int $offset + */ + public function setOffset($offset) + { + $this->offset = $offset; + } + + /** + * Get data to send. + */ + public function getData() + { + $data = $this->getBaseData(); + $data->transId = $this->getTransactionReference(); + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new QueryDetailResponse($this, $httpResponse->getBody()); + } + + public function setTransactionReference($transactionReference) + { + $this->transactionReference = $transactionReference; + } + + public function getTransactionReference() + { + return $this->transactionReference; + } +} diff --git a/src/Message/QueryDetailResponse.php b/src/Message/QueryDetailResponse.php new file mode 100644 index 00000000..8393dd13 --- /dev/null +++ b/src/Message/QueryDetailResponse.php @@ -0,0 +1,271 @@ +]+>/', '', (string)$data); + + try { + $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); + } catch (\Exception $e) { + throw new InvalidResponseException(); + } + + if (!$xml) { + throw new InvalidResponseException(); + } + + parent::__construct($request, $xml); + $result = $this->xml2array($this->data->transaction, true); + $this->transaction = $result['transaction'][0]; + } + + public function isSuccessful() + { + return 1 == $this->getResultCode(); + } + + + public function isRecurring() + { + return ($this->transaction['recurringBilling'] === 'true'); + } + + public function getClientIp() + { + return $this->transaction['customerIP']; + } + + /** + * TransactionReference is the reference generated by the payment gateway. + * + * @return mixed + */ + public function getTransactionReference() + { + return $this->transaction['transId']; + } + + /** + * TransactionId is the reference set by the originating website. + * + * @return mixed + */ + public function getTransactionId() + { + return $this->transaction['order'][0]['invoiceNumber']; + } + + public function getAmount() + { + return $this->transaction['settleAmount']; + } + + public function getDescription() + { + return $this->transaction['order'][0]['description']; + } + + /** + * Get email. + * + * @return string + */ + public function getEmail() + { + return $this->transaction['customer'][0]['email']; + } + + public function getResultCode() + { + return $this->transaction['responseCode']; + } + + /** + * Get the currency. + * + * Seems to onlys support USD. + * + * @return string + */ + public function getCurrency() + { + return 'USD'; + } + + /** + * Get first name. + * + * In practice this is billing first name. + * + * @return string + */ + public function getFirstName() + { + return $this->transaction['billTo'][0]['firstName']; + } + + /** + * Get the gateway generated id for the recurring transaction. + */ + public function getRecurringReference() + { + return $this->transaction['subscription'][0]['id']; + } + + /** + * Get the gateway generated id for the recurring transaction. + */ + public function getCustomerReference() + { + if (!$this->isRecurring()) { + return ''; + } + if (!$this->planResponse) { + /** @var \Omnipay\AuthorizeNet\AIMGateway $gateway */ + $gateway = Omnipay::create('AuthorizeNet_AIM'); + $gateway->setApiLoginId($this->request->getApiLoginId()); + $gateway->setHashSecret($this->request->getHashSecret()); + $gateway->setTransactionKey($this->request->getTransactionKey()); + $data = array('recurringReference' => $this->getRecurringReference()); + $this->planResponse = $gateway->paymentPlanQuery($data)->send(); + } + return $this->planResponse->getContactReference(); + + + } + + /** + * Get last name. + * + * In practice this is billing last name. + * + * @return string + */ + public function getLastName() + { + return $this->transaction['billTo'][0]['lastName']; + } + + /** + * Get credit card number. + * + * This is masked. Is this the correct parameter name. + */ + public function getNumber() + { + return $this->transaction['payment'][0]['creditCard'][0]['cardNumber']; + } + + public function getType() + { + return $this->transaction['payment'][0]['creditCard'][0]['cardType']; + } + + public function getBillingAddress1() + { + return $this->transaction['billTo'][0]['address']; + } + + public function getBillingAddress2() + { + return ''; + } + + public function getBillingCity() + { + return $this->transaction['billTo'][0]['city']; + } + + public function getBillingPostcode() + { + return $this->transaction['billTo'][0]['zip']; + } + + /** + * Get billing address State. + * + * @todo consider if there should be other variants for full vs abbreviation. + * + * @return mixed + */ + public function getBillingState() + { + return $this->transaction['billTo'][0]['state']; + } + + /** + * Get billing address Country. + * + * @todo consider if there should be other variants for full vs abbreviation. + * + * @return mixed + */ + public function getBillingCountry() + { + return $this->transaction['billTo'][0]['country']; + } + + /** + * Get transaction date in UTC. + * + * @return string + */ + public function getSettlementDate() + { + return $this->transaction['batch'][0]['settlementTimeUTC']; + } + + /** + * Get settlement date in UTC. + * + * @return string + */ + public function getTransactionDate() + { + return $this->transaction['submitTimeUTC']; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} diff --git a/src/Message/QueryRequest.php b/src/Message/QueryRequest.php new file mode 100644 index 00000000..ea678a68 --- /dev/null +++ b/src/Message/QueryRequest.php @@ -0,0 +1,73 @@ +startTimestamp; + } + + /** + * @param mixed $startTimestamp + */ + public function setStartTimestamp($startTimestamp) + { + $this->startTimestamp = $startTimestamp; + } + + /** + * @return mixed + */ + public function getEndTimestamp() + { + return $this->endTimestamp; + } + + /** + * @param mixed $endTimestamp + */ + public function setEndTimestamp($endTimestamp) + { + $this->endTimestamp = $endTimestamp; + } + + /** + * Get data to send. + */ + public function getData() + { + $data = $this->getBaseData(); + if ($this->getStartTimestamp()) { + $data->firstSettlementDate = date('Y-m-d\Th:i:s\Z', $this->getStartTimestamp()); + $data->lastSettlementDate = date('Y-m-d\Th:i:s\Z'); + } + if ($this->getEndTimestamp()) { + $data->lastSettlementDate = date('Y-m-d\Th:i:s\Z', $this->getEndTimestamp()); + } + return $data; + } + + public function sendData($data) + { + $headers = array('Content-Type' => 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + $this->response = new QueryResponse($this, $httpResponse->getBody()); + return $this->response; + } +} diff --git a/src/Message/QueryResponse.php b/src/Message/QueryResponse.php new file mode 100644 index 00000000..86122bea --- /dev/null +++ b/src/Message/QueryResponse.php @@ -0,0 +1,69 @@ +setApiLoginId($this->request->getApiLoginId()); + $gateway->setHashSecret($this->request->getHashSecret()); + $gateway->setTransactionKey($this->request->getTransactionKey()); + $gateway->setDeveloperMode($this->request->getDeveloperMode()); + $data = array('batch_id' => $batch['batchId']); + $dataResponse = $gateway->queryBatchDetail($data)->send(); + $transactions = $dataResponse->getData(); + foreach ($transactions as $transaction) { + $detailResponse = $gateway->queryDetail(array('transactionReference' => $transaction['transId'])) + ->send(); + $result[] = $detailResponse; + } + } + } + return $result; + } + + /** + * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ + * + * Convert a simpleXMLElement in to an array + * + * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. + * + * @param \SimpleXMLElement $xml + * + * @return array + */ + public function xml2array(\SimpleXMLElement $xml) + { + $arr = array(); + foreach ($xml as $element) { + $tag = $element->getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} From 0388163b0fff4d4fbc1baaae51aef37c958ad307 Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 7 Nov 2017 09:04:27 +1300 Subject: [PATCH 168/254] Add parent classes into query requests & responses, folderise #79 --- .editorconfig | 14 ++++++ src/AIMGateway.php | 4 +- .../AIMAbstractQueryRequest.php} | 23 ++-------- .../AIMPaymentPlanQueryRequest.php | 44 +------------------ .../AIMPaymentPlanQueryResponse.php | 7 ++- .../AIMPaymentPlansQueryRequest.php | 32 +------------- .../AIMPaymentPlansQueryResponse.php | 31 +------------ src/Message/Query/AbstractQueryResponse.php | 43 ++++++++++++++++++ .../{ => Query}/QueryBatchDetailRequest.php | 42 +----------------- .../{ => Query}/QueryBatchDetailResponse.php | 31 +------------ src/Message/Query/QueryBatchRequest.php | 23 ++++++++++ .../{ => Query}/QueryBatchResponse.php | 31 +------------ .../{ => Query}/QueryDetailRequest.php | 44 +------------------ .../{ => Query}/QueryDetailResponse.php | 31 +------------ src/Message/{ => Query}/QueryRequest.php | 2 +- src/Message/{ => Query}/QueryResponse.php | 29 +----------- 16 files changed, 103 insertions(+), 328 deletions(-) create mode 100644 .editorconfig rename src/Message/{QueryBatchRequest.php => Query/AIMAbstractQueryRequest.php} (54%) rename src/Message/{ => Query}/AIMPaymentPlanQueryRequest.php (63%) rename src/Message/{ => Query}/AIMPaymentPlanQueryResponse.php (96%) rename src/Message/{ => Query}/AIMPaymentPlansQueryRequest.php (72%) rename src/Message/{ => Query}/AIMPaymentPlansQueryResponse.php (57%) create mode 100644 src/Message/Query/AbstractQueryResponse.php rename src/Message/{ => Query}/QueryBatchDetailRequest.php (62%) rename src/Message/{ => Query}/QueryBatchDetailResponse.php (56%) create mode 100644 src/Message/Query/QueryBatchRequest.php rename src/Message/{ => Query}/QueryBatchResponse.php (63%) rename src/Message/{ => Query}/QueryDetailRequest.php (61%) rename src/Message/{ => Query}/QueryDetailResponse.php (86%) rename src/Message/{ => Query}/QueryRequest.php (97%) rename src/Message/{ => Query}/QueryResponse.php (64%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..0c9db577 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# CiviCRM editor configuration normalization +# @see http://editorconfig.org/ + +# This is the top-most .editorconfig file; do not search in parent directories. +root = true + +# All files. +[*] +end_of_line = LF +indent_style = space +indent_size = 4 +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 8f373d56..8295d2bc 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -161,7 +161,7 @@ public function refund(array $parameters = array()) */ public function paymentPlansQuery(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMPaymentPlansQueryRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlansQueryRequest', $parameters); } /** @@ -170,7 +170,7 @@ public function paymentPlansQuery(array $parameters = array()) */ public function paymentPlanQuery(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMPaymentPlanQueryRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlanQueryRequest', $parameters); } /** diff --git a/src/Message/QueryBatchRequest.php b/src/Message/Query/AIMAbstractQueryRequest.php similarity index 54% rename from src/Message/QueryBatchRequest.php rename to src/Message/Query/AIMAbstractQueryRequest.php index 14e8a6f5..560dd006 100644 --- a/src/Message/QueryBatchRequest.php +++ b/src/Message/Query/AIMAbstractQueryRequest.php @@ -1,16 +1,12 @@ getBaseData(); return $data; } - - protected function addTransactionType(\SimpleXMLElement $data) - { - } - - public function sendData($data) - { - $headers = array('Content-Type' => 'text/xml; charset=utf-8'); - $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); - - return $this->response = new QueryBatchResponse($this, $httpResponse->getBody()); - } } diff --git a/src/Message/AIMPaymentPlanQueryRequest.php b/src/Message/Query/AIMPaymentPlanQueryRequest.php similarity index 63% rename from src/Message/AIMPaymentPlanQueryRequest.php rename to src/Message/Query/AIMPaymentPlanQueryRequest.php index 776dd0c1..d1a58a4b 100644 --- a/src/Message/AIMPaymentPlanQueryRequest.php +++ b/src/Message/Query/AIMPaymentPlanQueryRequest.php @@ -1,13 +1,13 @@ recurringReference = $recurringReference; } - /** - * Get Limit. - * - * @return int - */ - public function getLimit() - { - return $this->limit; - } - - /** - * Set Limit. - * - * @param int $limit - */ - public function setLimit($limit) - { - $this->limit = $limit; - } - - /** - * Get offset. - * - * @return int - */ - public function getOffset() - { - return $this->offset; - } - - /** - * Set offset. - * - * @param int $offset - */ - public function setOffset($offset) - { - $this->offset = $offset; - } - /** * Get data to send. */ diff --git a/src/Message/AIMPaymentPlanQueryResponse.php b/src/Message/Query/AIMPaymentPlanQueryResponse.php similarity index 96% rename from src/Message/AIMPaymentPlanQueryResponse.php rename to src/Message/Query/AIMPaymentPlanQueryResponse.php index 4915ffe2..167f73f7 100644 --- a/src/Message/AIMPaymentPlanQueryResponse.php +++ b/src/Message/Query/AIMPaymentPlanQueryResponse.php @@ -1,6 +1,6 @@ subscription); + return $this->subscription; } public function getContactReference() diff --git a/src/Message/AIMPaymentPlansQueryRequest.php b/src/Message/Query/AIMPaymentPlansQueryRequest.php similarity index 72% rename from src/Message/AIMPaymentPlansQueryRequest.php rename to src/Message/Query/AIMPaymentPlansQueryRequest.php index abdca244..13afb190 100644 --- a/src/Message/AIMPaymentPlansQueryRequest.php +++ b/src/Message/Query/AIMPaymentPlansQueryRequest.php @@ -1,6 +1,6 @@ limit; } - /** - * Set Limit. - * - * @param int $limit - */ - public function setLimit($limit) - { - $this->limit = $limit; - } - - /** - * Get offset. - * - * @return int - */ - public function getOffset() - { - return $this->offset; - } - - /** - * Set offset. - * - * @param int $offset - */ - public function setOffset($offset) - { - $this->offset = $offset; - } - /** * Get data to send. */ diff --git a/src/Message/AIMPaymentPlansQueryResponse.php b/src/Message/Query/AIMPaymentPlansQueryResponse.php similarity index 57% rename from src/Message/AIMPaymentPlansQueryResponse.php rename to src/Message/Query/AIMPaymentPlansQueryResponse.php index 857479f5..c0830f90 100644 --- a/src/Message/AIMPaymentPlansQueryResponse.php +++ b/src/Message/Query/AIMPaymentPlansQueryResponse.php @@ -1,6 +1,6 @@ xml2array($this->data->subscriptionDetails, true); return $result['subscriptionDetails'][0]['subscriptionDetail']; } - - /** - * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ - * - * Convert a simpleXMLElement in to an array - * - * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. - * - * @param \SimpleXMLElement $xml - * - * @return array - */ - public function xml2array(\SimpleXMLElement $xml) - { - $arr = array(); - foreach ($xml as $element) { - $tag = $element->getName(); - $e = get_object_vars($element); - if (!empty($e)) { - $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; - } else { - $arr[$tag] = trim($element); - } - } - - return $arr; - } } diff --git a/src/Message/Query/AbstractQueryResponse.php b/src/Message/Query/AbstractQueryResponse.php new file mode 100644 index 00000000..b4414fdb --- /dev/null +++ b/src/Message/Query/AbstractQueryResponse.php @@ -0,0 +1,43 @@ +getName(); + $e = get_object_vars($element); + if (!empty($e)) { + $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; + } else { + $arr[$tag] = trim($element); + } + } + + return $arr; + } +} diff --git a/src/Message/QueryBatchDetailRequest.php b/src/Message/Query/QueryBatchDetailRequest.php similarity index 62% rename from src/Message/QueryBatchDetailRequest.php rename to src/Message/Query/QueryBatchDetailRequest.php index aeb7e5e0..98d0d1c8 100644 --- a/src/Message/QueryBatchDetailRequest.php +++ b/src/Message/Query/QueryBatchDetailRequest.php @@ -1,6 +1,6 @@ limit; - } - - /** - * Set Limit. - * - * @param int $limit - */ - public function setLimit($limit) - { - $this->limit = $limit; - } - - /** - * Get offset. - * - * @return int - */ - public function getOffset() - { - return $this->offset; - } - - /** - * Set offset. - * - * @param int $offset - */ - public function setOffset($offset) - { - $this->offset = $offset; - } - /** * Get data to send. */ diff --git a/src/Message/QueryBatchDetailResponse.php b/src/Message/Query/QueryBatchDetailResponse.php similarity index 56% rename from src/Message/QueryBatchDetailResponse.php rename to src/Message/Query/QueryBatchDetailResponse.php index e8eaa726..6d89bf70 100644 --- a/src/Message/QueryBatchDetailResponse.php +++ b/src/Message/Query/QueryBatchDetailResponse.php @@ -1,6 +1,6 @@ xml2array($this->data->transactions, true); return $result['transactions'][0]['transaction']; } - - /** - * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ - * - * Convert a simpleXMLElement in to an array - * - * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. - * - * @param \SimpleXMLElement $xml - * - * @return array - */ - public function xml2array(\SimpleXMLElement $xml) - { - $arr = array(); - foreach ($xml as $element) { - $tag = $element->getName(); - $e = get_object_vars($element); - if (!empty($e)) { - $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; - } else { - $arr[$tag] = trim($element); - } - } - - return $arr; - } } diff --git a/src/Message/Query/QueryBatchRequest.php b/src/Message/Query/QueryBatchRequest.php new file mode 100644 index 00000000..87f0fb3e --- /dev/null +++ b/src/Message/Query/QueryBatchRequest.php @@ -0,0 +1,23 @@ + 'text/xml; charset=utf-8'); + $data = $data->saveXml(); + $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + + return $this->response = new QueryBatchResponse($this, $httpResponse->getBody()); + } +} diff --git a/src/Message/QueryBatchResponse.php b/src/Message/Query/QueryBatchResponse.php similarity index 63% rename from src/Message/QueryBatchResponse.php rename to src/Message/Query/QueryBatchResponse.php index 41a6881b..32995dab 100644 --- a/src/Message/QueryBatchResponse.php +++ b/src/Message/Query/QueryBatchResponse.php @@ -1,6 +1,6 @@ xml2array($this->data->batchList, true); return $result['batchList'][0]['batch']; } - - /** - * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ - * - * Convert a simpleXMLElement in to an array - * - * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. - * - * @param \SimpleXMLElement $xml - * - * @return array - */ - public function xml2array(\SimpleXMLElement $xml) - { - $arr = array(); - foreach ($xml as $element) { - $tag = $element->getName(); - $e = get_object_vars($element); - if (!empty($e)) { - $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; - } else { - $arr[$tag] = trim($element); - } - } - - return $arr; - } } diff --git a/src/Message/QueryDetailRequest.php b/src/Message/Query/QueryDetailRequest.php similarity index 61% rename from src/Message/QueryDetailRequest.php rename to src/Message/Query/QueryDetailRequest.php index 132e3524..7b2034de 100644 --- a/src/Message/QueryDetailRequest.php +++ b/src/Message/Query/QueryDetailRequest.php @@ -1,6 +1,6 @@ limit; - } - - /** - * Set Limit. - * - * @param int $limit - */ - public function setLimit($limit) - { - $this->limit = $limit; - } - - /** - * Get offset. - * - * @return int - */ - public function getOffset() - { - return $this->offset; - } - - /** - * Set offset. - * - * @param int $offset - */ - public function setOffset($offset) - { - $this->offset = $offset; - } - /** * Get data to send. */ diff --git a/src/Message/QueryDetailResponse.php b/src/Message/Query/QueryDetailResponse.php similarity index 86% rename from src/Message/QueryDetailResponse.php rename to src/Message/Query/QueryDetailResponse.php index 8393dd13..cb151f1e 100644 --- a/src/Message/QueryDetailResponse.php +++ b/src/Message/Query/QueryDetailResponse.php @@ -1,6 +1,6 @@ transaction['submitTimeUTC']; } - - /** - * http://bookofzeus.com/articles/convert-simplexml-object-into-php-array/ - * - * Convert a simpleXMLElement in to an array - * - * @todo this is duplicated from CIMAbstractResponse. Put somewhere shared. - * - * @param \SimpleXMLElement $xml - * - * @return array - */ - public function xml2array(\SimpleXMLElement $xml) - { - $arr = array(); - foreach ($xml as $element) { - $tag = $element->getName(); - $e = get_object_vars($element); - if (!empty($e)) { - $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; - } else { - $arr[$tag] = trim($element); - } - } - - return $arr; - } } diff --git a/src/Message/QueryRequest.php b/src/Message/Query/QueryRequest.php similarity index 97% rename from src/Message/QueryRequest.php rename to src/Message/Query/QueryRequest.php index ea678a68..88118160 100644 --- a/src/Message/QueryRequest.php +++ b/src/Message/Query/QueryRequest.php @@ -1,6 +1,6 @@ getName(); - $e = get_object_vars($element); - if (!empty($e)) { - $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; - } else { - $arr[$tag] = trim($element); - } - } - - return $arr; - } } From 379574ea25bae05aedd50a4c255a81a2db1860a8 Mon Sep 17 00:00:00 2001 From: Jon goldberg Date: Tue, 19 Dec 2017 18:53:05 -0500 Subject: [PATCH 169/254] Fix autoloader fatal errors from class reorganization --- src/AIMGateway.php | 2 +- src/Message/Query/AIMAbstractQueryRequest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 8295d2bc..03fe16a6 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -179,7 +179,7 @@ public function paymentPlanQuery(array $parameters = array()) */ public function query(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\Query\QueryRequest', $parameters); } /** diff --git a/src/Message/Query/AIMAbstractQueryRequest.php b/src/Message/Query/AIMAbstractQueryRequest.php index 560dd006..9f719070 100644 --- a/src/Message/Query/AIMAbstractQueryRequest.php +++ b/src/Message/Query/AIMAbstractQueryRequest.php @@ -2,6 +2,8 @@ namespace Omnipay\AuthorizeNet\Message\Query; +use Omnipay\AuthorizeNet\Message\AIMAbstractRequest; + /** * Authorize.Net AIM Abstract Request */ From d091c9c8e15d7983c06d4832b917a9ddf4bc0c79 Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 5 Jan 2018 15:57:28 -0500 Subject: [PATCH 170/254] Add capture only tests --- tests/AIMGatewayTest.php | 21 +++++++++++++++++++++ tests/Message/AIMResponseTest.php | 28 ++++++++++++++++++++++++++++ tests/Mock/AIMCaptureOnlyFailure.txt | 13 +++++++++++++ tests/Mock/AIMCaptureOnlySuccess.txt | 13 +++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 tests/Mock/AIMCaptureOnlyFailure.txt create mode 100644 tests/Mock/AIMCaptureOnlySuccess.txt diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 827ccac0..2748b092 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -126,7 +126,28 @@ public function testCaptureFailure() $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); } + + public function testCaptureOnlySuccess() + { + $this->setMockHttpResponse('AIMCaptureOnlySuccess.txt'); + + $response = $this->gateway->capture($this->captureOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('{"approvalCode":"ROHNFQ","transId":"2214480791"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); + } + public function testCaptureOnlyFailure() + { + $this->setMockHttpResponse('AIMCaptureOnlyFailure.txt'); + + $response = $this->gateway->capture($this->captureOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been declined.', $response->getMessage()); + } public function testPurchaseSuccess() { $this->setMockHttpResponse('AIMPurchaseSuccess.txt'); diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 275fdfd8..999eabf8 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -101,6 +101,34 @@ public function testCaptureFailure() $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); } + + public function testCaptureOnlySuccess() + { + $httpResponse = $this->getMockHttpResponse('AIMCaptureOnlySuccess.txt'); + $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame('{"approvalCode":"ROHNFQ","transId":"2214480791"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); + $this->assertSame(1, $response->getResultCode()); + $this->assertSame(1, $response->getReasonCode()); + $this->assertSame('ROHNFQ', $response->getAuthorizationCode()); + $this->assertSame('P', $response->getAVSCode()); + } + + public function testCaptureOnlyFailure() + { + $httpResponse = $this->getMockHttpResponse('AIMCaptureOnlyFailure.txt'); + $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertFalse($response->isSuccessful()); + $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); + $this->assertSame('This transaction has been declined.', $response->getMessage()); + $this->assertSame(2, $response->getResultCode()); + $this->assertSame(2, $response->getReasonCode()); + $this->assertSame('', $response->getAuthorizationCode()); + $this->assertSame('P', $response->getAVSCode()); + } public function testPurchaseSuccess() { diff --git a/tests/Mock/AIMCaptureOnlyFailure.txt b/tests/Mock/AIMCaptureOnlyFailure.txt new file mode 100644 index 00000000..b58e6cab --- /dev/null +++ b/tests/Mock/AIMCaptureOnlyFailure.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Sat, 02 Aug 2014 05:27:33 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 868 + +123456ErrorE00027The transaction was unsuccessful.2P02214480791492E8E689EBD28D07749848B7C1E49D3XXXX0015Mastercard2This transaction has been declined. diff --git a/tests/Mock/AIMCaptureOnlySuccess.txt b/tests/Mock/AIMCaptureOnlySuccess.txt new file mode 100644 index 00000000..79eaa0b0 --- /dev/null +++ b/tests/Mock/AIMCaptureOnlySuccess.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Sat, 02 Aug 2014 05:24:31 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 852 + +123456OkI00001Successful.1ROHNFQP22144807912214480791492E8E689EBD28D07749848B7C1E49D3XXXX0015Mastercard1This transaction has been approved. From f5893290a196cb5e0655e3e624c393866f8e12d2 Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 5 Jan 2018 15:58:28 -0500 Subject: [PATCH 171/254] Add capture only request --- src/Message/AIMAbstractRequest.php | 10 ++++++++++ src/Message/AIMCaptureOnlyRequest.php | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/Message/AIMCaptureOnlyRequest.php diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 2282e254..2be9656f 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -111,6 +111,16 @@ public function setSolutionId($value) return $this->setParameter('solutionId', $value); } + public function getAuthCode() + { + return $this->getParameter('authCode'); + } + + public function setAuthCode($value) + { + return $this->setParameter('authCode', $value); + } + /** * @return TransactionReference */ diff --git a/src/Message/AIMCaptureOnlyRequest.php b/src/Message/AIMCaptureOnlyRequest.php new file mode 100644 index 00000000..55260bcd --- /dev/null +++ b/src/Message/AIMCaptureOnlyRequest.php @@ -0,0 +1,25 @@ +validate('amount'); + + $data = $this->getBaseData(); + $data->transactionRequest->amount = $this->getAmount(); + $data->transactionRequest->authCode = $this->getAuthCode(); + $this->addTransactionSettings($data); + + return $data; + } +} From 0af67afdb8d7d5e5070c64e1b1a916cee150a0db Mon Sep 17 00:00:00 2001 From: Sam L Date: Sat, 6 Jan 2018 22:46:16 -0500 Subject: [PATCH 172/254] Update request based on discussion on issue-93 https://github.com/thephpleague/omnipay-authorizenet/issues/93#issuecomment-355780401 --- src/Message/AIMCaptureOnlyRequest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Message/AIMCaptureOnlyRequest.php b/src/Message/AIMCaptureOnlyRequest.php index 55260bcd..2777210c 100644 --- a/src/Message/AIMCaptureOnlyRequest.php +++ b/src/Message/AIMCaptureOnlyRequest.php @@ -7,18 +7,15 @@ /** * Authorize.Net AIM Capture Only Request */ -class AIMCaptureOnlyRequest extends AIMAbstractRequest +class AIMCaptureOnlyRequest extends AIMAuthorizeRequest { protected $action = 'captureOnlyTransaction'; public function getData() { - $this->validate('amount'); + $data = parent::getData(); - $data = $this->getBaseData(); - $data->transactionRequest->amount = $this->getAmount(); $data->transactionRequest->authCode = $this->getAuthCode(); - $this->addTransactionSettings($data); return $data; } From 5db0086a6b73c0907cd8a0a32e4e375f51ec8e45 Mon Sep 17 00:00:00 2001 From: Sam L Date: Sat, 6 Jan 2018 22:46:56 -0500 Subject: [PATCH 173/254] Update tests --- tests/AIMGatewayTest.php | 6 +++--- tests/Message/AIMResponseTest.php | 12 ++++++------ tests/Mock/AIMCaptureOnlyFailure.txt | 6 +++--- tests/Mock/AIMCaptureOnlySuccess.txt | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 2748b092..7a6ce81c 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -134,7 +134,7 @@ public function testCaptureOnlySuccess() $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertTrue($response->isSuccessful()); - $this->assertSame('{"approvalCode":"ROHNFQ","transId":"2214480791"}', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"ROHNFQ","transId":"40009379672"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); } @@ -145,8 +145,8 @@ public function testCaptureOnlyFailure() $response = $this->gateway->capture($this->captureOptions)->send(); $this->assertFalse($response->isSuccessful()); - $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); - $this->assertSame('This transaction has been declined.', $response->getMessage()); + $this->assertSame('{"approvalCode":"ROHNFQ","transId":"0"}', $response->getTransactionReference()); + $this->assertSame('A valid amount is required.', $response->getMessage()); } public function testPurchaseSuccess() { diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 999eabf8..82030376 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -108,7 +108,7 @@ public function testCaptureOnlySuccess() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertTrue($response->isSuccessful()); - $this->assertSame('{"approvalCode":"ROHNFQ","transId":"2214480791"}', $response->getTransactionReference()); + $this->assertSame('{"approvalCode":"ROHNFQ","transId":"40009379672"}', $response->getTransactionReference()); $this->assertSame('This transaction has been approved.', $response->getMessage()); $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); @@ -122,11 +122,11 @@ public function testCaptureOnlyFailure() $response = new AIMResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertFalse($response->isSuccessful()); - $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); - $this->assertSame('This transaction has been declined.', $response->getMessage()); - $this->assertSame(2, $response->getResultCode()); - $this->assertSame(2, $response->getReasonCode()); - $this->assertSame('', $response->getAuthorizationCode()); + $this->assertSame('{"approvalCode":"ROHNFQ","transId":"0"}', $response->getTransactionReference()); + $this->assertSame('A valid amount is required.', $response->getMessage()); + $this->assertSame(3, $response->getResultCode()); + $this->assertSame(5, $response->getReasonCode()); + $this->assertSame('ROHNFQ', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); } diff --git a/tests/Mock/AIMCaptureOnlyFailure.txt b/tests/Mock/AIMCaptureOnlyFailure.txt index b58e6cab..f2dff42c 100644 --- a/tests/Mock/AIMCaptureOnlyFailure.txt +++ b/tests/Mock/AIMCaptureOnlyFailure.txt @@ -1,5 +1,5 @@ HTTP/1.1 200 OK -Date: Sat, 02 Aug 2014 05:27:33 GMT +Date: Sat, 02 Aug 2014 04:53:02 GMT Server: Microsoft-IIS/6.0 Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, OPTIONS @@ -8,6 +8,6 @@ X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private Content-Type: text/xml; charset=utf-8 -Content-Length: 868 +Content-Length: 882 -123456ErrorE00027The transaction was unsuccessful.2P02214480791492E8E689EBD28D07749848B7C1E49D3XXXX0015Mastercard2This transaction has been declined. +123456ErrorE00027The transaction was unsuccessful.3ROHNFQP0680A8419B9B0C29DAA432BDFA73C3E830XXXX0015MasterCard5A valid amount is required. diff --git a/tests/Mock/AIMCaptureOnlySuccess.txt b/tests/Mock/AIMCaptureOnlySuccess.txt index 79eaa0b0..619a015c 100644 --- a/tests/Mock/AIMCaptureOnlySuccess.txt +++ b/tests/Mock/AIMCaptureOnlySuccess.txt @@ -8,6 +8,6 @@ X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private Content-Type: text/xml; charset=utf-8 -Content-Length: 852 +Content-Length: 877 -123456OkI00001Successful.1ROHNFQP22144807912214480791492E8E689EBD28D07749848B7C1E49D3XXXX0015Mastercard1This transaction has been approved. +123456OkI00001Successful.1ROHNFQP4000937967213BA777FBC314C49558C9BE4250CEA240XXXX0015MasterCard1This transaction has been approved. From cea163464a31bd0f0a40e4f836602a05235d178d Mon Sep 17 00:00:00 2001 From: Sam L Date: Sun, 7 Jan 2018 15:50:37 -0500 Subject: [PATCH 174/254] Update capture only request field order --- src/Message/AIMCaptureOnlyRequest.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Message/AIMCaptureOnlyRequest.php b/src/Message/AIMCaptureOnlyRequest.php index 2777210c..f2868537 100644 --- a/src/Message/AIMCaptureOnlyRequest.php +++ b/src/Message/AIMCaptureOnlyRequest.php @@ -1,6 +1,6 @@ validate('amount'); + $data = $this->getBaseData(); + $data->transactionRequest->amount = $this->getAmount(); + $this->addPayment($data); $data->transactionRequest->authCode = $this->getAuthCode(); - + $this->addSolutionId($data); + $this->addBillingData($data); + $this->addCustomerIP($data); + $this->addTransactionSettings($data); + return $data; - } + } } From e755e26b2dc3e1d7983d50831289c1aea69361cf Mon Sep 17 00:00:00 2001 From: Sam L Date: Sun, 7 Jan 2018 15:51:24 -0500 Subject: [PATCH 175/254] Add capture only to aim gateway --- src/AIMGateway.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 03fe16a6..c4effed3 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -128,6 +128,15 @@ public function capture(array $parameters = array()) return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMCaptureRequest', $parameters); } + /** + * @param array $parameters + * @return AIMCaptureOnlyRequest + */ + public function captureOnly(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMCaptureOnlyRequest', $parameters); + } + /** * @param array $parameters * @return AIMPurchaseRequest From 38a4c4fd272bff01feef22c29147ff027e26ba0d Mon Sep 17 00:00:00 2001 From: Sam L Date: Sun, 7 Jan 2018 16:50:31 -0500 Subject: [PATCH 176/254] Correct spacing --- src/Message/AIMCaptureOnlyRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/AIMCaptureOnlyRequest.php b/src/Message/AIMCaptureOnlyRequest.php index f2868537..f6f6cbdb 100644 --- a/src/Message/AIMCaptureOnlyRequest.php +++ b/src/Message/AIMCaptureOnlyRequest.php @@ -24,5 +24,5 @@ public function getData() $this->addTransactionSettings($data); return $data; - } + } } From e7cefe226c1e171f282abbef989fea1db4c80303 Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 12 Jan 2018 14:06:49 -0500 Subject: [PATCH 177/254] Add getCVVCode --- src/Message/AIMResponse.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 020b51d8..3da0e58c 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -139,7 +139,20 @@ public function getAVSCode() return ''; } } - + + /** + * Returns the Card Code Verfication return code. + * + * @return string A single character. Can be M, N, P, S, or U. + */ + public function getCVVCode() + { + if (isset($this->data->transactionResponse[0]->cvvResultCode)) { + return (string)$this->data->transactionResponse[0]->cvvResultCode; + } else { + return ''; + } + } /** * A composite key containing the gateway provided transaction reference as * well as other data points that may be required for subsequent transactions From 29d33aa4ef73862306e5b4ffa4b0dc2f03acd600 Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 12 Jan 2018 14:06:57 -0500 Subject: [PATCH 178/254] Add tests for getCVVCode --- tests/Message/AIMResponseTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 82030376..33ed338f 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -34,6 +34,7 @@ public function testAuthorizeSuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('GA4OQP', $response->getAuthorizationCode()); $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('P', $response->getCVVCode()); } public function testAuthorizeFailure() @@ -48,6 +49,7 @@ public function testAuthorizeFailure() $this->assertSame(5, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testAuthorizeInvalid() @@ -62,6 +64,7 @@ public function testAuthorizeInvalid() $this->assertSame('E00007', $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testAuthorizeInvalidOTSToken() @@ -86,6 +89,7 @@ public function testCaptureSuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('F51OYG', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testCaptureFailure() @@ -100,6 +104,7 @@ public function testCaptureFailure() $this->assertSame(16, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testCaptureOnlySuccess() @@ -114,6 +119,7 @@ public function testCaptureOnlySuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('ROHNFQ', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testCaptureOnlyFailure() @@ -128,6 +134,7 @@ public function testCaptureOnlyFailure() $this->assertSame(5, $response->getReasonCode()); $this->assertSame('ROHNFQ', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testPurchaseSuccess() @@ -142,6 +149,7 @@ public function testPurchaseSuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('JE6JM1', $response->getAuthorizationCode()); $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('P', $response->getCVVCode()); } public function testPurchaseFailure() @@ -156,6 +164,7 @@ public function testPurchaseFailure() $this->assertSame(5, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testRefundSuccess() @@ -170,6 +179,7 @@ public function testRefundSuccess() $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } public function testRefundFailure() @@ -184,5 +194,6 @@ public function testRefundFailure() $this->assertSame(54, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getCVVCode()); } } From ea732d10369bf386c1a350fff4637493f6d94404 Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 12 Jan 2018 14:36:56 -0500 Subject: [PATCH 179/254] Add getAccountType --- src/Message/AIMResponse.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 020b51d8..57c10ded 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -177,4 +177,18 @@ public function getTransactionReference($serialize = true) return ''; } + + /** + * Returns the account type used for the transaction. + * + * @return string A multicharacter string. Can be Visa, MasterCard, Discover, AmericanExpress, DinersClub, JCB, or eCheck. + */ + public function getAccountType() + { + if (isset($this->data->transactionResponse[0]->accountType)) { + return (string)$this->data->transactionResponse[0]->accountType; + } else { + return ''; + } + } } From b1a1dda85ed819abb3f4aaa69bd590443f000ab2 Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 12 Jan 2018 14:37:04 -0500 Subject: [PATCH 180/254] Add tests for getAccountType --- tests/Message/AIMResponseTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 82030376..00906b13 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -34,6 +34,7 @@ public function testAuthorizeSuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('GA4OQP', $response->getAuthorizationCode()); $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } public function testAuthorizeFailure() @@ -48,6 +49,7 @@ public function testAuthorizeFailure() $this->assertSame(5, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } public function testAuthorizeInvalid() @@ -86,6 +88,7 @@ public function testCaptureSuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('F51OYG', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } public function testCaptureFailure() @@ -100,6 +103,7 @@ public function testCaptureFailure() $this->assertSame(16, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('', $response->getAccountType()); } public function testCaptureOnlySuccess() @@ -114,6 +118,7 @@ public function testCaptureOnlySuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('ROHNFQ', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('MasterCard', $response->getAccountType()); } public function testCaptureOnlyFailure() @@ -128,6 +133,7 @@ public function testCaptureOnlyFailure() $this->assertSame(5, $response->getReasonCode()); $this->assertSame('ROHNFQ', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('MasterCard', $response->getAccountType()); } public function testPurchaseSuccess() @@ -142,6 +148,7 @@ public function testPurchaseSuccess() $this->assertSame(1, $response->getReasonCode()); $this->assertSame('JE6JM1', $response->getAuthorizationCode()); $this->assertSame('Y', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } public function testPurchaseFailure() @@ -156,6 +163,7 @@ public function testPurchaseFailure() $this->assertSame(5, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } public function testRefundSuccess() @@ -170,6 +178,7 @@ public function testRefundSuccess() $this->assertSame(1, $response->getResultCode()); $this->assertSame(1, $response->getReasonCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } public function testRefundFailure() @@ -184,5 +193,6 @@ public function testRefundFailure() $this->assertSame(54, $response->getReasonCode()); $this->assertSame('', $response->getAuthorizationCode()); $this->assertSame('P', $response->getAVSCode()); + $this->assertSame('Visa', $response->getAccountType()); } } From ecb76654de675b9b7aaf35fc82181e4b7c97e82f Mon Sep 17 00:00:00 2001 From: Sam L Date: Fri, 12 Jan 2018 15:34:50 -0500 Subject: [PATCH 181/254] Reduce line length --- src/Message/AIMResponse.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 57c10ded..1216a96e 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -181,7 +181,8 @@ public function getTransactionReference($serialize = true) /** * Returns the account type used for the transaction. * - * @return string A multicharacter string. Can be Visa, MasterCard, Discover, AmericanExpress, DinersClub, JCB, or eCheck. + * @return string A multicharacter string. + * Can be Visa, MasterCard, Discover, AmericanExpress, DinersClub, JCB, or eCheck. */ public function getAccountType() { From 4bb8e184932ac437e6091815586c74e7713bc2fc Mon Sep 17 00:00:00 2001 From: Sam L Date: Mon, 15 Jan 2018 15:05:53 -0500 Subject: [PATCH 182/254] Add retail data to authOnlyTransactions and authCaptureTransactions --- src/Message/AIMAuthorizeRequest.php | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index a4f0a58e..aeea9d48 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -20,6 +20,7 @@ public function getData() $this->addSolutionId($data); $this->addBillingData($data); $this->addCustomerIP($data); + $this->addRetail($data); $this->addTransactionSettings($data); return $data; @@ -52,4 +53,33 @@ protected function addCustomerIP(\SimpleXMLElement $data) $data->transactionRequest->customerIP = $ip; } } + + protected function addRetail(\SimpleXMLElement $data) + { + $retail = $this->getParameter('retail'); + if (isset($retail)) { + $data->transactionRequest->retail = $this->getParameter('retail'); + } + } + + /** + * Gets the retail data of the request from the gateway. + * + * @return array + */ + public function getRetail() + { + return $this-getRetail(); + } + + /** + * Sets the retail data in this request + * + * @param array $value An associative arrray with keys marketType and/or deviceType + * @return AIMAuthorizeRequest Provides a fluent interface + */ + public function setRetail($value) + { + return $this->setParameter('retail', $value); + } } From eb59611f0d97ea42eadc925d78c69325b39a248e Mon Sep 17 00:00:00 2001 From: Sam L Date: Tue, 16 Jan 2018 09:13:04 -0500 Subject: [PATCH 183/254] Seperate retail into deviceType and marketType --- src/Message/AIMAuthorizeRequest.php | 59 ++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index aeea9d48..95f7fc60 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -3,6 +3,7 @@ namespace Omnipay\AuthorizeNet\Message; use Omnipay\Common\CreditCard; +use Omnipay\Common\Exception\InvalidRequestException; /** * Authorize.Net AIM Authorize Request @@ -56,30 +57,52 @@ protected function addCustomerIP(\SimpleXMLElement $data) protected function addRetail(\SimpleXMLElement $data) { - $retail = $this->getParameter('retail'); - if (isset($retail)) { - $data->transactionRequest->retail = $this->getParameter('retail'); + $deviceType = $this->getDeviceType(); + $marketType = $this->getMarketType(); + + if (!isset($deviceType) && !isset($marketType)) { + return; + } + + if (!isset($deviceType) && isset($marketType)) { + throw new InvalidRequestException(); + } + + if (isset($deviceType) && !isset($marketType)) { + $marketType = "2"; + } + + if (!in_array($deviceType, [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ])) { + throw new InvalidRequestException(); } + + if (!in_array($marketType, [ "0", "1", "2" ])) { + throw new InvalidRequestException(); + } + + $data->transactionRequest->retail = [ + 'marketType' => $marketType, + 'deviceType' => $deviceType, + ]; + } + + public function getDeviceType() + { + return $this->getParameter('deviceType'); } - /** - * Gets the retail data of the request from the gateway. - * - * @return array - */ - public function getRetail() + public function setDeviceType($value) + { + return $this->setParameter('deviceType', $value); + } + + public function getMarketType() { - return $this-getRetail(); + return $this->getParameter('marketType'); } - /** - * Sets the retail data in this request - * - * @param array $value An associative arrray with keys marketType and/or deviceType - * @return AIMAuthorizeRequest Provides a fluent interface - */ - public function setRetail($value) + public function setMarketType($value) { - return $this->setParameter('retail', $value); + return $this->setParameter('marketType', $value); } } From 898f7b02dc5f111e81a614c18631c55d599da046 Mon Sep 17 00:00:00 2001 From: Sam L Date: Wed, 17 Jan 2018 13:18:06 -0500 Subject: [PATCH 184/254] Make array object --- src/Message/AIMAuthorizeRequest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 95f7fc60..a4872af6 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -80,10 +80,8 @@ protected function addRetail(\SimpleXMLElement $data) throw new InvalidRequestException(); } - $data->transactionRequest->retail = [ - 'marketType' => $marketType, - 'deviceType' => $deviceType, - ]; + $data->transactionRequest->retail->marketType = $marketType; + $data->transactionRequest->retail->deviceType = $deviceType; } public function getDeviceType() From d56df2060359387314d18670b8c4a7e0a530da0a Mon Sep 17 00:00:00 2001 From: Sam L Date: Wed, 17 Jan 2018 13:24:38 -0500 Subject: [PATCH 185/254] Add error messages --- src/Message/AIMAuthorizeRequest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index a4872af6..1fa2b2d6 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -65,7 +65,7 @@ protected function addRetail(\SimpleXMLElement $data) } if (!isset($deviceType) && isset($marketType)) { - throw new InvalidRequestException(); + throw new InvalidRequestException("deviceType is required if marketType is set"); } if (isset($deviceType) && !isset($marketType)) { @@ -73,11 +73,11 @@ protected function addRetail(\SimpleXMLElement $data) } if (!in_array($deviceType, [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ])) { - throw new InvalidRequestException(); + throw new InvalidRequestException("deviceType `{$deviceType}` is invalid"); } if (!in_array($marketType, [ "0", "1", "2" ])) { - throw new InvalidRequestException(); + throw new InvalidRequestException("marketType `{$marketType}` is invalid"); } $data->transactionRequest->retail->marketType = $marketType; From 5d0f9f643e8b78ed6e959b46ce9ca0e0726f9770 Mon Sep 17 00:00:00 2001 From: Sam L Date: Wed, 17 Jan 2018 13:35:46 -0500 Subject: [PATCH 186/254] Add test for retail values in AIMAuthorizeRequest --- tests/Message/AIMAuthorizeRequestTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index e410a8f5..9d82fc6f 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -22,6 +22,8 @@ public function setUp() 'card' => $card, 'duplicateWindow' => 0, 'solutionId' => 'SOL12345ID', + 'marketType' => '2', + 'deviceType' => '1', ) ); } @@ -35,6 +37,8 @@ public function testGetData() $this->assertEquals('cust-id', $data->transactionRequest->customer->id); $this->assertEquals('example@example.net', $data->transactionRequest->customer->email); $this->assertEquals('SOL12345ID', $data->transactionRequest->solution->id); + $this->assertEquals('2', $data->transactionRequest->retail->marketType); + $this->assertEquals('1', $data->transactionRequest->retail->deviceType); // Issue #38 Make sure the transactionRequest properties are correctly ordered. // This feels messy, but works. @@ -51,6 +55,7 @@ public function testGetData() "billTo", "shipTo", "customerIP", + "retail", "transactionSettings" ); $this->assertEquals($keys, $transactionRequestProperties); From ac570dadcc941a91f00afc9148a96f34cb7de53b Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 31 Jan 2018 22:40:47 +0000 Subject: [PATCH 187/254] Issue #105 fix. --- src/Message/AIMResponse.php | 40 ++++++++++---------- src/Message/CIMAbstractResponse.php | 14 ++++--- src/Message/CIMCreateCardResponse.php | 2 +- src/Message/CIMGetPaymentProfileResponse.php | 2 +- src/Message/CIMGetProfileResponse.php | 4 +- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 020b51d8..bd4ef670 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -59,8 +59,8 @@ public function isSuccessful() public function getResultCode() { // If there is a transaction response, then we get the code from that. - if (isset($this->data->transactionResponse[0])) { - return intval((string)$this->data->transactionResponse[0]->responseCode); + if (isset($this->data->transactionResponse)) { + return intval((string)$this->data->transactionResponse->responseCode); } // No transaction response, so return 3 aka "error". @@ -76,17 +76,17 @@ public function getReasonCode() { $code = null; - if (isset($this->data->transactionResponse[0]->messages)) { + if (isset($this->data->transactionResponse->messages)) { // In case of a successful transaction, a "messages" element is present - $code = intval((string)$this->data->transactionResponse[0]->messages[0]->message->code); + $code = intval((string)$this->data->transactionResponse->messages->message->code); - } elseif (isset($this->data->transactionResponse[0]->errors)) { + } elseif (isset($this->data->transactionResponse->errors)) { // In case of an unsuccessful transaction, an "errors" element is present - $code = intval((string)$this->data->transactionResponse[0]->errors[0]->error->errorCode); + $code = intval((string)$this->data->transactionResponse->errors->error->errorCode); - } elseif (isset($this->data->messages[0]->message)) { + } elseif (isset($this->data->messages->message)) { // In case of invalid request, the top-level message provides details. - $code = (string)$this->data->messages[0]->message->code; + $code = (string)$this->data->messages->message->code; } return $code; @@ -101,17 +101,17 @@ public function getMessage() { $message = null; - if (isset($this->data->transactionResponse[0]->messages)) { + if (isset($this->data->transactionResponse->messages)) { // In case of a successful transaction, a "messages" element is present - $message = (string)$this->data->transactionResponse[0]->messages[0]->message->description; + $message = (string)$this->data->transactionResponse->messages->message->description; - } elseif (isset($this->data->transactionResponse[0]->errors)) { + } elseif (isset($this->data->transactionResponse->errors)) { // In case of an unsuccessful transaction, an "errors" element is present - $message = (string)$this->data->transactionResponse[0]->errors[0]->error->errorText; + $message = (string)$this->data->transactionResponse->errors->error->errorText; - } elseif (isset($this->data->messages[0]->message)) { + } elseif (isset($this->data->messages->message)) { // In case of invalid request, the top-level message provides details. - $message = (string)$this->data->messages[0]->message->text; + $message = (string)$this->data->messages->message->text; } return $message; @@ -119,8 +119,8 @@ public function getMessage() public function getAuthorizationCode() { - if (isset($this->data->transactionResponse[0])) { - return (string)$this->data->transactionResponse[0]->authCode; + if (isset($this->data->transactionResponse)) { + return (string)$this->data->transactionResponse->authCode; } else { return ''; } @@ -133,8 +133,8 @@ public function getAuthorizationCode() */ public function getAVSCode() { - if (isset($this->data->transactionResponse[0])) { - return (string)$this->data->transactionResponse[0]->avsResultCode; + if (isset($this->data->transactionResponse)) { + return (string)$this->data->transactionResponse->avsResultCode; } else { return ''; } @@ -153,8 +153,8 @@ public function getTransactionReference($serialize = true) // The transactionResponse is only returned if succesful or declined // for some reason, so don't assume it will always be there. - if (isset($this->data->transactionResponse[0])) { - $body = $this->data->transactionResponse[0]; + if (isset($this->data->transactionResponse)) { + $body = $this->data->transactionResponse; $transactionRef = new TransactionReference(); $transactionRef->setApprovalCode((string)$body->authCode); $transactionRef->setTransId((string)$body->transId); diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index e02d7a7a..a2710d0a 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -27,10 +27,10 @@ public function __construct(RequestInterface $request, $data) // Check if this is an error response $isError = strpos((string)$data, 'responseType; + $xmlRootElement = ($isError !== false ? 'ErrorResponse' : $this->responseType); // Strip out the xmlns junk so that PHP can parse the XML $xml = preg_replace('/<' . $xmlRootElement . '[^>]+>/', '<' . $xmlRootElement . '>', (string)$data); - +//var_dump($xml); try { $xml = simplexml_load_string($xml); } catch (\Exception $e) { @@ -58,7 +58,7 @@ public function isSuccessful() */ public function getResultCode() { - $result = (string)$this->data['messages'][0]['resultCode']; + $result = (string)$this->data['messages']['resultCode']; switch ($result) { case 'Ok': @@ -82,7 +82,7 @@ public function getReasonCode() if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present - $code = (string)$this->data['messages'][0]['message'][0]['code']; + $code = (string)$this->data['messages']['message']['code']; } return $code; @@ -114,7 +114,7 @@ public function getMessage() if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present - $message = (string)$this->data['messages'][0]['message'][0]['text']; + $message = (string)$this->data['messages']['message']['text']; } @@ -155,13 +155,15 @@ public function getCardReference() */ public function xml2array(\SimpleXMLElement $xml) { + return json_decode(json_encode($xml), true); + $arr = array(); foreach ($xml as $element) { $tag = $element->getName(); $e = get_object_vars($element); - if (!empty($e)) { + if (! empty($e)) { $arr[$tag][] = $element instanceof \SimpleXMLElement ? $this->xml2array($element) : $e; } else { $arr[$tag] = trim($element); diff --git a/src/Message/CIMCreateCardResponse.php b/src/Message/CIMCreateCardResponse.php index 8139b4fd..aee6639f 100644 --- a/src/Message/CIMCreateCardResponse.php +++ b/src/Message/CIMCreateCardResponse.php @@ -20,7 +20,7 @@ public function getCustomerProfileId() public function getCustomerPaymentProfileId() { if ($this->isSuccessful()) { - return $this->data['customerPaymentProfileIdList'][0]['numericString']; + return $this->data['customerPaymentProfileIdList']['numericString']; } return null; } diff --git a/src/Message/CIMGetPaymentProfileResponse.php b/src/Message/CIMGetPaymentProfileResponse.php index f97f2292..2de602ba 100644 --- a/src/Message/CIMGetPaymentProfileResponse.php +++ b/src/Message/CIMGetPaymentProfileResponse.php @@ -12,7 +12,7 @@ class CIMGetPaymentProfileResponse extends CIMCreatePaymentProfileResponse public function getCustomerPaymentProfileId() { if ($this->isSuccessful()) { - return $this->data['paymentProfile'][0]['customerPaymentProfileId']; + return $this->data['paymentProfile']['customerPaymentProfileId']; } return null; } diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index 41fc503b..b7e03be8 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -26,9 +26,9 @@ public function getMatchingPaymentProfileId($last4) return null; } - foreach ($this->data['profile'][0]['paymentProfiles'] as $paymentProfile) { + foreach ($this->data['profile']['paymentProfiles'] as $paymentProfile) { // For every payment profile check if the last4 matches the last4 of the card in request. - $cardLast4 = substr($paymentProfile['payment'][0]['creditCard'][0]['cardNumber'], -4); + $cardLast4 = substr($paymentProfile['payment']['creditCard']['cardNumber'], -4); if ($last4 == $cardLast4) { return (string)$paymentProfile['customerPaymentProfileId']; } From 50a3bc2cd11ee49af03f158018342438fc45cdbb Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 31 Jan 2018 22:42:20 +0000 Subject: [PATCH 188/254] Introduce PHP7.2 tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a910d105..57d8c461 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ php: - 5.6 - 7.0 - 7.1 - - hhvm + - 7.2 matrix: allow_failures: From 0064e7c40fc8cb7546dc12733a6f2b69b888398e Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 31 Jan 2018 22:47:29 +0000 Subject: [PATCH 189/254] Removed a var_dump that escaped. --- src/Message/CIMAbstractResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index a2710d0a..adfe6e1a 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -30,7 +30,7 @@ public function __construct(RequestInterface $request, $data) $xmlRootElement = ($isError !== false ? 'ErrorResponse' : $this->responseType); // Strip out the xmlns junk so that PHP can parse the XML $xml = preg_replace('/<' . $xmlRootElement . '[^>]+>/', '<' . $xmlRootElement . '>', (string)$data); -//var_dump($xml); + try { $xml = simplexml_load_string($xml); } catch (\Exception $e) { From 138fd4810b0526e2c9e5201dacd228a33d202d6c Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Thu, 17 May 2018 13:21:52 +0200 Subject: [PATCH 190/254] Update to v3 --- .travis.yml | 7 +------ composer.json | 6 +++--- phpunit.xml.dist | 3 --- src/Message/AIMAbstractRequest.php | 4 ++-- src/Message/CIMAbstractRequest.php | 4 ++-- src/Message/CIMCreateCardRequest.php | 4 ++-- src/Message/CIMCreatePaymentProfileRequest.php | 4 ++-- src/Message/CIMDeletePaymentProfileRequest.php | 4 ++-- src/Message/CIMGetPaymentProfileRequest.php | 4 ++-- src/Message/CIMGetProfileRequest.php | 4 ++-- src/Message/CIMUpdatePaymentProfileRequest.php | 4 ++-- src/Message/Query/AIMPaymentPlanQueryRequest.php | 4 ++-- src/Message/Query/AIMPaymentPlansQueryRequest.php | 4 ++-- src/Message/Query/QueryBatchDetailRequest.php | 4 ++-- src/Message/Query/QueryBatchRequest.php | 4 ++-- src/Message/Query/QueryDetailRequest.php | 4 ++-- src/Message/Query/QueryRequest.php | 4 ++-- src/Message/SIMAbstractRequest.php | 4 ++-- tests/CIMGatewayTest.php | 1 + tests/Message/AIMResponseTest.php | 3 ++- tests/Model/CardReferenceTest.php | 4 +++- tests/Model/TransactionReferenceTest.php | 4 +++- 22 files changed, 43 insertions(+), 45 deletions(-) diff --git a/.travis.yml b/.travis.yml index a910d105..5f827dc9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,11 @@ language: php php: - - 5.4 - - 5.5 - 5.6 - 7.0 - 7.1 - - hhvm + - 7.2 -matrix: - allow_failures: - - php: hhvm before_script: - composer install -n --dev --prefer-source diff --git a/composer.json b/composer.json index 402d88fb..eaae87cf 100644 --- a/composer.json +++ b/composer.json @@ -28,14 +28,14 @@ "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "~2.2" + "omnipay/common": "^3" }, "require-dev": { - "omnipay/tests": "~2.0" + "omnipay/tests": "^3" }, "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a35b7362..535809e1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,9 +14,6 @@ ./tests/ - - - ./src diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 2be9656f..3608c581 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -224,9 +224,9 @@ public function sendData($data) $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new AIMResponse($this, $httpResponse->getBody()); + return $this->response = new AIMResponse($this, $httpResponse->getBody()->getContents()); } /** diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 74d057bd..7e055c43 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -104,8 +104,8 @@ public function sendData($data) $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new CIMResponse($this, $httpResponse->getBody()); + return $this->response = new CIMResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 81fa4b37..99313b66 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -152,9 +152,9 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - $response = new CIMCreateCardResponse($this, $httpResponse->getBody()); + $response = new CIMCreateCardResponse($this, $httpResponse->getBody()->getContents()); if (!$response->isSuccessful() && $response->getReasonCode() == 'E00039') { // Duplicate profile. Try adding a new payment profile for the same profile and get the response diff --git a/src/Message/CIMCreatePaymentProfileRequest.php b/src/Message/CIMCreatePaymentProfileRequest.php index 5948165b..f2c4ed92 100644 --- a/src/Message/CIMCreatePaymentProfileRequest.php +++ b/src/Message/CIMCreatePaymentProfileRequest.php @@ -43,8 +43,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new CIMCreatePaymentProfileResponse($this, $httpResponse->getBody()); + return $this->response = new CIMCreatePaymentProfileResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/CIMDeletePaymentProfileRequest.php b/src/Message/CIMDeletePaymentProfileRequest.php index 4b30ac10..afb4c246 100644 --- a/src/Message/CIMDeletePaymentProfileRequest.php +++ b/src/Message/CIMDeletePaymentProfileRequest.php @@ -24,8 +24,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new CIMDeletePaymentProfileResponse($this, $httpResponse->getBody()); + return $this->response = new CIMDeletePaymentProfileResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/CIMGetPaymentProfileRequest.php b/src/Message/CIMGetPaymentProfileRequest.php index a8da6cf6..2181fdc4 100644 --- a/src/Message/CIMGetPaymentProfileRequest.php +++ b/src/Message/CIMGetPaymentProfileRequest.php @@ -25,8 +25,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new CIMGetPaymentProfileResponse($this, $httpResponse->getBody()); + return $this->response = new CIMGetPaymentProfileResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/CIMGetProfileRequest.php b/src/Message/CIMGetProfileRequest.php index 5f755475..caaea8e9 100644 --- a/src/Message/CIMGetProfileRequest.php +++ b/src/Message/CIMGetProfileRequest.php @@ -24,8 +24,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new CIMGetProfileResponse($this, $httpResponse->getBody()); + return $this->response = new CIMGetProfileResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/CIMUpdatePaymentProfileRequest.php b/src/Message/CIMUpdatePaymentProfileRequest.php index 37a7e1a9..4677adfb 100644 --- a/src/Message/CIMUpdatePaymentProfileRequest.php +++ b/src/Message/CIMUpdatePaymentProfileRequest.php @@ -44,8 +44,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new CIMUpdatePaymentProfileResponse($this, $httpResponse->getBody()); + return $this->response = new CIMUpdatePaymentProfileResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/Query/AIMPaymentPlanQueryRequest.php b/src/Message/Query/AIMPaymentPlanQueryRequest.php index d1a58a4b..244b4a73 100644 --- a/src/Message/Query/AIMPaymentPlanQueryRequest.php +++ b/src/Message/Query/AIMPaymentPlanQueryRequest.php @@ -47,8 +47,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new AIMPaymentPlanQueryResponse($this, $httpResponse->getBody()); + return $this->response = new AIMPaymentPlanQueryResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/Query/AIMPaymentPlansQueryRequest.php b/src/Message/Query/AIMPaymentPlansQueryRequest.php index 13afb190..77c4e6f1 100644 --- a/src/Message/Query/AIMPaymentPlansQueryRequest.php +++ b/src/Message/Query/AIMPaymentPlansQueryRequest.php @@ -46,8 +46,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new AIMPaymentPlansQueryResponse($this, $httpResponse->getBody()); + return $this->response = new AIMPaymentPlansQueryResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/Query/QueryBatchDetailRequest.php b/src/Message/Query/QueryBatchDetailRequest.php index 98d0d1c8..b390661c 100644 --- a/src/Message/Query/QueryBatchDetailRequest.php +++ b/src/Message/Query/QueryBatchDetailRequest.php @@ -29,9 +29,9 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new QueryBatchDetailResponse($this, $httpResponse->getBody()); + return $this->response = new QueryBatchDetailResponse($this, $httpResponse->getBody()->getContents()); } public function setBatchID($batchID) diff --git a/src/Message/Query/QueryBatchRequest.php b/src/Message/Query/QueryBatchRequest.php index 87f0fb3e..d9aa6684 100644 --- a/src/Message/Query/QueryBatchRequest.php +++ b/src/Message/Query/QueryBatchRequest.php @@ -16,8 +16,8 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new QueryBatchResponse($this, $httpResponse->getBody()); + return $this->response = new QueryBatchResponse($this, $httpResponse->getBody()->getContents()); } } diff --git a/src/Message/Query/QueryDetailRequest.php b/src/Message/Query/QueryDetailRequest.php index 7b2034de..78283293 100644 --- a/src/Message/Query/QueryDetailRequest.php +++ b/src/Message/Query/QueryDetailRequest.php @@ -27,9 +27,9 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new QueryDetailResponse($this, $httpResponse->getBody()); + return $this->response = new QueryDetailResponse($this, $httpResponse->getBody()->getContents()); } public function setTransactionReference($transactionReference) diff --git a/src/Message/Query/QueryRequest.php b/src/Message/Query/QueryRequest.php index 88118160..b7f0206d 100644 --- a/src/Message/Query/QueryRequest.php +++ b/src/Message/Query/QueryRequest.php @@ -65,9 +65,9 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - $this->response = new QueryResponse($this, $httpResponse->getBody()); + $this->response = new QueryResponse($this, $httpResponse->getBody()->getContents()); return $this->response; } } diff --git a/src/Message/SIMAbstractRequest.php b/src/Message/SIMAbstractRequest.php index 4167e1fe..9bfd7b5a 100644 --- a/src/Message/SIMAbstractRequest.php +++ b/src/Message/SIMAbstractRequest.php @@ -160,9 +160,9 @@ protected function getBillingData() public function sendData($data) { - $httpResponse = $this->httpClient->post($this->getEndpoint(), null, $data)->send(); + $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), [], http_build_query($data)); - return $this->response = new AIMResponse($this, $httpResponse->getBody()); + return $this->response = new AIMResponse($this, $httpResponse->getBody()->getContents()); } public function getEndpoint() diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 604f4707..3d4a85dd 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -214,6 +214,7 @@ public function testPurchaseFailure() public function testRefundSuccess() { + $this->markTestSkipped(); // $this->setMockHttpResponse('CIMRefundSuccess.txt'); // // $response = $this->gateway->refund($this->refundOptions)->send(); diff --git a/tests/Message/AIMResponseTest.php b/tests/Message/AIMResponseTest.php index 5846bea0..3e046436 100644 --- a/tests/Message/AIMResponseTest.php +++ b/tests/Message/AIMResponseTest.php @@ -18,7 +18,8 @@ public function getMockRequest($className = '\Omnipay\AuthorizeNet\Message\AIMAb public function testConstructEmpty() { - $this->setExpectedException('\Omnipay\Common\Exception\InvalidResponseException'); + $this->expectException('\Omnipay\Common\Exception\InvalidResponseException'); + new AIMResponse($this->getMockRequest(), ''); } diff --git a/tests/Model/CardReferenceTest.php b/tests/Model/CardReferenceTest.php index d471d2a4..11cea148 100644 --- a/tests/Model/CardReferenceTest.php +++ b/tests/Model/CardReferenceTest.php @@ -2,7 +2,9 @@ namespace Omnipay\AuthorizeNet\Model; -class CardReferenceTest extends \PHPUnit_Framework_TestCase +use Omnipay\Tests\TestCase; + +class CardReferenceTest extends TestCase { private $data; /** @var CardReference */ diff --git a/tests/Model/TransactionReferenceTest.php b/tests/Model/TransactionReferenceTest.php index b0cf0c80..8c0be267 100644 --- a/tests/Model/TransactionReferenceTest.php +++ b/tests/Model/TransactionReferenceTest.php @@ -2,7 +2,9 @@ namespace Omnipay\AuthorizeNet\Model; -class TransactionReferenceTest extends \PHPUnit_Framework_TestCase +use Omnipay\Tests\TestCase; + +class TransactionReferenceTest extends TestCase { private $data; /** @var TransactionReference */ From 3aa8002400c360c6d6a08c00dfc5491c30b92c85 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Thu, 17 May 2018 13:25:31 +0200 Subject: [PATCH 191/254] Better travisci --- .travis.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5f827dc9..741f61d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,26 @@ php: - 7.1 - 7.2 +# This triggers builds to run on the new TravisCI infrastructure. +# See: http://docs.travis-ci.com/user/workers/container-based-infrastructure/ +sudo: false -before_script: - - composer install -n --dev --prefer-source +## Cache composer +cache: + directories: + - $HOME/.composer/cache + +env: + global: + - setup=basic + +matrix: + include: + - php: 5.6 + env: setup=lowest + +install: + - if [[ $setup = 'basic' ]]; then travis_retry composer install --prefer-dist --no-interaction; fi + - if [[ $setup = 'lowest' ]]; then travis_retry composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable; fi script: vendor/bin/phpcs --standard=PSR2 src && vendor/bin/phpunit --coverage-text From 0ffbd6c078208ee61e667618c32de0a7bfc13896 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Thu, 17 May 2018 13:28:10 +0200 Subject: [PATCH 192/254] Fix codestyle --- composer.json | 12 ++++++++++-- grumphp.yml | 15 +++++++++++++++ src/Message/AIMResponse.php | 4 ---- src/Message/CIMAbstractResponse.php | 2 -- src/Message/Query/QueryDetailResponse.php | 2 -- 5 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 grumphp.yml diff --git a/composer.json b/composer.json index eaae87cf..6ccff1e5 100644 --- a/composer.json +++ b/composer.json @@ -31,11 +31,19 @@ "omnipay/common": "^3" }, "require-dev": { - "omnipay/tests": "^3" + "omnipay/tests": "^3", + "squizlabs/php_codesniffer": "^3", + "phpro/grumphp": "^0.14" }, "extra": { "branch-alias": { "dev-master": "3.0.x-dev" } - } + }, + "scripts": { + "test": "phpunit", + "check-style": "phpcs -p --standard=PSR2 src/", + "fix-style": "phpcbf -p --standard=PSR2 src/" + }, + "prefer-stable": true } diff --git a/grumphp.yml b/grumphp.yml new file mode 100644 index 00000000..4b767a09 --- /dev/null +++ b/grumphp.yml @@ -0,0 +1,15 @@ +parameters: + git_dir: . + bin_dir: vendor/bin + tasks: + phpunit: + config_file: ~ + testsuite: ~ + group: [] + always_execute: false + phpcs: + standard: PSR2 + warning_severity: ~ + ignore_patterns: + - tests/ + triggered_by: [php] \ No newline at end of file diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 6485d79b..7397dba4 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -79,11 +79,9 @@ public function getReasonCode() if (isset($this->data->transactionResponse[0]->messages)) { // In case of a successful transaction, a "messages" element is present $code = intval((string)$this->data->transactionResponse[0]->messages[0]->message->code); - } elseif (isset($this->data->transactionResponse[0]->errors)) { // In case of an unsuccessful transaction, an "errors" element is present $code = intval((string)$this->data->transactionResponse[0]->errors[0]->error->errorCode); - } elseif (isset($this->data->messages[0]->message)) { // In case of invalid request, the top-level message provides details. $code = (string)$this->data->messages[0]->message->code; @@ -104,11 +102,9 @@ public function getMessage() if (isset($this->data->transactionResponse[0]->messages)) { // In case of a successful transaction, a "messages" element is present $message = (string)$this->data->transactionResponse[0]->messages[0]->message->description; - } elseif (isset($this->data->transactionResponse[0]->errors)) { // In case of an unsuccessful transaction, an "errors" element is present $message = (string)$this->data->transactionResponse[0]->errors[0]->error->errorText; - } elseif (isset($this->data->messages[0]->message)) { // In case of invalid request, the top-level message provides details. $message = (string)$this->data->messages[0]->message->text; diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index e02d7a7a..db49d9e0 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -67,7 +67,6 @@ public function getResultCode() return static::TRANSACTION_RESULT_CODE_ERROR; default: return null; - } } @@ -115,7 +114,6 @@ public function getMessage() if (isset($this->data['messages'])) { // In case of a successful transaction, a "messages" element is present $message = (string)$this->data['messages'][0]['message'][0]['text']; - } return $message; diff --git a/src/Message/Query/QueryDetailResponse.php b/src/Message/Query/QueryDetailResponse.php index cb151f1e..359e896a 100644 --- a/src/Message/Query/QueryDetailResponse.php +++ b/src/Message/Query/QueryDetailResponse.php @@ -147,8 +147,6 @@ public function getCustomerReference() $this->planResponse = $gateway->paymentPlanQuery($data)->send(); } return $this->planResponse->getContactReference(); - - } /** From efe8ba9834e7a40eaa502ffeba239fae29c44c81 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Thu, 17 May 2018 13:50:45 +0200 Subject: [PATCH 193/254] Fix cs --- src/Message/AIMResponse.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index f40cd7f8..785b6c24 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -79,11 +79,9 @@ public function getReasonCode() if (isset($this->data->transactionResponse->messages)) { // In case of a successful transaction, a "messages" element is present $code = intval((string)$this->data->transactionResponse->messages->message->code); - } elseif (isset($this->data->transactionResponse->errors)) { // In case of an unsuccessful transaction, an "errors" element is present $code = intval((string)$this->data->transactionResponse->errors->error->errorCode); - } elseif (isset($this->data->messages->message)) { // In case of invalid request, the top-level message provides details. $code = (string)$this->data->messages->message->code; @@ -104,11 +102,9 @@ public function getMessage() if (isset($this->data->transactionResponse->messages)) { // In case of a successful transaction, a "messages" element is present $message = (string)$this->data->transactionResponse->messages->message->description; - } elseif (isset($this->data->transactionResponse->errors)) { // In case of an unsuccessful transaction, an "errors" element is present $message = (string)$this->data->transactionResponse->errors->error->errorText; - } elseif (isset($this->data->messages->message)) { // In case of invalid request, the top-level message provides details. $message = (string)$this->data->messages->message->text; From c8e03ff3996e8ecbac6ab3563bb588b066fe69bd Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Thu, 17 May 2018 14:53:10 +0200 Subject: [PATCH 194/254] Update README.md --- README.md | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index daad684c..1be68e11 100644 --- a/README.md +++ b/README.md @@ -11,21 +11,11 @@ processing library for PHP 5.3+. This package implements Authorize.Net support f ## Installation -Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply add it -to your `composer.json` file: - -```json -{ - "require": { - "omnipay/authorizenet": "~2.0" - } -} -``` - -And run composer to update your dependencies: +Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply require `league/omnipay` and `omnipay/authorizenet` with Composer: - $ curl -s http://getcomposer.org/installer | php - $ php composer.phar update +``` +composer require league/omnipay omnipay/authorizenet +``` ## Basic Usage From 04de992efa9a95632ccaa5f95d9c0f3f75b2545c Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Thu, 17 May 2018 14:53:23 +0200 Subject: [PATCH 195/254] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1be68e11..9c289280 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ processing library for PHP 5.3+. This package implements Authorize.Net support f Omnipay is installed via [Composer](http://getcomposer.org/). To install, simply require `league/omnipay` and `omnipay/authorizenet` with Composer: ``` -composer require league/omnipay omnipay/authorizenet +composer require league/omnipay omnipay/authorizenet:"3.x@dev" ``` ## Basic Usage From 2e9d853dec005d94abf9c6643b238b55373b5fc8 Mon Sep 17 00:00:00 2001 From: Robert Purcell Date: Mon, 21 May 2018 13:33:06 -0400 Subject: [PATCH 196/254] CVV is optional --- src/Message/AIMAuthorizeRequest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index a4f0a58e..5b863feb 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -42,7 +42,9 @@ protected function addPayment(\SimpleXMLElement $data) $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 (!empty($card->getCvv())) { + $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); + } } protected function addCustomerIP(\SimpleXMLElement $data) From b66ea0dc98f707dd54a542f8f65159f1aa6b9d0d Mon Sep 17 00:00:00 2001 From: Alberto Date: Sun, 30 Dec 2018 01:58:35 -0800 Subject: [PATCH 197/254] Add opaqueData to createCard on CIM --- src/Message/CIMAbstractRequest.php | 38 ++++++++++++++++++++++++ src/Message/CIMCreateCardRequest.php | 43 +++++++++++++++++++++------- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index 7e055c43..acb47c4a 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -72,6 +72,44 @@ public function getCustomerPaymentProfileId() return $this->getParameter('customerPaymentProfileId'); } + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @return string + */ + public function getOpaqueDataDescriptor() + { + return $this->getParameter('opaqueDataDescriptor'); + } + + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @return string + */ + public function getOpaqueDataValue() + { + return $this->getParameter('opaqueDataValue'); + } + + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @param string + * @return string + */ + public function setOpaqueDataDescriptor($value) + { + return $this->setParameter('opaqueDataDescriptor', $value); + } + + /** + * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data + * @param string + * @return string + */ + public function setOpaqueDataValue($value) + { + return $this->setParameter('opaqueDataValue', $value); + } + /** * Flag to force update consumer payment profile if duplicate is found * diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 99313b66..69f9c2ba 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -13,19 +13,34 @@ class CIMCreateCardRequest extends CIMAbstractRequest public function getData() { - $this->validate('card'); - - /** @var CreditCard $card */ - $card = $this->getCard(); - $card->validate(); $data = $this->getBaseData(); + $this->validateCard($data); $this->addProfileData($data); $this->addTransactionSettings($data); return $data; } + /** + * Validate card or skip if opaque data is available + * + * @param \SimpleXMLElement $data + */ + protected function validateCard(\SimpleXMLElement $data){ + + if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { + return; + } + + $this->validate('card'); + + /** @var CreditCard $card */ + $card = $this->getCard(); + $card->validate(); + + } + /** * Add customer profile data to the specified xml element * @@ -97,12 +112,18 @@ protected function addBillingData(\SimpleXMLElement $data) } $req = $data->addChild('payment'); - $req->creditCard->cardNumber = $card->getNumber(); - $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); - if ($card->getCvv()) { - $req->creditCard->cardCode = $card->getCvv(); - } else { - $this->setValidationMode(self::VALIDATION_MODE_NONE); + if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { + //Use opaqueData if available instead of card data + $req->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor(); + $req->opaqueData->dataValue = $this->getOpaqueDataValue(); + }else{ + $req->creditCard->cardNumber = $card->getNumber(); + $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); + if ($card->getCvv()) { + $req->creditCard->cardCode = $card->getCvv(); + } else { + $this->setValidationMode(self::VALIDATION_MODE_NONE); + } } } } From af657cefb0b52639a87dd1d10480f5e5384d561f Mon Sep 17 00:00:00 2001 From: Alberto Date: Sun, 30 Dec 2018 02:46:10 -0800 Subject: [PATCH 198/254] Fix psr2 style errors --- src/Message/CIMCreateCardRequest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 69f9c2ba..eca8a75f 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -27,7 +27,8 @@ public function getData() * * @param \SimpleXMLElement $data */ - protected function validateCard(\SimpleXMLElement $data){ + protected function validateCard(\SimpleXMLElement $data) + { if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { return; @@ -38,7 +39,6 @@ protected function validateCard(\SimpleXMLElement $data){ /** @var CreditCard $card */ $card = $this->getCard(); $card->validate(); - } /** @@ -116,7 +116,7 @@ protected function addBillingData(\SimpleXMLElement $data) //Use opaqueData if available instead of card data $req->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor(); $req->opaqueData->dataValue = $this->getOpaqueDataValue(); - }else{ + } else { $req->creditCard->cardNumber = $card->getNumber(); $req->creditCard->expirationDate = $card->getExpiryDate('Y-m'); if ($card->getCvv()) { From fe3f20ccc90872902f40e163480a39c96fd921f1 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sun, 30 Dec 2018 03:05:34 -0800 Subject: [PATCH 199/254] go back to previous getData order on CIMCreateCardRequest --- src/Message/CIMCreateCardRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index eca8a75f..3077558f 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -14,8 +14,8 @@ class CIMCreateCardRequest extends CIMAbstractRequest public function getData() { - $data = $this->getBaseData(); $this->validateCard($data); + $data = $this->getBaseData(); $this->addProfileData($data); $this->addTransactionSettings($data); From 87d07ae566bdf8d437483a3b3ae42fd8cdec1406 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sun, 30 Dec 2018 03:09:20 -0800 Subject: [PATCH 200/254] remove data variable not used on validateCard method --- src/Message/CIMCreateCardRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 3077558f..512cd853 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -14,7 +14,7 @@ class CIMCreateCardRequest extends CIMAbstractRequest public function getData() { - $this->validateCard($data); + $this->validateCard(); $data = $this->getBaseData(); $this->addProfileData($data); $this->addTransactionSettings($data); @@ -27,7 +27,7 @@ public function getData() * * @param \SimpleXMLElement $data */ - protected function validateCard(\SimpleXMLElement $data) + protected function validateCard() { if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { From 989feddd5242d65c84fd8198f77cb3ed6bc489ef Mon Sep 17 00:00:00 2001 From: Alberto Date: Sun, 30 Dec 2018 03:15:04 -0800 Subject: [PATCH 201/254] leave validate card which only validates the presence of the card param --- src/Message/CIMCreateCardRequest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index 512cd853..ea0e02de 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -14,7 +14,8 @@ class CIMCreateCardRequest extends CIMAbstractRequest public function getData() { - $this->validateCard(); + $this->validate('card'); + $this->cardValidate(); $data = $this->getBaseData(); $this->addProfileData($data); $this->addTransactionSettings($data); @@ -27,15 +28,13 @@ public function getData() * * @param \SimpleXMLElement $data */ - protected function validateCard() + protected function cardValidate() { if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { return; } - $this->validate('card'); - /** @var CreditCard $card */ $card = $this->getCard(); $card->validate(); From b6a881dc6b6dbc6de9a68ebfa31be1c3ae1d5a56 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 30 Dec 2018 16:55:17 +0000 Subject: [PATCH 202/254] Issue #118 merge together "split lines" aka "line folding" Guzzle PSR-7 treats these split lines as obsolete, and throws a fatal error if it encounters any. --- tests/Mock/CIMCreateCardFailure.txt | 3 +-- tests/Mock/CIMCreateCardFailureWithDuplicate.txt | 3 +-- tests/Mock/CIMCreateCardSuccess.txt | 3 +-- tests/Mock/CIMCreatePaymentProfileFailure.txt | 3 +-- tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt | 3 +-- tests/Mock/CIMCreatePaymentProfileSuccess.txt | 3 +-- tests/Mock/CIMGetPaymentProfileSuccess.txt | 3 +-- tests/Mock/CIMGetProfileSuccess.txt | 3 +-- tests/Mock/CIMUpdatePaymentProfileSuccess.txt | 3 +-- 9 files changed, 9 insertions(+), 18 deletions(-) diff --git a/tests/Mock/CIMCreateCardFailure.txt b/tests/Mock/CIMCreateCardFailure.txt index fe7bdc5a..86ce9e9e 100644 --- a/tests/Mock/CIMCreateCardFailure.txt +++ b/tests/Mock/CIMCreateCardFailure.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMCreateCardFailureWithDuplicate.txt b/tests/Mock/CIMCreateCardFailureWithDuplicate.txt index 617eaaad..6fc83e3e 100644 --- a/tests/Mock/CIMCreateCardFailureWithDuplicate.txt +++ b/tests/Mock/CIMCreateCardFailureWithDuplicate.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMCreateCardSuccess.txt b/tests/Mock/CIMCreateCardSuccess.txt index 97e06ed2..492e1eec 100644 --- a/tests/Mock/CIMCreateCardSuccess.txt +++ b/tests/Mock/CIMCreateCardSuccess.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMCreatePaymentProfileFailure.txt b/tests/Mock/CIMCreatePaymentProfileFailure.txt index 91b28e6c..abfebdc9 100644 --- a/tests/Mock/CIMCreatePaymentProfileFailure.txt +++ b/tests/Mock/CIMCreatePaymentProfileFailure.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt b/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt index 98b69db6..8d8ee7a9 100644 --- a/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt +++ b/tests/Mock/CIMCreatePaymentProfileFailureMaxProfileLimit.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMCreatePaymentProfileSuccess.txt b/tests/Mock/CIMCreatePaymentProfileSuccess.txt index 40bdb247..e860a255 100644 --- a/tests/Mock/CIMCreatePaymentProfileSuccess.txt +++ b/tests/Mock/CIMCreatePaymentProfileSuccess.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMGetPaymentProfileSuccess.txt b/tests/Mock/CIMGetPaymentProfileSuccess.txt index 9c4c6782..39e23720 100644 --- a/tests/Mock/CIMGetPaymentProfileSuccess.txt +++ b/tests/Mock/CIMGetPaymentProfileSuccess.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMGetProfileSuccess.txt b/tests/Mock/CIMGetProfileSuccess.txt index 8fedf2f1..33f23ab3 100644 --- a/tests/Mock/CIMGetProfileSuccess.txt +++ b/tests/Mock/CIMGetProfileSuccess.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET diff --git a/tests/Mock/CIMUpdatePaymentProfileSuccess.txt b/tests/Mock/CIMUpdatePaymentProfileSuccess.txt index 348ab7e0..7d7abd97 100644 --- a/tests/Mock/CIMUpdatePaymentProfileSuccess.txt +++ b/tests/Mock/CIMUpdatePaymentProfileSuccess.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET From 202c660a71cdb1b3e6c9a21c70064e3b1984a1ab Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 31 Dec 2018 00:05:33 +0000 Subject: [PATCH 203/254] Move some mystery numbers to constants. These are parameters (market place and device type) that come up time and time again across gateways, but have different values for each gateway, e.g. 0, 1, 2 vs E, M, R. A mapping should be standardised. --- src/Message/AIMAuthorizeRequest.php | 36 ++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 79ba07a7..8489f6f3 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -10,6 +10,21 @@ */ class AIMAuthorizeRequest extends AIMAbstractRequest { + const MARKET_TYPE_ECOMMERCE = '0'; + const MARKET_TYPE_MOTO = '1'; + const MARKET_TYPE_RETAIL = '2'; + + 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_BASED_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'; + protected $action = 'authOnlyTransaction'; public function getData() @@ -71,14 +86,29 @@ protected function addRetail(\SimpleXMLElement $data) } if (isset($deviceType) && !isset($marketType)) { - $marketType = "2"; + $marketType = static::MARKET_TYPE_RETAIL; } - if (!in_array($deviceType, [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ])) { + if (!in_array($deviceType, [ + static::DEVICE_TYPE_UNKNOWN, + static::DEVICE_TYPE_UNATTENDED_TERMINAL, + static::DEVICE_TYPE_SELF_SERVICE_TERMINAL, + static::DEVICE_TYPE_ELECTRONIC_CASH_REGISTER, + static::DEVICE_TYPE_PC_BASED_TERMINAL, + static::DEVICE_TYPE_AIRPAY, + static::DEVICE_TYPE_WIRELESS_POS, + static::DEVICE_TYPE_WEBSITE, + static::DEVICE_TYPE_DIAL_TERMINAL, + static::DEVICE_TYPE_VIRTUAL_TERMINAL, + ])) { throw new InvalidRequestException("deviceType `{$deviceType}` is invalid"); } - if (!in_array($marketType, [ "0", "1", "2" ])) { + if (!in_array($marketType, [ + static::MARKET_TYPE_ECOMMERCE, + static::MARKET_TYPE_MOTO, + static::MARKET_TYPE_RETAIL, + ])) { throw new InvalidRequestException("marketType `{$marketType}` is invalid"); } From 408773ad91d7ebfd78c2bfe1aa031ecb2cc0b229 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sun, 30 Dec 2018 23:31:37 -0800 Subject: [PATCH 204/254] remove duplicated methods from extended AIMAbstractRequest --- src/Message/CIMAbstractRequest.php | 38 ------------------------------ 1 file changed, 38 deletions(-) diff --git a/src/Message/CIMAbstractRequest.php b/src/Message/CIMAbstractRequest.php index acb47c4a..7e055c43 100644 --- a/src/Message/CIMAbstractRequest.php +++ b/src/Message/CIMAbstractRequest.php @@ -72,44 +72,6 @@ public function getCustomerPaymentProfileId() return $this->getParameter('customerPaymentProfileId'); } - /** - * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data - * @return string - */ - public function getOpaqueDataDescriptor() - { - return $this->getParameter('opaqueDataDescriptor'); - } - - /** - * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data - * @return string - */ - public function getOpaqueDataValue() - { - return $this->getParameter('opaqueDataValue'); - } - - /** - * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data - * @param string - * @return string - */ - public function setOpaqueDataDescriptor($value) - { - return $this->setParameter('opaqueDataDescriptor', $value); - } - - /** - * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data - * @param string - * @return string - */ - public function setOpaqueDataValue($value) - { - return $this->setParameter('opaqueDataValue', $value); - } - /** * Flag to force update consumer payment profile if duplicate is found * From 55b60383ff7ec80aab66347e4874a1775e190d1d Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 31 Dec 2018 00:26:08 -0800 Subject: [PATCH 205/254] Add tests for CIM create card feature using Opaque Data --- tests/CIMGatewayTest.php | 26 +++++++++++++++++++++ tests/Message/CIMCreateCardRequestTest.php | 21 +++++++++++++++++ tests/Message/CIMCreateCardResponseTest.php | 14 +++++++++++ 3 files changed, 61 insertions(+) diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 3d4a85dd..1ba63b9a 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -31,6 +31,18 @@ public function setUp() 'forceCardUpdate' => true ); + $validCard = $this->getValidCard(); + unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']); + //remove the actual card data since we are setting opaque values + $this->createCardFromOpaqueDataOptions = array( + 'email' => "kaylee@serenity.com", + 'card' => $validCard, + 'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT', + 'opaqueDataValue' => 'jb2RlIjoiNTB', + 'testMode' => true, + 'forceCardUpdate' => true + ); + $this->authorizeOptions = array( 'cardReference' => '{"customerProfileId":"28972084","customerPaymentProfileId":"26317840","customerShippingAddressId":"27057149"}', 'amount' => 10.00, @@ -89,6 +101,20 @@ public function testCreateCardSuccess() $this->assertSame('Successful.', $response->getMessage()); } + public function testCreateCardFromOpaqueDataSuccess() + { + $this->setMockHttpResponse(array('CIMCreateCardSuccess.txt','CIMGetPaymentProfileSuccess.txt')); + + $response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"customerProfileId":"28972084","customerPaymentProfileId":"26485433"}', + $response->getCardReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + public function testShouldCreateCardIfDuplicateCustomerProfileExists() { $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt', diff --git a/tests/Message/CIMCreateCardRequestTest.php b/tests/Message/CIMCreateCardRequestTest.php index 92911b00..f97eee6b 100644 --- a/tests/Message/CIMCreateCardRequestTest.php +++ b/tests/Message/CIMCreateCardRequestTest.php @@ -59,4 +59,25 @@ public function testGetDataShouldSetValidationModeToNoneIfNoCvvProvided() $this->assertFalse(isset($data->profile->paymentProfiles->payment->creditCard->cardCode)); $this->assertEquals(CIMCreatePaymentProfileRequest::VALIDATION_MODE_NONE, $this->request->getValidationMode()); } + + public function testGetDataOpaqueData() + { + + $validCard = $this->getValidCard(); + unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']); + //remove the actual card data since we are setting opaque values + $this->params = array( + 'email' => "kaylee@serenity.com", + 'card' => $validCard, + 'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT', + 'opaqueDataValue' => 'jb2RlIjoiNTB', + 'developerMode' => true + ); + $this->request->initialize($this->params); + + $data = $this->request->getData(); + + $this->assertEquals('COMMON.ACCEPT.INAPP.PAYMENT', $data->profile->paymentProfiles->payment->opaqueData->dataDescriptor); + $this->assertEquals('jb2RlIjoiNTB', $data->profile->paymentProfiles->payment->opaqueData->dataValue); + } } diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php index a68942cf..e2f80d89 100644 --- a/tests/Message/CIMCreateCardResponseTest.php +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -43,4 +43,18 @@ public function testCreateCardFailure() $this->assertNull($response->getCardReference()); } + + public function testCreateCardSuccessFromOpaqueData() + { + $httpResponse = $this->getMockHttpResponse('CIMCreateCardSuccess.txt'); + $response = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertTrue($response->isSuccessful()); + $this->assertEquals('I00001', $response->getReasonCode()); + $this->assertEquals("1", $response->getResultCode()); + $this->assertEquals("Successful.", $response->getMessage()); + + $this->assertEquals('28972084', $response->getCustomerProfileId()); + $this->assertEquals('26317840', $response->getCustomerPaymentProfileId()); + } } From 598894884fd9ba45f0e74c99b30a7657e5188015 Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 31 Dec 2018 00:51:10 -0800 Subject: [PATCH 206/254] adds example of opaque data on CIM createCard --- README.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9c289280..53803e18 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The following gateways are provided by this package: * AuthorizeNet_SIM * AuthorizeNet_DPM -In addition, `Accept.JS` is supported by the AIM driver. More details are provided below. +In addition, `Accept.JS` is supported by the AIM driver and CIM (create card). More details are provided below. For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay) repository. @@ -45,15 +45,15 @@ The card is tokenized into two values returned in `opaqueData` object from Accep These two values must be POSTed back to the merchant application, usually as a part of the payment form. Make sure the raw credit card details are NOT posted back to your site. -How this is handled is beyond this short note, but examples are always welcome in the documentation. +How this is handled is beyond this short note, but examples are always welcomed in the documentation. -On the server, the tokenized detailt are passed into the `payment` or `authorize` request object. +On the server, the tokenized details are passed into the `payment` or `authorize` request object. You will still need to pass in the `CreditCard` object, as that contains details of the payee and recipient, but just leave the credit card details of that object blank. For example: ```php // $gateway is an instantiation of the AIM driver. -// $dataDescriptor and $dataValue come from the paymentr form at the front end. +// $dataDescriptor and $dataValue come from the payment form at the front end. $request = $gateway->purchase( [ @@ -66,6 +66,56 @@ $request = $gateway->purchase( ); ``` +CIM Create Card feature usage: +Accept.js must be implemented on your frontend payment form, once Accept.js 'tokenizes' the customer's +card, just send the two opaque fields and remove the Card's (Number, Expiration and CVV) from your post request. + +Accept.js goal is to remove the need of Card information from ever going into your server so be sure to remove that data +before posting to your server. + +The create card feature on CIM will automatically create a Customer Profile and a Payment Profile with the +'tokenized' card for each customer you request it for on your authorize.net account, you can use these Payment Profiles +later to request payments from your customers. + +In order to create a Customer & Payment Profile pass the opaque fields and the card array with the billing information +to the createCard method on the CIM driver: + +```php +// $gateway is an instantiation of the CIM driver. //Omnipay::create( 'AuthorizeNet_CIM' ) +// $dataDescriptor and $dataValue come from the payment form at the front end. + +$request = $gateway->createCard( + [ + 'opaqueDataDescriptor' => $dataDescriptor, + 'opaqueDataValue' => $dataValue, + 'name' => $name, + 'email' => $email, //Authorize.net will use the email to identify the CustomerProfile + 'customerType' => 'individual', + 'customerId' => $user_customer_id,//a customer ID generated by your system or send null + 'description' => 'MEMBER',//whichever description you wish to send + 'forceCardUpdate' => true + 'card' => [ + 'billingFirstName' => $name, + 'billingLastName' => $last_name, + 'billingAddress1' => $address, + 'billingCity' => $city, + 'billingState' => $state, + 'billingPostcode' => $zipcode, + 'billingPhone' => '', + //... may include shipping info but do not include card (number, cvv or expiration) + ], + ] +); +$response = $request->send(); +$data = $response->getData(); + +$data['paymentProfile']['customerProfileId']; +$data['paymentProfile']['customerPaymentProfileId']; +//Now you can use these 2 fields to reference this customer and this payment profile for later use with +//the rest of the CIM driver features as usual. +``` + + ## Support If you are having general issues with Omnipay, we suggest posting on From 079a991ee571139027a106879254ce5e981eb5c0 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 5 Jan 2019 01:11:43 -0800 Subject: [PATCH 207/254] Allow CreatePaymentProfile from opaque data --- src/Message/CIMCreateCardRequest.php | 6 ++++- .../CIMCreatePaymentProfileRequest.php | 6 +---- tests/CIMGatewayTest.php | 26 +++++++++++++++++++ tests/Message/CIMCreateCardResponseTest.php | 14 ---------- .../CIMCreatePaymentProfileRequestTest.php | 21 +++++++++++++++ 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index ea0e02de..cb3ba6aa 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -214,8 +214,12 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) $createPaymentProfileResponse = $this->makeCreatePaymentProfileRequest($parameters); if ($createPaymentProfileResponse->isSuccessful()) { $parameters['customerPaymentProfileId'] = $createPaymentProfileResponse->getCustomerPaymentProfileId(); - } elseif ($this->getForceCardUpdate() !== true) { + } elseif ( + $this->getForceCardUpdate() !== true || + ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) + ) { // force card update flag turned off. No need to further process. + // also if opaque data is being used we are not able to update existing payment profiles return $createCardResponse; } diff --git a/src/Message/CIMCreatePaymentProfileRequest.php b/src/Message/CIMCreatePaymentProfileRequest.php index f2c4ed92..4c399146 100644 --- a/src/Message/CIMCreatePaymentProfileRequest.php +++ b/src/Message/CIMCreatePaymentProfileRequest.php @@ -14,11 +14,7 @@ class CIMCreatePaymentProfileRequest extends CIMCreateCardRequest public function getData() { $this->validate('card', 'customerProfileId'); - - /** @var CreditCard $card */ - $card = $this->getCard(); - $card->validate(); - + $this->cardValidate(); $data = $this->getBaseData(); $data->customerProfileId = $this->getCustomerProfileId(); $this->addPaymentProfileData($data); diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 1ba63b9a..5c6e1a21 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -130,6 +130,21 @@ public function testShouldCreateCardIfDuplicateCustomerProfileExists() $this->assertSame('Successful.', $response->getMessage()); } + public function testShouldCreateCardFromOpaqueDataIfDuplicateCustomerProfileExists() + { + $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt', + 'CIMGetProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + + $response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame( + '{"customerProfileId":"28775801","customerPaymentProfileId":"26485433"}', + $response->getCardReference() + ); + $this->assertSame('Successful.', $response->getMessage()); + } + public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndForceCardUpdateIsSet() { // Duplicate **payment** profile @@ -146,6 +161,17 @@ public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndForceC $this->assertSame('Successful.', $response->getMessage()); } + public function testDoesntUpdateExistingPaymentProfileFromOpaqueData() + { + // Duplicate **payment** profile + $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileFailure.txt', + 'CIMGetProfileSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + + $response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + } + public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndMaxPaymentProfileLimitIsMet() { $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php index e2f80d89..a68942cf 100644 --- a/tests/Message/CIMCreateCardResponseTest.php +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -43,18 +43,4 @@ public function testCreateCardFailure() $this->assertNull($response->getCardReference()); } - - public function testCreateCardSuccessFromOpaqueData() - { - $httpResponse = $this->getMockHttpResponse('CIMCreateCardSuccess.txt'); - $response = new CIMCreateCardResponse($this->getMockRequest(), $httpResponse->getBody()); - - $this->assertTrue($response->isSuccessful()); - $this->assertEquals('I00001', $response->getReasonCode()); - $this->assertEquals("1", $response->getResultCode()); - $this->assertEquals("Successful.", $response->getMessage()); - - $this->assertEquals('28972084', $response->getCustomerProfileId()); - $this->assertEquals('26317840', $response->getCustomerPaymentProfileId()); - } } diff --git a/tests/Message/CIMCreatePaymentProfileRequestTest.php b/tests/Message/CIMCreatePaymentProfileRequestTest.php index cf407618..eaad61a7 100644 --- a/tests/Message/CIMCreatePaymentProfileRequestTest.php +++ b/tests/Message/CIMCreatePaymentProfileRequestTest.php @@ -31,4 +31,25 @@ public function testGetData() $this->assertEquals($card['number'], $data->paymentProfile->payment->creditCard->cardNumber); $this->assertEquals('testMode', $data->validationMode); } + + public function testGetDataOpaqueData() + { + $validCard = $this->getValidCard(); + unset($validCard['number'],$validCard['expiryMonth'],$validCard['expiryYear'],$validCard['cvv']); + //remove the actual card data since we are setting opaque values + $this->request->initialize( + array( + 'customerProfileId' => '28775801', + 'email' => "kaylee@serenity.com", + 'card' => $validCard, + 'opaqueDataDescriptor' => 'COMMON.ACCEPT.INAPP.PAYMENT', + 'opaqueDataValue' => 'jb2RlIjoiNTB', + 'developerMode' => true + ) + ); + + $data = $this->request->getData(); + $this->assertEquals('COMMON.ACCEPT.INAPP.PAYMENT', $data->paymentProfile->payment->opaqueData->dataDescriptor); + $this->assertEquals('jb2RlIjoiNTB', $data->paymentProfile->payment->opaqueData->dataValue); + } } From 55b6f52e641c6ad5ef86d84bf50935f5543d25c0 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 5 Jan 2019 01:19:49 -0800 Subject: [PATCH 208/254] Fix psr2 style --- src/Message/CIMCreateCardRequest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index cb3ba6aa..e87638a2 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -214,8 +214,7 @@ public function createPaymentProfile(CIMCreateCardResponse $createCardResponse) $createPaymentProfileResponse = $this->makeCreatePaymentProfileRequest($parameters); if ($createPaymentProfileResponse->isSuccessful()) { $parameters['customerPaymentProfileId'] = $createPaymentProfileResponse->getCustomerPaymentProfileId(); - } elseif ( - $this->getForceCardUpdate() !== true || + } elseif ($this->getForceCardUpdate() !== true || ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) ) { // force card update flag turned off. No need to further process. From 66a83f18ad2b0b08615ac742ab4f8308017f1c23 Mon Sep 17 00:00:00 2001 From: Alberto Date: Sat, 5 Jan 2019 03:04:05 -0800 Subject: [PATCH 209/254] Enable CIM UpdatePaymentProfile --- src/CIMGateway.php | 5 +++++ src/Message/CIMUpdatePaymentProfileRequest.php | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index b515f5b2..ee824974 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -46,6 +46,11 @@ public function createCard(array $parameters = array()) return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMCreateCardRequest', $parameters); } + public function updateCard(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMUpdatePaymentProfileRequest', $parameters); + } + public function getPaymentProfile(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMGetPaymentProfileRequest', $parameters); diff --git a/src/Message/CIMUpdatePaymentProfileRequest.php b/src/Message/CIMUpdatePaymentProfileRequest.php index 4677adfb..fe6e8973 100644 --- a/src/Message/CIMUpdatePaymentProfileRequest.php +++ b/src/Message/CIMUpdatePaymentProfileRequest.php @@ -15,9 +15,7 @@ public function getData() { $this->validate('card', 'customerProfileId', 'customerPaymentProfileId'); - /** @var CreditCard $card */ - $card = $this->getCard(); - $card->validate(); + $this->cardValidate(); $data = $this->getBaseData(); $data->customerProfileId = $this->getCustomerProfileId(); From 6ac192d634963aefdfafc90e43001c6fb27c36a3 Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 7 Jan 2019 22:12:43 -0800 Subject: [PATCH 210/254] Fix the HttpClient for tests on CIMIntegrationTests and fix a couple tests --- tests/CIMGatewayIntegrationTest.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 7b4a9087..95b28cc0 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -2,7 +2,7 @@ namespace Omnipay\AuthorizeNet; -use Guzzle\Http\Client; +use Omnipay\Common\Http\Client; use Omnipay\AuthorizeNet\Message\CIMResponse; use Omnipay\Tests\TestCase; @@ -67,7 +67,13 @@ public function testCustomerAndPaymentProfile() { // Create a customer profile with the specified email (email is the identifier) $email = uniqid('', true) . '@example.com'; - $cardRef = $this->createCard(array('email' => $email)); + $valid_card = $this->getValidCard(); + $cardRef = $this->createCard( + array( + 'email' => $email, + 'card' => $valid_card + ) + ); // Create a new card in an existing customer profile $params = array( @@ -84,7 +90,7 @@ public function testCustomerAndPaymentProfile() // Create a card with same number in an existing customer profile (should fail) $params = array( - 'card' => $this->getValidCard(), + 'card' => $valid_card, 'name' => 'Kaywinnet Lee Frye', 'email' => $email, ); @@ -96,7 +102,7 @@ public function testCustomerAndPaymentProfile() // Create a card with the same number in an existing customer profile with auto-update enabled $params = array( - 'card' => $this->getValidCard(), + 'card' => $valid_card, 'name' => 'Kaywinnet Lee Frye', 'email' => $email, 'forceCardUpdate' => true From 3135045259cafd785c89fec54a5f508ff31b118b Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 7 Jan 2019 22:14:06 -0800 Subject: [PATCH 211/254] Enabled CIMGetProfile on CIMGateway and added a test for it --- src/CIMGateway.php | 5 +++++ tests/CIMGatewayIntegrationTest.php | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index ee824974..120e567b 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -56,6 +56,11 @@ public function getPaymentProfile(array $parameters = array()) return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMGetPaymentProfileRequest', $parameters); } + public function getCustomerProfile(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMGetProfileRequest', $parameters); + } + public function deleteCard(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMDeletePaymentProfileRequest', $parameters); diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index 95b28cc0..c44b1094 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -118,6 +118,29 @@ public function testCustomerAndPaymentProfile() ); } + public function testGetCustomerProfile() + { + // Create a customer profile with the specified email (email is the identifier) + $email = uniqid('', true) . '@example.com'; + $cardRef = $this->createCard(array('email' => $email)); + $cardRef = json_decode($cardRef,true); + // Grab the customer Profile ID from the createCard response. + $params = array( + 'customerProfileId' => $cardRef['customerProfileId'] + ); + // Return just the customer profile without billing data + $request = $this->gateway->getCustomerProfile($params); + $request->setDeveloperMode(true); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Should be successful.'); + $data = $response->getData(); + $this->assertEquals( + $email, + $data['profile']['email'], + 'Should be the same email' + ); + } + public function testPaymentProfileDelete() { From 1bce345b96b1f9c16a6ee08fa41b76757c5bf5b6 Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 7 Jan 2019 23:58:14 -0800 Subject: [PATCH 212/254] Enabled CIMCreatePaymentProfile as createAdditionalCard on CIMGateway --- src/CIMGateway.php | 5 +++++ tests/CIMGatewayIntegrationTest.php | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/CIMGateway.php b/src/CIMGateway.php index 120e567b..489dee86 100644 --- a/src/CIMGateway.php +++ b/src/CIMGateway.php @@ -51,6 +51,11 @@ public function updateCard(array $parameters = array()) return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMUpdatePaymentProfileRequest', $parameters); } + public function createAdditionalCard(array $parameters = array()) + { + return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMCreatePaymentProfileRequest', $parameters); + } + public function getPaymentProfile(array $parameters = array()) { return $this->createRequest('\Omnipay\AuthorizeNet\Message\CIMGetPaymentProfileRequest', $parameters); diff --git a/tests/CIMGatewayIntegrationTest.php b/tests/CIMGatewayIntegrationTest.php index c44b1094..61da8403 100644 --- a/tests/CIMGatewayIntegrationTest.php +++ b/tests/CIMGatewayIntegrationTest.php @@ -74,6 +74,7 @@ public function testCustomerAndPaymentProfile() 'card' => $valid_card ) ); + $decodedCardRef = json_decode($cardRef,true); // Create a new card in an existing customer profile $params = array( @@ -88,6 +89,18 @@ public function testCustomerAndPaymentProfile() $this->assertTrue($response->isSuccessful(), 'Should be successful as we have created a payment profile'); $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + // Create a new card in an existing customer profile using its customer profile ID + $params = array( + 'card' => $this->getValidCard(), + 'customerProfileId' => $decodedCardRef['customerProfileId'] + ); + $params['card']['number'] = '4012888818888'; + $request = $this->gateway->createAdditionalCard($params); + $request->setDeveloperMode(true); + $response = $request->send(); + $this->assertTrue($response->isSuccessful(), 'Should be successful as we have created a payment profile'); + $this->assertNotNull($response->getCardReference(), 'Card reference should be returned'); + // Create a card with same number in an existing customer profile (should fail) $params = array( 'card' => $valid_card, From 7e118ad2b918ce5276092ebc63a7cfa99762d94b Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 20 Jan 2019 00:16:55 +0000 Subject: [PATCH 213/254] Issue #123 support HMAC SHA-512 signatureKey --- README.md | 15 +++++++++++++++ src/AIMGateway.php | 16 +++++++++++++--- src/Message/AIMAbstractRequest.php | 14 ++++++++++++++ src/Message/SIMAbstractRequest.php | 10 ++++++++++ src/Message/SIMAuthorizeRequest.php | 10 +++++++++- src/SIMGateway.php | 10 +++++----- 6 files changed, 66 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9c289280..898cc948 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,21 @@ $request = $gateway->purchase( ); ``` +## DPM and SIM Signatures + +DPM and SIM used to sign their requests with the `transactionKey` using the mdh HMAC algorithm. +From early 2019, this algorithm is being removed completely. +Instead, the SHA-512 HMAC algorithm is used to sign the DPM and SIM requsts, +and to validate the received notifications. + +To start using the SHA-512 signing, set your `signatureKey` in the gateway: + +```php +$gateway->setSignatureKey('48D2C629E4A...{100}...E7CA3C4E6CD7223D'); +``` + +The `signatureKey` can be generated in the *API Credentials & Keys* section of your account setings. + ## Support If you are having general issues with Omnipay, we suggest posting on diff --git a/src/AIMGateway.php b/src/AIMGateway.php index c4effed3..8b0ba2da 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -24,11 +24,11 @@ public function getName() public function getDefaultParameters() { return array( - 'apiLoginId' => '', - 'transactionKey' => '', + 'apiLoginId' => null, + 'transactionKey' => null, 'testMode' => false, 'developerMode' => false, - 'hashSecret' => '', + 'hashSecret' => null, 'liveEndpoint' => 'https://api2.authorize.net/xml/v1/request.api', 'developerEndpoint' => 'https://apitest.authorize.net/xml/v1/request.api', ); @@ -54,6 +54,16 @@ public function setTransactionKey($value) return $this->setParameter('transactionKey', $value); } + public function getSignatureKey() + { + return $this->getParameter('signatureKey'); + } + + public function setSignatureKey($value) + { + return $this->setParameter('signatureKey', $value); + } + public function getDeveloperMode() { return $this->getParameter('developerMode'); diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 3608c581..8133b928 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -36,6 +36,20 @@ public function setTransactionKey($value) return $this->setParameter('transactionKey', $value); } + // AIM does not use signatureKey, but it is included here just + // to get the tests to run. Some structural refactoring will be + // needed to work around this. + + public function getSignatureKey() + { + return $this->getParameter('signatureKey'); + } + + public function setSignatureKey($value) + { + return $this->setParameter('signatureKey', $value); + } + public function getDeveloperMode() { return $this->getParameter('developerMode'); diff --git a/src/Message/SIMAbstractRequest.php b/src/Message/SIMAbstractRequest.php index 9bfd7b5a..7224cb9b 100644 --- a/src/Message/SIMAbstractRequest.php +++ b/src/Message/SIMAbstractRequest.php @@ -34,6 +34,16 @@ public function setTransactionKey($value) return $this->setParameter('transactionKey', $value); } + public function getSignatureKey() + { + return $this->getParameter('signatureKey'); + } + + public function setSignatureKey($value) + { + return $this->setParameter('signatureKey', $value); + } + public function getDeveloperMode() { return $this->getParameter('developerMode'); diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index 9f91d4cb..0e043597 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -78,11 +78,19 @@ public function getHash($data) ).'^'; // If x_currency_code is specified, then it must follow the final trailing carat. + if ($this->getCurrency()) { $fingerprint .= $this->getCurrency(); } - return hash_hmac('md5', $fingerprint, $this->getTransactionKey()); + // The md5 hash against the transactionKey is being removed 2019 and + // replaced with an SHA-512 hash against the signatureKey. + + if ($signatureKey = $this->getSignatureKey()) { + return hash_hmac('sha512', $fingerprint, hex2bin($signatureKey)); + } else { + return hash_hmac('md5', $fingerprint, $this->getTransactionKey()); + } } public function sendData($data) diff --git a/src/SIMGateway.php b/src/SIMGateway.php index 67b47b4d..ae8a143b 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -16,7 +16,7 @@ public function getDefaultParameters() { $parameters = parent::getDefaultParameters(); $parameters = array_merge($parameters, array( - 'hashSecret' => '', + 'signatureKey' => null, 'liveEndpoint' => 'https://secure2.authorize.net/gateway/transact.dll', 'developerEndpoint' => 'https://test.authorize.net/gateway/transact.dll' )); @@ -33,14 +33,14 @@ public function setApiLoginId($value) return $this->setParameter('apiLoginId', $value); } - public function getTransactionKey() + public function getSignatureKey() { - return $this->getParameter('transactionKey'); + return $this->getParameter('signatureKey'); } - public function setTransactionKey($value) + public function setSignatureKey($value) { - return $this->setParameter('transactionKey', $value); + return $this->setParameter('signatureKey', $value); } public function getDeveloperMode() From 7871bd3288877b1b0a4ed90d2126445ad66875a0 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 20 Jan 2019 00:52:15 +0000 Subject: [PATCH 214/254] Issue #123 add test for generation of signature key. --- tests/Message/DPMAuthorizeRequestTest.php | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Message/DPMAuthorizeRequestTest.php b/tests/Message/DPMAuthorizeRequestTest.php index 1d4157d3..54521bd1 100644 --- a/tests/Message/DPMAuthorizeRequestTest.php +++ b/tests/Message/DPMAuthorizeRequestTest.php @@ -29,6 +29,37 @@ public function testGetData() $this->assertArrayNotHasKey('x_test_request', $data); } + /** + * Issue #123 test the signature key. + */ + public function testSha512hash() + { + $signatureKey = + '48D2C629E4A6D3E19AC47767C8B7EFEA4AE2004F8FA9C190F19D0238D871978B' + . 'E35925A6AD9256FE623934C1099DFEFD6449D54744E5734CE7CA3C4E6CD7223D'; + + $this->request->setSignatureKey($signatureKey); + + $data = $this->request->getData(); + $hash = $data['x_fp_hash']; + + // Now check the hash. + + $fingerprint = implode( + '^', + array( + $this->request->getApiLoginId(), + $data['x_fp_sequence'], + $data['x_fp_timestamp'], + $data['x_amount'] + ) + ).'^'; + + $this->assertTrue( + hash_equals(hash_hmac('sha512', $fingerprint, hex2bin($signatureKey)), $hash) + ); + } + public function testGetDataTestMode() { $this->request->setTestMode(true); From 9e8eeaeb61e09e31fa949501888df4223a522d15 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 4 Feb 2019 16:05:29 +0000 Subject: [PATCH 215/254] Add track data to authOnlyTransactions and authCaptureTransactions Rewrite of issue #104; could not merge due to nature of changes. --- src/Message/AIMAuthorizeRequest.php | 52 ++++++++++++++++++----- tests/Message/AIMAuthorizeRequestTest.php | 26 ++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 8489f6f3..f69de0e9 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -48,19 +48,51 @@ protected function addPayment(\SimpleXMLElement $data) * @link http://developer.authorize.net/api/reference/features/acceptjs.html Documentation on opaque data */ if ($this->getOpaqueDataDescriptor() && $this->getOpaqueDataValue()) { - $data->transactionRequest->payment->opaqueData->dataDescriptor = $this->getOpaqueDataDescriptor(); - $data->transactionRequest->payment->opaqueData->dataValue = $this->getOpaqueDataValue(); + $data + ->transactionRequest + ->payment + ->opaqueData + ->dataDescriptor = $this->getOpaqueDataDescriptor(); + + $data->transactionRequest + ->payment + ->opaqueData + ->dataValue = $this->getOpaqueDataValue(); + return; } - $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'); - if (!empty($card->getCvv())) { - $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); + // Try trackData first. + + $creditCard = $this->getCard(); + + if ($track1 = $creditCard->getTrack1()) { + $data + ->transactionRequest + ->payment + ->trackData + ->track1 = $track1; + } else { + // Validate the standard credit card number. + $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'); + + if (!empty($card->getCvv())) { + $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); + } } } diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index 9d82fc6f..cfbab078 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -87,6 +87,32 @@ public function testGetDataOpaqueData() $this->assertEquals('jb2RlIjoiNTB', $data->transactionRequest->payment->opaqueData->dataValue); } + public function testGetDataTrack1() + { + $track1 = '%B5581123456781323^SMITH/JOHN^16071021473810559010203?'; + + $this->request->getCard()->setTracks($track1); + $data = $this->request->getData(); + + $this->assertEquals( + $track1, + $data + ->transactionRequest + ->payment + ->trackData + ->track1 + ); + + // With track1 set, the card number must NOT be set. + + $this->assertNull($data + ->transactionRequest + ->payment + ->creditCard + ->cardNumber + ); + } + public function testShouldIncludeDuplicateWindowSetting() { $data = $this->request->getData(); From 58948ff930d665e1b43a78618d85cc7cb8dafa3e Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Mon, 4 Feb 2019 16:21:08 +0000 Subject: [PATCH 216/254] Add track2 support to AIM request. Incorporating bits of https://github.com/artspeople/omnipay-authorizenet/pull/104 which seem to have got lost along the line. --- src/Message/AIMAuthorizeRequest.php | 10 +++++++++- tests/Message/AIMAuthorizeRequestTest.php | 12 +++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index f69de0e9..7b5c4e97 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -66,12 +66,20 @@ protected function addPayment(\SimpleXMLElement $data) $creditCard = $this->getCard(); - if ($track1 = $creditCard->getTrack1()) { + if (($track1 = $creditCard->getTrack1()) + && ($track2 = $creditCard->getTrack2()) + ) { $data ->transactionRequest ->payment ->trackData ->track1 = $track1; + + $data + ->transactionRequest + ->payment + ->trackData + ->track2 = $track2; } else { // Validate the standard credit card number. $this->validate('card'); diff --git a/tests/Message/AIMAuthorizeRequestTest.php b/tests/Message/AIMAuthorizeRequestTest.php index cfbab078..3437860b 100644 --- a/tests/Message/AIMAuthorizeRequestTest.php +++ b/tests/Message/AIMAuthorizeRequestTest.php @@ -90,8 +90,9 @@ public function testGetDataOpaqueData() public function testGetDataTrack1() { $track1 = '%B5581123456781323^SMITH/JOHN^16071021473810559010203?'; + $track2 = ';5581123456781323=160710212423468?'; - $this->request->getCard()->setTracks($track1); + $this->request->getCard()->setTracks($track1 . $track2); $data = $this->request->getData(); $this->assertEquals( @@ -103,6 +104,15 @@ public function testGetDataTrack1() ->track1 ); + $this->assertEquals( + $track2, + $data + ->transactionRequest + ->payment + ->trackData + ->track2 + ); + // With track1 set, the card number must NOT be set. $this->assertNull($data From 4d6c14faad49f075b9cf9b6b65bfcfc294aeff0c Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 5 Feb 2019 22:25:03 +0000 Subject: [PATCH 217/254] Issue #125 fix query message paths. We can probably use the class name resolution operator here (::class) but would prefer to add some tests for the query messages before doing that. --- src/AIMGateway.php | 60 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/AIMGateway.php b/src/AIMGateway.php index 8b0ba2da..ec744b5c 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -126,7 +126,10 @@ public function setDuplicateWindow($value) */ public function authorize(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest', + $parameters + ); } /** @@ -135,7 +138,10 @@ public function authorize(array $parameters = array()) */ public function capture(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMCaptureRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\AIMCaptureRequest', + $parameters + ); } /** @@ -144,7 +150,10 @@ public function capture(array $parameters = array()) */ public function captureOnly(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMCaptureOnlyRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\AIMCaptureOnlyRequest', + $parameters + ); } /** @@ -153,7 +162,10 @@ public function captureOnly(array $parameters = array()) */ public function purchase(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMPurchaseRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\AIMPurchaseRequest', + $parameters + ); } /** @@ -162,7 +174,10 @@ public function purchase(array $parameters = array()) */ public function void(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMVoidRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\AIMVoidRequest', + $parameters + ); } /** @@ -171,7 +186,10 @@ public function void(array $parameters = array()) */ public function refund(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\AIMRefundRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\AIMRefundRequest', + $parameters + ); } /** @@ -180,7 +198,10 @@ public function refund(array $parameters = array()) */ public function paymentPlansQuery(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlansQueryRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlansQueryRequest', + $parameters + ); } /** @@ -189,7 +210,10 @@ public function paymentPlansQuery(array $parameters = array()) */ public function paymentPlanQuery(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlanQueryRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlanQueryRequest', + $parameters + ); } /** @@ -198,7 +222,10 @@ public function paymentPlanQuery(array $parameters = array()) */ public function query(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\Query\QueryRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\Query\QueryRequest', + $parameters + ); } /** @@ -207,7 +234,10 @@ public function query(array $parameters = array()) */ public function queryBatch(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryBatchRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\Query\QueryBatchRequest', + $parameters + ); } /** @@ -216,7 +246,10 @@ public function queryBatch(array $parameters = array()) */ public function queryBatchDetail(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryBatchDetailRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\Query\QueryBatchDetailRequest', + $parameters + ); } /** @@ -225,6 +258,9 @@ public function queryBatchDetail(array $parameters = array()) */ public function queryDetail(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\QueryDetailRequest', $parameters); + return $this->createRequest( + '\Omnipay\AuthorizeNet\Message\Query\QueryDetailRequest', + $parameters + ); } } From 475085a0ccd8d9ee0c14f8e728bf5be9342525dd Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Tue, 5 Feb 2019 23:58:29 +0000 Subject: [PATCH 218/254] Issue #125 plus some general tidy up of references and docblocks --- composer.json | 5 ++- src/AIMGateway.php | 38 ++++++++++--------- src/DPMGateway.php | 2 + src/Message/AIMCaptureOnlyRequest.php | 2 - src/Message/CIMAbstractResponse.php | 2 + src/Message/CIMCreateCardRequest.php | 2 +- .../CIMCreatePaymentProfileRequest.php | 2 - .../CIMUpdatePaymentProfileRequest.php | 2 - src/Message/DPMAuthorizeRequest.php | 2 + src/Message/DPMCompleteRequest.php | 2 - src/Message/DPMResponse.php | 5 ++- .../Query/AIMPaymentPlanQueryRequest.php | 2 - .../Query/AIMPaymentPlanQueryResponse.php | 9 +++-- .../Query/AIMPaymentPlansQueryRequest.php | 2 +- .../Query/AIMPaymentPlansQueryResponse.php | 2 - src/Message/Query/AbstractQueryResponse.php | 3 -- src/Message/Query/QueryBatchDetailRequest.php | 2 - .../Query/QueryBatchDetailResponse.php | 3 -- src/Message/Query/QueryBatchRequest.php | 2 - src/Message/Query/QueryBatchResponse.php | 3 -- src/Message/Query/QueryDetailRequest.php | 2 - src/Message/Query/QueryDetailResponse.php | 3 -- src/Message/Query/QueryRequest.php | 3 -- src/Message/Query/QueryResponse.php | 5 --- src/Message/SIMAuthorizeRequest.php | 2 + src/Message/SIMAuthorizeResponse.php | 4 +- src/Message/SIMCompleteAuthorizeRequest.php | 3 ++ tests/DPMGatewayTest.php | 3 +- tests/Message/CIMCreateCardResponseTest.php | 1 + .../CIMCreatePaymentProfileResponseTest.php | 1 + .../CIMGetPaymentProfileResponseTest.php | 1 + tests/Message/CIMGetProfileResponseTest.php | 1 + .../CIMUpdatePaymentProfileResponseTest.php | 1 + 33 files changed, 55 insertions(+), 67 deletions(-) diff --git a/composer.json b/composer.json index 6ccff1e5..e301dfd1 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,10 @@ "psr-4": { "Omnipay\\AuthorizeNet\\" : "src/" } }, "require": { - "omnipay/common": "^3" + "omnipay/common": "^3", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*" }, "require-dev": { "omnipay/tests": "^3", diff --git a/src/AIMGateway.php b/src/AIMGateway.php index ec744b5c..7d491e82 100644 --- a/src/AIMGateway.php +++ b/src/AIMGateway.php @@ -3,12 +3,14 @@ namespace Omnipay\AuthorizeNet; use Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest; +use Omnipay\AuthorizeNet\Message\AIMCaptureOnlyRequest; use Omnipay\AuthorizeNet\Message\AIMCaptureRequest; -use Omnipay\AuthorizeNet\Message\AIMPaymentPlanQueryResponse; +use Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlanQueryResponse; use Omnipay\AuthorizeNet\Message\AIMPurchaseRequest; -use Omnipay\AuthorizeNet\Message\QueryRequest; use Omnipay\AuthorizeNet\Message\AIMRefundRequest; use Omnipay\AuthorizeNet\Message\AIMVoidRequest; +use Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlansQueryRequest; +use Omnipay\AuthorizeNet\Message\Query\QueryResponse; use Omnipay\Common\AbstractGateway; /** @@ -127,7 +129,7 @@ public function setDuplicateWindow($value) public function authorize(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\AIMAuthorizeRequest', + AIMAuthorizeRequest::class, $parameters ); } @@ -139,7 +141,7 @@ public function authorize(array $parameters = array()) public function capture(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\AIMCaptureRequest', + AIMCaptureRequest::class, $parameters ); } @@ -151,7 +153,7 @@ public function capture(array $parameters = array()) public function captureOnly(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\AIMCaptureOnlyRequest', + AIMCaptureOnlyRequest::class, $parameters ); } @@ -163,7 +165,7 @@ public function captureOnly(array $parameters = array()) public function purchase(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\AIMPurchaseRequest', + AIMPurchaseRequest::class, $parameters ); } @@ -175,7 +177,7 @@ public function purchase(array $parameters = array()) public function void(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\AIMVoidRequest', + AIMVoidRequest::class, $parameters ); } @@ -187,7 +189,7 @@ public function void(array $parameters = array()) public function refund(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\AIMRefundRequest', + AIMRefundRequest::class, $parameters ); } @@ -199,19 +201,19 @@ public function refund(array $parameters = array()) public function paymentPlansQuery(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlansQueryRequest', + Message\Query\AIMPaymentPlansQueryRequest::class, $parameters ); } /** * @param array $parameters - * @return AIMPaymentPlanQueryResponse + * @return \Omnipay\Common\Message\AbstractRequest */ public function paymentPlanQuery(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\Query\AIMPaymentPlanQueryRequest', + Message\Query\AIMPaymentPlanQueryRequest::class, $parameters ); } @@ -223,43 +225,43 @@ public function paymentPlanQuery(array $parameters = array()) public function query(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\Query\QueryRequest', + Message\Query\QueryRequest::class, $parameters ); } /** * @param array $parameters - * @return QueryBatchResponse + * @return Message\Query\QueryBatchRequest */ public function queryBatch(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\Query\QueryBatchRequest', + Message\Query\QueryBatchRequest::class, $parameters ); } /** * @param array $parameters - * @return QueryBatchDetailResponse + * @return Message\Query\QueryBatchDetailRequest */ public function queryBatchDetail(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\Query\QueryBatchDetailRequest', + Message\Query\QueryBatchDetailRequest::class, $parameters ); } /** * @param array $parameters - * @return QueryDetailResponse + * @return Message\Query\QueryDetailRequest */ public function queryDetail(array $parameters = array()) { return $this->createRequest( - '\Omnipay\AuthorizeNet\Message\Query\QueryDetailRequest', + Message\Query\QueryDetailRequest::class, $parameters ); } diff --git a/src/DPMGateway.php b/src/DPMGateway.php index b5117ddf..33064030 100644 --- a/src/DPMGateway.php +++ b/src/DPMGateway.php @@ -14,6 +14,8 @@ public function getName() /** * Helper to generate the authorize direct-post form. + * @param array $parameters + * @return \Omnipay\Common\Message\AbstractRequest */ public function authorize(array $parameters = array()) { diff --git a/src/Message/AIMCaptureOnlyRequest.php b/src/Message/AIMCaptureOnlyRequest.php index f6f6cbdb..b8bd2270 100644 --- a/src/Message/AIMCaptureOnlyRequest.php +++ b/src/Message/AIMCaptureOnlyRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\CreditCard; - /** * Authorize.Net AIM Capture Only Request */ diff --git a/src/Message/CIMAbstractResponse.php b/src/Message/CIMAbstractResponse.php index efa4c8e1..da10c185 100644 --- a/src/Message/CIMAbstractResponse.php +++ b/src/Message/CIMAbstractResponse.php @@ -155,6 +155,8 @@ public function xml2array(\SimpleXMLElement $xml) { return json_decode(json_encode($xml), true); + // Old parser below, just keeping on a hunch. + $arr = array(); foreach ($xml as $element) { diff --git a/src/Message/CIMCreateCardRequest.php b/src/Message/CIMCreateCardRequest.php index e87638a2..2ae1e790 100644 --- a/src/Message/CIMCreateCardRequest.php +++ b/src/Message/CIMCreateCardRequest.php @@ -26,7 +26,7 @@ public function getData() /** * Validate card or skip if opaque data is available * - * @param \SimpleXMLElement $data + * @throws \Omnipay\Common\Exception\InvalidCreditCardException */ protected function cardValidate() { diff --git a/src/Message/CIMCreatePaymentProfileRequest.php b/src/Message/CIMCreatePaymentProfileRequest.php index 4c399146..1134341a 100644 --- a/src/Message/CIMCreatePaymentProfileRequest.php +++ b/src/Message/CIMCreatePaymentProfileRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\CreditCard; - /** * Request to create customer payment profile for existing customer. */ diff --git a/src/Message/CIMUpdatePaymentProfileRequest.php b/src/Message/CIMUpdatePaymentProfileRequest.php index fe6e8973..8585981c 100644 --- a/src/Message/CIMUpdatePaymentProfileRequest.php +++ b/src/Message/CIMUpdatePaymentProfileRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\CreditCard; - /** * Request to create customer payment profile for existing customer. */ diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 62425e04..8bcf1829 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -53,6 +53,8 @@ public function getData() * The form may have most of the fields hidden, or may allow the user to change some details - * that depends on the use-case. * So this method will provide us with an object used to build the form. + * @param $data + * @return DPMResponse */ public function sendData($data) { diff --git a/src/Message/DPMCompleteRequest.php b/src/Message/DPMCompleteRequest.php index 26ad0434..54cf5774 100644 --- a/src/Message/DPMCompleteRequest.php +++ b/src/Message/DPMCompleteRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\Exception\InvalidRequestException; - /** * Authorize.Net DPM Complete Authorize Request */ diff --git a/src/Message/DPMResponse.php b/src/Message/DPMResponse.php index 76298bb3..24511baa 100644 --- a/src/Message/DPMResponse.php +++ b/src/Message/DPMResponse.php @@ -72,8 +72,8 @@ class DPMResponse extends AbstractResponse implements RedirectResponseInterface public function __construct(RequestInterface $request, $data, $postUrl) { - $this->request = $request; - $this->data = $data; + parent::__construct($request, $data); + $this->postUrl = $postUrl; } @@ -127,6 +127,7 @@ public function getRedirectData() * Move a field to the list of hidden form fields. * The hidden fields are those we don't want to show the user, but * must still be posted. + * @param $field_name */ public function hideField($field_name) { diff --git a/src/Message/Query/AIMPaymentPlanQueryRequest.php b/src/Message/Query/AIMPaymentPlanQueryRequest.php index 244b4a73..de0945cf 100644 --- a/src/Message/Query/AIMPaymentPlanQueryRequest.php +++ b/src/Message/Query/AIMPaymentPlanQueryRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\Common\CreditCard; - /** * Authorize.Net AIM Authorize Request */ diff --git a/src/Message/Query/AIMPaymentPlanQueryResponse.php b/src/Message/Query/AIMPaymentPlanQueryResponse.php index 167f73f7..6c171164 100644 --- a/src/Message/Query/AIMPaymentPlanQueryResponse.php +++ b/src/Message/Query/AIMPaymentPlanQueryResponse.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractRequest; use Omnipay\Common\Message\AbstractResponse; @@ -20,7 +18,12 @@ class AIMPaymentPlanQueryResponse extends AbstractQueryResponse public function __construct(AbstractRequest $request, $data) { // Strip out the xmlns junk so that PHP can parse the XML - $xml = preg_replace('/]+>/', '', (string)$data); + $xml = preg_replace( + '/]+>/', + '', + (string)$data + ); + try { $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); } catch (\Exception $e) { diff --git a/src/Message/Query/AIMPaymentPlansQueryRequest.php b/src/Message/Query/AIMPaymentPlansQueryRequest.php index 77c4e6f1..59a03967 100644 --- a/src/Message/Query/AIMPaymentPlansQueryRequest.php +++ b/src/Message/Query/AIMPaymentPlansQueryRequest.php @@ -2,7 +2,7 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\Common\CreditCard; +use Omnipay\AuthorizeNet\Message\AIMAbstractRequest; /** * Authorize.Net AIM Authorize Request diff --git a/src/Message/Query/AIMPaymentPlansQueryResponse.php b/src/Message/Query/AIMPaymentPlansQueryResponse.php index c0830f90..a23ca137 100644 --- a/src/Message/Query/AIMPaymentPlansQueryResponse.php +++ b/src/Message/Query/AIMPaymentPlansQueryResponse.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractRequest; use Omnipay\Common\Message\AbstractResponse; diff --git a/src/Message/Query/AbstractQueryResponse.php b/src/Message/Query/AbstractQueryResponse.php index b4414fdb..c01727e5 100644 --- a/src/Message/Query/AbstractQueryResponse.php +++ b/src/Message/Query/AbstractQueryResponse.php @@ -2,9 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; -use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractRequest; use Omnipay\Common\Message\AbstractResponse; use Omnipay\Omnipay; diff --git a/src/Message/Query/QueryBatchDetailRequest.php b/src/Message/Query/QueryBatchDetailRequest.php index b390661c..c2295f2a 100644 --- a/src/Message/Query/QueryBatchDetailRequest.php +++ b/src/Message/Query/QueryBatchDetailRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\Common\CreditCard; - /** * Authorize.Net AIM Authorize Request */ diff --git a/src/Message/Query/QueryBatchDetailResponse.php b/src/Message/Query/QueryBatchDetailResponse.php index 6d89bf70..c4547730 100644 --- a/src/Message/Query/QueryBatchDetailResponse.php +++ b/src/Message/Query/QueryBatchDetailResponse.php @@ -2,11 +2,8 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractRequest; -use Omnipay\Common\Message\AbstractResponse; /** * Authorize.Net AIM Response diff --git a/src/Message/Query/QueryBatchRequest.php b/src/Message/Query/QueryBatchRequest.php index d9aa6684..a15b64ae 100644 --- a/src/Message/Query/QueryBatchRequest.php +++ b/src/Message/Query/QueryBatchRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\Common\CreditCard; - /** * Authorize.Net AIM Authorize Request */ diff --git a/src/Message/Query/QueryBatchResponse.php b/src/Message/Query/QueryBatchResponse.php index 32995dab..869ecfb5 100644 --- a/src/Message/Query/QueryBatchResponse.php +++ b/src/Message/Query/QueryBatchResponse.php @@ -2,11 +2,8 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractRequest; -use Omnipay\Common\Message\AbstractResponse; /** * Authorize.Net AIM Response diff --git a/src/Message/Query/QueryDetailRequest.php b/src/Message/Query/QueryDetailRequest.php index 78283293..a0590880 100644 --- a/src/Message/Query/QueryDetailRequest.php +++ b/src/Message/Query/QueryDetailRequest.php @@ -2,8 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\Common\CreditCard; - /** * Authorize.Net AIM Authorize Request */ diff --git a/src/Message/Query/QueryDetailResponse.php b/src/Message/Query/QueryDetailResponse.php index 359e896a..f2b51f75 100644 --- a/src/Message/Query/QueryDetailResponse.php +++ b/src/Message/Query/QueryDetailResponse.php @@ -2,11 +2,8 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Common\Message\AbstractRequest; -use Omnipay\Common\Message\AbstractResponse; use Omnipay\Omnipay; /** diff --git a/src/Message/Query/QueryRequest.php b/src/Message/Query/QueryRequest.php index b7f0206d..e0429563 100644 --- a/src/Message/Query/QueryRequest.php +++ b/src/Message/Query/QueryRequest.php @@ -2,9 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\Common\CreditCard; -use Omnipay\Omnipay; - /** * Authorize.Net AIM Authorize Request */ diff --git a/src/Message/Query/QueryResponse.php b/src/Message/Query/QueryResponse.php index 7ad8d349..f6c067e6 100644 --- a/src/Message/Query/QueryResponse.php +++ b/src/Message/Query/QueryResponse.php @@ -2,11 +2,6 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Model\CardReference; -use Omnipay\AuthorizeNet\Model\TransactionReference; -use Omnipay\Common\Exception\InvalidResponseException; -use Omnipay\Common\Message\AbstractRequest; -use Omnipay\Common\Message\AbstractResponse; use Omnipay\Omnipay; /** diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index 0e043597..4c35f219 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -64,6 +64,8 @@ public function getData() * modified en-route. * It uses the TransactionKey, which is a shared secret between the merchant * and Authorize.Net The sequence and timestamp provide additional salt. + * @param $data + * @return string */ public function getHash($data) { diff --git a/src/Message/SIMAuthorizeResponse.php b/src/Message/SIMAuthorizeResponse.php index c21e06a1..0daad075 100644 --- a/src/Message/SIMAuthorizeResponse.php +++ b/src/Message/SIMAuthorizeResponse.php @@ -15,8 +15,8 @@ class SIMAuthorizeResponse extends AbstractResponse implements RedirectResponseI public function __construct(RequestInterface $request, $data, $redirectUrl) { - $this->request = $request; - $this->data = $data; + parent::__construct($request, $data); + $this->redirectUrl = $redirectUrl; } diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index 1eb5fd18..26d3f7f0 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -63,6 +63,9 @@ public function getData() * CHECKME: should this be the transactionReference in the hash, not the transactionId? * The transaction reference and the amount are both sent by the remote gateway (x_trans_id * and x_amount) and it is those that should be checked against. + * @param $transaction_reference + * @param $amount + * @return string */ public function getHash($transaction_reference, $amount) { diff --git a/tests/DPMGatewayTest.php b/tests/DPMGatewayTest.php index 3140ef62..9993b784 100644 --- a/tests/DPMGatewayTest.php +++ b/tests/DPMGatewayTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet; +use Omnipay\Common\Exception\InvalidRequestException; use Omnipay\Tests\GatewayTestCase; class DPMGatewayTest extends GatewayTestCase @@ -78,7 +79,7 @@ public function testCompleteAuthorize() } /** - * @expectedException Omnipay\Common\Exception\InvalidRequestException + * @expectedException \Omnipay\Common\Exception\InvalidRequestException * @expectedExceptionMessage Incorrect amount * * The hash is correct, so the sender knows the shared secret, but the amount diff --git a/tests/Message/CIMCreateCardResponseTest.php b/tests/Message/CIMCreateCardResponseTest.php index a68942cf..7e3f7cd3 100644 --- a/tests/Message/CIMCreateCardResponseTest.php +++ b/tests/Message/CIMCreateCardResponseTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Tests\TestCase; class CIMCreateCardResponseTest extends TestCase diff --git a/tests/Message/CIMCreatePaymentProfileResponseTest.php b/tests/Message/CIMCreatePaymentProfileResponseTest.php index 70b33914..4730b4c9 100644 --- a/tests/Message/CIMCreatePaymentProfileResponseTest.php +++ b/tests/Message/CIMCreatePaymentProfileResponseTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Tests\TestCase; class CIMCreatePaymentProfileResponseTest extends TestCase diff --git a/tests/Message/CIMGetPaymentProfileResponseTest.php b/tests/Message/CIMGetPaymentProfileResponseTest.php index 76576c65..2573fad8 100644 --- a/tests/Message/CIMGetPaymentProfileResponseTest.php +++ b/tests/Message/CIMGetPaymentProfileResponseTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Tests\TestCase; class CIMGetPaymentProfileResponseTest extends TestCase diff --git a/tests/Message/CIMGetProfileResponseTest.php b/tests/Message/CIMGetProfileResponseTest.php index c1abda05..d339c9ce 100644 --- a/tests/Message/CIMGetProfileResponseTest.php +++ b/tests/Message/CIMGetProfileResponseTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Tests\TestCase; class CIMGetProfileResponseTest extends TestCase diff --git a/tests/Message/CIMUpdatePaymentProfileResponseTest.php b/tests/Message/CIMUpdatePaymentProfileResponseTest.php index 0e08ddcf..e13c0bb8 100644 --- a/tests/Message/CIMUpdatePaymentProfileResponseTest.php +++ b/tests/Message/CIMUpdatePaymentProfileResponseTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Tests\TestCase; class CIMUpdatePaymentProfileResponseTest extends TestCase From aa43c8b8c8252c7bb5c9eff4d9703c49367aaa5f Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 6 Feb 2019 22:27:08 +0000 Subject: [PATCH 219/254] Issue #125 mask "action" validation error in "query" functions. --- src/Message/AIMAbstractRequest.php | 4 +- src/Message/Query/AIMAbstractQueryRequest.php | 14 ++++++- src/Message/Query/QueryBatchRequest.php | 15 +++++-- src/Message/Query/QueryRequest.php | 40 ++++++++++++++----- 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 8133b928..9a5bb5ae 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -276,8 +276,8 @@ protected function addReferenceId(\SimpleXMLElement $data) protected function addTransactionType(\SimpleXMLElement $data) { - if (!$this->action) { - // The extending class probably hasn't specified an "action" + if (! $this->action) { + // The extending class probably hasn't specified an "action". throw new InvalidRequestException(); } diff --git a/src/Message/Query/AIMAbstractQueryRequest.php b/src/Message/Query/AIMAbstractQueryRequest.php index 9f719070..e3ca2433 100644 --- a/src/Message/Query/AIMAbstractQueryRequest.php +++ b/src/Message/Query/AIMAbstractQueryRequest.php @@ -2,16 +2,26 @@ namespace Omnipay\AuthorizeNet\Message\Query; -use Omnipay\AuthorizeNet\Message\AIMAbstractRequest; - /** * Authorize.Net AIM Abstract Request */ + +use Omnipay\AuthorizeNet\Message\AIMAbstractRequest; +use SimpleXMLElement; + abstract class AIMAbstractQueryRequest extends AIMAbstractRequest { protected $limit = 1000; protected $offset = 1; + /** + * Disable validation check on the parent method. + */ + protected function addTransactionType(SimpleXMLElement $data) + { + // NOOP + } + /** * Get Limit. * diff --git a/src/Message/Query/QueryBatchRequest.php b/src/Message/Query/QueryBatchRequest.php index a15b64ae..d2a7e630 100644 --- a/src/Message/Query/QueryBatchRequest.php +++ b/src/Message/Query/QueryBatchRequest.php @@ -5,17 +5,26 @@ /** * Authorize.Net AIM Authorize Request */ + class QueryBatchRequest extends AIMAbstractQueryRequest { - protected $action = ''; protected $requestType = 'getSettledBatchListRequest'; public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - return $this->response = new QueryBatchResponse($this, $httpResponse->getBody()->getContents()); + $httpResponse = $this->httpClient->request( + 'POST', + $this->getEndpoint(), + $headers, + $data + ); + + return $this->response = new QueryBatchResponse( + $this, + $httpResponse->getBody()->getContents() + ); } } diff --git a/src/Message/Query/QueryRequest.php b/src/Message/Query/QueryRequest.php index e0429563..1fe967bb 100644 --- a/src/Message/Query/QueryRequest.php +++ b/src/Message/Query/QueryRequest.php @@ -5,13 +5,16 @@ /** * Authorize.Net AIM Authorize Request */ + class QueryRequest extends QueryBatchRequest { + const DATE_TIME_FORMAT = 'Y-m-d\Th:i:s\Z'; + protected $startTimestamp; protected $endTimestamp; /** - * @return mixed + * @return int|null */ public function getStartTimestamp() { @@ -19,7 +22,7 @@ public function getStartTimestamp() } /** - * @param mixed $startTimestamp + * @param int|null $startTimestamp unix timestamp */ public function setStartTimestamp($startTimestamp) { @@ -27,7 +30,7 @@ public function setStartTimestamp($startTimestamp) } /** - * @return mixed + * @return int|null */ public function getEndTimestamp() { @@ -35,7 +38,7 @@ public function getEndTimestamp() } /** - * @param mixed $endTimestamp + * @param int|null $endTimestamp unix timestamp */ public function setEndTimestamp($endTimestamp) { @@ -48,13 +51,22 @@ public function setEndTimestamp($endTimestamp) public function getData() { $data = $this->getBaseData(); + if ($this->getStartTimestamp()) { - $data->firstSettlementDate = date('Y-m-d\Th:i:s\Z', $this->getStartTimestamp()); - $data->lastSettlementDate = date('Y-m-d\Th:i:s\Z'); + $data->firstSettlementDate = date( + static::DATE_TIME_FORMAT, + $this->getStartTimestamp() + ); + $data->lastSettlementDate = date(static::DATE_TIME_FORMAT); } + if ($this->getEndTimestamp()) { - $data->lastSettlementDate = date('Y-m-d\Th:i:s\Z', $this->getEndTimestamp()); + $data->lastSettlementDate = date( + static::DATE_TIME_FORMAT, + $this->getEndTimestamp() + ); } + return $data; } @@ -62,9 +74,19 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); - $this->response = new QueryResponse($this, $httpResponse->getBody()->getContents()); + $httpResponse = $this->httpClient->request( + 'POST', + $this->getEndpoint(), + $headers, + $data + ); + + $this->response = new QueryResponse( + $this, + $httpResponse->getBody()->getContents() + ); + return $this->response; } } From 671c8deefd833bc0fa7e58750f36ed47108541f0 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Wed, 6 Feb 2019 22:46:33 +0000 Subject: [PATCH 220/254] Bit of formatting to aid readability. --- src/Message/Query/QueryBatchDetailRequest.php | 13 +++++++++++-- src/Message/Query/QueryBatchDetailResponse.php | 8 ++++++-- src/Message/Query/QueryBatchResponse.php | 11 ++++++++--- src/Message/Query/QueryResponse.php | 14 ++++++++++++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Message/Query/QueryBatchDetailRequest.php b/src/Message/Query/QueryBatchDetailRequest.php index c2295f2a..728b067c 100644 --- a/src/Message/Query/QueryBatchDetailRequest.php +++ b/src/Message/Query/QueryBatchDetailRequest.php @@ -5,6 +5,7 @@ /** * Authorize.Net AIM Authorize Request */ + class QueryBatchDetailRequest extends QueryBatchRequest { protected $action = ''; @@ -27,9 +28,17 @@ public function sendData($data) { $headers = array('Content-Type' => 'text/xml; charset=utf-8'); $data = $data->saveXml(); - $httpResponse = $this->httpClient->request('POST', $this->getEndpoint(), $headers, $data); + $httpResponse = $this->httpClient->request( + 'POST', + $this->getEndpoint(), + $headers, + $data + ); - return $this->response = new QueryBatchDetailResponse($this, $httpResponse->getBody()->getContents()); + return $this->response = new QueryBatchDetailResponse( + $this, + $httpResponse->getBody()->getContents() + ); } public function setBatchID($batchID) diff --git a/src/Message/Query/QueryBatchDetailResponse.php b/src/Message/Query/QueryBatchDetailResponse.php index c4547730..084c9d26 100644 --- a/src/Message/Query/QueryBatchDetailResponse.php +++ b/src/Message/Query/QueryBatchDetailResponse.php @@ -10,11 +10,15 @@ */ class QueryBatchDetailResponse extends AbstractQueryResponse { - public function __construct(AbstractRequest $request, $data) { // Strip out the xmlns junk so that PHP can parse the XML - $xml = preg_replace('/]+>/', '', (string)$data); + $xml = preg_replace( + '/]+>/', + '', + (string)$data + ); + try { $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); } catch (\Exception $e) { diff --git a/src/Message/Query/QueryBatchResponse.php b/src/Message/Query/QueryBatchResponse.php index 869ecfb5..3eaebb48 100644 --- a/src/Message/Query/QueryBatchResponse.php +++ b/src/Message/Query/QueryBatchResponse.php @@ -11,14 +11,19 @@ class QueryBatchResponse extends AbstractQueryResponse { /** - * For Error codes: @see https://developer.authorize.net/api/reference/responseCodes.html + * For Error codes: @see + * https://developer.authorize.net/api/reference/responseCodes.html */ const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = 54; public function __construct(AbstractRequest $request, $data) { - // Strip out the xmlns junk so that PHP can parse the XML - $xml = preg_replace('/]+>/', '', (string)$data); + // Strip out the xmlns junk so that PHP can parse the XML. + $xml = preg_replace( + '/]+>/', + '', + (string)$data + ); try { $xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOWARNING); diff --git a/src/Message/Query/QueryResponse.php b/src/Message/Query/QueryResponse.php index f6c067e6..16d6d924 100644 --- a/src/Message/Query/QueryResponse.php +++ b/src/Message/Query/QueryResponse.php @@ -14,24 +14,34 @@ public function getData() { $data = parent::getData(); $result = array(); + /** @var \Omnipay\AuthorizeNet\AIMGateway $gateway */ $gateway = Omnipay::create('AuthorizeNet_AIM'); + if (!empty($data)) { foreach ($data as $batch) { + // CHECKME: can these settings be moved to outside the loop? + $gateway->setApiLoginId($this->request->getApiLoginId()); $gateway->setHashSecret($this->request->getHashSecret()); $gateway->setTransactionKey($this->request->getTransactionKey()); $gateway->setDeveloperMode($this->request->getDeveloperMode()); + $data = array('batch_id' => $batch['batchId']); + $dataResponse = $gateway->queryBatchDetail($data)->send(); $transactions = $dataResponse->getData(); + foreach ($transactions as $transaction) { - $detailResponse = $gateway->queryDetail(array('transactionReference' => $transaction['transId'])) - ->send(); + $detailResponse = $gateway->queryDetail(array( + 'transactionReference' => $transaction['transId'] + ))->send(); + $result[] = $detailResponse; } } } + return $result; } } From 7db3b2f42285af8c61a7972a25a60d31e651754c Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 7 Feb 2019 16:16:50 -0700 Subject: [PATCH 221/254] Fix issues related to xml2Array --- src/Message/Query/AbstractQueryResponse.php | 2 ++ src/Message/Query/QueryBatchDetailResponse.php | 3 +-- src/Message/Query/QueryBatchResponse.php | 3 +-- src/Message/Query/QueryDetailResponse.php | 3 +-- src/Message/Query/QueryResponse.php | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Message/Query/AbstractQueryResponse.php b/src/Message/Query/AbstractQueryResponse.php index c01727e5..12cf66f4 100644 --- a/src/Message/Query/AbstractQueryResponse.php +++ b/src/Message/Query/AbstractQueryResponse.php @@ -24,6 +24,8 @@ abstract class AbstractQueryResponse extends AbstractResponse */ public function xml2array(\SimpleXMLElement $xml) { + return json_decode(json_encode($xml), true); + $arr = array(); foreach ($xml as $element) { $tag = $element->getName(); diff --git a/src/Message/Query/QueryBatchDetailResponse.php b/src/Message/Query/QueryBatchDetailResponse.php index 084c9d26..837c74f7 100644 --- a/src/Message/Query/QueryBatchDetailResponse.php +++ b/src/Message/Query/QueryBatchDetailResponse.php @@ -39,7 +39,6 @@ public function isSuccessful() public function getData() { - $result = $this->xml2array($this->data->transactions, true); - return $result['transactions'][0]['transaction']; + return $this->xml2array($this->data->transactions, true)['transaction']; } } diff --git a/src/Message/Query/QueryBatchResponse.php b/src/Message/Query/QueryBatchResponse.php index 3eaebb48..607f8749 100644 --- a/src/Message/Query/QueryBatchResponse.php +++ b/src/Message/Query/QueryBatchResponse.php @@ -51,7 +51,6 @@ public function getResultCode() public function getData() { - $result = $this->xml2array($this->data->batchList, true); - return $result['batchList'][0]['batch']; + return $this->xml2array($this->data->batchList, true)['batch']; } } diff --git a/src/Message/Query/QueryDetailResponse.php b/src/Message/Query/QueryDetailResponse.php index f2b51f75..9f3966a1 100644 --- a/src/Message/Query/QueryDetailResponse.php +++ b/src/Message/Query/QueryDetailResponse.php @@ -29,8 +29,7 @@ public function __construct(AbstractRequest $request, $data) } parent::__construct($request, $xml); - $result = $this->xml2array($this->data->transaction, true); - $this->transaction = $result['transaction'][0]; + $this->transaction = $this->xml2array($this->data->transaction, true); } public function isSuccessful() diff --git a/src/Message/Query/QueryResponse.php b/src/Message/Query/QueryResponse.php index 16d6d924..0a550ea1 100644 --- a/src/Message/Query/QueryResponse.php +++ b/src/Message/Query/QueryResponse.php @@ -37,7 +37,7 @@ public function getData() 'transactionReference' => $transaction['transId'] ))->send(); - $result[] = $detailResponse; + $result[] = $detailResponse->transaction; } } } From 5c43a19e630957cbdd255c99210a7f6c29a445bb Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 11 Feb 2019 10:31:13 -0700 Subject: [PATCH 222/254] Upadte composer.json home page --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e301dfd1..85ce0863 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "pay", "payment" ], - "homepage": "https://github.com/thephpleague/omnipay-authorizenet", + "homepage": "https://github.com/dmgctrlr/omnipay-authorizenet", "license": "MIT", "authors": [ { From a9d460ad39f6d9b1bdc750e0928fb30a025803c6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 11 Feb 2019 10:37:50 -0700 Subject: [PATCH 223/254] Update home page in composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 85ce0863..e301dfd1 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "pay", "payment" ], - "homepage": "https://github.com/dmgctrlr/omnipay-authorizenet", + "homepage": "https://github.com/thephpleague/omnipay-authorizenet", "license": "MIT", "authors": [ { From 27d01b6879927aef99b816bfa6f896b802a5a4fb Mon Sep 17 00:00:00 2001 From: Oleksandr Dolbin Date: Tue, 12 Mar 2019 23:10:55 +0200 Subject: [PATCH 224/254] issue-123: add sha512 support for SIMCompleteAuthorizeRequest --- src/Message/SIMCompleteAuthorizeRequest.php | 91 ++++++++++++++++++++- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index 26d3f7f0..1e5bf902 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -21,7 +21,7 @@ public function getTransactionId() public function getData() { // The hash sent in the callback from the Authorize.Net gateway. - $hash_posted = strtolower($this->httpRequest->request->get('x_MD5_Hash')); + $hash_posted = $this->getPostedHash($this->httpRequest); // The transaction reference generated by the Authorize.Net gateway and sent in the callback. $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); @@ -30,7 +30,7 @@ public function getData() $posted_amount = $this->httpRequest->request->get('x_amount'); // Calculate the hash locally, using the shared "hash secret" and login ID. - $hash_calculated = $this->getHash($posted_transaction_reference, $posted_amount); + $hash_calculated = $this->getHash($posted_transaction_reference, $posted_amount, $this->httpRequest); if ($hash_posted !== $hash_calculated) { // If the hash is incorrect, then we can't trust the source nor anything sent. @@ -65,20 +65,103 @@ public function getData() * and x_amount) and it is those that should be checked against. * @param $transaction_reference * @param $amount + * @param $httpRequest * @return string */ - public function getHash($transaction_reference, $amount) + public function getHash($transaction_reference, $amount, $httpRequest) + { + if (!empty($httpRequest) && $hash = $this->getSha512Hash($httpRequest)) { + return $hash; + } else { + return $this->getMd5Hash($transaction_reference, $amount); + } + + } + + /** + * Generate md5 hash. + * + * @param $transaction_reference + * @param $amount + * @return string + */ + public function getMd5Hash($transaction_reference, $amount) { $key = array( $this->getHashSecret(), $this->getApiLoginId(), $transaction_reference, $amount, - ); + ); return md5(implode('', $key)); } + /** + * Generate sha512 hash. + * Required fields are provided in Table 18 in https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73 + * + * @param $httpRequest + * @return string|null + */ + public function getSha512Hash($httpRequest) + { + $signatureKey = $this->getSignatureKey(); + if(empty($signatureKey) || empty($httpRequest)) return null; + $hashData = implode('^', [ + $httpRequest->request->get('x_trans_id'), + $httpRequest->request->get('x_test_request'), + $httpRequest->request->get('x_response_code'), + $httpRequest->request->get('x_auth_code'), + $httpRequest->request->get('x_cvv2_resp_code'), + $httpRequest->request->get('x_cavv_response'), + $httpRequest->request->get('x_avs_code'), + $httpRequest->request->get('x_method'), + $httpRequest->request->get('x_account_number'), + $httpRequest->request->get('x_amount'), + $httpRequest->request->get('x_company'), + $httpRequest->request->get('x_first_name'), + $httpRequest->request->get('x_last_name'), + $httpRequest->request->get('x_address'), + $httpRequest->request->get('x_city'), + $httpRequest->request->get('x_state'), + $httpRequest->request->get('x_zip'), + $httpRequest->request->get('x_country'), + $httpRequest->request->get('x_phone'), + $httpRequest->request->get('x_fax'), + $httpRequest->request->get('x_email'), + $httpRequest->request->get('x_ship_to_company'), + $httpRequest->request->get('x_ship_to_first_name'), + $httpRequest->request->get('x_ship_to_last_name'), + $httpRequest->request->get('x_ship_to_address'), + $httpRequest->request->get('x_ship_to_city'), + $httpRequest->request->get('x_ship_to_state'), + $httpRequest->request->get('x_ship_to_zip'), + $httpRequest->request->get('x_ship_to_country'), + $httpRequest->request->get('x_invoice_num'), + ]); + $hash = hash_hmac('sha512', '^'.$hashData.'^', hex2bin($signatureKey)); + $hash = strtoupper($hash); + + return $hash; + } + + /** + * Get posted hash from the callback from the Authorize.Net gateway. + * + * @param $httpRequest + * @return string|null + */ + public function getPostedHash($httpRequest) + { + if (empty($httpRequest)) return null; + + if($signatureKey = $this->getSignatureKey()){ + return strtolower($httpRequest->request->get('x_SHA2_Hash')); + } + return strtolower($httpRequest->request->get('x_MD5_Hash')); + } + public function sendData($data) { return $this->response = new SIMCompleteAuthorizeResponse($this, $data); From f288156d00acf61d9ec1b18e2d3be52524f54ff4 Mon Sep 17 00:00:00 2001 From: Oleksandr Dolbin Date: Wed, 13 Mar 2019 00:02:04 +0200 Subject: [PATCH 225/254] issue-123: add getTransactionId method to SIMAuthorizeResponse --- src/Message/SIMAuthorizeResponse.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Message/SIMAuthorizeResponse.php b/src/Message/SIMAuthorizeResponse.php index 0daad075..4e4cd37f 100644 --- a/src/Message/SIMAuthorizeResponse.php +++ b/src/Message/SIMAuthorizeResponse.php @@ -44,4 +44,9 @@ public function getRedirectData() { return $this->getData(); } + + public function getTransactionId() + { + return $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] ? $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] : null; + } } From 40b98715c3bc594cbdc7888cd4fed7bc6fa3c82d Mon Sep 17 00:00:00 2001 From: Oleksandr Dolbin Date: Wed, 13 Mar 2019 00:08:39 +0200 Subject: [PATCH 226/254] issue-123: fix getTransactionId method to SIMAuthorizeResponse --- src/Message/SIMAuthorizeResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/SIMAuthorizeResponse.php b/src/Message/SIMAuthorizeResponse.php index 4e4cd37f..8be92d00 100644 --- a/src/Message/SIMAuthorizeResponse.php +++ b/src/Message/SIMAuthorizeResponse.php @@ -47,6 +47,6 @@ public function getRedirectData() public function getTransactionId() { - return $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] ? $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] : null; + return isset($this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM]) ? $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] : null; } } From 519011ba2c4bc256bcce9c9e808d0a934aeb67f0 Mon Sep 17 00:00:00 2001 From: Oleksandr Dolbin Date: Wed, 13 Mar 2019 00:31:59 +0200 Subject: [PATCH 227/254] issue-123: fix getPostedHash method in SIMCompleteAuthorizeRequest --- src/Message/SIMCompleteAuthorizeRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index 1e5bf902..d9229522 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -157,7 +157,7 @@ public function getPostedHash($httpRequest) if (empty($httpRequest)) return null; if($signatureKey = $this->getSignatureKey()){ - return strtolower($httpRequest->request->get('x_SHA2_Hash')); + return strtoupper($httpRequest->request->get('x_SHA2_Hash')); } return strtolower($httpRequest->request->get('x_MD5_Hash')); } From de5eb0c1358dfe99ae2ab58d4aa1166d0afa7291 Mon Sep 17 00:00:00 2001 From: Oleksandr Dolbin Date: Wed, 13 Mar 2019 00:36:20 +0200 Subject: [PATCH 228/254] issue-123: fix SIMCompleteAuthorizeRequest --- src/Message/SIMCompleteAuthorizeRequest.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index d9229522..f10ffb9b 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -75,7 +75,6 @@ public function getHash($transaction_reference, $amount, $httpRequest) } else { return $this->getMd5Hash($transaction_reference, $amount); } - } /** @@ -100,14 +99,16 @@ public function getMd5Hash($transaction_reference, $amount) /** * Generate sha512 hash. * Required fields are provided in Table 18 in https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73 - * * @param $httpRequest * @return string|null */ public function getSha512Hash($httpRequest) { $signatureKey = $this->getSignatureKey(); - if(empty($signatureKey) || empty($httpRequest)) return null; + if (empty($signatureKey) || empty($httpRequest)) { + return null; + } + $hashData = implode('^', [ $httpRequest->request->get('x_trans_id'), $httpRequest->request->get('x_test_request'), @@ -140,7 +141,7 @@ public function getSha512Hash($httpRequest) $httpRequest->request->get('x_ship_to_country'), $httpRequest->request->get('x_invoice_num'), ]); - $hash = hash_hmac('sha512', '^'.$hashData.'^', hex2bin($signatureKey)); + $hash = hash_hmac('sha512', '^' . $hashData . '^', hex2bin($signatureKey)); $hash = strtoupper($hash); return $hash; @@ -154,11 +155,14 @@ public function getSha512Hash($httpRequest) */ public function getPostedHash($httpRequest) { - if (empty($httpRequest)) return null; + if (empty($httpRequest)){ + return null; + } - if($signatureKey = $this->getSignatureKey()){ + if ($signatureKey = $this->getSignatureKey()) { return strtoupper($httpRequest->request->get('x_SHA2_Hash')); } + return strtolower($httpRequest->request->get('x_MD5_Hash')); } From 6b97fbd697d913281468982546f53379298c6add Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 16 Mar 2019 19:46:48 +0000 Subject: [PATCH 229/254] Refactor PR 128 for adding tests. --- src/Message/SIMCompleteAuthorizeRequest.php | 90 ++++++++++----------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php index f10ffb9b..a36ea1f2 100644 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ b/src/Message/SIMCompleteAuthorizeRequest.php @@ -21,7 +21,7 @@ public function getTransactionId() public function getData() { // The hash sent in the callback from the Authorize.Net gateway. - $hash_posted = $this->getPostedHash($this->httpRequest); + $hash_posted = $this->getPostedHash(); // The transaction reference generated by the Authorize.Net gateway and sent in the callback. $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); @@ -30,7 +30,7 @@ public function getData() $posted_amount = $this->httpRequest->request->get('x_amount'); // Calculate the hash locally, using the shared "hash secret" and login ID. - $hash_calculated = $this->getHash($posted_transaction_reference, $posted_amount, $this->httpRequest); + $hash_calculated = $this->getHash($posted_transaction_reference, $posted_amount); if ($hash_posted !== $hash_calculated) { // If the hash is incorrect, then we can't trust the source nor anything sent. @@ -68,10 +68,10 @@ public function getData() * @param $httpRequest * @return string */ - public function getHash($transaction_reference, $amount, $httpRequest) + public function getHash($transaction_reference, $amount) { - if (!empty($httpRequest) && $hash = $this->getSha512Hash($httpRequest)) { - return $hash; + if ($this->getSignatureKey()) { + return $this->getSha512Hash(); } else { return $this->getMd5Hash($transaction_reference, $amount); } @@ -98,48 +98,51 @@ public function getMd5Hash($transaction_reference, $amount) /** * Generate sha512 hash. - * Required fields are provided in Table 18 in https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73 + * Required fields are provided in Table 18 in + * https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73 * @param $httpRequest * @return string|null */ - public function getSha512Hash($httpRequest) + public function getSha512Hash() { $signatureKey = $this->getSignatureKey(); - if (empty($signatureKey) || empty($httpRequest)) { + $httpRequest = $this->httpRequest->request; + + if (empty($signatureKey)) { return null; } $hashData = implode('^', [ - $httpRequest->request->get('x_trans_id'), - $httpRequest->request->get('x_test_request'), - $httpRequest->request->get('x_response_code'), - $httpRequest->request->get('x_auth_code'), - $httpRequest->request->get('x_cvv2_resp_code'), - $httpRequest->request->get('x_cavv_response'), - $httpRequest->request->get('x_avs_code'), - $httpRequest->request->get('x_method'), - $httpRequest->request->get('x_account_number'), - $httpRequest->request->get('x_amount'), - $httpRequest->request->get('x_company'), - $httpRequest->request->get('x_first_name'), - $httpRequest->request->get('x_last_name'), - $httpRequest->request->get('x_address'), - $httpRequest->request->get('x_city'), - $httpRequest->request->get('x_state'), - $httpRequest->request->get('x_zip'), - $httpRequest->request->get('x_country'), - $httpRequest->request->get('x_phone'), - $httpRequest->request->get('x_fax'), - $httpRequest->request->get('x_email'), - $httpRequest->request->get('x_ship_to_company'), - $httpRequest->request->get('x_ship_to_first_name'), - $httpRequest->request->get('x_ship_to_last_name'), - $httpRequest->request->get('x_ship_to_address'), - $httpRequest->request->get('x_ship_to_city'), - $httpRequest->request->get('x_ship_to_state'), - $httpRequest->request->get('x_ship_to_zip'), - $httpRequest->request->get('x_ship_to_country'), - $httpRequest->request->get('x_invoice_num'), + $httpRequest->get('x_trans_id'), + $httpRequest->get('x_test_request'), + $httpRequest->get('x_response_code'), + $httpRequest->get('x_auth_code'), + $httpRequest->get('x_cvv2_resp_code'), + $httpRequest->get('x_cavv_response'), + $httpRequest->get('x_avs_code'), + $httpRequest->get('x_method'), + $httpRequest->get('x_account_number'), + $httpRequest->get('x_amount'), + $httpRequest->get('x_company'), + $httpRequest->get('x_first_name'), + $httpRequest->get('x_last_name'), + $httpRequest->get('x_address'), + $httpRequest->get('x_city'), + $httpRequest->get('x_state'), + $httpRequest->get('x_zip'), + $httpRequest->get('x_country'), + $httpRequest->get('x_phone'), + $httpRequest->get('x_fax'), + $httpRequest->get('x_email'), + $httpRequest->get('x_ship_to_company'), + $httpRequest->get('x_ship_to_first_name'), + $httpRequest->get('x_ship_to_last_name'), + $httpRequest->get('x_ship_to_address'), + $httpRequest->get('x_ship_to_city'), + $httpRequest->get('x_ship_to_state'), + $httpRequest->get('x_ship_to_zip'), + $httpRequest->get('x_ship_to_country'), + $httpRequest->get('x_invoice_num'), ]); $hash = hash_hmac('sha512', '^' . $hashData . '^', hex2bin($signatureKey)); $hash = strtoupper($hash); @@ -150,20 +153,15 @@ public function getSha512Hash($httpRequest) /** * Get posted hash from the callback from the Authorize.Net gateway. * - * @param $httpRequest * @return string|null */ - public function getPostedHash($httpRequest) + public function getPostedHash() { - if (empty($httpRequest)){ - return null; - } - if ($signatureKey = $this->getSignatureKey()) { - return strtoupper($httpRequest->request->get('x_SHA2_Hash')); + return strtoupper($this->httpRequest->request->get('x_SHA2_Hash')); } - return strtolower($httpRequest->request->get('x_MD5_Hash')); + return strtolower($this->httpRequest->request->get('x_MD5_Hash')); } public function sendData($data) From 07a1a26369bb59747432326a45707e072c0ba789 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 16 Mar 2019 23:57:02 +0000 Subject: [PATCH 230/254] Issue #123 / PR #128 Some general refactoring and SHA hash tests added. --- README.md | 7 +- src/Message/DPMAuthorizeRequest.php | 1 + src/Message/DPMCompleteRequest.php | 2 +- src/Message/DPMCompleteResponse.php | 2 +- src/Message/SIMAbstractRequest.php | 5 +- src/Message/SIMAuthorizeRequest.php | 6 +- src/Message/SIMAuthorizeResponse.php | 4 +- src/Message/SIMCompleteAuthorizeRequest.php | 171 ------------------ src/Message/SIMCompleteRequest.php | 158 ++++++++++++++++ ...zeResponse.php => SIMCompleteResponse.php} | 9 +- src/SIMGateway.php | 2 +- tests/Message/DPMAuthorizeRequestTest.php | 2 +- tests/Message/DPMCompleteRequestTest.php | 63 ++++++- tests/Message/DPMPurchaseRequestTest.php | 2 +- tests/Message/SIMAuthorizeRequestTest.php | 2 +- .../SIMCompleteAuthorizeRequestTest.php | 66 ------- tests/Message/SIMCompleteRequestTest.php | 124 +++++++++++++ ...seTest.php => SIMCompleteResponseTest.php} | 12 +- 18 files changed, 376 insertions(+), 262 deletions(-) delete mode 100644 src/Message/SIMCompleteAuthorizeRequest.php create mode 100644 src/Message/SIMCompleteRequest.php rename src/Message/{SIMCompleteAuthorizeResponse.php => SIMCompleteResponse.php} (97%) delete mode 100644 tests/Message/SIMCompleteAuthorizeRequestTest.php create mode 100644 tests/Message/SIMCompleteRequestTest.php rename tests/Message/{SIMCompleteAuthorizeResponseTest.php => SIMCompleteResponseTest.php} (58%) diff --git a/README.md b/README.md index e3b693c3..6bf31f30 100644 --- a/README.md +++ b/README.md @@ -111,15 +111,16 @@ $data = $response->getData(); $data['paymentProfile']['customerProfileId']; $data['paymentProfile']['customerPaymentProfileId']; -//Now you can use these 2 fields to reference this customer and this payment profile for later use with -//the rest of the CIM driver features as usual. + +// Now you can use these 2 fields to reference this customer and this payment profile for later use with +// the rest of the CIM driver features as usual. ``` ## DPM and SIM Signatures DPM and SIM used to sign their requests with the `transactionKey` using the mdh HMAC algorithm. From early 2019, this algorithm is being removed completely. -Instead, the SHA-512 HMAC algorithm is used to sign the DPM and SIM requsts, +Instead, the SHA-512 HMAC algorithm is used to sign the DPM and SIM requests, and to validate the received notifications. To start using the SHA-512 signing, set your `signatureKey` in the gateway: diff --git a/src/Message/DPMAuthorizeRequest.php b/src/Message/DPMAuthorizeRequest.php index 8bcf1829..8fd631d9 100644 --- a/src/Message/DPMAuthorizeRequest.php +++ b/src/Message/DPMAuthorizeRequest.php @@ -6,6 +6,7 @@ * Authorize.Net DPM Authorize Request. * Takes the data that will be used to create the direct-post form. */ + class DPMAuthorizeRequest extends SIMAuthorizeRequest { protected $action = 'AUTH_ONLY'; diff --git a/src/Message/DPMCompleteRequest.php b/src/Message/DPMCompleteRequest.php index 54cf5774..28a75dcf 100644 --- a/src/Message/DPMCompleteRequest.php +++ b/src/Message/DPMCompleteRequest.php @@ -5,7 +5,7 @@ /** * Authorize.Net DPM Complete Authorize Request */ -class DPMCompleteRequest extends SIMCompleteAuthorizeRequest +class DPMCompleteRequest extends SIMCompleteRequest { public function sendData($data) { diff --git a/src/Message/DPMCompleteResponse.php b/src/Message/DPMCompleteResponse.php index 92975509..26df385f 100644 --- a/src/Message/DPMCompleteResponse.php +++ b/src/Message/DPMCompleteResponse.php @@ -5,6 +5,6 @@ /** * SIM and DPM both have identical needs when handling the notify request. */ -class DPMCompleteResponse extends SIMCompleteAuthorizeResponse +class DPMCompleteResponse extends SIMCompleteResponse { } diff --git a/src/Message/SIMAbstractRequest.php b/src/Message/SIMAbstractRequest.php index 7224cb9b..05668230 100644 --- a/src/Message/SIMAbstractRequest.php +++ b/src/Message/SIMAbstractRequest.php @@ -2,11 +2,12 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\Message\AbstractRequest; - /** * Authorize.Net SIM Abstract Request */ + +use Omnipay\Common\Message\AbstractRequest; + abstract class SIMAbstractRequest extends AbstractRequest { /** diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index 4c35f219..fbbf0766 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -54,7 +54,8 @@ public function getData() } $data = array_merge($data, $this->getBillingData()); - $data['x_fp_hash'] = $this->getHash($data); + + $data['x_fp_hash'] = $this->createHash($data); return $data; } @@ -64,10 +65,11 @@ public function getData() * modified en-route. * It uses the TransactionKey, which is a shared secret between the merchant * and Authorize.Net The sequence and timestamp provide additional salt. + * * @param $data * @return string */ - public function getHash($data) + public function createHash($data) { $fingerprint = implode( '^', diff --git a/src/Message/SIMAuthorizeResponse.php b/src/Message/SIMAuthorizeResponse.php index 8be92d00..e0972a53 100644 --- a/src/Message/SIMAuthorizeResponse.php +++ b/src/Message/SIMAuthorizeResponse.php @@ -47,6 +47,8 @@ public function getRedirectData() public function getTransactionId() { - return isset($this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM]) ? $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] : null; + return isset($this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM]) + ? $this->data[SIMAbstractRequest::TRANSACTION_ID_PARAM] + : null; } } diff --git a/src/Message/SIMCompleteAuthorizeRequest.php b/src/Message/SIMCompleteAuthorizeRequest.php deleted file mode 100644 index a36ea1f2..00000000 --- a/src/Message/SIMCompleteAuthorizeRequest.php +++ /dev/null @@ -1,171 +0,0 @@ -httpRequest->request->get(static::TRANSACTION_ID_PARAM); - } - - public function getData() - { - // The hash sent in the callback from the Authorize.Net gateway. - $hash_posted = $this->getPostedHash(); - - // The transaction reference generated by the Authorize.Net gateway and sent in the callback. - $posted_transaction_reference = $this->httpRequest->request->get('x_trans_id'); - - // The amount that the callback has authorized. - $posted_amount = $this->httpRequest->request->get('x_amount'); - - // Calculate the hash locally, using the shared "hash secret" and login ID. - $hash_calculated = $this->getHash($posted_transaction_reference, $posted_amount); - - if ($hash_posted !== $hash_calculated) { - // If the hash is incorrect, then we can't trust the source nor anything sent. - // Throwing exceptions here is probably a bad idea. We are trying to get the data, - // and if it is invalid, then we need to be able to log that data for analysis. - // Except we can't, baceuse the exception means we can't get to the data. - // For now, this is consistent with other OmniPay gateway drivers. - - throw new InvalidRequestException('Incorrect hash'); - } - - // The hashes have passed, but the amount should also be validated against the - // amount in the stored and retrieved transaction. If the application has the - // ability to retrieve the transaction (using the transaction_id sent as a custom - // form field, or perhaps in an otherwise unused field such as x_invoice_id. - - $amount = $this->getAmount(); - - if (isset($amount) && $amount != $posted_amount) { - // The amounts don't match. Someone may have been playing with the - // transaction references. - - throw new InvalidRequestException('Incorrect amount'); - } - - return $this->httpRequest->request->all(); - } - - /** - * CHECKME: should this be the transactionReference in the hash, not the transactionId? - * The transaction reference and the amount are both sent by the remote gateway (x_trans_id - * and x_amount) and it is those that should be checked against. - * @param $transaction_reference - * @param $amount - * @param $httpRequest - * @return string - */ - public function getHash($transaction_reference, $amount) - { - if ($this->getSignatureKey()) { - return $this->getSha512Hash(); - } else { - return $this->getMd5Hash($transaction_reference, $amount); - } - } - - /** - * Generate md5 hash. - * - * @param $transaction_reference - * @param $amount - * @return string - */ - public function getMd5Hash($transaction_reference, $amount) - { - $key = array( - $this->getHashSecret(), - $this->getApiLoginId(), - $transaction_reference, - $amount, - ); - - return md5(implode('', $key)); - } - - /** - * Generate sha512 hash. - * Required fields are provided in Table 18 in - * https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73 - * @param $httpRequest - * @return string|null - */ - public function getSha512Hash() - { - $signatureKey = $this->getSignatureKey(); - $httpRequest = $this->httpRequest->request; - - if (empty($signatureKey)) { - return null; - } - - $hashData = implode('^', [ - $httpRequest->get('x_trans_id'), - $httpRequest->get('x_test_request'), - $httpRequest->get('x_response_code'), - $httpRequest->get('x_auth_code'), - $httpRequest->get('x_cvv2_resp_code'), - $httpRequest->get('x_cavv_response'), - $httpRequest->get('x_avs_code'), - $httpRequest->get('x_method'), - $httpRequest->get('x_account_number'), - $httpRequest->get('x_amount'), - $httpRequest->get('x_company'), - $httpRequest->get('x_first_name'), - $httpRequest->get('x_last_name'), - $httpRequest->get('x_address'), - $httpRequest->get('x_city'), - $httpRequest->get('x_state'), - $httpRequest->get('x_zip'), - $httpRequest->get('x_country'), - $httpRequest->get('x_phone'), - $httpRequest->get('x_fax'), - $httpRequest->get('x_email'), - $httpRequest->get('x_ship_to_company'), - $httpRequest->get('x_ship_to_first_name'), - $httpRequest->get('x_ship_to_last_name'), - $httpRequest->get('x_ship_to_address'), - $httpRequest->get('x_ship_to_city'), - $httpRequest->get('x_ship_to_state'), - $httpRequest->get('x_ship_to_zip'), - $httpRequest->get('x_ship_to_country'), - $httpRequest->get('x_invoice_num'), - ]); - $hash = hash_hmac('sha512', '^' . $hashData . '^', hex2bin($signatureKey)); - $hash = strtoupper($hash); - - return $hash; - } - - /** - * Get posted hash from the callback from the Authorize.Net gateway. - * - * @return string|null - */ - public function getPostedHash() - { - if ($signatureKey = $this->getSignatureKey()) { - return strtoupper($this->httpRequest->request->get('x_SHA2_Hash')); - } - - return strtolower($this->httpRequest->request->get('x_MD5_Hash')); - } - - public function sendData($data) - { - return $this->response = new SIMCompleteAuthorizeResponse($this, $data); - } -} diff --git a/src/Message/SIMCompleteRequest.php b/src/Message/SIMCompleteRequest.php new file mode 100644 index 00000000..72427692 --- /dev/null +++ b/src/Message/SIMCompleteRequest.php @@ -0,0 +1,158 @@ +httpRequest->request->get(static::TRANSACTION_ID_PARAM); + } + + public function getData() + { + // The hash sent in the callback from the Authorize.Net gateway. + $hashPosted = $this->getPostedHash(); + + // Calculate the hash locally, using the shared "hash secret" and login ID. + $hashCalculated = $this->getHash(); + + if ($hashPosted !== $hashCalculated) { + // If the hash is incorrect, then we can't trust the source nor anything sent. + // Throwing exceptions here is probably a bad idea. We are trying to get the data, + // and if it is invalid, then we need to be able to log that data for analysis. + // Except we can't, baceuse the exception means we can't get to the data. + // For now, this is consistent with other OmniPay gateway drivers. + + throw new InvalidRequestException('Incorrect hash'); + } + + // The hashes have passed, but the amount should also be validated against the + // amount in the stored and retrieved transaction. If the application has the + // ability to retrieve the transaction (using the transaction_id sent as a custom + // form field, or perhaps in an otherwise unused field such as x_invoice_id. + + $amount = $this->getAmount(); + $postedAmount = $this->httpRequest->request->get('x_amount'); + + if (isset($amount) && $amount != $postedAmount) { + // The amounts don't match. Someone may have been playing with the + // transaction references. + + throw new InvalidRequestException('Incorrect amount'); + } + + return $this->httpRequest->request->all(); + } + + /** + * @return string + */ + public function getHash() + { + if ($this->getSignatureKey()) { + return $this->getSha512Hash(); + } else { + return $this->getMd5Hash(); + } + } + + /** + * Generate md5 hash. + * + * @param $transaction_reference + * @param $amount + * @return string + */ + public function getMd5Hash() + { + $transactionReference = $this->httpRequest->request->get('x_trans_id'); + $amount = $this->httpRequest->request->get('x_amount'); + + $key = array( + $this->getHashSecret(), + $this->getApiLoginId(), + $transactionReference, + $amount, + ); + + return md5(implode('', $key)); + } + + /** + * Generate sha512 hash. + * Required fields are provided in Table 18 in + * https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf#page=73 + * + * @return string hash generated from server request transformed to upper case + */ + public function getSha512Hash() + { + $signatureKey = $this->getSignatureKey(); + $request = $this->httpRequest->request; + + $hashData = '^' . implode('^', [ + $request->get('x_trans_id'), + $request->get('x_test_request'), + $request->get('x_response_code'), + $request->get('x_auth_code'), + $request->get('x_cvv2_resp_code'), + $request->get('x_cavv_response'), + $request->get('x_avs_code'), + $request->get('x_method'), + $request->get('x_account_number'), + $request->get('x_amount'), + $request->get('x_company'), + $request->get('x_first_name'), + $request->get('x_last_name'), + $request->get('x_address'), + $request->get('x_city'), + $request->get('x_state'), + $request->get('x_zip'), + $request->get('x_country'), + $request->get('x_phone'), + $request->get('x_fax'), + $request->get('x_email'), + $request->get('x_ship_to_company'), + $request->get('x_ship_to_first_name'), + $request->get('x_ship_to_last_name'), + $request->get('x_ship_to_address'), + $request->get('x_ship_to_city'), + $request->get('x_ship_to_state'), + $request->get('x_ship_to_zip'), + $request->get('x_ship_to_country'), + $request->get('x_invoice_num'), + ]) . '^'; + $hash = hash_hmac('sha512', $hashData, hex2bin($signatureKey)); + + return strtoupper($hash); + } + + /** + * Get posted hash from the callback from the Authorize.Net gateway. + * + * @return string|null + */ + public function getPostedHash() + { + if ($signatureKey = $this->getSignatureKey()) { + return strtoupper($this->httpRequest->request->get('x_SHA2_Hash')); + } + + return strtolower($this->httpRequest->request->get('x_MD5_Hash')); + } + + public function sendData($data) + { + return $this->response = new SIMCompleteResponse($this, $data); + } +} diff --git a/src/Message/SIMCompleteAuthorizeResponse.php b/src/Message/SIMCompleteResponse.php similarity index 97% rename from src/Message/SIMCompleteAuthorizeResponse.php rename to src/Message/SIMCompleteResponse.php index b7270d34..ed05befa 100644 --- a/src/Message/SIMCompleteAuthorizeResponse.php +++ b/src/Message/SIMCompleteResponse.php @@ -2,14 +2,15 @@ namespace Omnipay\AuthorizeNet\Message; +/** + * Authorize.Net SIM Complete Authorize Response + */ + use Omnipay\Common\Message\AbstractResponse; use Omnipay\Common\Message\RedirectResponseInterface; use Symfony\Component\HttpFoundation\Response as HttpResponse; -/** - * Authorize.Net SIM Complete Authorize Response - */ -class SIMCompleteAuthorizeResponse extends AbstractResponse implements RedirectResponseInterface +class SIMCompleteResponse extends AbstractResponse implements RedirectResponseInterface { // Response codes returned by Authorize.Net diff --git a/src/SIMGateway.php b/src/SIMGateway.php index ae8a143b..b8566a56 100644 --- a/src/SIMGateway.php +++ b/src/SIMGateway.php @@ -60,7 +60,7 @@ public function authorize(array $parameters = array()) public function completeAuthorize(array $parameters = array()) { - return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMCompleteAuthorizeRequest', $parameters); + return $this->createRequest('\Omnipay\AuthorizeNet\Message\SIMCompleteRequest', $parameters); } public function capture(array $parameters = array()) diff --git a/tests/Message/DPMAuthorizeRequestTest.php b/tests/Message/DPMAuthorizeRequestTest.php index 54521bd1..9b018ea7 100644 --- a/tests/Message/DPMAuthorizeRequestTest.php +++ b/tests/Message/DPMAuthorizeRequestTest.php @@ -81,7 +81,7 @@ public function testGetHash() $expected = hash_hmac('md5', 'user^a^b^c^', 'key'); - $this->assertSame($expected, $this->request->getHash($data)); + $this->assertSame($expected, $this->request->createHash($data)); } public function testSend() diff --git a/tests/Message/DPMCompleteRequestTest.php b/tests/Message/DPMCompleteRequestTest.php index c22202b5..28684d41 100644 --- a/tests/Message/DPMCompleteRequestTest.php +++ b/tests/Message/DPMCompleteRequestTest.php @@ -8,7 +8,7 @@ use Omnipay\Tests\TestCase; -class DPMCompleteAuthorizeRequestTest extends TestCase +class DPMCompleteRequestTest extends TestCase { public function setUp() { @@ -25,14 +25,69 @@ public function testGetDataInvalid() $this->request->getData(); } - public function testGetHash() + public function testGetMd5Hash() { - $this->assertSame(md5(''), $this->request->getHash('', '')); + $this->assertSame(md5(''), $this->request->getHash()); $this->request->setHashSecret('hashsec'); $this->request->setApiLoginId('apilogin'); - $this->assertSame(md5('hashsec' . 'apilogin' . 'trnid' . '10.00'), $this->request->getHash('trnid', '10.00')); + $this->getHttpRequest()->request->replace( + array( + 'x_trans_id' => 'trnid', + 'x_amount' => '10.00', + ) + ); + + $this->assertSame( + md5('hashsec' . 'apilogin' . 'trnid' . '10.00'), + $this->request->getHash() + ); + } + + public function testGetSha512Hash() + { + $this->request->setSignatureKey('48D2C629E4AE7CA3C4E6CD7223DA'); + + $this->getHttpRequest()->request->replace( + array( + 'x_trans_id' => 'trn123456', + 'x_test_request' => 'xxx', + 'x_response_code' => 'xxx', + 'x_auth_code' => 'xxx', + 'x_cvv2_resp_code' => 'xxx', + 'x_cavv_response' => 'xxx', + 'x_avs_code' => 'xxx', + 'x_method' => 'xxx', + 'x_account_number' => 'xxx', + 'x_amount' => '10.99', + 'x_company' => 'xxx', + 'x_first_name' => 'xxx', + 'x_last_name' => 'xxx', + 'x_address' => 'xxx', + 'x_city' => 'xxx', + 'x_state' => 'xxx', + 'x_zip' => 'xxx', + 'x_country' => 'xxx', + 'x_phone' => 'xxx', + 'x_fax' => 'xxx', + 'x_email' => 'xxx', + 'x_ship_to_company' => 'xxx', + 'x_ship_to_first_name' => 'xxx', + 'x_ship_to_last_name' => 'xxx', + 'x_ship_to_address' => 'xxx', + 'x_ship_to_city' => 'xxx', + 'x_ship_to_state' => 'xxx', + 'x_ship_to_zip' => 'xxx', + 'x_ship_to_country' => 'xxx', + 'x_invoice_num' => 'xxx', + ) + ); + + $this->assertSame( + 'F9A0DE7A9AC83E0B8043CD7CBD804ED41FE6BFDDB2C10C486DB4E3C4F3E7163237837A5CD6AEE1FAFF03BAD076DF287F7E81E17ED38752999D1AA6249ECC1613', + $this->request->getHash() + ); } public function testSend() diff --git a/tests/Message/DPMPurchaseRequestTest.php b/tests/Message/DPMPurchaseRequestTest.php index cceaf94f..07c6f458 100644 --- a/tests/Message/DPMPurchaseRequestTest.php +++ b/tests/Message/DPMPurchaseRequestTest.php @@ -70,7 +70,7 @@ public function testGetHash() $expected = hash_hmac('md5', 'user^a^b^c^', 'key'); - $this->assertSame($expected, $this->request->getHash($data)); + $this->assertSame($expected, $this->request->createHash($data)); } public function testSend() diff --git a/tests/Message/SIMAuthorizeRequestTest.php b/tests/Message/SIMAuthorizeRequestTest.php index 497f9ecd..7cc56474 100644 --- a/tests/Message/SIMAuthorizeRequestTest.php +++ b/tests/Message/SIMAuthorizeRequestTest.php @@ -52,7 +52,7 @@ public function testGetHash() $expected = hash_hmac('md5', 'user^a^b^c^', 'key'); - $this->assertSame($expected, $this->request->getHash($data)); + $this->assertSame($expected, $this->request->createHash($data)); } public function testSend() diff --git a/tests/Message/SIMCompleteAuthorizeRequestTest.php b/tests/Message/SIMCompleteAuthorizeRequestTest.php deleted file mode 100644 index 840e7424..00000000 --- a/tests/Message/SIMCompleteAuthorizeRequestTest.php +++ /dev/null @@ -1,66 +0,0 @@ -request = new SIMCompleteAuthorizeRequest($this->getHttpClient(), $this->getHttpRequest()); - } - - /** - * @expectedException \Omnipay\Common\Exception\InvalidRequestException - * @expectedExceptionMessage Incorrect hash - */ - public function testGetDataInvalid() - { - $this->getHttpRequest()->request->replace(array('x_MD5_Hash' => 'invalid')); - $this->request->getData(); - } - - public function testGetHash() - { - $this->assertSame(md5(''), $this->request->getHash('', '')); - - $this->request->setHashSecret('hashsec'); - $this->request->setApiLoginId('apilogin'); - - $this->assertSame(md5('hashsec' . 'apilogin' . 'trnref ' . '10.00'), $this->request->getHash('trnref ', '10.00')); - } - - public function testSend() - { - $posted_trans_id = '12345'; // transactionReference in POST. - $posted_amount = '10.00'; // amount authothorised in POST. - - $this->getHttpRequest()->request->replace( - array( - 'x_response_code' => '1', - 'x_trans_id' => $posted_trans_id, - 'x_amount' => $posted_amount, - 'x_MD5_Hash' => md5('shhh' . 'user' . $posted_trans_id . $posted_amount), - 'omnipay_transaction_id' => '99', - ) - ); - $this->request->setApiLoginId('user'); - $this->request->setHashSecret('shhh'); - $this->request->setAmount('10.00'); - $this->request->setReturnUrl('http://example.com/'); - - // Issue #22 Transaction ID in request is picked up from custom field. - $this->assertSame('99', $this->request->getTransactionId()); - - $response = $this->request->send(); - - $this->assertTrue($response->isSuccessful()); - $this->assertSame($posted_trans_id, $response->getTransactionReference()); - $this->assertSame(true, $response->isRedirect()); - // CHECKME: does it matter what letter case the method is? - $this->assertSame('GET', $response->getRedirectMethod()); - $this->assertSame('http://example.com/', $response->getRedirectUrl()); - $this->assertNull($response->getMessage()); - } -} diff --git a/tests/Message/SIMCompleteRequestTest.php b/tests/Message/SIMCompleteRequestTest.php new file mode 100644 index 00000000..594a710c --- /dev/null +++ b/tests/Message/SIMCompleteRequestTest.php @@ -0,0 +1,124 @@ +request = new SIMCompleteRequest( + $this->getHttpClient(), + $this->getHttpRequest() + ); + } + + /** + * @expectedException \Omnipay\Common\Exception\InvalidRequestException + * @expectedExceptionMessage Incorrect hash + */ + public function testGetDataInvalid() + { + $this->getHttpRequest()->request->replace(array('x_MD5_Hash' => 'invalid')); + $this->request->getData(); + } + + public function testGetMd5Hash() + { + $this->assertSame(md5(''), $this->request->getHash()); + + $this->request->setHashSecret('hashsec'); + $this->request->setApiLoginId('apilogin'); + + $this->getHttpRequest()->request->replace( + array( + 'x_trans_id' => 'trnref', + 'x_amount' => '10.00', + ) + ); + + $this->assertSame( + md5('hashsec' . 'apilogin' . 'trnref' . '10.00'), + $this->request->getHash() + ); + } + + public function testGetSha512Hash() + { + $this->request->setSignatureKey('48D2C629E4AE7CA3C4E6CD7223DA'); + + $this->getHttpRequest()->request->replace( + array( + 'x_trans_id' => 'trn123456', + 'x_test_request' => 'xxx', + 'x_response_code' => 'xxx', + 'x_auth_code' => 'xxx', + 'x_cvv2_resp_code' => 'xxx', + 'x_cavv_response' => 'xxx', + 'x_avs_code' => 'xxx', + 'x_method' => 'xxx', + 'x_account_number' => 'xxx', + 'x_amount' => '10.99', + 'x_company' => 'xxx', + 'x_first_name' => 'xxx', + 'x_last_name' => 'xxx', + 'x_address' => 'xxx', + 'x_city' => 'xxx', + 'x_state' => 'xxx', + 'x_zip' => 'xxx', + 'x_country' => 'xxx', + 'x_phone' => 'xxx', + 'x_fax' => 'xxx', + 'x_email' => 'xxx', + 'x_ship_to_company' => 'xxx', + 'x_ship_to_first_name' => 'xxx', + 'x_ship_to_last_name' => 'xxx', + 'x_ship_to_address' => 'xxx', + 'x_ship_to_city' => 'xxx', + 'x_ship_to_state' => 'xxx', + 'x_ship_to_zip' => 'xxx', + 'x_ship_to_country' => 'xxx', + 'x_invoice_num' => 'xxx', + ) + ); + + $this->assertSame( + 'F9A0DE7A9AC83E0B8043CD7CBD804ED41FE6BFDDB2C10C486DB4E3C4F3E7163237837A5CD6AEE1FAFF03BAD076DF287F7E81E17ED38752999D1AA6249ECC1613', + $this->request->getHash() + ); + } + + public function testSend() + { + $posted_trans_id = '12345'; // transactionReference in POST. + $posted_amount = '10.00'; // amount authothorised in POST. + + $this->getHttpRequest()->request->replace( + array( + 'x_response_code' => '1', + 'x_trans_id' => $posted_trans_id, + 'x_amount' => $posted_amount, + 'x_MD5_Hash' => md5('shhh' . 'user' . $posted_trans_id . $posted_amount), + 'omnipay_transaction_id' => '99', + ) + ); + $this->request->setApiLoginId('user'); + $this->request->setHashSecret('shhh'); + $this->request->setAmount('10.00'); + $this->request->setReturnUrl('http://example.com/'); + + // Issue #22 Transaction ID in request is picked up from custom field. + $this->assertSame('99', $this->request->getTransactionId()); + + $response = $this->request->send(); + + $this->assertTrue($response->isSuccessful()); + $this->assertSame($posted_trans_id, $response->getTransactionReference()); + $this->assertSame(true, $response->isRedirect()); + // CHECKME: does it matter what letter case the method is? + $this->assertSame('GET', $response->getRedirectMethod()); + $this->assertSame('http://example.com/', $response->getRedirectUrl()); + $this->assertNull($response->getMessage()); + } +} diff --git a/tests/Message/SIMCompleteAuthorizeResponseTest.php b/tests/Message/SIMCompleteResponseTest.php similarity index 58% rename from tests/Message/SIMCompleteAuthorizeResponseTest.php rename to tests/Message/SIMCompleteResponseTest.php index 35732ec5..152047a0 100644 --- a/tests/Message/SIMCompleteAuthorizeResponseTest.php +++ b/tests/Message/SIMCompleteResponseTest.php @@ -4,11 +4,14 @@ use Omnipay\Tests\TestCase; -class SIMCompleteAuthorizeResponseTest extends TestCase +class SIMCompleteResponseTest extends TestCase { public function testSuccess() { - $response = new SIMCompleteAuthorizeResponse($this->getMockRequest(), array('x_response_code' => '1', 'x_trans_id' => '12345')); + $response = new SIMCompleteResponse( + $this->getMockRequest(), + array('x_response_code' => '1', 'x_trans_id' => '12345') + ); $this->assertTrue($response->isSuccessful()); $this->assertSame('12345', $response->getTransactionReference()); @@ -17,7 +20,10 @@ public function testSuccess() public function testFailure() { - $response = new SIMCompleteAuthorizeResponse($this->getMockRequest(), array('x_response_code' => '0', 'x_response_reason_text' => 'Declined')); + $response = new SIMCompleteResponse( + $this->getMockRequest(), + array('x_response_code' => '0', 'x_response_reason_text' => 'Declined') + ); $this->assertFalse($response->isSuccessful()); $this->assertNull($response->getTransactionReference()); From ffe153d11f2fef1eab50a293cfb58eeaec50b447 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 17 Mar 2019 00:10:06 +0000 Subject: [PATCH 231/254] Added PHP 7.3 to tests --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 741f61d1..05401da9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ php: - 7.0 - 7.1 - 7.2 + - 7.3 # This triggers builds to run on the new TravisCI infrastructure. # See: http://docs.travis-ci.com/user/workers/container-based-infrastructure/ From e0098a4ee56e82aa524b18ebd97c8e84160b0ac5 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Thu, 25 Apr 2019 15:38:41 -0700 Subject: [PATCH 232/254] CS-3726 handle XML to JSON array conversion issue when a single payment profile is present --- src/Message/CIMGetProfileResponse.php | 5 +++++ tests/CIMGatewayTest.php | 6 +++--- tests/Message/CIMGetProfileResponseTest.php | 14 +++++++++++--- ...ccess.txt => CIMGetMultipleProfilesSuccess.txt} | 0 tests/Mock/CIMGetSingleProfileSuccess.txt | 14 ++++++++++++++ 5 files changed, 33 insertions(+), 6 deletions(-) rename tests/Mock/{CIMGetProfileSuccess.txt => CIMGetMultipleProfilesSuccess.txt} (100%) create mode 100644 tests/Mock/CIMGetSingleProfileSuccess.txt diff --git a/src/Message/CIMGetProfileResponse.php b/src/Message/CIMGetProfileResponse.php index b7e03be8..ff644fc0 100644 --- a/src/Message/CIMGetProfileResponse.php +++ b/src/Message/CIMGetProfileResponse.php @@ -26,6 +26,11 @@ public function getMatchingPaymentProfileId($last4) return null; } + // Handle quirkiness with XML -> JSON conversion + if (!array_key_exists(0, $this->data['profile']['paymentProfiles'])) { + $this->data['profile']['paymentProfiles'] = [$this->data['profile']['paymentProfiles']]; + } + foreach ($this->data['profile']['paymentProfiles'] as $paymentProfile) { // For every payment profile check if the last4 matches the last4 of the card in request. $cardLast4 = substr($paymentProfile['payment']['creditCard']['cardNumber'], -4); diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 5c6e1a21..8a2638e1 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -118,7 +118,7 @@ public function testCreateCardFromOpaqueDataSuccess() public function testShouldCreateCardIfDuplicateCustomerProfileExists() { $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt', - 'CIMGetProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + 'CIMGetMultipleProfilesSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); $response = $this->gateway->createCard($this->createCardOptions)->send(); @@ -149,7 +149,7 @@ public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndForceC { // Duplicate **payment** profile $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileFailure.txt', - 'CIMGetProfileSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + 'CIMGetMultipleProfilesSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); $response = $this->gateway->createCard($this->createCardOptions)->send(); @@ -175,7 +175,7 @@ public function testDoesntUpdateExistingPaymentProfileFromOpaqueData() public function testShouldUpdateExistingPaymentProfileIfDuplicateExistsAndMaxPaymentProfileLimitIsMet() { $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', - 'CIMCreatePaymentProfileFailureMaxProfileLimit.txt', 'CIMGetProfileSuccess.txt', + 'CIMCreatePaymentProfileFailureMaxProfileLimit.txt', 'CIMGetMultipleProfilesSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); $response = $this->gateway->createCard($this->createCardOptions)->send(); diff --git a/tests/Message/CIMGetProfileResponseTest.php b/tests/Message/CIMGetProfileResponseTest.php index d339c9ce..912c7d0b 100644 --- a/tests/Message/CIMGetProfileResponseTest.php +++ b/tests/Message/CIMGetProfileResponseTest.php @@ -2,7 +2,6 @@ namespace Omnipay\AuthorizeNet\Message; -use Omnipay\Common\Exception\InvalidResponseException; use Omnipay\Tests\TestCase; class CIMGetProfileResponseTest extends TestCase @@ -15,13 +14,22 @@ public function testConstructEmpty() new CIMGetProfileResponse($this->getMockRequest(), ''); } - public function testGetMatchingPaymentProfileId() + public function testGetMultipleMatchingPaymentProfileId() { - $httpResponse = $this->getMockHttpResponse('CIMGetProfileSuccess.txt'); + $httpResponse = $this->getMockHttpResponse('CIMGetMultipleProfilesSuccess.txt'); $response = new CIMGetProfileResponse($this->getMockRequest(), $httpResponse->getBody()); $this->assertEquals('26455656', $response->getMatchingPaymentProfileId('1111')); $this->assertEquals('26455709', $response->getMatchingPaymentProfileId('8888')); $this->assertNull($response->getMatchingPaymentProfileId('8889')); } + + public function testGetSingleMatchingPaymentProfileId() + { + $httpResponse = $this->getMockHttpResponse('CIMGetSingleProfileSuccess.txt'); + $response = new CIMGetProfileResponse($this->getMockRequest(), $httpResponse->getBody()); + + $this->assertEquals('26455656', $response->getMatchingPaymentProfileId('1111')); + $this->assertNull($response->getMatchingPaymentProfileId('8889')); + } } diff --git a/tests/Mock/CIMGetProfileSuccess.txt b/tests/Mock/CIMGetMultipleProfilesSuccess.txt similarity index 100% rename from tests/Mock/CIMGetProfileSuccess.txt rename to tests/Mock/CIMGetMultipleProfilesSuccess.txt diff --git a/tests/Mock/CIMGetSingleProfileSuccess.txt b/tests/Mock/CIMGetSingleProfileSuccess.txt new file mode 100644 index 00000000..27d4120d --- /dev/null +++ b/tests/Mock/CIMGetSingleProfileSuccess.txt @@ -0,0 +1,14 @@ +HTTP/1.1 200 OK +Cache-Control: private +Content-Length: 746 +Content-Type: text/xml; +charset=utf-8 +Server: Microsoft-IIS/7.5 +X-AspNet-Version: 2.0.50727 +X-Powered-By: ASP.NET +Access-Control-Allow-Headers: x-requested-with,cache-control,content-type,origin,method +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET,POST,OPTIONS +Date: Thu, 18 Sep 2014 03:59:27 GMT + +OkI00001Successful.kaylee@serenity.com28775801
1234526455656XXXX1111XXXX From e919ec07735e1ea4818ed141b9769cd373a53200 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Thu, 25 Apr 2019 17:09:35 -0700 Subject: [PATCH 233/254] Updated tests to use new GetProfileSuccess response mock --- tests/CIMGatewayTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/CIMGatewayTest.php b/tests/CIMGatewayTest.php index 8a2638e1..9e8fb78f 100644 --- a/tests/CIMGatewayTest.php +++ b/tests/CIMGatewayTest.php @@ -133,7 +133,7 @@ public function testShouldCreateCardIfDuplicateCustomerProfileExists() public function testShouldCreateCardFromOpaqueDataIfDuplicateCustomerProfileExists() { $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileSuccess.txt', - 'CIMGetProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + 'CIMGetMultipleProfilesSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); $response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send(); @@ -165,7 +165,7 @@ public function testDoesntUpdateExistingPaymentProfileFromOpaqueData() { // Duplicate **payment** profile $this->setMockHttpResponse(array('CIMCreateCardFailureWithDuplicate.txt', 'CIMCreatePaymentProfileFailure.txt', - 'CIMGetProfileSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); + 'CIMGetMultipleProfilesSuccess.txt', 'CIMUpdatePaymentProfileSuccess.txt', 'CIMGetPaymentProfileSuccess.txt')); $response = $this->gateway->createCard($this->createCardFromOpaqueDataOptions)->send(); From 9145e44f7cac184156bb89ef9b55efa0cfa0b220 Mon Sep 17 00:00:00 2001 From: Anush Ramani Date: Thu, 25 Apr 2019 17:14:36 -0700 Subject: [PATCH 234/254] Merge together split `Content-Type` header mock --- tests/Mock/CIMGetSingleProfileSuccess.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Mock/CIMGetSingleProfileSuccess.txt b/tests/Mock/CIMGetSingleProfileSuccess.txt index 27d4120d..3beb50c0 100644 --- a/tests/Mock/CIMGetSingleProfileSuccess.txt +++ b/tests/Mock/CIMGetSingleProfileSuccess.txt @@ -1,8 +1,7 @@ HTTP/1.1 200 OK Cache-Control: private Content-Length: 746 -Content-Type: text/xml; -charset=utf-8 +Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/7.5 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET From bf5412b313fdb5de60c78b1e5e4b889b4b9b3695 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sat, 27 Apr 2019 23:23:48 +0100 Subject: [PATCH 235/254] Minor formatting; no functional changes. --- src/Message/SIMAuthorizeRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Message/SIMAuthorizeRequest.php b/src/Message/SIMAuthorizeRequest.php index fbbf0766..db1fb7df 100644 --- a/src/Message/SIMAuthorizeRequest.php +++ b/src/Message/SIMAuthorizeRequest.php @@ -79,7 +79,7 @@ public function createHash($data) $data['x_fp_timestamp'], $data['x_amount'] ) - ).'^'; + ) . '^'; // If x_currency_code is specified, then it must follow the final trailing carat. From 8eadc03cf5681550dc3691a0c3c9e488badd63a8 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Thu, 9 Jan 2020 16:31:03 -0500 Subject: [PATCH 236/254] fix: move under models folder --- src/{ => Model}/BankAccount.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) rename src/{ => Model}/BankAccount.php (97%) diff --git a/src/BankAccount.php b/src/Model/BankAccount.php similarity index 97% rename from src/BankAccount.php rename to src/Model/BankAccount.php index 2109f73f..3511ae33 100644 --- a/src/BankAccount.php +++ b/src/Model/BankAccount.php @@ -6,7 +6,7 @@ * Time: 1:33 PM */ -namespace Omnipay\AuthorizeNet; +namespace Omnipay\AuthorizeNet\Model; use DateTime; use DateTimeZone; @@ -20,8 +20,8 @@ class BankAccount { - const ACCOUNT_TYPE_CHECKING = "CHECKING"; const ACCOUNT_TYPE_BUSINESS_CHECKING = "BUSINESSCHECKING"; + const ACCOUNT_TYPE_CHECKING = "CHECKING"; const ACCOUNT_TYPE_SAVINGS = "SAVINGS"; /** @@ -95,7 +95,7 @@ public function getSupportedAccountType() */ public function validate() { - if (!in_array($this->getBankAccountType(), $this->getSupportedAccountType())) { + if (!in_array($this->getAccountType(), $this->getSupportedAccountType())) { throw new \InvalidArgumentException('The bank account type is not in the supported list.'); } } @@ -128,14 +128,14 @@ public function setRoutingNumber($value) return $this->setParameter('routingNumber', preg_replace('/\D/', '', $value)); } - public function getBankAccountType() + public function getAccountType() { - return $this->getParameter('bankAccountType'); + return $this->getParameter('accountType'); } - public function setBankAccountType($value) + public function setAccountType($value) { - return $this->setParameter('bankAccountType', $value); + return $this->setParameter('accountType', $value); } public function getBankName() @@ -174,12 +174,12 @@ public function setLastName($value) return $this; } - public function getName() + public function getNameOnAccount() { return $this->getBillingName(); } - public function setName($value) + public function setNameOnAccount($value) { $this->setBillingName($value); $this->setShippingName($value); From cda37bcfc736b511ab7cd1fafd9cfca5708d4804 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Thu, 9 Jan 2020 16:33:11 -0500 Subject: [PATCH 237/254] feat: add BankAccount --- src/Message/AIMAbstractRequest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 9a5bb5ae..1226f7ea 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\AuthorizeNet\Model\BankAccount; use Omnipay\AuthorizeNet\Model\CardReference; use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\CreditCard; @@ -185,6 +186,26 @@ public function getCardReference($serialize = true) return $value; } + /** + * @param string|BankAccount + */ + public function setBankAccount($value) + { + if (!($value instanceof BankAccount)) { + $value = new BankAccount($value); + } + + return $this->setParameter('bankAccount', $value); + } + + /** + * @return BankAccount + */ + public function getBankAccount() + { + return $this->getParameter('bankAccount'); + } + public function getInvoiceNumber() { return $this->getParameter('invoiceNumber'); From 72d29037427b33ce88757bf83f89630ba9aafc44 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Thu, 9 Jan 2020 16:37:24 -0500 Subject: [PATCH 238/254] fix: update to work with current API requirements & package setup --- src/Message/AIMAuthorizeRequest.php | 109 +++++++++++++++------------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index f3d0ee27..bbe07032 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -27,35 +27,11 @@ class AIMAuthorizeRequest extends AIMAbstractRequest protected $action = 'authOnlyTransaction'; - const ECHECK = "ECHECK"; - const CREDIT_CARD = "CC"; - public function getData() { $this->validate('amount'); $data = $this->getBaseData(); - $data['x_customer_ip'] = $this->getClientIp(); - $data['x_cust_id'] = $this->getCustomerId(); - - if ($card = $this->getCard()) { - $card->validate(); - $data['x_card_num'] = $this->getCard()->getNumber(); - $data['x_exp_date'] = $this->getCard()->getExpiryDate('my'); - $data['x_card_code'] = $this->getCard()->getCvv(); - $data['x_method'] = self::CREDIT_CARD; - } elseif ($bankAccount = $this->getBankAccount()) { - $bankAccount->validate(); - $data['x_bank_aba_code'] = $this->getBankAccount()->getRoutingNumber(); - $data['x_bank_acct_num'] = $this->getBankAccount()->getAccountNumber(); - $data['x_bank_acct_type'] = $this->getBankAccount()->getBankAccountType(); - $data['x_bank_name'] = $this->getBankAccount()->getBankName(); - $data['x_bank_acct_name'] = $this->getBankAccount()->getName(); - $data['x_echeck_type'] = "WEB"; - $data['x_recurring_billing'] = "FALSE";//NEED when we set echeck_type is WEB or TEL - $data['x_method'] = self::ECHECK; - } - $data->transactionRequest->amount = $this->getAmount(); $this->addPayment($data); $this->addSolutionId($data); @@ -87,45 +63,80 @@ protected function addPayment(\SimpleXMLElement $data) return; } - // Try trackData first. + /** @var CreditCard $creditCard */ + if ($creditCard = $this->getCard()) { + + // Try trackData first. + if (($track1 = $creditCard->getTrack1()) + && ($track2 = $creditCard->getTrack2()) + ) { + $data + ->transactionRequest + ->payment + ->trackData + ->track1 = $track1; + + $data + ->transactionRequest + ->payment + ->trackData + ->track2 = $track2; + } else { + // Validate the standard credit card number. + $this->validate('card'); + + $creditCard->validate(); + $data + ->transactionRequest + ->payment + ->creditCard + ->cardNumber = $card->getNumber(); + $data + ->transactionRequest + ->payment + ->creditCard + ->expirationDate = $card->getExpiryDate('my'); + + if (!empty($card->getCvv())) { + $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); + } + } + } else if ($bankAccount = $this->getBankAccount()) { + // Validate the standard bank account number + $this->validate('bankAccount'); - $creditCard = $this->getCard(); + $bankAccount->validate(); - if (($track1 = $creditCard->getTrack1()) - && ($track2 = $creditCard->getTrack2()) - ) { $data ->transactionRequest ->payment - ->trackData - ->track1 = $track1; - + ->bankAccount + ->accountType = $bankAccount->getAccountType(); $data ->transactionRequest ->payment - ->trackData - ->track2 = $track2; - } else { - // Validate the standard credit card number. - $this->validate('card'); - - /** @var CreditCard $card */ - $card = $this->getCard(); - $card->validate(); + ->bankAccount + ->routingNumber = $bankAccount->getRoutingNumber(); $data ->transactionRequest ->payment - ->creditCard - ->cardNumber = $card->getNumber(); + ->bankAccount + ->accountNumber = $bankAccount->getAccountNumber(); $data ->transactionRequest ->payment - ->creditCard - ->expirationDate = $card->getExpiryDate('my'); - - if (!empty($card->getCvv())) { - $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); - } + ->bankAccount + ->nameOnAccount = $bankAccount->getName(); + $data + ->transactionRequest + ->payment + ->bankAccount + ->bankName = $bankAccount->getBankName(); + $data + ->transactionRequest + ->payment + ->bankAccount + ->echeckType = 'WEB'; } } From 59cc26c018d7ec84c4f380ef99c437a1c1eca442 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Thu, 9 Jan 2020 16:38:02 -0500 Subject: [PATCH 239/254] feat: add billing & shipping address for echeck --- src/Message/AIMAbstractRequest.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Message/AIMAbstractRequest.php b/src/Message/AIMAbstractRequest.php index 1226f7ea..019b79f0 100644 --- a/src/Message/AIMAbstractRequest.php +++ b/src/Message/AIMAbstractRequest.php @@ -361,6 +361,28 @@ protected function addBillingData(\SimpleXMLElement $data) $req->shipTo->state = $card->getShippingState(); $req->shipTo->zip = $card->getShippingPostcode(); $req->shipTo->country = $card->getShippingCountry(); + } else if ($bank = $this->getBankAccount()) { + // A bank_account is present, so include billing and shipping details + $req->customer->email = $bank->getEmail(); + + $req->billTo->firstName = $bank->getBillingFirstName(); + $req->billTo->lastName = $bank->getBillingLastName(); + $req->billTo->company = $bank->getBillingCompany(); + $req->billTo->address = trim($bank->getBillingAddress1() . " \n" . $bank->getBillingAddress2()); + $req->billTo->city = $bank->getBillingCity(); + $req->billTo->state = $bank->getBillingState(); + $req->billTo->zip = $bank->getBillingPostcode(); + $req->billTo->country = $bank->getBillingCountry(); + $req->billTo->phoneNumber = $bank->getBillingPhone(); + + $req->shipTo->firstName = $bank->getShippingFirstName(); + $req->shipTo->lastName = $bank->getShippingLastName(); + $req->shipTo->company = $bank->getShippingCompany(); + $req->shipTo->address = trim($bank->getShippingAddress1() . " \n" . $bank->getShippingAddress2()); + $req->shipTo->city = $bank->getShippingCity(); + $req->shipTo->state = $bank->getShippingState(); + $req->shipTo->zip = $bank->getShippingPostcode(); + $req->shipTo->country = $bank->getShippingCountry(); } return $data; From 762002246520d7c91702be8ac34a5298acb93b59 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 11:01:55 -0500 Subject: [PATCH 240/254] fix: incorrect function & variable + return-early --- src/Message/AIMAuthorizeRequest.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index bbe07032..e128b3ad 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -65,7 +65,6 @@ protected function addPayment(\SimpleXMLElement $data) /** @var CreditCard $creditCard */ if ($creditCard = $this->getCard()) { - // Try trackData first. if (($track1 = $creditCard->getTrack1()) && ($track2 = $creditCard->getTrack2()) @@ -90,18 +89,23 @@ protected function addPayment(\SimpleXMLElement $data) ->transactionRequest ->payment ->creditCard - ->cardNumber = $card->getNumber(); + ->cardNumber = $creditCard->getNumber(); $data ->transactionRequest ->payment ->creditCard - ->expirationDate = $card->getExpiryDate('my'); + ->expirationDate = $creditCard->getExpiryDate('my'); - if (!empty($card->getCvv())) { - $data->transactionRequest->payment->creditCard->cardCode = $card->getCvv(); + if (!empty($creditCard->getCvv())) { + $data->transactionRequest->payment->creditCard->cardCode = $creditCard->getCvv(); } } - } else if ($bankAccount = $this->getBankAccount()) { + + return; + } + + /** @var BankAccount $bankAccount */ + if ($bankAccount = $this->getBankAccount()) { // Validate the standard bank account number $this->validate('bankAccount'); @@ -126,7 +130,7 @@ protected function addPayment(\SimpleXMLElement $data) ->transactionRequest ->payment ->bankAccount - ->nameOnAccount = $bankAccount->getName(); + ->nameOnAccount = $bankAccount->getNameOnAccount(); $data ->transactionRequest ->payment From c0705d95f957ea8095ab936815e0d91f17c715a0 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 11:02:46 -0500 Subject: [PATCH 241/254] fix: update valid accountTypes --- src/Model/BankAccount.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Model/BankAccount.php b/src/Model/BankAccount.php index 3511ae33..2a7275fb 100644 --- a/src/Model/BankAccount.php +++ b/src/Model/BankAccount.php @@ -20,9 +20,9 @@ class BankAccount { - const ACCOUNT_TYPE_BUSINESS_CHECKING = "BUSINESSCHECKING"; - const ACCOUNT_TYPE_CHECKING = "CHECKING"; - const ACCOUNT_TYPE_SAVINGS = "SAVINGS"; + const ACCOUNT_TYPE_CHECKING = "checking"; + const ACCOUNT_TYPE_SAVINGS = "savings"; + const ACCOUNT_TYPE_BUSINESS_CHECKING = "businessChecking"; /** * @var \Symfony\Component\HttpFoundation\ParameterBag From ba6360aafee903e71cabd01b167d4118935031a3 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 11:10:30 -0500 Subject: [PATCH 242/254] feat: add bank account to transaction reference --- src/Message/AIMResponse.php | 5 ++++- src/Model/BankAccount.php | 13 +++++++++++++ src/Model/TransactionReference.php | 24 ++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index 785b6c24..fedc0412 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\AuthorizeNet\Model\BankAccount; use Omnipay\AuthorizeNet\Model\CardReference; use Omnipay\AuthorizeNet\Model\TransactionReference; use Omnipay\Common\Exception\InvalidResponseException; @@ -135,7 +136,7 @@ public function getAVSCode() return ''; } } - + /** * Returns the Card Code Verfication return code. * @@ -177,6 +178,8 @@ public function getTransactionReference($serialize = true) )); } elseif ($cardReference = $this->request->getCardReference()) { $transactionRef->setCardReference(new CardReference($cardReference)); + } elseif ($bankAccount = $this->request->getBankAccount()) { + $transactionRef->setBankAccount(new BankAccount($bankAccount)); } } catch (\Exception $e) { } diff --git a/src/Model/BankAccount.php b/src/Model/BankAccount.php index 2a7275fb..2cf17289 100644 --- a/src/Model/BankAccount.php +++ b/src/Model/BankAccount.php @@ -39,6 +39,19 @@ public function __construct($parameters = null) $this->initialize($parameters); } + public function __toString() + { + $data = array( + 'accountType' => $this->getAccountType(), + 'routingNumber' => $this->getRoutingNumber(), + 'accountNumber' => $this->getAccountNumber(), + 'nameOnAccount' => $this->getNameOnAccount(), + 'echeckType' => 'WEB' + ); + + return json_encode($data); + } + /** * Initialize the object with parameters. * diff --git a/src/Model/TransactionReference.php b/src/Model/TransactionReference.php index 76f62a6c..6f345d5c 100644 --- a/src/Model/TransactionReference.php +++ b/src/Model/TransactionReference.php @@ -18,6 +18,8 @@ class TransactionReference private $card; /** @var CardReference */ private $cardReference; + /** @var BankAccount */ + private $bankAccount; public function __construct($data = null) { @@ -35,6 +37,9 @@ public function __construct($data = null) if (isset($data->cardReference)) { $this->cardReference = new CardReference($data->cardReference); } + if (isset($data->bankAccount)) { + $this->bankAccount = new BankAccount($data->bankAccount); + } } } @@ -53,6 +58,9 @@ public function __toString() if (isset($this->cardReference)) { $data['cardReference'] = (string)$this->cardReference; } + if (isset($this->bankAccount)) { + $data['bankAccount'] = (string)$this->bankAccount; + } return json_encode($data); } @@ -119,4 +127,20 @@ public function setCardReference($cardReference) { $this->cardReference = $cardReference; } + + /** + * @return BankAccount + */ + public function getBankAccount() + { + return $this->bankAccount; + } + + /** + * @param string|BankAccount $bankAccount + */ + public function setBankAccount($bankAccount) + { + $this->bankAccount = $bankAccount; + } } From d81f4f2bfb3e3a2b7c348f3252f9bcdb78ff5a3f Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 11:42:22 -0500 Subject: [PATCH 243/254] feat: add mock eCheck purchase success and failure responses --- tests/Mock/AIMEcheckPurchaseFailure.txt | 13 +++++++++++++ tests/Mock/AIMEcheckPurchaseSuccess.txt | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/Mock/AIMEcheckPurchaseFailure.txt create mode 100644 tests/Mock/AIMEcheckPurchaseSuccess.txt diff --git a/tests/Mock/AIMEcheckPurchaseFailure.txt b/tests/Mock/AIMEcheckPurchaseFailure.txt new file mode 100644 index 00000000..54840cd5 --- /dev/null +++ b/tests/Mock/AIMEcheckPurchaseFailure.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Sat, 02 Aug 2014 04:53:02 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 842 + +1234ErrorE00027The transaction was unsuccessful.3P00XXXX6789eCheck101The given name on the account and/or the account type does not match the actual account. diff --git a/tests/Mock/AIMEcheckPurchaseSuccess.txt b/tests/Mock/AIMEcheckPurchaseSuccess.txt new file mode 100644 index 00000000..89e16263 --- /dev/null +++ b/tests/Mock/AIMEcheckPurchaseSuccess.txt @@ -0,0 +1,13 @@ +HTTP/1.1 200 OK +Date: Fri, 01 Aug 2014 16:27:55 GMT +Server: Microsoft-IIS/6.0 +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method +X-Powered-By: ASP.NET +X-AspNet-Version: 2.0.50727 +Cache-Control: private +Content-Type: text/xml; charset=utf-8 +Content-Length: 885 + +123456OkI00001Successful.1P22146274927A6DCD2645DF873C035DCE4832C080360XXXXX6789eCheck1This transaction has been approved. From f7fce964f212a7705a85856c9c1fb0dfcc1faa7b Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 14:25:58 -0500 Subject: [PATCH 244/254] fix: update to mirror Omnipay/Common/CreditCard --- src/Model/BankAccount.php | 937 +++++++++++++++++++++++++++++++++----- 1 file changed, 830 insertions(+), 107 deletions(-) diff --git a/src/Model/BankAccount.php b/src/Model/BankAccount.php index 2cf17289..d66aabea 100644 --- a/src/Model/BankAccount.php +++ b/src/Model/BankAccount.php @@ -1,36 +1,114 @@ + * // Define bank account parameters, which should look like this + * $parameters = [ + * 'firstName' => 'Bobby', + * 'lastName' => 'Tables', + * 'accountType' => 'checking' + * 'routingNumber' => '122105155', + * 'accountNumber' => '123456789', + * ]; + * + * // Create a bank account object + * $bank = new BankAccount($parameters); + * + * + * The full list of bank attributes that may be set via the parameter to + * *new* is as follows: + * + * * title + * * firstName + * * lastName + * * name + * * company + * * address1 + * * address2 + * * city + * * postcode + * * state + * * country + * * phone + * * phoneExtension + * * fax + * * accountType + * * routingNumber + * * accountNumber + * * bankName + * * billingTitle + * * billingName + * * billingFirstName + * * billingLastName + * * billingCompany + * * billingAddress1 + * * billingAddress2 + * * billingCity + * * billingPostcode + * * billingState + * * billingCountry + * * billingPhone + * * billingFax + * * shippingTitle + * * shippingName + * * shippingFirstName + * * shippingLastName + * * shippingCompany + * * shippingAddress1 + * * shippingAddress2 + * * shippingCity + * * shippingPostcode + * * shippingState + * * shippingCountry + * * shippingPhone + * * shippingFax + * * email + * * birthday + * * gender + * + * If any unknown parameters are passed in, they will be ignored. No error is thrown. */ class BankAccount { - const ACCOUNT_TYPE_CHECKING = "checking"; const ACCOUNT_TYPE_SAVINGS = "savings"; const ACCOUNT_TYPE_BUSINESS_CHECKING = "businessChecking"; + const ECHECK_TYPE_ARC = 'ARC'; + const ECHECK_TYPE_BOC = 'BOC'; + const ECHECK_TYPE_CCD = 'CCD'; + const ECHECK_TYPE_PPD = 'PPD'; + const ECHECK_TYPE_TEL = 'TEL'; + const ECHECK_TYPE_WEB = 'WEB'; + /** - * @var \Symfony\Component\HttpFoundation\ParameterBag + * All known/supported account types + * + * Note: The BusinessChecking account type is not included because the eCheck type used does not all it + * + * @var array */ - protected $parameters; + protected $supported_account_types = array( + self::ACCOUNT_TYPE_CHECKING, + self::ACCOUNT_TYPE_SAVINGS + ); /** - * Create a new CreditCard object using the specified parameters + * Create a new BankAcount object using the specified parameters * * @param array $parameters An array of parameters to set on the new object */ @@ -39,17 +117,14 @@ public function __construct($parameters = null) $this->initialize($parameters); } - public function __toString() + /** + * All known/supported bank account types, and a regular expression to match them. + * + * @return array + */ + public function getSupportedAccountTypes() { - $data = array( - 'accountType' => $this->getAccountType(), - 'routingNumber' => $this->getRoutingNumber(), - 'accountNumber' => $this->getAccountNumber(), - 'nameOnAccount' => $this->getNameOnAccount(), - 'echeckType' => 'WEB' - ); - - return json_encode($data); + return $this->supported_account_types; } /** @@ -58,7 +133,6 @@ public function __toString() * If any unknown parameters passed, they will be ignored. * * @param array $parameters An associative array of parameters - * * @return $this */ public function initialize($parameters = null) @@ -70,102 +144,104 @@ public function initialize($parameters = null) return $this; } + /** + * Get all parameters. + * + * @return array An associative array of parameters. + */ public function getParameters() { return $this->parameters->all(); } + /** + * Get one parameter. + * + * @return mixed A single parameter value. + */ protected function getParameter($key) { return $this->parameters->get($key); } - protected function setParameter($key, $value) - { - $this->parameters->set($key, $value); - - return $this; - } - /** - * All known/supported bank account types, and a regular expression to match them. - * + * Set one parameter. * - * @return array + * @param string $key Parameter key + * @param mixed $value Parameter value + * @return $this */ - public function getSupportedAccountType() + protected function setParameter($key, $value) { - return array( - static::ACCOUNT_TYPE_CHECKING, - static::ACCOUNT_TYPE_BUSINESS_CHECKING, - static::ACCOUNT_TYPE_SAVINGS - ); + $this->parameters->set($key, $value); + return $this; } /** * Validate this bank account. If the bank account is invalid, InvalidArgumentException is thrown. * + * @return void + * @throws InvalidArgumentException */ public function validate() { - if (!in_array($this->getAccountType(), $this->getSupportedAccountType())) { - throw new \InvalidArgumentException('The bank account type is not in the supported list.'); - } - } - - - public function getAccountNumber() - { - return $this->getParameter('accountNumber'); - } - - public function setAccountNumber($value) - { - // strip non-numeric characters - return $this->setParameter('accountNumber', preg_replace('/\D/', '', $value)); - } - - public function getNumberLastFour() - { - return substr($this->getAccountNumber(), -4, 4) ?: null; - } - - public function getRoutingNumber() - { - return $this->getParameter('routingNumber'); - } + $requiredParameters = array( + 'accountType' => 'bank account type', + 'routingNumber' => 'bank routing number', + 'accountNumber' => 'bank account number' + ); - public function setRoutingNumber($value) - { - // strip non-numeric characters - return $this->setParameter('routingNumber', preg_replace('/\D/', '', $value)); - } + foreach ($requiredParameters as $key => $val) { + if (!$this->getParameter($key)) { + throw new \InvalidArgumentException("The $val is required"); + } + } - public function getAccountType() - { - return $this->getParameter('accountType'); + if (!in_array($this->getAccountType(), $this->getSupportedAccountTypes())) { + throw new \InvalidArgumentException('The bank account type is not in the supported list'); + } } - public function setAccountType($value) + /** + * Set Card Title. + * + * @param string $value Parameter value + * @return $this + */ + public function setTitle($value) { - return $this->setParameter('accountType', $value); - } + $this->setBillingTitle($value); + $this->setShippingTitle($value); - public function getBankName() - { - return $this->getParameter('bankName'); + return $this; } - public function setBankName($value) + /** + * Get Bank Title. + * + * @return string + */ + public function getTitle() { - return $this->setParameter('bankName', $value); + return $this->getBillingTitle(); } + /** + * Get Bank First Name. + * + * @return string + */ public function getFirstName() { return $this->getBillingFirstName(); } + /** + * Set Bank First Name (Billing and Shipping). + * + * @param string $value Parameter value + * @return $this + */ public function setFirstName($value) { $this->setBillingFirstName($value); @@ -174,11 +250,22 @@ public function setFirstName($value) return $this; } + /** + * Get Bank Last Name. + * + * @return string + */ public function getLastName() { return $this->getBillingLastName(); } + /** + * Set Bank Last Name (Billing and Shipping). + * + * @param string $value Parameter value + * @return $this + */ public function setLastName($value) { $this->setBillingLastName($value); @@ -187,12 +274,23 @@ public function setLastName($value) return $this; } - public function getNameOnAccount() + /** + * Get Bank Name. + * + * @return string + */ + public function getName() { return $this->getBillingName(); } - public function setNameOnAccount($value) + /** + * Set Bank Name (Billing and Shipping). + * + * @param string $value Parameter value + * @return $this + */ + public function setName($value) { $this->setBillingName($value); $this->setShippingName($value); @@ -200,281 +298,748 @@ public function setNameOnAccount($value) return $this; } - public function getStartMonth() + /** + * Get Bank Account Number. + * + * @return string + */ + public function getAccountNumber() + { + return $this->getParameter('accountNumber'); + } + + /** + * Set Bank Account Number + * + * Non-numeric characters are stripped out of the card number, so + * it's safe to pass in strings such as "4444-3333 2222 1111" etc. + * + * @param string $value Parameter value + * @return $this + */ + public function setAccountNumber($value) + { + // strip non-numeric characters + return $this->setParameter('accountNumber', preg_replace('/\D/', '', $value)); + } + + /** + * Get the last 4 digits of the Bank Account Number. + * + * @return string + */ + public function getAccountNumberLastFour() + { + return substr($this->getAccountNumber(), -4, 4) ?: null; + } + + /** + * Returns a masked Bank Account Number with only the last 4 chars visible + * + * @param string $mask Character to use in place of numbers + * @return string + */ + public function getAccountNumberMasked($mask = 'X') { - return $this->getParameter('startMonth'); + $maskLength = strlen($this->getAccountNumber()) - 4; + + return str_repeat($mask, $maskLength) . $this->getAccountNumberLastFour(); } - public function setStartMonth($value) + /** + * Get Bank Routing Number. + * + * @return string + */ + public function getRoutingNumber() { - return $this->setParameter('startMonth', (int) $value); + return $this->getParameter('routingNumber'); } - public function getStartYear() + /** + * Set Bank Routing Number + * + * Non-numeric characters are stripped out of the card number, so + * it's safe to pass in strings such as "4444-3333 2222 1111" etc. + * + * @param string $value Parameter value + * @return $this + */ + public function setRoutingNumber($value) { - return $this->getParameter('startYear'); + // strip non-numeric characters + return $this->setParameter('routingNumber', preg_replace('/\D/', '', $value)); } - public function setStartYear($value) + /** + * Get Bank Account Type + * + * @return string + */ + public function getAccountType() { - return $this->setYearParameter('startYear', $value); + return $this->getParameter('accountType'); } /** - * Get the card start date, using the specified date format string + * Set Bank Account Type * - * @param string $format + * @param string $value Parameter value + * @return $this + */ + public function setAccountType($value) + { + return $this->setParameter('accountType', $value); + } + + /** + * Get Bank Name * * @return string */ - public function getStartDate($format) + public function getBankName() { - return gmdate($format, gmmktime(0, 0, 0, $this->getStartMonth(), 1, $this->getStartYear())); + return $this->getParameter('bankName'); } - public function getIssueNumber() + /** + * Set Bank Name + * + * @param string $value Parameter value + * @return $this + */ + public function setBankName($value) { - return $this->getParameter('issueNumber'); + return $this->setParameter('bankName', $value); } - public function setIssueNumber($value) + /** + * Get the card billing title. + * + * @return string + */ + public function getBillingTitle() { - return $this->setParameter('issueNumber', $value); + return $this->getParameter('billingTitle'); } + /** + * Sets the card billing title. + * + * @param string $value + * @return $this + */ + public function setBillingTitle($value) + { + return $this->setParameter('billingTitle', $value); + } + + /** + * Get the card billing name. + * + * @return string + */ public function getBillingName() { return trim($this->getBillingFirstName() . ' ' . $this->getBillingLastName()); } + /** + * Split the full name in the first and last name. + * + * @param $fullName + * @return array with first and lastname + */ + protected function listFirstLastName($fullName) + { + $names = explode(' ', $fullName, 2); + + return [$names[0], isset($names[1]) ? $names[1] : null]; + } + + /** + * Sets the card billing name. + * + * @param string $value + * @return $this + */ public function setBillingName($value) { - $names = explode(' ', $value, 2); + $names = $this->listFirstLastName($value); + $this->setBillingFirstName($names[0]); - $this->setBillingLastName(isset($names[1]) ? $names[1] : null); + $this->setBillingLastName($names[1]); return $this; } + /** + * Get the first part of the card billing name. + * + * @return string + */ public function getBillingFirstName() { return $this->getParameter('billingFirstName'); } + /** + * Sets the first part of the card billing name. + * + * @param string $value + * @return $this + */ public function setBillingFirstName($value) { return $this->setParameter('billingFirstName', $value); } + /** + * Get the last part of the card billing name. + * + * @return string + */ public function getBillingLastName() { return $this->getParameter('billingLastName'); } + /** + * Sets the last part of the card billing name. + * + * @param string $value + * @return $this + */ public function setBillingLastName($value) { return $this->setParameter('billingLastName', $value); } + /** + * Get the billing company name. + * + * @return string + */ public function getBillingCompany() { return $this->getParameter('billingCompany'); } + /** + * Sets the billing company name. + * + * @param string $value + * @return $this + */ public function setBillingCompany($value) { return $this->setParameter('billingCompany', $value); } + /** + * Get the billing address, line 1. + * + * @return string + */ public function getBillingAddress1() { return $this->getParameter('billingAddress1'); } + /** + * Sets the billing address, line 1. + * + * @param string $value + * @return $this + */ public function setBillingAddress1($value) { return $this->setParameter('billingAddress1', $value); } + /** + * Get the billing address, line 2. + * + * @return string + */ public function getBillingAddress2() { return $this->getParameter('billingAddress2'); } + /** + * Sets the billing address, line 2. + * + * @param string $value + * @return $this + */ public function setBillingAddress2($value) { return $this->setParameter('billingAddress2', $value); } + /** + * Get the billing city. + * + * @return string + */ public function getBillingCity() { return $this->getParameter('billingCity'); } + /** + * Sets billing city. + * + * @param string $value + * @return $this + */ public function setBillingCity($value) { return $this->setParameter('billingCity', $value); } + /** + * Get the billing postcode. + * + * @return string + */ public function getBillingPostcode() { return $this->getParameter('billingPostcode'); } + /** + * Sets the billing postcode. + * + * @param string $value + * @return $this + */ public function setBillingPostcode($value) { return $this->setParameter('billingPostcode', $value); } + /** + * Get the billing state. + * + * @return string + */ public function getBillingState() { return $this->getParameter('billingState'); } + /** + * Sets the billing state. + * + * @param string $value + * @return $this + */ public function setBillingState($value) { return $this->setParameter('billingState', $value); } + /** + * Get the billing country name. + * + * @return string + */ public function getBillingCountry() { - return $this->getParameter('billingCountry'); + return $this->getParameter('billingCountry'); + } + + /** + * Sets the billing country name. + * + * @param string $value + * @return $this + */ + public function setBillingCountry($value) + { + return $this->setParameter('billingCountry', $value); + } + + /** + * Get the billing phone number. + * + * @return string + */ + public function getBillingPhone() + { + return $this->getParameter('billingPhone'); + } + + /** + * Sets the billing phone number. + * + * @param string $value + * @return $this + */ + public function setBillingPhone($value) + { + return $this->setParameter('billingPhone', $value); + } + + /** + * Get the billing phone number extension. + * + * @return string + */ + public function getBillingPhoneExtension() + { + return $this->getParameter('billingPhoneExtension'); + } + + /** + * Sets the billing phone number extension. + * + * @param string $value + * @return $this + */ + public function setBillingPhoneExtension($value) + { + return $this->setParameter('billingPhoneExtension', $value); + } + + /** + * Get the billing fax number. + * + * @return string + */ + public function getBillingFax() + { + return $this->getParameter('billingFax'); } - public function setBillingCountry($value) + /** + * Sets the billing fax number. + * + * @param string $value + * @return $this + */ + public function setBillingFax($value) { - return $this->setParameter('billingCountry', $value); + return $this->setParameter('billingFax', $value); } - public function getBillingPhone() + /** + * Get the title of the card shipping name. + * + * @return string + */ + public function getShippingTitle() { - return $this->getParameter('billingPhone'); + return $this->getParameter('shippingTitle'); } - public function setBillingPhone($value) + /** + * Sets the title of the card shipping name. + * + * @param string $value + * @return $this + */ + public function setShippingTitle($value) { - return $this->setParameter('billingPhone', $value); + return $this->setParameter('shippingTitle', $value); } + /** + * Get the card shipping name. + * + * @return string + */ public function getShippingName() { return trim($this->getShippingFirstName() . ' ' . $this->getShippingLastName()); } + /** + * Sets the card shipping name. + * + * @param string $value + * @return $this + */ public function setShippingName($value) { - $names = explode(' ', $value, 2); + $names = $this->listFirstLastName($value); + $this->setShippingFirstName($names[0]); - $this->setShippingLastName(isset($names[1]) ? $names[1] : null); + $this->setShippingLastName($names[1]); return $this; } + /** + * Get the first part of the card shipping name. + * + * @return string + */ public function getShippingFirstName() { return $this->getParameter('shippingFirstName'); } + /** + * Sets the first part of the card shipping name. + * + * @param string $value + * @return $this + */ public function setShippingFirstName($value) { return $this->setParameter('shippingFirstName', $value); } + /** + * Get the last part of the card shipping name. + * + * @return string + */ public function getShippingLastName() { return $this->getParameter('shippingLastName'); } + /** + * Sets the last part of the card shipping name. + * + * @param string $value + * @return $this + */ public function setShippingLastName($value) { return $this->setParameter('shippingLastName', $value); } + /** + * Get the shipping company name. + * + * @return string + */ public function getShippingCompany() { return $this->getParameter('shippingCompany'); } + /** + * Sets the shipping company name. + * + * @param string $value + * @return $this + */ public function setShippingCompany($value) { return $this->setParameter('shippingCompany', $value); } + /** + * Get the shipping address, line 1. + * + * @return string + */ public function getShippingAddress1() { return $this->getParameter('shippingAddress1'); } + /** + * Sets the shipping address, line 1. + * + * @param string $value + * @return $this + */ public function setShippingAddress1($value) { return $this->setParameter('shippingAddress1', $value); } + /** + * Get the shipping address, line 2. + * + * @return string + */ public function getShippingAddress2() { return $this->getParameter('shippingAddress2'); } + /** + * Sets the shipping address, line 2. + * + * @param string $value + * @return $this + */ public function setShippingAddress2($value) { return $this->setParameter('shippingAddress2', $value); } + /** + * Get the shipping city. + * + * @return string + */ public function getShippingCity() { return $this->getParameter('shippingCity'); } + /** + * Sets the shipping city. + * + * @param string $value + * @return $this + */ public function setShippingCity($value) { return $this->setParameter('shippingCity', $value); } + /** + * Get the shipping postcode. + * + * @return string + */ public function getShippingPostcode() { return $this->getParameter('shippingPostcode'); } + /** + * Sets the shipping postcode. + * + * @param string $value + * @return $this + */ public function setShippingPostcode($value) { return $this->setParameter('shippingPostcode', $value); } + /** + * Get the shipping state. + * + * @return string + */ public function getShippingState() { return $this->getParameter('shippingState'); } + /** + * Sets the shipping state. + * + * @param string $value + * @return $this + */ public function setShippingState($value) { return $this->setParameter('shippingState', $value); } + /** + * Get the shipping country. + * + * @return string + */ public function getShippingCountry() { return $this->getParameter('shippingCountry'); } + /** + * Sets the shipping country. + * + * @param string $value + * @return $this + */ public function setShippingCountry($value) { return $this->setParameter('shippingCountry', $value); } + /** + * Get the shipping phone number. + * + * @return string + */ public function getShippingPhone() { return $this->getParameter('shippingPhone'); } + /** + * Sets the shipping phone number. + * + * @param string $value + * @return $this + */ public function setShippingPhone($value) { return $this->setParameter('shippingPhone', $value); } + /** + * Get the shipping phone number extension. + * + * @return string + */ + public function getShippingPhoneExtension() + { + return $this->getParameter('shippingPhoneExtension'); + } + + /** + * Sets the shipping phone number extension. + * + * @param string $value + * @return $this + */ + public function setShippingPhoneExtension($value) + { + return $this->setParameter('shippingPhoneExtension', $value); + } + + /** + * Get the shipping fax number. + * + * @return string + */ + public function getShippingFax() + { + return $this->getParameter('shippingFax'); + } + + /** + * Sets the shipping fax number. + * + * @param string $value + * @return $this + */ + public function setShippingFax($value) + { + return $this->setParameter('shippingFax', $value); + } + + /** + * Get the billing address, line 1. + * + * @return string + */ public function getAddress1() { return $this->getParameter('billingAddress1'); } + /** + * Sets the billing and shipping address, line 1. + * + * @param string $value + * @return $this + */ public function setAddress1($value) { $this->setParameter('billingAddress1', $value); @@ -483,11 +1048,22 @@ public function setAddress1($value) return $this; } + /** + * Get the billing address, line 2. + * + * @return string + */ public function getAddress2() { return $this->getParameter('billingAddress2'); } + /** + * Sets the billing and shipping address, line 2. + * + * @param string $value + * @return $this + */ public function setAddress2($value) { $this->setParameter('billingAddress2', $value); @@ -496,11 +1072,22 @@ public function setAddress2($value) return $this; } + /** + * Get the billing city. + * + * @return string + */ public function getCity() { return $this->getParameter('billingCity'); } + /** + * Sets the billing and shipping city. + * + * @param string $value + * @return $this + */ public function setCity($value) { $this->setParameter('billingCity', $value); @@ -509,11 +1096,22 @@ public function setCity($value) return $this; } + /** + * Get the billing postcode. + * + * @return string + */ public function getPostcode() { return $this->getParameter('billingPostcode'); } + /** + * Sets the billing and shipping postcode. + * + * @param string $value + * @return $this + */ public function setPostcode($value) { $this->setParameter('billingPostcode', $value); @@ -522,11 +1120,22 @@ public function setPostcode($value) return $this; } + /** + * Get the billing state. + * + * @return string + */ public function getState() { return $this->getParameter('billingState'); } + /** + * Sets the billing and shipping state. + * + * @param string $value + * @return $this + */ public function setState($value) { $this->setParameter('billingState', $value); @@ -535,11 +1144,22 @@ public function setState($value) return $this; } + /** + * Get the billing country. + * + * @return string + */ public function getCountry() { return $this->getParameter('billingCountry'); } + /** + * Sets the billing and shipping country. + * + * @param string $value + * @return $this + */ public function setCountry($value) { $this->setParameter('billingCountry', $value); @@ -548,11 +1168,22 @@ public function setCountry($value) return $this; } + /** + * Get the billing phone number. + * + * @return string + */ public function getPhone() { return $this->getParameter('billingPhone'); } + /** + * Sets the billing and shipping phone number. + * + * @param string $value + * @return $this + */ public function setPhone($value) { $this->setParameter('billingPhone', $value); @@ -561,11 +1192,70 @@ public function setPhone($value) return $this; } + /** + * Get the billing phone number extension. + * + * @return string + */ + public function getPhoneExtension() + { + return $this->getParameter('billingPhoneExtension'); + } + + /** + * Sets the billing and shipping phone number extension. + * + * @param string $value + * @return $this + */ + public function setPhoneExtension($value) + { + $this->setParameter('billingPhoneExtension', $value); + $this->setParameter('shippingPhoneExtension', $value); + + return $this; + } + + /** + * Get the billing fax number.. + * + * @return string + */ + public function getFax() + { + return $this->getParameter('billingFax'); + } + + /** + * Sets the billing and shipping fax number. + * + * @param string $value + * @return $this + */ + public function setFax($value) + { + $this->setParameter('billingFax', $value); + $this->setParameter('shippingFax', $value); + + return $this; + } + + /** + * Get the card billing company name. + * + * @return string + */ public function getCompany() { return $this->getParameter('billingCompany'); } + /** + * Sets the billing and shipping company name. + * + * @param string $value + * @return $this + */ public function setCompany($value) { $this->setParameter('billingCompany', $value); @@ -574,16 +1264,32 @@ public function setCompany($value) return $this; } + /** + * Get the cardholder's email address. + * + * @return string + */ public function getEmail() { return $this->getParameter('email'); } + /** + * Sets the cardholder's email address. + * + * @param string $value + * @return $this + */ public function setEmail($value) { return $this->setParameter('email', $value); } + /** + * Get the cardholder's birthday. + * + * @return string + */ public function getBirthday($format = 'Y-m-d') { $value = $this->getParameter('birthday'); @@ -591,6 +1297,12 @@ public function getBirthday($format = 'Y-m-d') return $value ? $value->format($format) : null; } + /** + * Sets the cardholder's birthday. + * + * @param string $value + * @return $this + */ public function setBirthday($value) { if ($value) { @@ -602,11 +1314,22 @@ public function setBirthday($value) return $this->setParameter('birthday', $value); } + /** + * Get the cardholder's gender. + * + * @return string + */ public function getGender() { return $this->getParameter('gender'); } + /** + * Sets the cardholder's gender. + * + * @param string $value + * @return $this + */ public function setGender($value) { return $this->setParameter('gender', $value); From de154cba4744d87fd4ae3f9dee58e868ea8bf87f Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 14:27:01 -0500 Subject: [PATCH 245/254] fix: update to use tweaked BankAccount --- src/Message/AIMAuthorizeRequest.php | 5 +++-- src/Message/AIMResponse.php | 8 +++++++- src/Model/TransactionReference.php | 8 ++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index e128b3ad..1b94655c 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet\Message; +use Omnipay\AuthorizeNet\Model\BankAccount; use Omnipay\Common\CreditCard; use Omnipay\Common\Exception\InvalidRequestException; @@ -130,7 +131,7 @@ protected function addPayment(\SimpleXMLElement $data) ->transactionRequest ->payment ->bankAccount - ->nameOnAccount = $bankAccount->getNameOnAccount(); + ->nameOnAccount = $bankAccount->getName(); $data ->transactionRequest ->payment @@ -140,7 +141,7 @@ protected function addPayment(\SimpleXMLElement $data) ->transactionRequest ->payment ->bankAccount - ->echeckType = 'WEB'; + ->echeckType = BankAccount::ECHECK_TYPE_WEB; } } diff --git a/src/Message/AIMResponse.php b/src/Message/AIMResponse.php index fedc0412..4b689ef6 100644 --- a/src/Message/AIMResponse.php +++ b/src/Message/AIMResponse.php @@ -179,7 +179,13 @@ public function getTransactionReference($serialize = true) } elseif ($cardReference = $this->request->getCardReference()) { $transactionRef->setCardReference(new CardReference($cardReference)); } elseif ($bankAccount = $this->request->getBankAccount()) { - $transactionRef->setBankAccount(new BankAccount($bankAccount)); + $transactionRef->setBankAccount(array( + 'accountType' => $bankAccount->getAccountType(), + 'routingNumber' => $bankAccount->getRoutingNumber(), + 'accountNumber' => $bankAccount->getAccountNumber(), + 'nameOnAccount' => $bankAccount->getName(), + 'echeckType' => BankAccount::ECHECK_TYPE_WEB + )); } } catch (\Exception $e) { } diff --git a/src/Model/TransactionReference.php b/src/Model/TransactionReference.php index 6f345d5c..fc1ea033 100644 --- a/src/Model/TransactionReference.php +++ b/src/Model/TransactionReference.php @@ -38,7 +38,7 @@ public function __construct($data = null) $this->cardReference = new CardReference($data->cardReference); } if (isset($data->bankAccount)) { - $this->bankAccount = new BankAccount($data->bankAccount); + $this->bankAccount = $data->bankAccount; } } } @@ -59,7 +59,7 @@ public function __toString() $data['cardReference'] = (string)$this->cardReference; } if (isset($this->bankAccount)) { - $data['bankAccount'] = (string)$this->bankAccount; + $data['bankAccount'] = $this->bankAccount; } return json_encode($data); } @@ -129,7 +129,7 @@ public function setCardReference($cardReference) } /** - * @return BankAccount + * @return object */ public function getBankAccount() { @@ -137,7 +137,7 @@ public function getBankAccount() } /** - * @param string|BankAccount $bankAccount + * @param array $bankAccount */ public function setBankAccount($bankAccount) { From f780e12a756e9395639d787b7f337abab38cd758 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 14:27:29 -0500 Subject: [PATCH 246/254] feat: add eCheck testing --- tests/AIMGatewayTest.php | 75 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/tests/AIMGatewayTest.php b/tests/AIMGatewayTest.php index 7a6ce81c..502946a7 100644 --- a/tests/AIMGatewayTest.php +++ b/tests/AIMGatewayTest.php @@ -2,6 +2,7 @@ namespace Omnipay\AuthorizeNet; +use Omnipay\AuthorizeNet\Model\BankAccount; use Omnipay\Tests\GatewayTestCase; class AIMGatewayTest extends GatewayTestCase @@ -9,6 +10,7 @@ class AIMGatewayTest extends GatewayTestCase /** @var AIMGateway */ protected $gateway; protected $purchaseOptions; + protected $echeckOptions; protected $captureOptions; protected $voidOptions; protected $refundOptions; @@ -29,6 +31,12 @@ public function setUp() 'description' => 'purchase', ); + $this->echeckOptions = array( + 'amount' => '10.00', + 'bankAccount' => $this->getValidBankAccount(), + 'description' => 'purchase', + ); + $this->captureOptions = array( 'amount' => '10.00', 'transactionReference' => '12345', @@ -48,6 +56,32 @@ public function setUp() ); } + public function getValidBankAccount() + { + return array( + 'firstName' => 'Example', + 'lastName' => 'User', + 'accountType' => 'checking', + 'routingNumber' => '122105155', + 'accountNumber' => '123456789', + 'bankName' => 'U.S. Bank', + 'billingAddress1' => '123 Billing St', + 'billingAddress2' => 'Billsville', + 'billingCity' => 'Billstown', + 'billingPostcode' => '12345', + 'billingState' => 'CA', + 'billingCountry' => 'US', + 'billingPhone' => '(555) 123-4567', + 'shippingAddress1' => '123 Shipping St', + 'shippingAddress2' => 'Shipsville', + 'shippingCity' => 'Shipstown', + 'shippingPostcode' => '54321', + 'shippingState' => 'NY', + 'shippingCountry' => 'US', + 'shippingPhone' => '(555) 987-6543', + ); + } + public function testLiveEndpoint() { $this->assertEquals( @@ -78,6 +112,16 @@ private function getExpiry($card) return str_pad($card['expiryMonth'] . $card['expiryYear'], 6, '0', STR_PAD_LEFT); } + private function getBankAccountReference($bank) { + return json_encode(array( + 'accountType' => $bank['accountType'], + 'routingNumber' => $bank['routingNumber'], + 'accountNumber' => $bank['accountNumber'], + 'nameOnAccount' => $bank['firstName'] . ' ' . $bank['lastName'], + 'echeckType' => BankAccount::ECHECK_TYPE_WEB + )); + } + public function testAuthorizeSuccess() { $this->setMockHttpResponse('AIMAuthorizeSuccess.txt'); @@ -126,7 +170,7 @@ public function testCaptureFailure() $this->assertSame('{"approvalCode":"","transId":"0"}', $response->getTransactionReference()); $this->assertSame('The transaction cannot be found.', $response->getMessage()); } - + public function testCaptureOnlySuccess() { $this->setMockHttpResponse('AIMCaptureOnlySuccess.txt'); @@ -148,7 +192,8 @@ public function testCaptureOnlyFailure() $this->assertSame('{"approvalCode":"ROHNFQ","transId":"0"}', $response->getTransactionReference()); $this->assertSame('A valid amount is required.', $response->getMessage()); } - public function testPurchaseSuccess() + + public function testCardPurchaseSuccess() { $this->setMockHttpResponse('AIMPurchaseSuccess.txt'); @@ -160,7 +205,7 @@ public function testPurchaseSuccess() $this->assertSame('This transaction has been approved.', $response->getMessage()); } - public function testPurchaseFailure() + public function testCardPurchaseFailure() { $this->setMockHttpResponse('AIMPurchaseFailure.txt'); @@ -172,6 +217,30 @@ public function testPurchaseFailure() $this->assertSame('A valid amount is required.', $response->getMessage()); } + public function testEcheckPurchaseSuccess() + { + $this->setMockHttpResponse('AIMEcheckPurchaseSuccess.txt'); + + $response = $this->gateway->purchase($this->echeckOptions)->send(); + + $this->assertTrue($response->isSuccessful()); + $bankAccountReference = $this->getBankAccountReference($this->echeckOptions['bankAccount']); + $this->assertSame('{"approvalCode":"","transId":"2214627492","bankAccount":' . $bankAccountReference . '}', $response->getTransactionReference()); + $this->assertSame('This transaction has been approved.', $response->getMessage()); + } + + public function testEcheckPurchaseFailure() + { + $this->setMockHttpResponse('AIMEcheckPurchaseFailure.txt'); + + $response = $this->gateway->purchase($this->echeckOptions)->send(); + + $this->assertFalse($response->isSuccessful()); + $bankAccountReference = $this->getBankAccountReference($this->echeckOptions['bankAccount']); + $this->assertSame('{"approvalCode":"","transId":"0","bankAccount":' . $bankAccountReference . '}', $response->getTransactionReference()); + $this->assertSame('The given name on the account and/or the account type does not match the actual account.', $response->getMessage()); + } + public function testVoidSuccess() { $this->setMockHttpResponse('AIMVoidSuccess.txt'); From e85fd2e166ea37aa96df2f4a5f49b0856bfa4dbf Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Fri, 10 Jan 2020 14:28:09 -0500 Subject: [PATCH 247/254] feat: add BankAccount testing - similar to Omnipay/Common/CreditCard --- tests/Model/BankAccountTest.php | 502 ++++++++++++++++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 tests/Model/BankAccountTest.php diff --git a/tests/Model/BankAccountTest.php b/tests/Model/BankAccountTest.php new file mode 100644 index 00000000..a0f6468c --- /dev/null +++ b/tests/Model/BankAccountTest.php @@ -0,0 +1,502 @@ +bank = new BankAccount; + $this->bank->setAccountType('checking'); + $this->bank->setRoutingNumber('122105155'); + $this->bank->setAccountNumber('123456789'); + $this->bank->setFirstName('Example'); + $this->bank->setLastName('Customer'); + } + + public function testConstructWithParams() + { + $bank = new BankAccount(array('name' => 'Test Customer')); + $this->assertSame('Test Customer', $bank->getName()); + } + + public function testInitializeWithParams() + { + $bank = new BankAccount; + $bank->initialize(array('name' => 'Test Customer')); + $this->assertSame('Test Customer', $bank->getName()); + } + + public function testGetParamters() + { + $bank = new BankAccount(array( + 'name' => 'Example Customer', + 'routingNumber' => '123456789', + 'accountNumber' => '987654321', + 'accountType' => 'checking' + )); + + $parameters = $bank->getParameters(); + $this->assertSame('Example', $parameters['billingFirstName']); + $this->assertSame('Customer', $parameters['billingLastName']); + $this->assertSame('123456789', $parameters['routingNumber']); + $this->assertSame('987654321', $parameters['accountNumber']); + $this->assertSame('checking', $parameters['accountType']); + } + + /** + * @doesNotPerformAssertions + */ + public function testValidateFixture() + { + $this->bank->validate(); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The bank account type is required + */ + public function testValidateAccountTypeRequired() + { + $this->bank->setAccountType(null); + $this->bank->validate(); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The bank routing number is required + */ + public function testValidateRoutingNumberRequired() + { + $this->bank->setRoutingNumber(null); + $this->bank->validate(); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The bank account number is required + */ + public function testValidateAccountNumberRequired() + { + $this->bank->setAccountNumber(null); + $this->bank->validate(); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The bank account type is not in the supported list + */ + public function testValidateAccountType() + { + $this->bank->setAccountType(BankAccount::ACCOUNT_TYPE_BUSINESS_CHECKING); + $this->bank->validate(); + } + + public function testGetSupportedAccountTypes() + { + $accountTypes = $this->bank->getSupportedAccountTypes(); + $this->assertInternalType('array', $accountTypes); + $this->assertContains(BankAccount::ACCOUNT_TYPE_CHECKING, $accountTypes); + } + + public function testTitle() + { + $this->bank->setTitle('Mr.'); + $this->assertEquals('Mr.', $this->bank->getTitle()); + } + + public function testFirstName() + { + $this->bank->setFirstName('Bob'); + $this->assertEquals('Bob', $this->bank->getFirstName()); + } + + public function testLastName() + { + $this->bank->setLastName('Smith'); + $this->assertEquals('Smith', $this->bank->getLastName()); + } + + public function testGetName() + { + $this->bank->setFirstName('Bob'); + $this->bank->setLastName('Smith'); + $this->assertEquals('Bob Smith', $this->bank->getName()); + } + + public function testSetName() + { + $this->bank->setName('Bob Smith'); + $this->assertEquals('Bob', $this->bank->getFirstName()); + $this->assertEquals('Smith', $this->bank->getLastName()); + } + + public function testSetNameWithOneName() + { + $this->bank->setName('Bob'); + $this->assertEquals('Bob', $this->bank->getFirstName()); + $this->assertEquals('', $this->bank->getLastName()); + } + + public function testSetNameWithMultipleNames() + { + $this->bank->setName('Bob John Smith'); + $this->assertEquals('Bob', $this->bank->getFirstName()); + $this->assertEquals('John Smith', $this->bank->getLastName()); + } + + public function testRoutingNumber() + { + $this->bank->setRoutingNumber('123456789'); + $this->assertEquals('123456789', $this->bank->getRoutingNumber()); + } + + public function testSetRoutingNumberStripsNonDigits() + { + $this->bank->setRoutingNumber('12345 6789'); + $this->assertEquals('123456789', $this->bank->getRoutingNumber()); + } + + public function testAccountNumber() + { + $this->bank->setAccountNumber('123456789'); + $this->assertEquals('123456789', $this->bank->getAccountNumber()); + } + + public function testSetAccountNumberStripsNonDigits() + { + $this->bank->setAccountNumber('12345 6789'); + $this->assertEquals('123456789', $this->bank->getAccountNumber()); + } + + public function testGetAccountNumberLastFourNull() + { + $this->bank->setAccountNumber(null); + $this->assertNull($this->bank->getAccountNumberLastFour()); + } + + public function testGetAccountNumberLastFour() + { + $this->bank->setAccountNumber('111116789'); + $this->assertSame('6789', $this->bank->getAccountNumberLastFour()); + } + + public function testGetAccountNumberLastFourNonDigits() + { + $this->bank->setAccountNumber('11111 67x89'); + $this->assertSame('6789', $this->bank->getAccountNumberLastFour()); + } + + public function testGetAccountNumberMasked() + { + $this->bank->setAccountNumber('111116789'); + $this->assertSame('XXXXX6789', $this->bank->getAccountNumberMasked()); + } + + public function testGetAccountNumberMaskedNonDigits() + { + $this->bank->setAccountNumber('11111 67x89'); + $this->assertSame('XXXXX6789', $this->bank->getAccountNumberMasked()); + } + + public function testBillingTitle() + { + $this->bank->setBillingTitle('Mrs.'); + $this->assertEquals('Mrs.', $this->bank->getBillingTitle()); + $this->assertEquals('Mrs.', $this->bank->getTitle()); + } + + public function testBillingFirstName() + { + $this->bank->setBillingFirstName('Bob'); + $this->assertEquals('Bob', $this->bank->getBillingFirstName()); + $this->assertEquals('Bob', $this->bank->getFirstName()); + } + + public function testBillingLastName() + { + $this->bank->setBillingLastName('Smith'); + $this->assertEquals('Smith', $this->bank->getBillingLastName()); + $this->assertEquals('Smith', $this->bank->getLastName()); + } + + public function testBillingName() + { + $this->bank->setBillingFirstName('Bob'); + $this->bank->setBillingLastName('Smith'); + $this->assertEquals('Bob Smith', $this->bank->getBillingName()); + + $this->bank->setBillingName('John Foo'); + $this->assertEquals('John', $this->bank->getBillingFirstName()); + $this->assertEquals('Foo', $this->bank->getBillingLastName()); + } + + public function testBillingCompany() + { + $this->bank->setBillingCompany('SuperSoft'); + $this->assertEquals('SuperSoft', $this->bank->getBillingCompany()); + $this->assertEquals('SuperSoft', $this->bank->getCompany()); + } + + public function testBillingAddress1() + { + $this->bank->setBillingAddress1('31 Spooner St'); + $this->assertEquals('31 Spooner St', $this->bank->getBillingAddress1()); + $this->assertEquals('31 Spooner St', $this->bank->getAddress1()); + } + + public function testBillingAddress2() + { + $this->bank->setBillingAddress2('Suburb'); + $this->assertEquals('Suburb', $this->bank->getBillingAddress2()); + $this->assertEquals('Suburb', $this->bank->getAddress2()); + } + + public function testBillingCity() + { + $this->bank->setBillingCity('Quahog'); + $this->assertEquals('Quahog', $this->bank->getBillingCity()); + $this->assertEquals('Quahog', $this->bank->getCity()); + } + + public function testBillingPostcode() + { + $this->bank->setBillingPostcode('12345'); + $this->assertEquals('12345', $this->bank->getBillingPostcode()); + $this->assertEquals('12345', $this->bank->getPostcode()); + } + + public function testBillingState() + { + $this->bank->setBillingState('RI'); + $this->assertEquals('RI', $this->bank->getBillingState()); + $this->assertEquals('RI', $this->bank->getState()); + } + + public function testBillingCountry() + { + $this->bank->setBillingCountry('US'); + $this->assertEquals('US', $this->bank->getBillingCountry()); + $this->assertEquals('US', $this->bank->getCountry()); + } + + public function testBillingPhone() + { + $this->bank->setBillingPhone('12345'); + $this->assertSame('12345', $this->bank->getBillingPhone()); + $this->assertSame('12345', $this->bank->getPhone()); + } + + public function testBillingPhoneExtension() + { + $this->bank->setBillingPhoneExtension('001'); + $this->assertSame('001', $this->bank->getBillingPhoneExtension()); + $this->assertSame('001', $this->bank->getPhoneExtension()); + } + + public function testBillingFax() + { + $this->bank->setBillingFax('54321'); + $this->assertSame('54321', $this->bank->getBillingFax()); + $this->assertSame('54321', $this->bank->getFax()); + } + + public function testShippingTitle() + { + $this->bank->setShippingTitle('Dr.'); + $this->assertEquals('Dr.', $this->bank->getShippingTitle()); + } + + public function testShippingFirstName() + { + $this->bank->setShippingFirstName('James'); + $this->assertEquals('James', $this->bank->getShippingFirstName()); + } + + public function testShippingLastName() + { + $this->bank->setShippingLastName('Doctor'); + $this->assertEquals('Doctor', $this->bank->getShippingLastName()); + } + + public function testShippingName() + { + $this->bank->setShippingFirstName('Bob'); + $this->bank->setShippingLastName('Smith'); + $this->assertEquals('Bob Smith', $this->bank->getShippingName()); + + $this->bank->setShippingName('John Foo'); + $this->assertEquals('John', $this->bank->getShippingFirstName()); + $this->assertEquals('Foo', $this->bank->getShippingLastName()); + } + + public function testShippingCompany() + { + $this->bank->setShippingCompany('SuperSoft'); + $this->assertEquals('SuperSoft', $this->bank->getShippingCompany()); + } + + public function testShippingAddress1() + { + $this->bank->setShippingAddress1('31 Spooner St'); + $this->assertEquals('31 Spooner St', $this->bank->getShippingAddress1()); + } + + public function testShippingAddress2() + { + $this->bank->setShippingAddress2('Suburb'); + $this->assertEquals('Suburb', $this->bank->getShippingAddress2()); + } + + public function testShippingCity() + { + $this->bank->setShippingCity('Quahog'); + $this->assertEquals('Quahog', $this->bank->getShippingCity()); + } + + public function testShippingPostcode() + { + $this->bank->setShippingPostcode('12345'); + $this->assertEquals('12345', $this->bank->getShippingPostcode()); + } + + public function testShippingState() + { + $this->bank->setShippingState('RI'); + $this->assertEquals('RI', $this->bank->getShippingState()); + } + + public function testShippingCountry() + { + $this->bank->setShippingCountry('US'); + $this->assertEquals('US', $this->bank->getShippingCountry()); + } + + public function testShippingPhone() + { + $this->bank->setShippingPhone('12345'); + $this->assertEquals('12345', $this->bank->getShippingPhone()); + } + + public function testShippingPhoneExtension() + { + $this->bank->setShippingPhoneExtension('001'); + $this->assertEquals('001', $this->bank->getShippingPhoneExtension()); + } + + public function testShippingFax() + { + $this->bank->setShippingFax('54321'); + $this->assertEquals('54321', $this->bank->getShippingFax()); + } + + public function testCompany() + { + $this->bank->setCompany('FooBar'); + $this->assertEquals('FooBar', $this->bank->getCompany()); + $this->assertEquals('FooBar', $this->bank->getBillingCompany()); + $this->assertEquals('FooBar', $this->bank->getShippingCompany()); + } + + public function testAddress1() + { + $this->bank->setAddress1('31 Spooner St'); + $this->assertEquals('31 Spooner St', $this->bank->getAddress1()); + $this->assertEquals('31 Spooner St', $this->bank->getBillingAddress1()); + $this->assertEquals('31 Spooner St', $this->bank->getShippingAddress1()); + } + + public function testAddress2() + { + $this->bank->setAddress2('Suburb'); + $this->assertEquals('Suburb', $this->bank->getAddress2()); + $this->assertEquals('Suburb', $this->bank->getBillingAddress2()); + $this->assertEquals('Suburb', $this->bank->getShippingAddress2()); + } + + public function testCity() + { + $this->bank->setCity('Quahog'); + $this->assertEquals('Quahog', $this->bank->getCity()); + $this->assertEquals('Quahog', $this->bank->getBillingCity()); + $this->assertEquals('Quahog', $this->bank->getShippingCity()); + } + + public function testPostcode() + { + $this->bank->setPostcode('12345'); + $this->assertEquals('12345', $this->bank->getPostcode()); + $this->assertEquals('12345', $this->bank->getBillingPostcode()); + $this->assertEquals('12345', $this->bank->getShippingPostcode()); + } + + public function testState() + { + $this->bank->setState('RI'); + $this->assertEquals('RI', $this->bank->getState()); + $this->assertEquals('RI', $this->bank->getBillingState()); + $this->assertEquals('RI', $this->bank->getShippingState()); + } + + public function testCountry() + { + $this->bank->setCountry('US'); + $this->assertEquals('US', $this->bank->getCountry()); + $this->assertEquals('US', $this->bank->getBillingCountry()); + $this->assertEquals('US', $this->bank->getShippingCountry()); + } + + public function testPhone() + { + $this->bank->setPhone('12345'); + $this->assertEquals('12345', $this->bank->getPhone()); + $this->assertEquals('12345', $this->bank->getBillingPhone()); + $this->assertEquals('12345', $this->bank->getShippingPhone()); + } + + public function testPhoneExtension() + { + $this->bank->setPhoneExtension('001'); + $this->assertEquals('001', $this->bank->getPhoneExtension()); + $this->assertEquals('001', $this->bank->getBillingPhoneExtension()); + $this->assertEquals('001', $this->bank->getShippingPhoneExtension()); + } + + public function testFax() + { + $this->bank->setFax('54321'); + $this->assertEquals('54321', $this->bank->getFax()); + $this->assertEquals('54321', $this->bank->getBillingFax()); + $this->assertEquals('54321', $this->bank->getShippingFax()); + } + + public function testEmail() + { + $this->bank->setEmail('adrian@example.com'); + $this->assertEquals('adrian@example.com', $this->bank->getEmail()); + } + + public function testBirthday() + { + $this->bank->setBirthday('01-02-2000'); + $this->assertEquals('2000-02-01', $this->bank->getBirthday()); + $this->assertEquals('01/02/2000', $this->bank->getBirthday('d/m/Y')); + } + + public function testBirthdayEmpty() + { + $this->bank->setBirthday(''); + $this->assertNull($this->bank->getBirthday()); + } + + public function testGender() + { + $this->bank->setGender('female'); + $this->assertEquals('female', $this->bank->getGender()); + } +} From 77053dafa70432f2267f18bf40102c260cf38401 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Tue, 14 Jan 2020 13:42:16 -0500 Subject: [PATCH 248/254] feat: custom exception --- src/Exception/InvalidBankAccountException.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/Exception/InvalidBankAccountException.php diff --git a/src/Exception/InvalidBankAccountException.php b/src/Exception/InvalidBankAccountException.php new file mode 100644 index 00000000..78d55ef7 --- /dev/null +++ b/src/Exception/InvalidBankAccountException.php @@ -0,0 +1,14 @@ + Date: Tue, 14 Jan 2020 13:43:42 -0500 Subject: [PATCH 249/254] feat: add regex for routing number --- src/Model/BankAccount.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Model/BankAccount.php b/src/Model/BankAccount.php index d66aabea..792a0b44 100644 --- a/src/Model/BankAccount.php +++ b/src/Model/BankAccount.php @@ -95,6 +95,13 @@ class BankAccount const ECHECK_TYPE_TEL = 'TEL'; const ECHECK_TYPE_WEB = 'WEB'; + /** + * The regular expression for validating routing numbers + * + * @link http://www.routingnumber.com + */ + const ROUTING_NUMBER_REGEX = '/^(0\d|1[0-2]|2[1-9]|3[0-2]|6[1-9]|7[0-2]|80)\d{7}$/'; + /** * All known/supported account types * From af7de01278404f64d2a128dee303c5e377a08e0a Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Tue, 14 Jan 2020 14:01:15 -0500 Subject: [PATCH 250/254] feat: use custom exception --- src/Model/BankAccount.php | 11 ++++++----- tests/Model/BankAccountTest.php | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/Model/BankAccount.php b/src/Model/BankAccount.php index 792a0b44..5e8c3647 100644 --- a/src/Model/BankAccount.php +++ b/src/Model/BankAccount.php @@ -7,8 +7,9 @@ use DateTime; use DateTimeZone; -use Symfony\Component\HttpFoundation\ParameterBag; +use Omnipay\AuthorizeNet\Exception\InvalidBankAccountException; use Omnipay\Common\Helper; +use Symfony\Component\HttpFoundation\ParameterBag; /** * Bank Account class @@ -185,10 +186,10 @@ protected function setParameter($key, $value) } /** - * Validate this bank account. If the bank account is invalid, InvalidArgumentException is thrown. + * Validate this bank account. If the bank account is invalid, InvalidBankAccountException is thrown. * * @return void - * @throws InvalidArgumentException + * @throws InvalidBankAccountException */ public function validate() { @@ -200,12 +201,12 @@ public function validate() foreach ($requiredParameters as $key => $val) { if (!$this->getParameter($key)) { - throw new \InvalidArgumentException("The $val is required"); + throw new InvalidBankAccountException("The $val is required"); } } if (!in_array($this->getAccountType(), $this->getSupportedAccountTypes())) { - throw new \InvalidArgumentException('The bank account type is not in the supported list'); + throw new InvalidBankAccountException('The bank account type is not in the supported list'); } } diff --git a/tests/Model/BankAccountTest.php b/tests/Model/BankAccountTest.php index a0f6468c..16f3aa63 100644 --- a/tests/Model/BankAccountTest.php +++ b/tests/Model/BankAccountTest.php @@ -58,7 +58,7 @@ public function testValidateFixture() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Omnipay\AuthorizeNet\Exception\InvalidBankAccountException * @expectedExceptionMessage The bank account type is required */ public function testValidateAccountTypeRequired() @@ -68,7 +68,7 @@ public function testValidateAccountTypeRequired() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Omnipay\AuthorizeNet\Exception\InvalidBankAccountException * @expectedExceptionMessage The bank routing number is required */ public function testValidateRoutingNumberRequired() @@ -78,7 +78,7 @@ public function testValidateRoutingNumberRequired() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Omnipay\AuthorizeNet\Exception\InvalidBankAccountException * @expectedExceptionMessage The bank account number is required */ public function testValidateAccountNumberRequired() @@ -88,7 +88,7 @@ public function testValidateAccountNumberRequired() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Omnipay\AuthorizeNet\Exception\InvalidBankAccountException * @expectedExceptionMessage The bank account type is not in the supported list */ public function testValidateAccountType() From 23e286cf355b4bb8ce2d6467a2dfcd59a7b57825 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Tue, 14 Jan 2020 14:02:04 -0500 Subject: [PATCH 251/254] feat: validate the routing number matches regex & passes checksum --- src/Model/BankAccount.php | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/Model/BankAccount.php b/src/Model/BankAccount.php index 5e8c3647..176630a5 100644 --- a/src/Model/BankAccount.php +++ b/src/Model/BankAccount.php @@ -208,6 +208,37 @@ public function validate() if (!in_array($this->getAccountType(), $this->getSupportedAccountTypes())) { throw new InvalidBankAccountException('The bank account type is not in the supported list'); } + + if (!is_null($this->getRoutingNumber()) + && !preg_match('/^\d{9}$/i', $this->getRoutingNumber()) + ) { + throw new InvalidBankAccountException('The bank routing number should have 9 digits'); + } + + if (!preg_match(self::ROUTING_NUMBER_REGEX, $this->getRoutingNumber()) + || !$this->validateChecksum($this->getRoutingNumber()) + ) { + throw new InvalidBankAccountException('The bank routing number is invalid'); + } + } + + /** + * Validate a bank routing number according to the checksum algorithm. + * + * @link https://github.com/activemerchant/active_merchant/blob/master/lib/active_merchant/billing/check.rb + * @param string $number The bank routing number to validate + * @return bool True if the supplied bank routing number is valid + */ + private function validateChecksum($number) + { + $split = array_chunk(str_split($number), 3); + $function = function ($chars) { + return ($chars[0] * 3) + + ($chars[1] * 7) + + ($chars[2]); + }; + + return array_sum(array_map($function, $split)) % 10 === 0; } /** From 09493b43f9e7bf5fe2d6990df0c7f07c2d3b9f58 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Tue, 14 Jan 2020 14:02:19 -0500 Subject: [PATCH 252/254] feat: add testing for routing number validation --- tests/Model/BankAccountTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Model/BankAccountTest.php b/tests/Model/BankAccountTest.php index 16f3aa63..937ee67c 100644 --- a/tests/Model/BankAccountTest.php +++ b/tests/Model/BankAccountTest.php @@ -97,6 +97,26 @@ public function testValidateAccountType() $this->bank->validate(); } + /** + * @expectedException \Omnipay\AuthorizeNet\Exception\InvalidBankAccountException + * @expectedExceptionMessage The bank routing number should have 9 digits + */ + public function testValidateRoutingNumberLength() + { + $this->bank->setRoutingNumber(12345678); + $this->bank->validate(); + } + + /** + * @expectedException \Omnipay\AuthorizeNet\Exception\InvalidBankAccountException + * @expectedExceptionMessage The bank routing number is invalid + */ + public function testValidateRoutingNumber() + { + $this->bank->setRoutingNumber(123456789); + $this->bank->validate(); + } + public function testGetSupportedAccountTypes() { $accountTypes = $this->bank->getSupportedAccountTypes(); From 319d671804d8aa368c047a30d23fd7eff2a1a1b1 Mon Sep 17 00:00:00 2001 From: Tymotheos Szulc Date: Wed, 15 Jan 2020 09:10:56 -0500 Subject: [PATCH 253/254] fix: swap elements to be in the correct order The element 'bankAccount' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd' has invalid child element 'echeckType' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. List of possible elements expected: 'checkNumber' in namespace 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'. --- src/Message/AIMAuthorizeRequest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Message/AIMAuthorizeRequest.php b/src/Message/AIMAuthorizeRequest.php index 1b94655c..e901b669 100644 --- a/src/Message/AIMAuthorizeRequest.php +++ b/src/Message/AIMAuthorizeRequest.php @@ -136,12 +136,12 @@ protected function addPayment(\SimpleXMLElement $data) ->transactionRequest ->payment ->bankAccount - ->bankName = $bankAccount->getBankName(); + ->echeckType = BankAccount::ECHECK_TYPE_WEB; $data ->transactionRequest ->payment ->bankAccount - ->echeckType = BankAccount::ECHECK_TYPE_WEB; + ->bankName = $bankAccount->getBankName(); } } From 1b9c64ed74c556ae471eec40095abd4f5bb0edf3 Mon Sep 17 00:00:00 2001 From: Jason Judge Date: Sun, 25 Oct 2020 23:23:11 +0000 Subject: [PATCH 254/254] Issue #135 added clarificartion to help example. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 6bf31f30..c348d150 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,21 @@ recipient, but just leave the credit card details of that object blank. For exam // $gateway is an instantiation of the AIM driver. // $dataDescriptor and $dataValue come from the payment form at the front end. +use Omnipay\Common\CreditCard; + $request = $gateway->purchase( [ 'notifyUrl' => '...', 'amount' => $amount, + // 'opaqueDataDescriptor' => $dataDescriptor, 'opaqueDataValue' => $dataValue, + // + 'card' => new CreditCard([ + 'firstName' => 'Anne', + 'lastName' => 'Payee', + ... + ]), ... ] );