Normal   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 250
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 1
Metric Value
eloc 99
c 6
b 0
f 1
dl 0
loc 250
rs 10
wmc 23

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getPurchaseUrl() 0 3 1
A getVerificationUrl() 0 3 1
B purchase() 0 44 6
A getPaymentUrl() 0 3 1
A metadata() 0 13 3
B verify() 0 43 6
A createReceipt() 0 3 1
A pay() 0 8 1
A translateStatus() 0 28 2
1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Zarinpal\Strategies;
4
5
use GuzzleHttp\Client;
6
use Shetabit\Multipay\Abstracts\Driver;
7
use Shetabit\Multipay\Contracts\ReceiptInterface;
8
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
9
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
10
use Shetabit\Multipay\Invoice;
11
use Shetabit\Multipay\Receipt;
12
use Shetabit\Multipay\RedirectionForm;
13
use Shetabit\Multipay\Request;
14
15
class Normal extends Driver
16
{
17
    /**
18
     * HTTP Client.
19
     *
20
     * @var object
21
     */
22
    protected $client;
23
24
    /**
25
     * Invoice
26
     *
27
     * @var Invoice
28
     */
29
    protected $invoice;
30
31
    /**
32
     * Driver settings
33
     *
34
     * @var object
35
     */
36
    protected $settings;
37
38
    /**
39
     * Zarinpal constructor.
40
     * Construct the class with the relevant settings.
41
     *
42
     * @param Invoice $invoice
43
     * @param $settings
44
     */
45
    public function __construct(Invoice $invoice, $settings)
46
    {
47
        $this->invoice($invoice);
48
        $this->settings = (object) $settings;
49
        $this->client = new Client();
50
    }
51
52
    /**
53
     * Purchase Invoice.
54
     *
55
     * @return string
56
     *
57
     * @throws PurchaseFailedException
58
     * @throws \SoapFault
59
     */
60
    public function purchase()
61
    {
62
        $amount = $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1); // convert to rial
63
64
        if (!empty($this->invoice->getDetails()['description'])) {
65
            $description = $this->invoice->getDetails()['description'];
66
        } else {
67
            $description = $this->settings->description;
68
        }
69
70
        $data = [
71
            "merchant_id" => $this->settings->merchantId,
72
            "amount" => $amount,
73
            "currency" => 'IRR',
74
            "callback_url" => $this->settings->callbackUrl,
75
            "description" => $description,
76
            "metadata" => $this->metadata(),
77
        ];
78
79
        $response = $this
80
            ->client
81
            ->request(
82
                'POST',
83
                $this->settings->apiPurchaseUrl,
84
                [
85
                    "json" => $data,
86
                    "headers" => [
87
                        'Content-Type' => 'application/json',
88
                    ],
89
                    "http_errors" => false,
90
                ]
91
            );
92
93
        $result = json_decode($response->getBody()->getContents(), true);
94
95
        if (!empty($result['errors']) || empty($result['data']) || $result['data']['code'] != 100) {
96
            $bodyResponse = $result['errors']['code'];
97
            throw new PurchaseFailedException($this->translateStatus($bodyResponse), $bodyResponse);
98
        }
99
100
        $this->invoice->transactionId($result['data']["authority"]);
101
102
        // return the transaction's id
103
        return $this->invoice->getTransactionId();
104
    }
105
106
    /**
107
     * Pay the Invoice
108
     *
109
     * @return RedirectionForm
110
     */
111
    public function pay(): RedirectionForm
112
    {
113
        $transactionId = $this->invoice->getTransactionId();
114
        $paymentUrl = $this->getPaymentUrl();
115
116
        $payUrl = $paymentUrl . $transactionId;
117
118
        return $this->redirectWithForm($payUrl, [], 'GET');
119
    }
120
121
    /**
122
     * Verify payment
123
     *
124
     * @return ReceiptInterface
125
     *
126
     * @throws InvalidPaymentException
127
     */
128
    public function verify(): ReceiptInterface
129
    {
130
        $authority = $this->invoice->getTransactionId() ?? Request::input('Authority');
131
        $data = [
132
            "merchant_id" => $this->settings->merchantId,
133
            "authority" => $authority,
134
            "amount" => $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1), // convert to rial
135
        ];
136
137
        $response = $this->client->request(
138
            'POST',
139
            $this->getVerificationUrl(),
140
            [
141
                'json' => $data,
142
                "headers" => [
143
                    'Content-Type' => 'application/json',
144
                ],
145
                "http_errors" => false,
146
            ]
147
        );
148
149
        $result = json_decode($response->getBody()->getContents(), true);
150
151
        if (empty($result['data']) || !isset($result['data']['ref_id']) || ($result['data']['code'] != 100 && $result['data']['code'] != 101)) {
152
            $bodyResponse = $result['errors']['code'];
153
            throw new InvalidPaymentException($this->translateStatus($bodyResponse), $bodyResponse);
154
        }
155
156
        $refId = $result['data']['ref_id'];
157
158
        $receipt =  $this->createReceipt($refId);
159
        $receipt->detail([
160
            'code' => $result['data']['code'],
161
            'message' => $result['data']['message'] ?? null,
162
            'card_hash' => $result['data']['card_hash'] ?? null,
163
            'card_pan' => $result['data']['card_pan'] ?? null,
164
            'ref_id' => $refId,
165
            'fee_type' => $result['data']['fee_type'] ?? null,
166
            'fee' => $result['data']['fee'] ?? null,
167
            'order_id' => $result['data']['order_id'] ?? null,
168
        ]);
169
170
        return $receipt;
171
    }
172
173
    /**
174
     * Generate the payment's receipt
175
     *
176
     * @param $referenceId
177
     *
178
     * @return Receipt
179
     */
180
    public function createReceipt($referenceId)
181
    {
182
        return new Receipt('zarinpal', $referenceId);
183
    }
184
185
    /**
186
     * Retrieve purchase url
187
     *
188
     * @return string
189
     */
190
    protected function getPurchaseUrl(): string
191
    {
192
        return $this->settings->apiPurchaseUrl;
193
    }
194
195
    /**
196
     * Retrieve Payment url
197
     *
198
     * @return string
199
     */
200
    protected function getPaymentUrl(): string
201
    {
202
        return $this->settings->apiPaymentUrl;
203
    }
204
205
    /**
206
     * Retrieve verification url
207
     *
208
     * @return string
209
     */
210
    protected function getVerificationUrl(): string
211
    {
212
        return $this->settings->apiVerificationUrl;
213
    }
214
215
    /**
216
     * Convert status to a readable message.
217
     *
218
     * @param $status
219
     *
220
     * @return mixed|string
221
     */
222
    private function translateStatus($status)
223
    {
224
        $translations = [
225
            '100' => 'تراکنش با موفقیت انجام گردید',
226
            '101' => 'عمليات پرداخت موفق بوده و قبلا عملیات وریفای تراكنش انجام شده است',
227
            '-9' => 'خطای اعتبار سنجی',
228
            '-10' => 'ای پی و يا مرچنت كد پذيرنده صحيح نمی باشد',
229
            '-11' => 'مرچنت کد فعال نیست لطفا با تیم پشتیبانی ما تماس بگیرید',
230
            '-12' => 'تلاش بیش از حد در یک بازه زمانی کوتاه',
231
            '-15' => 'ترمینال شما به حالت تعلیق در آمده با تیم پشتیبانی تماس بگیرید',
232
            '-16' => 'سطح تاييد پذيرنده پايين تر از سطح نقره ای می باشد',
233
            '-30' => 'اجازه دسترسی به تسویه اشتراکی شناور ندارید',
234
            '-31' => 'حساب بانکی تسویه را به پنل اضافه کنید مقادیر وارد شده برای تسهیم صحيح نمی باشد',
235
            '-32' => 'مقادیر وارد شده برای تسهیم صحيح نمی باشد',
236
            '-33' => 'درصد های وارد شده صحيح نمی باشد',
237
            '-34' => 'مبلغ از کل تراکنش بیشتر است',
238
            '-35' => 'تعداد افراد دریافت کننده تسهیم بیش از حد مجاز است',
239
            '-40' => 'پارامترهای اضافی نامعتبر، expire_in معتبر نیست',
240
            '-50' => 'مبلغ پرداخت شده با مقدار مبلغ در وریفای متفاوت است',
241
            '-51' => 'پرداخت ناموفق',
242
            '-52' => 'خطای غیر منتظره با پشتیبانی تماس بگیرید',
243
            '-53' => 'اتوریتی برای این مرچنت کد نیست',
244
            '-54' => 'اتوریتی نامعتبر است',
245
        ];
246
247
        $unknownError = 'خطای ناشناخته رخ داده است. در صورت کسر مبلغ از حساب حداکثر پس از 72 ساعت به حسابتان برمیگردد';
248
249
        return array_key_exists($status, $translations) ? $translations[$status] : $unknownError;
250
    }
251
252
    private function metadata(): array
253
    {
254
        $metadata = [];
255
256
        if (!empty($this->invoice->getDetails()['mobile'])) {
257
            $metadata['mobile'] = $this->invoice->getDetails()['mobile'];
258
        }
259
260
        if (!empty($this->invoice->getDetails()['email'])) {
261
            $metadata['email'] = $this->invoice->getDetails()['email'];
262
        }
263
264
        return array_merge($this->invoice->getDetails() ?? [], $metadata);
265
    }
266
}
267