Passed
Pull Request — master (#89)
by
unknown
07:22
created

Asanpardakht::prepareVerificationData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 8
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 13
rs 10
1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Asanpardakht;
4
5
use GuzzleHttp\Client;
6
use Shetabit\Multipay\Abstracts\Driver;
7
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
8
use Shetabit\Multipay\Contracts\ReceiptInterface;
9
use Shetabit\Multipay\Invoice;
10
use Shetabit\Multipay\Receipt;
11
use Shetabit\Multipay\RedirectionForm;
12
13
class Asanpardakht extends Driver
14
{
15
    const TokenURL = 'Token';
16
    const TimeURL = 'Time';
17
    const TranResultURL = 'TranResult';
18
    const CardHashURL = 'CardHash';
19
    const SettlementURL = 'Settlement';
20
    const VerifyURL = 'Verify';
21
    const CancelURL = 'Cancel';
22
    const ReverseURL = 'Reverse';
23
24
    /**
25
     * Invoice
26
     *
27
     * @var Invoice
28
     */
29
    protected $invoice;
30
31
    /**
32
     * Response
33
     *
34
     * @var object
35
     */
36
    protected $response;
37
38
    /**
39
     * PayGateTransactionId
40
     *
41
     */
42
    protected $payGateTransactionId;
43
44
    /**
45
     * Driver settings
46
     *
47
     * @var object
48
     */
49
    protected $settings;
50
51
    /**
52
     * Asanpardakht constructor.
53
     * Construct the class with the relevant settings.
54
     *
55
     * @param Invoice $invoice
56
     * @param $settings
57
     */
58
    public function __construct(Invoice $invoice, $settings)
59
    {
60
        $this->invoice($invoice);
61
        $this->settings = (object)$settings;
62
63
        //convert to rial
64
        $this->invoice->amount($this->invoice->getAmount() * 10);
65
    }
66
67
    /**
68
     * Purchase Invoice.
69
     *
70
     * @return string
71
     *
72
     * @throws PurchaseFailedException
73
     */
74
    public function purchase()
75
    {
76
        $this->invoice->uuid(crc32($this->invoice->getUuid()));
77
78
        $result = $this->token();
79
80
        if (!isset($result['status_code']) or $result['status_code'] != 200) {
81
            $this->purchaseFailed($result['status_code']);
82
        }
83
84
        $this->invoice->transactionId($result['content']);
85
86
        // return the transaction's id
87
        return $this->invoice->getTransactionId();
88
    }
89
90
    /**
91
     * Pay the Invoice
92
     *
93
     * @return RedirectionForm
94
     */
95
    public function pay(): RedirectionForm
96
    {
97
        $data = [
98
            'RefID' => $this->invoice->getTransactionId()
99
        ];
100
101
        //set mobileap for get user cards
102
        if (!empty($this->invoice->getDetails()['mobile'])) {
103
            $data['mobileap'] = $this->invoice->getDetails()['mobile'];
104
        }
105
106
        return $this->redirectWithForm($this->settings->apiPaymentUrl, $data, 'POST');
107
    }
108
109
    /**
110
     * Verify payment
111
     *
112
     * @return mixed|Receipt
113
     *
114
     * @throws PurchaseFailedException
115
     */
116
    public function verify(): ReceiptInterface
117
    {
118
        $result = $this->transactionResult();
119
120
        if (!isset($result['status_code']) or $result['status_code'] != 200) {
121
            $this->purchaseFailed($result['status_code']);
122
        }
123
124
        $this->payGateTransactionId = $result['content']['payGateTranID'];
125
126
        //step1: verify
127
        $verify_result = $this->verifyTransaction();
128
129
        if (!isset($verify_result['status_code']) or $verify_result['status_code'] != 200) {
130
            $this->purchaseFailed($verify_result['status_code']);
131
        }
132
133
        //step2: settlement
134
        $this->settlement();
135
136
        $receipt = $this->createReceipt($this->payGateTransactionId);
137
        $receipt->detail([
138
            'traceNo' => $this->payGateTransactionId,
139
            'referenceNo' => $result['content']['rrn'],
140
            'transactionId' => $result['content']['refID'],
141
            'cardNo' => $result['content']['cardNumber'],
142
        ]);
143
144
        return $receipt;
145
    }
146
147
    /**
148
     * send request to Asanpardakht
149
     *
150
     * @param $method
151
     * @param $url
152
     * @param array $data
153
     * @return array
154
     */
155
    protected function callApi($method, $url, $data = []): array
156
    {
157
        $client = new Client(['base_uri' => $this->settings->apiRestPaymentUrl]);
158
159
        $response = $client->request($method, $url, [
160
            "json" => $data,
161
            "headers" => [
162
                'Content-Type' => 'application/json',
163
                'usr' => $this->settings->username,
164
                'pwd' => $this->settings->password
165
            ],
166
            "http_errors" => false,
167
        ]);
168
169
        return [
170
            'status_code' => $response->getStatusCode(),
171
            'content' => json_decode($response->getBody()->getContents(), true)
172
        ];
173
    }
174
175
    /**
176
     * Generate the payment's receipt
177
     *
178
     * @param $referenceId
179
     *
180
     * @return Receipt
181
     */
182
    protected function createReceipt($referenceId): Receipt
183
    {
184
        $receipt = new Receipt('asanpardakht', $referenceId);
185
186
        return $receipt;
187
    }
188
189
    /**
190
     * call create token request
191
     *
192
     * @return array
193
     */
194
    public function token(): array
195
    {
196
        return $this->callApi('POST', self::TokenURL, [
197
            'serviceTypeId' => 1,
198
            'merchantConfigurationId' => $this->settings->merchantConfigID,
199
            'localInvoiceId' => $this->invoice->getUuid(),
200
            'amountInRials' => $this->invoice->getAmount(),
201
            'localDate' => $this->getTime()['content'],
202
            'callbackURL' => $this->settings->callbackUrl . "?" . http_build_query(['invoice' => $this->invoice->getUuid()]),
203
            'paymentId' => "0",
204
            'additionalData' => '',
205
        ]);
206
    }
207
208
    /**
209
     * call reserve request
210
     *
211
     * @return array
212
     */
213
    public function reverse(): array
214
    {
215
        return $this->callApi('POST', self::ReverseURL, [
216
            'merchantConfigurationId' => (int)$this->settings->merchantConfigID,
217
            'payGateTranId' => (int)$this->invoice->getUuid()
218
        ]);
219
    }
220
221
    /**
222
     * send cancel request
223
     *
224
     * @return array
225
     */
226
    public function cancel(): array
227
    {
228
        return $this->callApi('POST', self::CancelURL, [
229
            'merchantConfigurationId' => (int)$this->settings->merchantConfigID,
230
            'payGateTranId' => (int)$this->payGateTransactionId
231
        ]);
232
    }
233
234
    /**
235
     * send verify request
236
     *
237
     * @return array
238
     */
239
    public function verifyTransaction(): array
240
    {
241
        return $this->callApi('POST', self::VerifyURL, [
242
            'merchantConfigurationId' => (int)$this->settings->merchantConfigID,
243
            'payGateTranId' => (int)$this->payGateTransactionId
244
        ]);
245
    }
246
247
    /**
248
     * send settlement request
249
     *
250
     * @return array
251
     */
252
    public function settlement(): array
253
    {
254
        return $this->callApi('POST', self::SettlementURL, [
255
            'merchantConfigurationId' => (int)$this->settings->merchantConfigID,
256
            'payGateTranId' => (int)$this->payGateTransactionId
257
        ]);
258
    }
259
260
    /**
261
     * get card hash request
262
     *
263
     * @return array
264
     */
265
    public function cardHash(): array
266
    {
267
        return $this->callApi('GET', self::CardHashURL . '?merchantConfigurationId=' . $this->settings->merchantConfigID . '&localInvoiceId=' . $this->invoice->getTransactionId(), []);
268
    }
269
270
    /**
271
     * get transaction result
272
     *
273
     * @return array
274
     */
275
    public function transactionResult(): array
276
    {
277
        return $this->callApi('GET', self::TranResultURL . '?merchantConfigurationId=' . $this->settings->merchantConfigID . '&localInvoiceId=' . $this->invoice->getTransactionId(), []);
278
    }
279
280
    /**
281
     * get Asanpardakht server time
282
     *
283
     * @return array
284
     */
285
    public function getTime(): array
286
    {
287
        return $this->callApi('GET', self::TimeURL);
288
    }
289
290
    /**
291
     * Trigger an exception
292
     *
293
     * @param $status
294
     *
295
     * @throws PurchaseFailedException
296
     */
297
    protected function purchaseFailed($status)
298
    {
299
        $translations = [
300
            400 => "bad request",
301
            401 => "unauthorized. probably wrong or unsent header(s)",
302
            471 => "identity not trusted to proceed",
303
            472 => "no records found",
304
            473 => "invalid merchant username or password",
305
            474 => "invalid incoming request machine ip. check response body to see your actual public IP address",
306
            475 => "invoice identifier is not a number",
307
            476 => "request amount is not a number",
308
            477 => "request local date length is invalid",
309
            478 => "request local date is not in valid format",
310
            479 => "invalid service type id",
311
            480 => "invalid payer id",
312
            481 => "incorrect settlement description format",
313
            482 => "settlement slices does not match total amount",
314
            483 => "unregistered iban",
315
            484 => "internal error for other reasons",
316
            485 => "invalid local date",
317
            486 => "amount not in range",
318
            487 => "service not found or not available for merchant",
319
            488 => "invalid default callback",
320
            489 => "duplicate local invoice id",
321
            490 => "merchant disabled or misconfigured",
322
            491 => "too many settlement destinations",
323
            492 => "unprocessable request",
324
            493 => "error processing special request for other reasons like business restrictions",
325
            494 => "invalid payment_id for governmental payment",
326
            495 => "invalid referenceId in additionalData",
327
            496 => "invalid json in additionalData",
328
            497 => "invalid payment_id location",
329
            571 => "misconfiguration OR not yet processed",
330
            572 => "misconfiguration OR transaction status undetermined",
331
            573 => "misconfiguraed valid ips for configuration OR unable to request for verification due to an internal error",
332
            574 => "internal error in uthorization",
333
            575 => "no valid ibans found for merchant",
334
            576 => "internal error",
335
            577 => "internal error",
336
            578 => "no default sharing is defined for merchant",
337
            579 => "cant submit ibans with default sharing endpoint",
338
            580 => "error processing special request"
339
        ];
340
341
        if (array_key_exists($status, $translations)) {
342
            throw new PurchaseFailedException($translations[$status]);
343
        } else {
344
            throw new PurchaseFailedException('خطای ناشناخته ای رخ داده است.');
345
        }
346
    }
347
}
348