Completed
Push — master ( 6d74cf...9e122c )
by Leith
02:02
created

PurchaseResponse::getMessage()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
ccs 8
cts 8
cp 1
rs 9.2
cc 4
eloc 8
nc 4
nop 0
crap 4
1
<?php
2
3
namespace Omnipay\OCBC\Message;
4
5
use Guzzle\Http\Message\Response as HttpResponse;
6
use Omnipay\Common\Exception\InvalidRequestException;
7
use Omnipay\Common\Exception\InvalidResponseException;
8
use Omnipay\Common\Message\AbstractResponse;
9
use Omnipay\Common\Message\RequestInterface;
10
11
/**
12
 * OCBC Purchase Response
13
 */
14
class PurchaseResponse extends AbstractResponse
15
{
16
    /**
17
     * @var HttpResponse  HTTP response object
18
     */
19
    public $response;
20
21
    /**
22
     * @var bool  Flag indicating whether the HTTP response object returned a '200 OK' HTTP header
23
     */
24
    protected $isHttpSuccess = false;
25
26
    /**
27
     * @var string  Status code from the response that determines success
28
     */
29
    protected $successStatus = 'S';
30
31
    /**
32
     * Constructor
33
     *
34
     * Also verifies that signature supplied in the response is valid
35
     *
36
     * @param PurchaseRequest $request   The initiating request
37
     * @param HttpResponse    $response  HTTP response object
38
     */
39 9
    public function __construct(PurchaseRequest $request, $response)
40
    {
41 9
        $this->response = $response;
42
43 9
        $code = $this->response->getStatusCode();
44 9
        $this->isHttpSuccess = $code == 200;
45
46 9
        $data = $response->getBody(true);
47
48 9
        if ($this->isHttpSuccess) {
49 7
            $data = json_decode($data, true);
50
            // case of 'results' node is inconsistent between documentation and experimentation, so handle both
51 7
            if (isset($data['results'])) {
52 1
                $data = $data['results'];
53 6
            } elseif (isset($data['Results'])) {
54 7
                $data = $data['Results'];
55
            }
56
        } else {
57 2
            $data = json_decode(json_encode($response->xml()->children('http://wso2.org/apimanager/security')), true);
58
        }
59
60 9
        parent::__construct($request, $data);
61
62 9
        if ($this->isHttpSuccess) {
63
            // Build and validate signature
64
            // 'Merchant Transaction Password'
65 7
            $merchantPassword = $request->getPassword();
66
            // 'Merchant Account No'
67 7
            $merchantAccountNo = $request->getMerchantId();
68
            // 'Merchant Transaction ID'
69 7
            $merchantTransactionId = null;
70
            // 'Transaction Amount'
71 7
            $transactionAmount = $request->getAmount();
72
            // 'Transaction ID'
73 7
            $transactionId = null;
74
            // 'Transaction Status'
75 7
            $transactionStatus = null;
76
            // 'Response Code'
77 7
            $responseCode = null;
78
79
            // make sure keys to build signature are in response
80
            $response_keys = array(
81 7
                'merchantTransactionId' => 'merchantTranId',
82
                'transactionId' => 'transactionId',
83
                'transactionStatus' => 'txnStatus',
84
                'responseCode' => 'responseCode',
85
            );
86 7
            foreach ($response_keys as $variable => $key) {
87 7
                if (isset($data[$key])) {
88 7
                    ${$variable} = $data[$key];
89
                }
90 7
                if (${$variable} === null) {
91 7
                    throw new InvalidResponseException('Invalid response from payment gateway (missing data)');
92
                }
93
            }
94
            // make sure variables to build signature were correctly fetched from the request
95
            $request_variables = array(
96 6
                'merchantPassword',
97
                'merchantAccountNo',
98
                'transactionAmount',
99
            );
100 6
            foreach ($request_variables as $variable) {
101 6
                if (${$variable} === null) {
102 6
                    throw new InvalidRequestException('Invalid request from merchant (missing data)');
103
                }
104
            }
105
            $signature_data = $merchantPassword
106 5
                .$merchantAccountNo
107 5
                .$merchantTransactionId
108 5
                .$transactionAmount
109 5
                .$transactionId
110 5
                .$transactionStatus
111 5
                .$responseCode;
112
113 5
            $signature = strtoupper(openssl_digest(strtoupper($signature_data), 'sha512'));
114
115 5
            if (!isset($this->data['txnSignature2']) || $signature != $this->data['txnSignature2']) {
116 1
                throw new InvalidResponseException('Invalid response from payment gateway (signature mismatch)');
117
            }
118
        }
119 6
    }
120
121
    /**
122
     * Is the response successful?
123
     *
124
     * Based on both HTTP status code and body content, since 200-level responses are JSON and 400/500-level are XML
125
     * For example see tests/Mock/ResponseSuccess.txt
126
     *
127
     * @return bool
128
     */
129 5
    public function isSuccessful()
130
    {
131
        // check HTTP response code first
132 5
        if (!$this->isHttpSuccess) {
133 2
            return false;
134
        }
135
136
        // check transaction status is JSON response if the HTTP response was successful
137 3
        return isset($this->data['txnStatus'])
138 3
            && $this->data['txnStatus'] == $this->successStatus
139 3
            && $this->getCode() === '0';
140
    }
141
142
    /**
143
     * What is the relevant description of the transaction response?
144
     *
145
     * @return string|null
146
     */
147 6
    public function getMessage()
148
    {
149
        // check for HTTP failure response first
150 6
        if (!$this->isHttpSuccess) {
151 2
            if (isset($this->data['message'])) {
152 1
                return $this->data['message'];
153
            }
154
            // no message available
155 1
            return null;
156
        }
157
158
        // check if descriptive message is available
159 4
        if (isset($this->data['responseDesc'])) {
160 3
            return $this->data['responseDesc'];
161
        }
162
163
        // use general transaction status (if unavailable would error in constructor)
164 1
        return $this->data['txnStatus'];
165
    }
166
167
    /**
168
     * @return string|null
169
     */
170 5
    public function getCode()
171
    {
172 5
        if (!$this->isHttpSuccess && isset($this->data['code'])) {
173 1
            return $this->data['code'];
174
        }
175 4
        if (isset($this->data['responseCode'])) {
176 3
            return $this->data['responseCode'];
177
        }
178 1
    }
179
180
    /**
181
     * @return string|null
182
     */
183 4
    public function getTransactionId()
184
    {
185 4
        if (isset($this->data['merchantTranId'])) {
186 2
            return $this->data['merchantTranId'];
187
        }
188 2
    }
189
190
    /**
191
     * @return string|null
192
     */
193 5
    public function getTransactionReference()
194
    {
195 5
        if (isset($this->data['transactionId'])) {
196 3
            return $this->data['transactionId'];
197
        }
198 2
    }
199
}
200