Skip to content

Commit f4fc378

Browse files
committed
Merge pull request thephpleague#12 from rushi/XOL-2788
XOL-2788 Void an Authorize.net transaction if it has not been settled
2 parents adfd19b + c7d9a71 commit f4fc378

File tree

9 files changed

+106
-10
lines changed

9 files changed

+106
-10
lines changed

src/Message/CIMAbstractRequest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,13 @@ public function getBaseData()
9393

9494
return $data;
9595
}
96+
97+
public function sendData($data)
98+
{
99+
$headers = array('Content-Type' => 'text/xml; charset=utf-8');
100+
$data = $data->saveXml();
101+
$httpResponse = $this->httpClient->post($this->getEndpoint(), $headers, $data)->send();
102+
103+
return $this->response = new CIMResponse($this, $httpResponse->getBody());
104+
}
96105
}

src/Message/CIMAbstractResponse.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/**
1111
* Authorize.Net CIM Response
1212
*/
13-
class CIMAbstractResponse extends AbstractResponse
13+
abstract class CIMAbstractResponse extends AbstractResponse
1414
{
1515
protected $xmlRootElement = null;
1616

@@ -79,6 +79,21 @@ public function getReasonCode()
7979
return $code;
8080
}
8181

82+
/**
83+
* A reason code is the a part of the "directResponse" attribute returned by Authorize.net. This is the third
84+
* element within the "directResponse" attribute which is a CSV string.
85+
*/
86+
public function getResponseReasonCode()
87+
{
88+
$responseCode = null;
89+
if (isset($this->data['directResponse'])) {
90+
$directResponse = explode(',', (string)$this->data['directResponse']);
91+
$responseCode = $directResponse[2];
92+
}
93+
94+
return $responseCode;
95+
}
96+
8297
/**
8398
* Text description of the status.
8499
*

src/Message/CIMRefundRequest.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,24 @@ class CIMRefundRequest extends CIMCaptureRequest
99
{
1010
protected $action = "profileTransRefund";
1111

12+
protected $voidIfRefundFails = false;
13+
14+
/**
15+
* @return boolean
16+
*/
17+
public function isVoidIfRefundFails()
18+
{
19+
return $this->voidIfRefundFails;
20+
}
21+
22+
/**
23+
* @param boolean $voidIfRefundFails
24+
*/
25+
public function setVoidIfRefundFails($voidIfRefundFails)
26+
{
27+
$this->voidIfRefundFails = $voidIfRefundFails;
28+
}
29+
1230
/**
1331
* Adds reference for original transaction to a partially filled request data object.
1432
*
@@ -25,4 +43,21 @@ protected function addTransactionReferenceData(\SimpleXMLElement $data)
2543
$action->transId = $transRef['transId'];
2644
return $data;
2745
}
46+
47+
public function send()
48+
{
49+
/** @var CIMResponse $response */
50+
$response = parent::send();
51+
$parameters = $this->getParameters();
52+
53+
if (!$response->isSuccessful() && $this->voidIfRefundFails &&
54+
$response->getResponseReasonCode() === CIMResponse::ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT) {
55+
// An attempt to a refund a transaction that was not settled. We can just void the entire transaction
56+
$voidRequest = new CIMVoidRequest($this->httpClient, $this->httpRequest);
57+
$voidRequest->initialize($parameters);
58+
$response = $voidRequest->send();
59+
}
60+
61+
return $response;
62+
}
2863
}

src/Message/CIMResponse.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
*/
88
class CIMResponse extends CIMAbstractResponse
99
{
10+
/**
11+
* For Error codes: @see https://developer.authorize.net/api/reference/responseCodes.html
12+
*/
13+
const ERROR_RESPONSE_CODE_CANNOT_ISSUE_CREDIT = '54';
14+
1015
protected $xmlRootElement = 'createCustomerProfileTransactionResponse';
1116

1217
public function getTransactionReference()

src/Message/CIMVoidRequest.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@
77
*/
88
class CIMVoidRequest extends CIMAbstractRequest
99
{
10+
protected $xmlRootElement = 'createCustomerProfileTransactionRequest';
1011
protected $action = 'voidTransaction';
1112

1213
public function getData()
1314
{
1415
$this->validate('transactionReference');
1516

1617
$data = $this->getBaseData();
17-
$data->transactionRequest->refTransId = $this->getTransactionReference();
18-
$this->addTestModeSetting($data);
18+
$transRef = json_decode($this->getTransactionReference(), true);
19+
if (is_array($transRef) && isset($transRef['transId'])) {
20+
$data->transaction->profileTransVoid->transId = $transRef["transId"];
21+
}
1922

2023
return $data;
2124
}

tests/CIMGatewayIntegrationTest.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,13 @@ public function testAuthorizeAndVoid()
164164
$this->assertTrue($response->isSuccessful(), 'Purchase transaction should get created');
165165
$this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist');
166166

167-
$transactionRef = json_decode($response->getTransactionReference(), true);
168-
169167
// Make a refund on the purchase transaction
170-
$params = array('transactionReference' => $transactionRef['transId']);
171-
$request = $this->gateway->void($params);
168+
$request = $this->gateway->void(array('transactionReference' => $response->getTransactionReference()));
172169
$request->setDeveloperMode(true);
173170

174171
$response = $request->send();
175172
$this->assertTrue($response->isSuccessful(), 'Refund transaction should get created');
176173
$this->assertNotNull($response->getTransactionReference(), 'Transaction reference should exist');
174+
$this->assertEquals('Successful.', $response->getMessage());
177175
}
178176
}

tests/CIMGatewayTest.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,12 +220,22 @@ public function testRefundFailure()
220220
$response = $this->gateway->refund($this->refundOptions)->send();
221221

222222
$this->assertFalse($response->isSuccessful());
223-
$this->assertNull(
224-
$response->getTransactionReference()
225-
);
223+
$this->assertNull($response->getTransactionReference());
226224
$this->assertSame(
227225
'The referenced transaction does not meet the criteria for issuing a credit.',
228226
$response->getMessage()
229227
);
230228
}
229+
230+
public function testShouldVoidTransactionIfTryingToRefundAnUnsettledTransaction()
231+
{
232+
$this->setMockHttpResponse(array('CIMRefundFailure.txt', 'CIMVoidResponse.txt'));
233+
$this->refundOptions['voidIfRefundFails'] = true;
234+
235+
$response = $this->gateway->refund($this->refundOptions)->send();
236+
237+
$this->assertTrue($response->isSuccessful());
238+
$this->assertNotNull($response->getTransactionReference());
239+
$this->assertEquals('Successful.', $response->getMessage());
240+
}
231241
}

tests/Message/CIMResponseTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,12 @@ public function testGetTransactionReference()
2929
$response->getTransactionReference()
3030
);
3131
}
32+
33+
public function testShouldReturnResponseReasonCodeFromDirectResponse()
34+
{
35+
$httpResponse = $this->getMockHttpResponse('CIMRefundFailure.txt')->getBody();
36+
$response = new CIMResponse($this->getMockRequest(), $httpResponse);
37+
38+
$this->assertEquals(54, $response->getResponseReasonCode());
39+
}
3240
}

tests/Mock/CIMVoidResponse.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
HTTP/1.1 200 OK
2+
Date: Sat, 02 Aug 2014 06:07:08 GMT
3+
Server: Microsoft-IIS/6.0
4+
Access-Control-Allow-Origin: *
5+
Access-Control-Allow-Methods: GET, POST, OPTIONS
6+
Access-Control-Allow-Headers: x-requested-with, cache-control, content-type, origin, method
7+
X-Powered-By: ASP.NET
8+
X-AspNet-Version: 2.0.50727
9+
Cache-Control: private
10+
Content-Type: text/xml; charset=utf-8
11+
Content-Length: 836
12+
13+
<?xml version="1.0" encoding="utf-8"?><createCustomerProfileTransactionResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><directResponse>1,1,1,This transaction has been approved.,4A6ZAK,P,2252208237,,,0.00,CC,void,,,,,,,,12345,,,,,,,,,,,,,,,,,,0E3D23E0BB8AD22BDFD412B205E42308,,,,,,,,,,,,,XXXX1111,Visa,,,,,,,,,,,,,,,,</directResponse></createCustomerProfileTransactionResponse>

0 commit comments

Comments
 (0)