Skip to content

Commit 812385c

Browse files
author
Andrew Keynes
committed
Initial SecureXML API integration
1 parent 8b10a49 commit 812385c

20 files changed

+718
-27
lines changed

src/Message/AbstractRequest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
/**
6+
* SecurePay Direct Post Abstract Request.
7+
*/
8+
abstract class AbstractRequest extends \Omnipay\Common\Message\AbstractRequest
9+
{
10+
public $testEndpoint;
11+
public $liveEndpoint;
12+
13+
public function getMerchantId()
14+
{
15+
return $this->getParameter('merchantId');
16+
}
17+
18+
public function setMerchantId($value)
19+
{
20+
return $this->setParameter('merchantId', $value);
21+
}
22+
23+
public function getTransactionPassword()
24+
{
25+
return $this->getParameter('transactionPassword');
26+
}
27+
28+
public function setTransactionPassword($value)
29+
{
30+
return $this->setParameter('transactionPassword', $value);
31+
}
32+
33+
public function getEndpoint()
34+
{
35+
return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint;
36+
}
37+
}

src/Message/DirectPostAbstractRequest.php

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,11 @@
22

33
namespace Omnipay\SecurePay\Message;
44

5-
use Omnipay\Common\Message\AbstractRequest;
6-
75
/**
86
* SecurePay Direct Post Abstract Request
97
*/
108
abstract class DirectPostAbstractRequest extends AbstractRequest
119
{
1210
public $testEndpoint = 'https://api.securepay.com.au/test/directpost/authorise';
1311
public $liveEndpoint = 'https://api.securepay.com.au/live/directpost/authorise';
14-
15-
public function getMerchantId()
16-
{
17-
return $this->getParameter('merchantId');
18-
}
19-
20-
public function setMerchantId($value)
21-
{
22-
return $this->setParameter('merchantId', $value);
23-
}
24-
25-
public function getTransactionPassword()
26-
{
27-
return $this->getParameter('transactionPassword');
28-
}
29-
30-
public function setTransactionPassword($value)
31-
{
32-
return $this->setParameter('transactionPassword', $value);
33-
}
34-
35-
public function getEndpoint()
36-
{
37-
return $this->getTestMode() ? $this->testEndpoint : $this->liveEndpoint;
38-
}
3912
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
/**
6+
* SecurePay SecureXML Abstract Request.
7+
*/
8+
abstract class SecureXMLAbstractRequest extends AbstractRequest
9+
{
10+
public $testEndpoint = 'https://test.securepay.com.au/xmlapi/payment';
11+
public $liveEndpoint = 'https://api.securepay.com.au/xmlapi/payment';
12+
13+
/**
14+
* Set the messageID on the request.
15+
*
16+
* This is returned intact on any response so you could add a local
17+
* database ID here to ease in matching data later.
18+
*/
19+
public function setMessageId($value)
20+
{
21+
return $this->setParameter('messageId', $value);
22+
}
23+
24+
/**
25+
* Get the messageID for the request.
26+
*
27+
* @return string User-supplied messageID or generated one based on
28+
* timestamp.
29+
*/
30+
public function getMessageId()
31+
{
32+
return empty($this->getParameter('messageId'))
33+
? substr(md5(microtime()), 0, 30)
34+
: $this->getParameter('messageId');
35+
}
36+
37+
public function sendData($data)
38+
{
39+
$httpResponse = $this->httpClient->post($this->getEndpoint(), null, $data->asXML())->send();
40+
41+
return $this->response = new SecureXMLResponse($this, $httpResponse->xml());
42+
}
43+
44+
/**
45+
* XML Template of a SecurePayMessage.
46+
*
47+
* As per section 5.1 of the documentation, these elements are common to
48+
* all requests.
49+
*
50+
* @return \SimpleXMLElement SecurePayMessage template.
51+
*/
52+
protected function getBaseXML()
53+
{
54+
foreach ($this->requiredFields as $field) {
55+
$this->validate($field);
56+
}
57+
58+
$xml = new \SimpleXMLElement('<SecurePayMessage/>');
59+
60+
$messageInfo = $xml->addChild('MessageInfo');
61+
$messageInfo->addChild('messageID', $this->getMessageId());
62+
$messageInfo->addChild('messageTimestamp', $this->generateTimestamp());
63+
$messageInfo->addChild('timeoutValue', 60);
64+
$messageInfo->addChild('apiVersion', 'xml-4.2');
65+
66+
$merchantInfo = $xml->addChild('MerchantInfo');
67+
$merchantInfo->addChild('merchantID', $this->getMerchantId());
68+
$merchantInfo->addChild('password', $this->getTransactionPassword());
69+
70+
$xml->addChild('RequestType', 'Payment'); // Not related to the transaction type
71+
72+
$payment = $xml->addChild('Payment');
73+
$txnList = $payment->addChild('TxnList');
74+
$txnList->addAttribute('count', 1); // One transaction per request supported by current API.
75+
76+
$transaction = $txnList->addChild('Txn');
77+
$transaction->addAttribute('ID', 1); // One transaction per request supported by current API.
78+
$transaction->addChild('txnType', $this->txnType);
79+
$transaction->addChild('txnSource', 23); // Must always be 23 for SecureXML.
80+
$transaction->addChild('amount', $this->getAmountInteger());
81+
$transaction->addChild('currency', $this->getCurrency());
82+
$transaction->addChild('purchaseOrderNo', $this->getTransactionId());
83+
84+
return $xml;
85+
}
86+
87+
/**
88+
* @return \SimpleXMLElement SecurePayMessage with card details.
89+
*/
90+
protected function getBaseXMLWithCard()
91+
{
92+
$this->getCard()->validate();
93+
94+
$xml = $this->getBaseXML();
95+
96+
$card = $xml->Payment->TxnList->Txn->addChild('CreditCardInfo');
97+
$card->addChild('cardNumber', $this->getCard()->getNumber());
98+
$card->addChild('cvv', $this->getCard()->getCvv());
99+
$card->addChild('expiryDate', $this->getCard()->getExpiryDate('m/y'));
100+
101+
return $xml;
102+
}
103+
104+
/**
105+
* Generates a SecureXML timestamp.
106+
*
107+
* SecureXML requires a specific timestamp format as per appendix E of the
108+
* documentation.
109+
*
110+
* @return string SecureXML formatted timestamp.
111+
*/
112+
protected function generateTimestamp()
113+
{
114+
$date = new \DateTime();
115+
116+
// API requires the timezone offset in minutes
117+
return $date->format(sprintf('YmdHis000%+04d', $date->format('Z') / 60));
118+
}
119+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
/**
6+
* SecurePay SecureXML Authorize Request.
7+
*
8+
* Verify that the amount is available and hold for capture.
9+
*
10+
* Returns a 'preauthID' value that must be supplied in any subsequent capture
11+
* request.
12+
*/
13+
class SecureXMLAuthorizeRequest extends SecureXMLAbstractRequest
14+
{
15+
protected $txnType = 10; // Preauthorise, as per Appendix A of documentation.
16+
protected $requiredFields = array('amount', 'card', 'transactionId');
17+
18+
public function getData()
19+
{
20+
return $this->getBaseXMLWithCard();
21+
}
22+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
/**
6+
* SecurePay SecureXML Capture Request.
7+
*
8+
* Capture a partial or full amount that has been held by a prior authorize
9+
* request.
10+
*
11+
* The transactionId (purchaseOrderNo) and preauthID must match the prior
12+
* authorize transaction for the capture to succeed.
13+
*/
14+
class SecureXMLCaptureRequest extends SecureXMLAbstractRequest
15+
{
16+
protected $txnType = 11; // Preauthorise Complete, as per Appendix A of documentation.
17+
protected $requiredFields = array('amount', 'transactionId', 'preauthId');
18+
19+
public function getData()
20+
{
21+
$xml = $this->getBaseXML();
22+
23+
$xml->Payment->TxnList->Txn->addChild('preauthID', $this->getPreauthId());
24+
25+
return $xml;
26+
}
27+
28+
/**
29+
* Set the preauthId that was returned as part of the original authorize
30+
* request.
31+
*/
32+
public function setPreauthId($value)
33+
{
34+
return $this->setParameter('preauthId', $value);
35+
}
36+
37+
/**
38+
* @return string The preauthId from the authorize request that this
39+
* capture matches.
40+
*/
41+
public function getPreauthId()
42+
{
43+
return $this->getParameter('preauthId');
44+
}
45+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
/**
6+
* SecurePay SecureXML Purchase Request.
7+
*/
8+
class SecureXMLPurchaseRequest extends SecureXMLAbstractRequest
9+
{
10+
protected $txnType = 0; // Standard Payment, as per Appendix A of documentation.
11+
protected $requiredFields = array('amount', 'card', 'transactionId');
12+
13+
public function getData()
14+
{
15+
return $this->getBaseXMLWithCard();
16+
}
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
/**
6+
* SecurePay SecureXML Refund Request.
7+
*
8+
* Refund a partial or full amount from a prior purchase.
9+
*
10+
* The transactionReference (txnID) and transactionId (purchaseOrderNo) must
11+
* match the original transaction for a refund to be successful.
12+
*/
13+
class SecureXMLRefundRequest extends SecureXMLAbstractRequest
14+
{
15+
protected $txnType = 4; // Refund, as per Appendix A of documentation.
16+
protected $requiredFields = array('amount', 'transactionId', 'transactionReference');
17+
18+
public function getData()
19+
{
20+
$xml = $this->getBaseXML();
21+
$xml->Payment->TxnList->Txn->addChild('txnID', $this->getTransactionReference());
22+
23+
return $xml;
24+
}
25+
}

src/Message/SecureXMLResponse.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace Omnipay\SecurePay\Message;
4+
5+
use Omnipay\Common\Message\AbstractResponse;
6+
7+
class SecureXMLResponse extends AbstractResponse
8+
{
9+
/**
10+
* Determine if the transaction is successful or not.
11+
*
12+
* @note Rather than using HTTP status codes, the SecureXML API returns a
13+
* status code as part of the response if there is an internal API issue.
14+
*
15+
* @return bool
16+
*/
17+
public function isSuccessful()
18+
{
19+
// As per appendix F, 000 means the message was processed correctly
20+
if ((string) $this->data->Status->statusCode !== '000'
21+
|| ($this->hasTransaction()
22+
&& (string) $this->data->Payment->TxnList->Txn->approved !== 'Yes')) {
23+
return false;
24+
}
25+
26+
return true;
27+
}
28+
29+
/**
30+
* Determine if we have had payment information returned.
31+
*
32+
* @note For certain errors a Payment element is returned but has an empty
33+
* TxnList so this will tell us if we actually have a transaction to check.
34+
*
35+
* @return bool True if we have a transaction.
36+
*/
37+
protected function hasTransaction()
38+
{
39+
return isset($this->data->Payment->TxnList->Txn);
40+
}
41+
42+
/**
43+
* @link https://www.securepay.com.au/_uploads/files/SecurePay_Response_Codes.pdf
44+
*
45+
* @return string Gateway failure code or transaction code if available.
46+
*/
47+
public function getCode()
48+
{
49+
return $this->hasTransaction()
50+
? (string) $this->data->Payment->TxnList->Txn->responseCode
51+
: (string) $this->data->Status->statusCode;
52+
}
53+
54+
/**
55+
* @return string Gateway failure message or transaction message if
56+
* available.
57+
*/
58+
public function getMessage()
59+
{
60+
return $this->hasTransaction()
61+
? (string) $this->data->Payment->TxnList->Txn->responseText
62+
: (string) $this->data->Status->statusDescription;
63+
}
64+
65+
/**
66+
* @return string Unique SecurePay bank transaction reference.
67+
*/
68+
public function getTransactionReference()
69+
{
70+
return $this->hasTransaction()
71+
? (string) $this->data->Payment->TxnList->Txn->txnID
72+
: null;
73+
}
74+
}

0 commit comments

Comments
 (0)