Passed
Pull Request — master (#136)
by
unknown
04:49 queued 02:05
created

Rayanpay::purchase()   B

Complexity

Conditions 6
Paths 20

Size

Total Lines 58
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 6
eloc 36
c 3
b 0
f 0
nc 20
nop 0
dl 0
loc 58
rs 8.7217

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
        if (($this->invoice->getAmount() * 10) <= 1000) {
109
            throw new PurchaseFailedException('مقدار مبلغ ارسالی بزگتر از 1000 باشد.');
110
        }
111
112
        $referenceId = hexdec(uniqid());
113
        $amount = $this->invoice->getAmount();
114
115
        $callback = $this->settings->callbackUrl . "?referenceId=" . $referenceId . "&price=" . $amount . "&mobile=" . $mobile;
116
117
        $data = [
118
            'referenceId' => $referenceId,
119
            'amount' => $amount,
120
            'msisdn' => $mobile,
121
            'gatewayId' => 100,
122
            'callbackUrl' => $callback,
123
            'gateSwitchingAllowed' => true,
124
        ];
125
126
        $response = $this->makeHttpChargeRequest(
127
            $data,
128
            $this->settings->apiPayStart,
129
            'payment_start',
130
            true
131
        );
132
133
        $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

133
        $body = json_decode(/** @scrutinizer ignore-type */ $response, true);
Loading history...
134
135
        $this->invoice->transactionId($referenceId);
136
137
        // Get RefIf From Html Form Becuese GetWay Not Provide In Api
138
        $dom = new \DOMDocument();
139
        $dom->loadHTML($body['bankRedirectHtml']);
140
        $xp = new \DOMXPath($dom);
141
        $nodes = $xp->query('//input[@name="RefId"]');
142
        $node = $nodes->item(0);
143
        session()->put('RefId', $node->getAttribute('value'));
0 ignored issues
show
Bug introduced by
The function session was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

143
        /** @scrutinizer ignore-call */ 
144
        session()->put('RefId', $node->getAttribute('value'));
Loading history...
144
        return $this->invoice->getTransactionId();
145
    }
146
147
    /**
148
     * Pay the Invoice render html redirect to getway
149
     *
150
     * @return RedirectionForm
151
     */
152
    public function pay(): RedirectionForm
153
    {
154
        return $this->redirectWithForm($this->settings->apiPurchaseUrl, [
155
            'x_GateChanged' => 0,
156
            'RefId' => session('RefId')
0 ignored issues
show
Bug introduced by
The function session was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

156
            'RefId' => /** @scrutinizer ignore-call */ session('RefId')
Loading history...
157
        ], 'POST');
158
    }
159
160
    /**
161
     * Verify payment
162
     *
163
     * @return ReceiptInterface
164
     *
165
     * @throws InvalidPaymentException
166
     * @throws \GuzzleHttp\Exception\GuzzleException
167
     */
168
    public function verify(): ReceiptInterface
169
    {
170
        $data = [
171
            'referenceId' => (int)$this->getInvoice()->getTransactionId(),
172
            'header' => '',
173
            'content' => http_build_query($_POST),
174
        ];
175
176
        $response = $this->makeHttpChargeRequest(
177
            $data,
178
            $this->settings->apiPayVerify,
179
            'payment_parse',
180
            true
181
        );
182
183
        $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

183
        $body = json_decode(/** @scrutinizer ignore-type */ $response, true);
Loading history...
184
185
        $receipt = $this->createReceipt($body['paymentId']);
186
187
        $receipt->detail([
188
            'paymentId' => $body['paymentId'],
189
            'hashedBankCardNumber' => $body['hashedBankCardNumber'],
190
            'endDate' => $body['endDate'],
191
        ]);
192
193
        return $receipt;
194
    }
195
196
    /**
197
     * Generate the payment's receipt
198
     *
199
     * @param $referenceId
200
     *
201
     * @return Receipt
202
     */
203
    protected function createReceipt($referenceId)
204
    {
205
        $receipt = new Receipt('rayanpay', $referenceId);
206
207
        return $receipt;
208
    }
209
210
211
    /**
212
     * Trigger an exception
213
     *
214
     * @param $status
215
     * @param $method
216
     * @throws InvalidPaymentException
217
     */
218
    private function notVerified($status, $method)
219
    {
220
        $message = "";
221
        if ($method == 'token') {
222
            switch ($status) {
223
224
                case '400' :
225
                    $message = 'نقص در پارامترهای ارسالی';
226
                    break;
227
228
                case '401' :
229
                    $message = 'کد کاربری/رمز عبور /کلاینت/آی پی نامعتبر است';
230
                    break;
231
232
                case '500' :
233
                    $message = 'خطایی سمت سرور رخ داده است';
234
                    break;
235
            }
236
        } elseif ($method == 'payment_start') {
237
            switch ($status) {
238
                case '400' :
239
                    $message = 'شناسه ارسالی تکراری می باشد ';
240
                    break;
241
                case '401' :
242
                    $message = 'توکن نامعتبر';
243
                    break;
244
245
                case '601' :
246
                    $message = 'اتصال به درگاه خطا دارد (پرداخت ناموفق)';
247
                    break;
248
249
                case '500' :
250
                    $message = 'خطایی سمت سرور رخ داده است (احتمال تکراری بودن شماره ref شما یا اگر شماره موبایل دارید باید فرمت زیر باشد 989121112233 )';
251
                    break;
252
            }
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
268
        } elseif ($method == 'payment_parse') {
269
            switch ($status) {
270
271
                case '401':
272
                    $message = 'توکن نامعتبر است';
273
                    break;
274
275
                case '500':
276
                    $message = 'خطایی سمت سرور رخ داده است';
277
                    break;
278
279
                case '600':
280
                    $message = 'وضعیت نامشخص';
281
                    break;
282
283
                case '601':
284
                    $message = 'پرداخت ناموفق';
285
                    break;
286
287
                case '602':
288
                    $message = 'پرداخت یافت نشد';
289
                    break;
290
291
                case '608':
292
                    $message = 'قوانین پرداخت یافت نشد (برای پرداخت هایی که قوانین دارند)';
293
                    break;
294
295
                case '609':
296
                    $message = 'وضعیت پرداخت نامعتبر میباشد';
297
                    break;
298
            }
299
        }
300
        if ($message) {
301
            throw new InvalidPaymentException($message);
302
        } else {
303
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.' . $method);
304
        }
305
    }
306
307
    private function makeHttpChargeRequest($data, $url, $method, $forAuth = true)
308
    {
309
        $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...
310
        if ($forAuth) {
311
            $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

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