Passed
Pull Request — master (#247)
by
unknown
03:11
created

Snapppay::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 1
eloc 4
c 2
b 0
f 1
nc 1
nop 2
dl 0
loc 6
rs 10
1
<?php
2
3
4
namespace Shetabit\Multipay\Drivers\Snapppay;
5
6
use GuzzleHttp\Client;
7
use GuzzleHttp\Exception\GuzzleException;
8
use GuzzleHttp\RequestOptions;
9
use Shetabit\Multipay\Abstracts\Driver;
10
use Shetabit\Multipay\Contracts\ReceiptInterface;
11
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
12
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
13
use Shetabit\Multipay\Invoice;
14
use Shetabit\Multipay\Receipt;
15
use Shetabit\Multipay\RedirectionForm;
16
use Shetabit\Multipay\Request;
17
18
class Snapppay extends Driver
19
{
20
    /**
21
     * Digipay Client.
22
     *
23
     * @var Client
24
     */
25
    protected $client;
26
27
    /**
28
     * Invoice
29
     *
30
     * @var Invoice
31
     */
32
    protected $invoice;
33
34
    /**
35
     * Driver settings
36
     *
37
     * @var object
38
     */
39
    protected $settings;
40
    /**
41
     * snapppay Oauth Token
42
     *
43
     * @var string
44
     */
45
    protected $oauthToken;
46
47
    /**
48
     * Snapppay payment url
49
     *
50
     * @var string
51
     */
52
    protected $paymentUrl;
53
    protected $paymentToken;
54
55
    /**
56
     * Snapppay constructor.
57
     * Construct the class with the relevant settings.
58
     *
59
     * @param Invoice $invoice
60
     * @param $settings
61
     */
62
    public function __construct(Invoice $invoice, $settings)
63
    {
64
        $this->invoice($invoice);
65
        $this->settings = (object)$settings;
66
        $this->client = new Client();
67
        $this->oauthToken = $this->oauth();
68
    }
69
70
    /**
71
     * @throws PurchaseFailedException
72
     */
73
    public function purchase(): string
74
    {
75
        $phone = $this->invoice->getDetail('phone') ?? $this->invoice->getDetail('mobile');
76
        $phoneNumber = preg_replace('/\D/', '', $phone);
77
78
        // Check if the number starts with '0' and is 11 digits long
79
        if (strlen($phoneNumber) === 11 && $phoneNumber[0] === '0') {
80
            // Replace the leading '0' with '+98'
81
            $phoneNumber = '+98' . substr($phoneNumber, 1);
82
        }
83
        $data = [
84
            "amount" => $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1),
85
            "cartList" => [
86
                [
87
                    "cartId" => 1,
88
                    "cartItems" => [
89
                        [
90
                            "amount" => 0,
91
                            "category" => "string",
92
                            "count" => 1,
93
                            "id" => 0,
94
                            "name" => "string",
95
                            "commissionType" => 0
96
                        ]
97
                    ],
98
                    "isShipmentIncluded" => false,
99
                    "isTaxIncluded" => false,
100
                    "shippingAmount" => 0,
101
                    "taxAmount" => 0,
102
                    "totalAmount" => $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1),
103
                ]
104
            ],
105
106
107
            "discountAmount" => 0,
108
            "externalSourceAmount" => 0,
109
            "mobile" => $phoneNumber,
110
            "paymentMethodTypeDto" => "INSTALLMENT",
111
            "returnURL" => $this->settings->callbackUrl,
112
            "transactionId" => $this->invoice->getUuid()
113
        ];
114
115
        $response = $this->client->request(
116
            'POST',
117
            $this->settings->apiPurchaseUrl,
118
            [
119
                RequestOptions::BODY => json_encode($data),
120
                RequestOptions::HEADERS => [
121
                    'Content-Type' => 'application/json',
122
                    'Authorization' => 'Bearer ' . $this->oauthToken,
123
                ],
124
                RequestOptions::HTTP_ERRORS => false,
125
            ]
126
        );
127
128
        $body = json_decode($response->getBody()->getContents(), true);
129
        if ($response->getStatusCode() != 200) {
130
            // error has happened
131
            $message = $body['result']['message'] ?? 'خطا در هنگام درخواست برای پرداخت رخ داده است.';
132
            throw new PurchaseFailedException($message);
133
        }
134
        $this->invoice->transactionId($body['response']['paymentToken']);
135
        $this->setPaymentUrl($body['response']['paymentPageUrl']);
136
137
        // return the transaction's id
138
        return $this->invoice->getTransactionId();
139
    }
140
141
    public function pay(): RedirectionForm
142
    {
143
        parse_str(parse_url($this->getPaymentUrl(), PHP_URL_QUERY), $formData);
144
        return $this->redirectWithForm($this->getPaymentUrl(), $formData, 'GET');
145
    }
146
147
    /**
148
     * @throws InvalidPaymentException
149
     */
150
    public function verify(): ReceiptInterface
151
    {
152
        $response = $this->client->request(
153
            'POST',
154
            $this->settings->apiVerificationUrl,
155
            [
156
                RequestOptions::BODY => json_encode(['paymentToken' => $this->invoice->getTransactionId()]),
157
                RequestOptions::HEADERS => [
158
                    'Content-Type' => 'application/json',
159
                    'Authorization' => 'Bearer ' . $this->oauthToken,
160
                ],
161
                RequestOptions::HTTP_ERRORS => false,
162
            ]
163
        );
164
        $body = json_decode($response->getBody()->getContents(), true);
165
        if ($response->getStatusCode() != 200) {
166
            $message = $body['result']['message'] ?? 'تراکنش تایید نشد';
167
            throw new InvalidPaymentException($message, (int)$response->getStatusCode());
168
        }
169
170
        return (new Receipt('snapppay', $body["response"]['transactionId']))->detail($body);
171
    }
172
173
    /**
174
     * @throws PurchaseFailedException
175
     */
176
    protected function oauth()
177
    {
178
        $response = $this
179
            ->client
180
            ->request(
181
                'POST',
182
                $this->settings->apiOauthUrl,
183
                [
184
                    RequestOptions::HEADERS => [
185
                        'Authorization' => 'Basic ' . base64_encode("{$this->settings->client_id}:{$this->settings->client_secret}"),
186
                    ],
187
                    RequestOptions::MULTIPART => [
188
                        [
189
                            "name" => "username",
190
                            "contents" => $this->settings->username,
191
                        ],
192
                        [
193
                            "name" => "password",
194
                            "contents" => $this->settings->password,
195
                        ],
196
                        [
197
                            "name" => "grant_type",
198
                            "contents" => 'password',
199
                        ],
200
                    ],
201
                    RequestOptions::HTTP_ERRORS => false,
202
                ]
203
            );
204
205
206
        if ($response->getStatusCode() != 200) {
207
            if ($response->getStatusCode() == 401) {
208
                throw new PurchaseFailedException("خطا نام کاربری یا رمز عبور شما اشتباه می باشد.");
209
            } else {
210
                throw new PurchaseFailedException("خطا در هنگام احراز هویت.");
211
            }
212
        }
213
214
215
        $body = json_decode($response->getBody()->getContents(), true);
216
        $this->oauthToken = $body['access_token'];
217
        return $body['access_token'];
218
    }
219
220
    /**
221
     * @return string
222
     */
223
    public function getPaymentUrl(): string
224
    {
225
        return $this->paymentUrl;
226
    }
227
228
    public function getPaymentToken(): string
229
    {
230
        return $this->paymentToken;
231
    }
232
233
    /**
234
     * @param string $paymentUrl
235
     */
236
    public function setPaymentUrl(string $paymentUrl): void
237
    {
238
        $this->paymentUrl = $paymentUrl;
239
    }
240
241
    public function setPaymentToken(string $paymentToken): void
242
    {
243
        $this->paymentToken = $paymentToken;
244
    }
245
}
246