Passed
Push — master ( 4b4977...15b078 )
by mahdi
02:48
created

Zibal::translateStatus()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 16
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 21
rs 9.7333
1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Zibal;
4
5
use GuzzleHttp\Client;
6
use Shetabit\Multipay\Abstracts\Driver;
7
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
8
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
9
use Shetabit\Multipay\Contracts\ReceiptInterface;
10
use Shetabit\Multipay\Invoice;
11
use Shetabit\Multipay\Receipt;
12
use Shetabit\Multipay\RedirectionForm;
13
use Shetabit\Multipay\Request;
14
15
class Zibal extends Driver
16
{
17
    /**
18
     * Zibal 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
     * Zibal 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 \GuzzleHttp\Exception\GuzzleException
58
     */
59
    public function purchase()
60
    {
61
        $details = $this->invoice->getDetails();
62
63
        $amount = $this->invoice->getAmount() * ($this->settings->currency == 'T' ? 10 : 1); // convert to rial
64
65
        $orderId = crc32($this->invoice->getUuid()).time();
66
        if (!empty($details['orderId'])) {
67
            $orderId = $details['orderId'];
68
        } elseif (!empty($details['order_id'])) {
69
            $orderId = $details['order_id'];
70
        }
71
72
        $data = array(
73
            "merchant"=> $this->settings->merchantId, //required
74
            "callbackUrl"=> $this->settings->callbackUrl, //required
75
            "amount"=> $amount, //required
76
            "orderId"=> $orderId, //optional
77
        );
78
79
        // Pass current $data array to add existing optional details
80
        $data = $this->checkOptionalDetails($data);
81
82
        $response = $this->client->request(
83
            'POST',
84
            $this->settings->apiPurchaseUrl,
85
            ["json" => $data, "http_errors" => false]
86
        );
87
88
        $body = json_decode($response->getBody()->getContents(), false);
89
90
        if ($body->result != 100) {
91
            // some error has happened
92
            throw new PurchaseFailedException($body->message);
93
        }
94
95
        $this->invoice->transactionId($body->trackId);
96
97
        // return the transaction's id
98
        return $this->invoice->getTransactionId();
99
    }
100
101
    /**
102
     * Pay the Invoice
103
     *
104
     * @return RedirectionForm
105
     */
106
    public function pay() : RedirectionForm
107
    {
108
        $payUrl = $this->settings->apiPaymentUrl.$this->invoice->getTransactionId();
109
110
        if (strtolower($this->settings->mode) == 'direct') {
111
            $payUrl .= '/direct';
112
        }
113
114
        return $this->redirectWithForm($payUrl);
115
    }
116
117
    /**
118
     * Verify payment
119
     *
120
     * @return mixed|void
121
     *
122
     * @throws InvalidPaymentException
123
     * @throws \GuzzleHttp\Exception\GuzzleException
124
     */
125
    public function verify() : ReceiptInterface
126
    {
127
        $successFlag = Request::input('success');
128
        $status = Request::input('status');
129
        $orderId = Request::input('orderId');
0 ignored issues
show
Unused Code introduced by
The assignment to $orderId is dead and can be removed.
Loading history...
130
        $transactionId = $this->invoice->getTransactionId() ?? Request::input('trackId');
131
132
        if ($successFlag != 1) {
133
            $this->notVerified($this->translateStatus($status), $status);
134
        }
135
136
        //start verfication
137
        $data = array(
138
            "merchant" => $this->settings->merchantId, //required
139
            "trackId" => $transactionId, //required
140
        );
141
142
        $response = $this->client->request(
143
            'POST',
144
            $this->settings->apiVerificationUrl,
145
            ["json" => $data, "http_errors" => false]
146
        );
147
148
        $body = json_decode($response->getBody()->getContents(), false);
149
150
        if ($body->result != 100) {
151
            $this->notVerified($body->message, $body->result);
152
        }
153
154
        /*
155
            for more info:
156
            var_dump($body);
157
        */
158
159
        return $this->createReceipt($body->refNumber);
160
    }
161
162
    /**
163
     * Generate the payment's receipt
164
     *
165
     * @param $referenceId
166
     *
167
     * @return Receipt
168
     */
169
    protected function createReceipt($referenceId)
170
    {
171
        $receipt = new Receipt('Zibal', $referenceId);
172
173
        return $receipt;
174
    }
175
176
    private function translateStatus($status)
177
    {
178
        $translations = [
179
            -2 => 'خطای داخلی',
180
            -1 => 'در انتظار پردخت',
181
            2 => 'پرداخت شده - تاییدنشده',
182
            3 => 'تراکنش توسط کاربر لغو شد.',
183
            4 => 'شماره کارت نامعتبر می‌باشد.',
184
            5 => 'موجودی حساب کافی نمی‌باشد.',
185
            6 => 'رمز واردشده اشتباه می‌باشد.',
186
            7 => 'تعداد درخواست‌ها بیش از حد مجاز می‌باشد.',
187
            8 => 'تعداد پرداخت اینترنتی روزانه بیش از حد مجاز می‌باشد.',
188
            9 => 'مبلغ پرداخت اینترنتی روزانه بیش از حد مجاز می‌باشد.',
189
            10 => 'صادرکننده‌ی کارت نامعتبر می‌باشد.',
190
            11 => '‌خطای سوییچ',
191
            12 => 'کارت قابل دسترسی نمی‌باشد.'
192
        ];
193
194
        $unknownError = 'خطای ناشناخته ای رخ داده است.';
195
196
        return array_key_exists($status, $translations) ? $translations[$status] : $unknownError;
197
    }
198
199
    /**
200
     * Trigger an exception
201
     *
202
     * @param $message
203
     * @throws InvalidPaymentException
204
     */
205
    private function notVerified($message, $code = 0)
206
    {
207
        if (empty($message)) {
208
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.', $code);
209
        } else {
210
            throw new InvalidPaymentException($message, $code);
211
        }
212
    }
213
214
    /**
215
     * Retrieve data from details using its name.
216
     *
217
     * @return string
218
     */
219
    private function extractDetails($name)
220
    {
221
        $detail = null;
222
        if (!empty($this->invoice->getDetails()[$name])) {
223
            $detail = $this->invoice->getDetails()[$name];
224
        } elseif (!empty($this->settings->$name)) {
225
            $detail = $this->settings->$name;
226
        }
227
228
        return $detail;
229
    }
230
231
    /**
232
     * Checks optional parameters existence (except orderId) and
233
     * adds them to the given $data array and returns new array
234
     * with optional parameters for api call.
235
     *
236
     * To avoid errors and have a cleaner api call log, `null`
237
     * parameters are not sent.
238
     *
239
     * To add new parameter support in the future, all that
240
     * is needed is to add parameter name to $optionalParameters
241
     * array.
242
     *
243
     * @param $data
244
     *
245
     * @return array
246
     */
247
    private function checkOptionalDetails($data)
248
    {
249
        $optionalParameters = [
250
            'mobile',
251
            'description',
252
            'allowedCards',
253
            'feeMode',
254
            'percentMode',
255
            'multiplexingInfos'
256
        ];
257
258
        foreach ($optionalParameters as $parameter) {
259
            if (!is_null($this->extractDetails($parameter))) {
260
                $parameterArray = array(
261
                    $parameter => $this->extractDetails($parameter)
262
                );
263
                $data = array_merge($data, $parameterArray);
264
            }
265
        }
266
267
        return $data;
268
    }
269
}
270