Skip to content

Commit efede11

Browse files
committed
Add support for uppercase responses, more unit tests, some more documentation
1 parent 8a6a7b3 commit efede11

File tree

4 files changed

+140
-21
lines changed

4 files changed

+140
-21
lines changed

src/Message/CompletePurchaseResponse.php

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class CompletePurchaseResponse extends AbstractResponse
1414
protected $merchantParameters;
1515
/** @var string */
1616
protected $returnSignature;
17+
/** @var boolean */
18+
protected $usingUpcaseParameters = false;
19+
/** @var boolean */
20+
protected $usingUpcaseResponse = false;
1721

1822
/**
1923
* Constructor
@@ -27,22 +31,31 @@ public function __construct(RequestInterface $request, $data)
2731
{
2832
parent::__construct($request, $data);
2933

30-
$this->merchantParameters = $this->decodeMerchantParameters($data['Ds_MerchantParameters']);
34+
if (!empty($data['Ds_MerchantParameters'])) {
35+
$this->merchantParameters = $this->decodeMerchantParameters($data['Ds_MerchantParameters']);
36+
} elseif (!empty($data['DS_MERCHANTPARAMETERS'])) {
37+
$this->merchantParameters = $this->decodeMerchantParameters($data['DS_MERCHANTPARAMETERS']);
38+
$this->usingUpcaseResponse = true;
39+
} else {
40+
throw new InvalidResponseException('Invalid response from payment gateway (no data)');
41+
}
42+
3143
if (!empty($this->merchantParameters['Ds_Order'])) {
3244
$order = $this->merchantParameters['Ds_Order'];
3345
} elseif (!empty($this->merchantParameters['DS_ORDER'])) {
3446
$order = $this->merchantParameters['DS_ORDER'];
47+
$this->usingUpcaseParameters = true;
3548
} else {
3649
throw new InvalidResponseException();
3750
}
3851

3952
$this->returnSignature = $this->createReturnSignature(
40-
$data['Ds_MerchantParameters'],
53+
$data[$this->usingUpcaseResponse ? 'DS_MERCHANTPARAMETERS' : 'Ds_MerchantParameters'],
4154
$order,
4255
base64_decode($this->request->getHmacKey())
4356
);
4457

45-
if ($this->returnSignature != $data['Ds_Signature']) {
58+
if ($this->returnSignature != $data[$this->usingUpcaseResponse ? 'DS_SIGNATURE' : 'Ds_Signature']) {
4659
throw new InvalidResponseException('Invalid response from payment gateway (signature mismatch)');
4760
}
4861
}
@@ -54,10 +67,11 @@ public function __construct(RequestInterface $request, $data)
5467
*/
5568
public function isSuccessful()
5669
{
57-
return isset($this->merchantParameters['Ds_Response'])
58-
&& is_numeric($this->merchantParameters['Ds_Response'])
59-
&& 0 <= $this->merchantParameters['Ds_Response']
60-
&& 100 > $this->merchantParameters['Ds_Response'];
70+
$key = $this->usingUpcaseParameters ? 'DS_RESPONSE' : 'Ds_Response';
71+
return isset($this->merchantParameters[$key])
72+
&& is_numeric($this->merchantParameters[$key])
73+
&& 0 <= $this->merchantParameters[$key]
74+
&& 100 > $this->merchantParameters[$key];
6175
}
6276

6377
/**
@@ -73,20 +87,46 @@ public function getData()
7387
: $data;
7488
}
7589

90+
/**
91+
* Helper method to get a specific merchant parameter if available.
92+
*
93+
* @return null|mixed
94+
*/
95+
protected function getKey($key)
96+
{
97+
if ($this->usingUpcaseParameters) {
98+
$key = strtoupper($key);
99+
}
100+
return isset($this->merchantParameters[$key]) ? $this->merchantParameters[$key] : null;
101+
}
102+
103+
/**
104+
* Get the authorisation code if available.
105+
*
106+
* @return null|string
107+
*/
76108
public function getTransactionReference()
77109
{
78-
return isset($this->merchantParameters['Ds_AuthorisationCode'])
79-
? $this->merchantParameters['Ds_AuthorisationCode']
80-
: null;
110+
return $this->getKey('Ds_AuthorisationCode');
81111
}
82112

113+
/**
114+
* Get the merchant response message if available.
115+
*
116+
* @return null|string
117+
*/
83118
public function getMessage()
84119
{
85-
return isset($this->merchantParameters['Ds_Response']) ? $this->merchantParameters['Ds_Response'] : null;
120+
return $this->getKey('Ds_Response');
86121
}
87122

123+
/**
124+
* Get the card type if available.
125+
*
126+
* @return null|string
127+
*/
88128
public function getCardType()
89129
{
90-
return isset($this->merchantParameters['Ds_Card_Type']) ? $this->merchantParameters['Ds_Card_Type'] : null;
130+
return $this->getKey('Ds_Card_Type');
91131
}
92132
}

tests/Message/CompletePurchaseResponseTest.php

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ public function testCompletePurchaseSuccess()
1717
$this->getMockRequest(),
1818
array(
1919
'Ds_SignatureVersion' => 'HMAC_SHA256_V1',
20-
'Ds_MerchantParameters' => 'eyJEc19TaWduYXR1cmVWZXJzaW9uIjoiSE1BQ19TSEEyNTZfVjEiLCJEc19EYXRlIjoiMTBcLzE'
21-
.'xXC8yMDE1IiwiRHNfSG91ciI6IjEyOjAwIiwiRHNfU2VjdXJlUGF5bWVudCI6IjEiLCJEc19BbW91bnQiOiIxNDUiLCJEc19D'
22-
.'dXJyZW5jeSI6Ijk3OCIsIkRzX09yZGVyIjoiMDEyM2FiYyIsIkRzX01lcmNoYW50Q29kZSI6Ijk5OTAwODg4MSIsIkRzX1Rlc'
23-
.'m1pbmFsIjoiODcxIiwiRHNfUmVzcG9uc2UiOiIwMDAwIiwiRHNfVHJhbnNhY3Rpb25UeXBlIjoiMCIsIkRzX01lcmNoYW50RG'
24-
.'F0YSI6IlJlZjogOTl6eiIsIkRzX0F1dGhvcmlzYXRpb25Db2RlIjoiOTk5OTk5IiwiRHNfQ29uc3VtZXJMYW5ndWFnZSI6IjI'
25-
.'iLCJEc19DYXJkX0NvdW50cnkiOiI3MjQifQ==',
26-
'Ds_Signature' => 'wq466V5gAoRNWf_UyJfdS9VuNKElkHCfMQrTA0Oy4QE=',
20+
'Ds_MerchantParameters' => 'eyJEc19EYXRlIjoiMTBcLzExXC8yMDE1IiwiRHNfSG91ciI6IjEyOjAwIiwiRHNfU2VjdXJlUGF'
21+
.'5bWVudCI6IjEiLCJEc19BbW91bnQiOiIxNDUiLCJEc19DdXJyZW5jeSI6Ijk3OCIsIkRzX09yZGVyIjoiMDEyM2FiYyIsIkRz'
22+
.'X01lcmNoYW50Q29kZSI6Ijk5OTAwODg4MSIsIkRzX1Rlcm1pbmFsIjoiODcxIiwiRHNfUmVzcG9uc2UiOiIwMDAwIiwiRHNfV'
23+
.'HJhbnNhY3Rpb25UeXBlIjoiMCIsIkRzX01lcmNoYW50RGF0YSI6IlJlZjogOTl6eiIsIkRzX0F1dGhvcmlzYXRpb25Db2RlIj'
24+
.'oiOTk5OTk5IiwiRHNfQ29uc3VtZXJMYW5ndWFnZSI6IjIiLCJEc19DYXJkX0NvdW50cnkiOiI3MjQiLCJEc19DYXJkX1R5cGU'
25+
.'iOiJDIn0=',
26+
'Ds_Signature' => '5v_0NCL0OBXM2CsZUSNdGQKRvmc3itFvM_WgiKe-pKA=',
2727
)
2828
);
2929

@@ -48,10 +48,56 @@ public function testCompletePurchaseSuccess()
4848
'Ds_AuthorisationCode' => '999999',
4949
'Ds_ConsumerLanguage' => '2', // English
5050
'Ds_Card_Country' => '724', // Spain
51+
'Ds_Card_Type' => 'C', // Credit
5152
);
5253
$this->runChecks($checks);
5354
}
5455

56+
public function testCompletePurchaseSuccessUpperParameters()
57+
{
58+
$this->getMockRequest()->shouldReceive('getHmacKey')->once()->andReturn('Mk9m98IfEblmPfrpsawt7BmxObt98Jev');
59+
60+
$this->response = new CompletePurchaseResponse(
61+
$this->getMockRequest(),
62+
array(
63+
'DS_SIGNATUREVERSION' => 'HMAC_SHA256_V1',
64+
'DS_MERCHANTPARAMETERS' => 'eyJEU19EQVRFIjoiMTBcLzExXC8yMDE1IiwiRFNfSE9VUiI6IjEyOjAwIiwiRFNfU0VDVVJFUEF'
65+
.'ZTUVOVCI6IjEiLCJEU19BTU9VTlQiOiIxNDUiLCJEU19DVVJSRU5DWSI6Ijk3OCIsIkRTX09SREVSIjoiMDEyM2FiYyIsIkRT'
66+
.'X01FUkNIQU5UQ09ERSI6Ijk5OTAwODg4MSIsIkRTX1RFUk1JTkFMIjoiODcxIiwiRFNfUkVTUE9OU0UiOiIwMDAwIiwiRFNfV'
67+
.'FJBTlNBQ1RJT05UWVBFIjoiMCIsIkRTX01FUkNIQU5UREFUQSI6IlJlZjogOTl6eiIsIkRTX0FVVEhPUklTQVRJT05DT0RFIj'
68+
.'oiOTk5OTk5IiwiRFNfQ09OU1VNRVJMQU5HVUFHRSI6IjIiLCJEU19DQVJEX0NPVU5UUlkiOiI3MjQiLCJEU19DQVJEX1RZUEU'
69+
.'iOiJDIn0=',
70+
'DS_SIGNATURE' => 'skOah02ucd3CI_bVXJk0sRnaY_bg9Pq7OqvpCBC30Fs=',
71+
)
72+
);
73+
74+
$this->assertTrue($this->response->isSuccessful());
75+
$this->assertFalse($this->response->isRedirect());
76+
$this->assertSame('999999', $this->response->getTransactionReference());
77+
$this->assertSame(0, (int) $this->response->getMessage());
78+
79+
$checks = array(
80+
'DS_SIGNATUREVERSION' => 'HMAC_SHA256_V1',
81+
'DS_DATE' => '10/11/2015',
82+
'DS_HOUR' => '12:00',
83+
'DS_SECUREPAYMENT' => '1',
84+
'DS_AMOUNT' => '145',
85+
'DS_CURRENCY' => '978', // Euros
86+
'DS_ORDER' => '0123abc',
87+
'DS_MERCHANTCODE' => '999008881',
88+
'DS_TERMINAL' => '871',
89+
'DS_RESPONSE' => '0000',
90+
'DS_TRANSACTIONTYPE' => '0',
91+
'DS_MERCHANTDATA' => 'Ref: 99zz',
92+
'DS_AUTHORISATIONCODE' => '999999',
93+
'DS_CONSUMERLANGUAGE' => '2', // English
94+
'DS_CARD_COUNTRY' => '724', // Spain
95+
'DS_CARD_TYPE' => 'C', // Credit
96+
);
97+
$this->runChecks($checks);
98+
}
99+
100+
55101
public function testCompletePurchaseFailure()
56102
{
57103
$this->getMockRequest()->shouldReceive('getHmacKey')->once()->andReturn('Mk9m98IfEblmPfrpsawt7BmxObt98Jev');
@@ -73,6 +119,7 @@ public function testCompletePurchaseFailure()
73119
$this->assertFalse($this->response->isSuccessful());
74120
$this->assertFalse($this->response->isRedirect());
75121
$this->assertSame(180, (int) $this->response->getMessage());
122+
$this->assertNull($this->response->getCardType());
76123

77124
$checks = array(
78125
'Ds_SignatureVersion' => 'HMAC_SHA256_V1',
@@ -115,6 +162,7 @@ public function testCompletePurchaseError()
115162
$this->assertFalse($this->response->isSuccessful());
116163
$this->assertFalse($this->response->isRedirect());
117164
$this->assertSame(909, (int) $this->response->getMessage());
165+
$this->assertNull($this->response->getCardType());
118166

119167
$checks = array(
120168
'Ds_SignatureVersion' => 'HMAC_SHA256_V1',
@@ -138,9 +186,9 @@ public function testCompletePurchaseError()
138186

139187
/**
140188
* @expectedException Omnipay\Common\Exception\InvalidResponseException
141-
* @expectedExceptionMessage Invalid response from payment gateway
189+
* @expectedExceptionMessage Invalid response from payment gateway (no data)
142190
*/
143-
public function testCompletePurchaseInvalidNoOrder()
191+
public function testCompletePurchaseInvalidNoParameters()
144192
{
145193
$this->response = new CompletePurchaseResponse(
146194
$this->getMockRequest(),
@@ -152,6 +200,26 @@ public function testCompletePurchaseInvalidNoOrder()
152200
);
153201
}
154202

203+
/**
204+
* @expectedException Omnipay\Common\Exception\InvalidResponseException
205+
* @expectedExceptionMessage Invalid response from payment gateway
206+
*/
207+
public function testCompletePurchaseInvalidNoOrder()
208+
{
209+
$this->response = new CompletePurchaseResponse(
210+
$this->getMockRequest(),
211+
array(
212+
'Ds_SignatureVersion' => 'HMAC_SHA256_V1',
213+
'Ds_MerchantParameters' => 'eyJEc19EYXRlIjoiMTBcLzExXC8yMDE1IiwiRHNfSG91ciI6IjEyOjAwIiwiRHNfU2VjdXJlUGF'
214+
.'5bWVudCI6IjEiLCJEc19BbW91bnQiOiIxNDUiLCJEc19DdXJyZW5jeSI6Ijk3OCIsIkRzX01lcmNoYW50Q29kZSI6Ijk5OTAw'
215+
.'ODg4MSIsIkRzX1Rlcm1pbmFsIjoiODcxIiwiRHNfUmVzcG9uc2UiOiIwMDAwIiwiRHNfVHJhbnNhY3Rpb25UeXBlIjoiMCIsI'
216+
.'kRzX01lcmNoYW50RGF0YSI6IlJlZjogOTl6eiIsIkRzX0F1dGhvcmlzYXRpb25Db2RlIjoiOTk5OTk5IiwiRHNfQ29uc3VtZX'
217+
.'JMYW5ndWFnZSI6IjIiLCJEc19DYXJkX0NvdW50cnkiOiI3MjQiLCJEc19DYXJkX1R5cGUiOiJDIn0=',
218+
'Ds_Signature' => '4cB7506qDYAqG8022GHWT2LwSeGvF5Q1cn7NNAKTrRY=',
219+
)
220+
);
221+
}
222+
155223
/**
156224
* @expectedException Omnipay\Common\Exception\InvalidResponseException
157225
* @expectedExceptionMessage Invalid response from payment gateway (signature mismatch)

tests/Message/PurchaseRequestTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,12 @@ public function testGetHmacKey()
6565
{
6666
$this->assertSame('Mk9m98IfEblmPfrpsawt7BmxObt98Jev', $this->request->getHmacKey());
6767
}
68+
69+
public function testSetConsumerLanguage()
70+
{
71+
$this->request->setConsumerLanguage(1);
72+
$this->assertSame('001', $this->request->getConsumerLanguage());
73+
$this->request->setConsumerLanguage('en');
74+
$this->assertSame('002', $this->request->getConsumerLanguage());
75+
}
6876
}

tests/Message/PurchaseResponseTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public function testPurchaseSuccess()
7878
$this->assertNull($this->response->getMessage());
7979
}
8080

81+
/**
82+
* Confirm that the mcrypt extension is loaded
83+
*/
8184
public function testMcryptExists()
8285
{
8386
$this->assertTrue(extension_loaded('mcrypt'));

0 commit comments

Comments
 (0)