Completed
Push — master ( c2561f...e0b493 )
by recca
10:29 queued 03:42
created

Api::getApiEndpoint()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5.2596

Importance

Changes 0
Metric Value
dl 0
loc 20
ccs 8
cts 14
cp 0.5714
rs 9.2
c 0
b 0
f 0
cc 4
eloc 14
nc 4
nop 1
crap 5.2596
1
<?php
2
3
namespace PayumTW\Esunbank;
4
5
use LogicException;
6
use Detection\MobileDetect;
7
use Http\Message\MessageFactory;
8
use Payum\Core\HttpClientInterface;
9
use Payum\Core\Exception\Http\HttpException;
10
11
class Api
12
{
13
    /**
14
     * @var \Payum\Core\HttpClientInterface
15
     */
16
    protected $client;
17
18
    /**
19
     * @var \Http\Message\MessageFactory
20
     */
21
    protected $messageFactory;
22
23
    /**
24
     * @var array
25
     */
26
    protected $options = [];
27
28
    /**
29
     * $encrypter.
30
     *
31
     * @var Encrypter
32
     */
33
    protected $encrypter;
34
35
    /**
36
     * @param array $options
37
     * @param \Payum\Core\HttpClientInterface $client
38
     * @param \Http\Message\MessageFactory $messageFactory
39
     * @param Encrypter $encrypter
40
     *
41
     * @throws \Payum\Core\Exception\InvalidArgumentException if an option is invalid
42
     */
43 14
    public function __construct(array $options, HttpClientInterface $client, MessageFactory $messageFactory, Encrypter $encrypter = null)
44
    {
45 14
        $this->options = $options;
46 14
        $this->client = $client;
47 14
        $this->messageFactory = $messageFactory;
48 14
        $this->encrypter = $encrypter ?: new Encrypter();
49 14
        $this->encrypter->setKey($this->options['M']);
50 14
    }
51
52
    /**
53
     * @param array $fields
54
     * @return array
55
     */
56 3
    protected function doRequest(array $fields, $type = 'sync')
57
    {
58 3
        $request = $this->messageFactory->createRequest('POST', $this->getApiEndpoint($type), [
59 3
            'Content-Type' => 'application/x-www-form-urlencoded',
60 3
        ], http_build_query($this->encrypter->encryptRequest($fields)));
61
62 3
        $response = $this->client->send($request);
63
64 3
        if (false === ($response->getStatusCode() >= 200 && $response->getStatusCode() < 300)) {
65
            throw HttpException::factory($request, $response);
66
        }
67
68 3
        return $this->parseResponse(
69 3
            $response->getBody()->getContents()
70 3
        );
71
    }
72
73
    /**
74
     * parseResponse.
75
     *
76
     * @param array $response
77
     * @return array
78
     */
79 9
    public function parseResponse($response)
80
    {
81 9
        if (is_string($response) === true) {
82 9
            $response = $this->parseStr($response);
83 9
        }
84
85 9
        if (empty($response['DATA']) === true) {
86
            throw new LogicException('Response content is not valid');
87
        }
88
89 9
        $data = json_decode($response['DATA'], true);
90
91 9
        if (json_last_error() !== JSON_ERROR_NONE) {
92 7
            $data = [];
93 7
            parse_str(str_replace(',', '&', $response['DATA']), $data);
94 7
        }
95
96 9
        if (isset($data['returnCode']) === true) {
97 2
            $response['returnCode'] = $data['returnCode'];
98 2
        }
99
100 9
        if (isset($data['version']) === true) {
101 2
            $response['version'] = $data['version'];
102 2
        }
103
104 9
        if (isset($data['txnData']) === true) {
105 2
            $response = array_merge($response, $data['txnData']);
106 2
            unset($data['txnData']);
107 2
        }
108
109 9
        return array_merge($response, $data);
110
    }
111
112
    /**
113
     * parseStr.
114
     *
115
     * @param string $str
116
     * @return array
117
     */
118 9
    protected function parseStr($str)
119
    {
120 9
        $response = [];
121 9
        parse_str($str, $response);
122
123 9
        return $response;
124
    }
125
126
    /**
127
     * getApiEndpoint.
128
     *
129
     * @return string
130
     */
131 3
    public function getApiEndpoint($type = 'capture')
132
    {
133 3
        if ($this->options['sandbox'] === false) {
134
            $urls = [
135
                'capture' => $this->isMobile() === false ? 'https://acq.esunbank.com.tw/ACQTrans/esuncard/txnf014s' : 'https://acq.esunbank.com.tw/ACQTrans/esuncard/txnf014m',
136
                'cancel' => 'https://acq.esunbank.com.tw/ACQTrans/esuncard/txnf0150',
137
                'refund' => 'https://acq.esunbank.com.tw/ACQTrans/esuncard/txnf0160',
138
                'sync' => 'https://acq.esunbank.com.tw/ACQQuery/esuncard/txnf0180',
139
            ];
140
        } else {
141
            $urls = [
142 3
                'capture' => $this->isMobile() === false ? 'https://acqtest.esunbank.com.tw/ACQTrans/esuncard/txnf014s' : 'https://acqtest.esunbank.com.tw/ACQTrans/esuncard/txnf014m',
143 3
                'cancel' => 'https://acqtest.esunbank.com.tw/ACQTrans/esuncard/txnf0150',
144 3
                'refund' => 'https://acqtest.esunbank.com.tw/ACQTrans/esuncard/txnf0160',
145 3
                'sync' => 'https://acqtest.esunbank.com.tw/ACQQuery/esuncard/txnf0180',
146 3
            ];
147
        }
148
149 3
        return $urls[$type];
150
    }
151
152
    /**
153
     * createTransaction.
154
     *
155
     * @param array $params
156
     * @return array
157
     */
158 4
    public function createTransaction(array $params)
159
    {
160
        $supportedParams = [
161
            // 訂單編號, 由特約商店產生,不可重複,不可 包含【_】字元,英數限用大寫
162 4
            'ONO' => '',
163
            // 回覆位址, 'https://acqtest.esunbank.com.tw/ACQTrans/test/print.jsp'
164 4
            'U' => 'https://acqtest.esunbank.com.tw/ACQTrans/test/print.jsp',
165
            // 特店代碼
166 4
            'MID' => $this->options['MID'],
167
            // 銀行紅利折抵, Y:使用銀行紅利交易。 N:不使用銀行紅利交易
168 4
            'BPF' => 'N',
169
            // 分期代碼, 三期:0100103  六期:0100106 正式環境參數由業務經辦提供
170 4
            'IC' => '',
171
            // 交易金額, 台幣(901)
172 4
            'TA' => '',
173
            // 終端機代號, EC000001(一般交易) EC000002(分期)
174 4
            'TID' => 'EC000001',
175 4
        ];
176
177 4
        $params = array_replace(
178 4
            $supportedParams,
179 4
            array_intersect_key($params, $supportedParams)
180 4
        );
181
182 4
        if (empty($params['IC']) === true) {
183 2
            unset($params['IC']);
184 2
        } else {
185 2
            $params['TID'] = 'EC000002';
186
        }
187
188 4
        $params['BPF'] = strtoupper($params['BPF']);
189 4
        if ($params['BPF'] === 'N') {
190 2
            unset($params['BPF']);
191 2
        }
192
193 4
        return $this->encrypter->encryptRequest($params);
194
    }
195
196
    /**
197
     * getTransactionData.
198
     *
199
     * @param mixed $params
200
     * @return array
201
     */
202 1 View Code Duplication
    public function getTransactionData(array $params)
203
    {
204
        $supportedParams = [
205
            // 訂單編號, 由特約商店產生,不可重複,不可 包含【_】字元,英數限用大寫
206 1
            'ONO' => '',
207
            // 特店代碼
208 1
            'MID' => $this->options['MID'],
209 1
        ];
210
211 1
        $params = array_replace(
212 1
            $supportedParams,
213 1
            array_intersect_key($params, $supportedParams)
214 1
        );
215
216 1
        return $this->doRequest($params, 'sync');
217
    }
218
219
    /**
220
     * refundTransaction.
221
     *
222
     * @param array $params
223
     * @return array
224
     */
225 1
    public function refundTransaction(array $params)
226
    {
227
        $supportedParams = [
228
            // 05:授權 51:取消授權 71:退貨授權
229 1
            'TYP' => '71',
230
            // 訂單編號, 由特約商店產生,不可重複,不可 包含【_】字元,英數限用大寫
231 1
            'ONO' => null,
232
            // 特店代碼
233 1
            'MID' => $this->options['MID'],
234
            // 專案資訊
235 1
            'C' => null,
236 1
        ];
237
238 1
        $params = array_replace(
239 1
            $supportedParams,
240 1
            array_intersect_key($params, $supportedParams)
241 1
        );
242
243 1
        return $this->doRequest($params, 'refund');
244
    }
245
246
    /**
247
     * cancelTransaction.
248
     *
249
     * @param array $params
250
     * @return array
251
     */
252 1 View Code Duplication
    public function cancelTransaction(array $params)
253
    {
254
        $supportedParams = [
255
            // 訂單編號, 由特約商店產生,不可重複,不可 包含【_】字元,英數限用大寫
256 1
            'ONO' => '',
257
            // 特店代碼
258 1
            'MID' => $this->options['MID'],
259 1
        ];
260
261 1
        $params = array_replace(
262 1
            $supportedParams,
263 1
            array_intersect_key($params, $supportedParams)
264 1
        );
265
266 1
        return $this->doRequest($params, 'cancel');
267
    }
268
269
    /**
270
     * @param array $params
271
     * @return string
272
     */
273 4
    public function calculateHash($params)
274
    {
275 4
        return $this->encrypter->encrypt($params);
276
    }
277
278
    /**
279
     * verifyHash.
280
     *
281
     * @param array $response
282
     * @return bool
283
     */
284 4
    public function verifyHash($response)
285
    {
286
        // 尚未確定
287 4
        return empty($response['MACD']) === true
288 4
            ? false
289 4
            : $this->calculateHash($response) === $response['MACD'];
290
    }
291
292
    /**
293
     * isMobile.
294
     *
295
     * @return bool
296
     */
297 3
    protected function isMobile()
298
    {
299 3
        if (isset($this->options['mobile']) === true && is_null($this->options['mobile']) === false) {
300
            return $this->options['mobile'];
301
        }
302
303 3
        $detect = new MobileDetect();
304
305 3
        return ($detect->isMobile() === false && $detect->isTablet() === false) ? false : true;
306
    }
307
}
308