Rayanpay   A
last analyzed

Complexity

Total Complexity 39

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 155
c 1
b 0
f 0
dl 0
loc 310
rs 9.28
wmc 39

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A auth() 0 12 1
A makeHttpChargeRequest() 0 19 3
A createReceipt() 0 5 1
B purchase() 0 60 7
A verify() 0 26 1
A pay() 0 6 2
D notVerified() 0 82 23
1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Rayanpay;
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
14
class Rayanpay extends Driver
15
{
16
    /**
17
     * Sadad Client.
18
     *
19
     * @var object
20
     */
21
    protected $client;
22
23
    /**
24
     * Invoice
25
     *
26
     * @var Invoice
27
     */
28
    protected $invoice;
29
30
    /**
31
     * Driver settings
32
     *
33
     * @var object
34
     */
35
    protected $settings;
36
37
    /**
38
     * Open Gate By Render Html
39
     * @var string $htmlPay
40
     */
41
42
    /**
43
     * Sadad constructor.
44
     * Construct the class with the relevant settings.
45
     *
46
     * @param Invoice $invoice
47
     * @param $settings
48
     */
49
    public function __construct(Invoice $invoice, $settings)
50
    {
51
        $this->invoice($invoice);
52
        $this->settings = (object)$settings;
53
        $this->client = new Client(
54
            [
55
                'base_uri' => $this->settings->apiPurchaseUrl,
56
                'verify' => false
57
            ]
58
        );
59
    }
60
61
    /**
62
     * @throws InvalidPaymentException
63
     */
64
    private function auth()
65
    {
66
        $data = [
67
            'clientId' => $this->settings->client_id,
68
            'userName' => $this->settings->username,
69
            'password' => $this->settings->password,
70
        ];
71
        return $this->makeHttpChargeRequest(
72
            $data,
73
            $this->settings->apiTokenUrl,
74
            'token',
75
            false
76
        );
77
    }
78
79
    /**
80
     * Purchase Invoice.
81
     *
82
     * @return string
83
     *
84
     * @throws PurchaseFailedException
85
     * @throws \GuzzleHttp\Exception\GuzzleException
86
     */
87
    public function purchase()
88
    {
89
        $this->auth();
90
91
        $details = $this->invoice->getDetails();
92
93
        if (!empty($details['mobile'])) {
94
            $mobile = $details['mobile'];
95
        }
96
        if (!empty($details['phone'])) {
97
            $mobile = $details['phone'];
98
        }
99
100
        if (empty($mobile)) {
101
            throw new PurchaseFailedException('شماره موبایل را وارد کنید.');
102
        }
103
104
        if (preg_match('/^(?:98)?9[0-9]{9}$/', $mobile) == false) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $mobile does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/^(?:98)?9[0-9]{9}$/', $mobile) of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
105
            $mobile = '';
106
        }
107
108
        $amount = $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1); // convert to rial
109
110
        if ($amount <= 10000) {
111
            throw new PurchaseFailedException('مقدار مبلغ ارسالی بزگتر از 10000 ریال باشد.');
112
        }
113
114
        $referenceId = hexdec(uniqid());
115
116
        $callback = $this->settings->callbackUrl . "?referenceId=" . $referenceId . "&price=" . $amount . "&mobile=" . $mobile;
117
118
        $data = [
119
            'referenceId' => $referenceId,
120
            'amount' => $amount,
121
            'msisdn' => $mobile,
122
            'gatewayId' => 100,
123
            'callbackUrl' => $callback,
124
            'gateSwitchingAllowed' => true,
125
        ];
126
127
        $response = $this->makeHttpChargeRequest(
128
            $data,
129
            $this->settings->apiPayStart,
130
            'payment_start',
131
            true
132
        );
133
134
        $body = json_decode($response, true);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

134
        $body = json_decode(/** @scrutinizer ignore-type */ $response, true);
Loading history...
135
136
        $this->invoice->transactionId($referenceId);
137
138
        // Get RefIf From Html Form Becuese GetWay Not Provide In Api
139
        $dom = new \DOMDocument();
140
        $dom->loadHTML($body['bankRedirectHtml']);
141
        $xp = new \DOMXPath($dom);
142
        $nodes = $xp->query('//input[@name="RefId"]');
143
        $node = $nodes->item(0);
144
        $_SESSION['RefId'] = $node->getAttribute('value');
145
146
        return $this->invoice->getTransactionId();
147
    }
148
149
    /**
150
     * Pay the Invoice render html redirect to getway
151
     *
152
     * @return RedirectionForm
153
     */
154
    public function pay(): RedirectionForm
155
    {
156
        return $this->redirectWithForm($this->settings->apiPurchaseUrl, [
157
            'x_GateChanged' => 0,
158
            'RefId' => !empty($_SESSION['RefId']) ? $_SESSION['RefId'] : null,
159
        ], 'POST');
160
    }
161
162
    /**
163
     * Verify payment
164
     *
165
     * @return ReceiptInterface
166
     *
167
     * @throws InvalidPaymentException
168
     * @throws \GuzzleHttp\Exception\GuzzleException
169
     */
170
    public function verify(): ReceiptInterface
171
    {
172
        $data = [
173
            'referenceId' => (int)$this->getInvoice()->getTransactionId(),
174
            'header' => '',
175
            'content' => http_build_query($_POST),
176
        ];
177
178
        $response = $this->makeHttpChargeRequest(
179
            $data,
180
            $this->settings->apiPayVerify,
181
            'payment_parse',
182
            true
183
        );
184
185
        $body = json_decode($response, true);
0 ignored issues
show
Bug introduced by
It seems like $response can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

185
        $body = json_decode(/** @scrutinizer ignore-type */ $response, true);
Loading history...
186
187
        $receipt = $this->createReceipt($body['paymentId']);
188
189
        $receipt->detail([
190
            'paymentId' => $body['paymentId'],
191
            'hashedBankCardNumber' => $body['hashedBankCardNumber'],
192
            'endDate' => $body['endDate'],
193
        ]);
194
195
        return $receipt;
196
    }
197
198
    /**
199
     * Generate the payment's receipt
200
     *
201
     * @param $referenceId
202
     *
203
     * @return Receipt
204
     */
205
    protected function createReceipt($referenceId)
206
    {
207
        $receipt = new Receipt('rayanpay', $referenceId);
208
209
        return $receipt;
210
    }
211
212
213
    /**
214
     * Trigger an exception
215
     *
216
     * @param $status
217
     * @param $method
218
     * @throws InvalidPaymentException
219
     */
220
    private function notVerified($status, $method)
221
    {
222
        $message = "";
223
        if ($method == 'token') {
224
            switch ($status) {
225
                case '400':
226
                    $message = 'نقص در پارامترهای ارسالی';
227
                    break;
228
229
                case '401':
230
                    $message = 'کد کاربری/رمز عبور /کلاینت/آی پی نامعتبر است';
231
                    break;
232
233
                case '500':
234
                    $message = 'خطایی سمت سرور رخ داده است';
235
                    break;
236
            }
237
        } elseif ($method == 'payment_start') {
238
            switch ($status) {
239
                case '400':
240
                    $message = 'شناسه ارسالی تکراری می باشد ';
241
                    break;
242
                case '401':
243
                    $message = 'توکن نامعتبر';
244
                    break;
245
246
                case '601':
247
                    $message = 'اتصال به درگاه خطا دارد (پرداخت ناموفق)';
248
                    break;
249
250
                case '500':
251
                    $message = 'خطایی سمت سرور رخ داده است (احتمال تکراری بودن شماره ref شما یا اگر شماره موبایل دارید باید فرمت زیر باشد 989121112233 )';
252
                    break;
253
            }
254
        } elseif ($method == 'payment_status') {
255
            switch ($status) {
256
                case '401':
257
                    $message = 'توکن نامعتبر است';
258
                    break;
259
                case '601':
260
                    $message = 'پرداخت ناموفق';
261
                    break;
262
263
                case '600':
264
                    $message = 'پرداخت در حالت Pending می باشد و باید متد fullfill برای تعیین وضعیت صدا زده شود';
265
                    break;
266
            }
267
        } elseif ($method == 'payment_parse') {
268
            switch ($status) {
269
                case '401':
270
                    $message = 'توکن نامعتبر است';
271
                    break;
272
273
                case '500':
274
                    $message = 'خطایی سمت سرور رخ داده است';
275
                    break;
276
277
                case '600':
278
                    $message = 'وضعیت نامشخص';
279
                    break;
280
281
                case '601':
282
                    $message = 'پرداخت ناموفق';
283
                    break;
284
285
                case '602':
286
                    $message = 'پرداخت یافت نشد';
287
                    break;
288
289
                case '608':
290
                    $message = 'قوانین پرداخت یافت نشد (برای پرداخت هایی که قوانین دارند)';
291
                    break;
292
293
                case '609':
294
                    $message = 'وضعیت پرداخت نامعتبر میباشد';
295
                    break;
296
            }
297
        }
298
        if ($message) {
299
            throw new InvalidPaymentException($message, (int)$status);
300
        } else {
301
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.', (int)$status);
302
        }
303
    }
304
305
    private function makeHttpChargeRequest($data, $url, $method, $forAuth = true)
306
    {
307
        $header[] = 'Content-Type: application/json';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$header was never initialized. Although not strictly required by PHP, it is generally a good practice to add $header = array(); before regardless.
Loading history...
308
        if ($forAuth) {
309
            $header[] = 'Authorization: Bearer ' . $this->auth();
0 ignored issues
show
Bug introduced by
Are you sure $this->auth() of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

309
            $header[] = 'Authorization: Bearer ' . /** @scrutinizer ignore-type */ $this->auth();
Loading history...
310
        }
311
        $ch = curl_init($url);
312
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
313
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
314
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
315
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
316
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
317
        $result = curl_exec($ch);
318
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
319
        curl_close($ch);
320
        if ($http_code != 200) {
321
            return $this->notVerified($http_code, $method);
322
        }
323
        return $result;
324
    }
325
}
326