Passed
Push — master ( a063d5...db0222 )
by mahdi
08:15
created

Zibal::checkOptionalDetails()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 13
c 1
b 0
f 0
nc 3
nop 1
dl 0
loc 21
rs 9.8333
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
        // convert to toman
64
        $toman = $this->invoice->getAmount() * 10;
65
66
        $orderId = crc32($this->invoice->getUuid()).time();
67
        if (!empty($details['orderId'])) {
68
            $orderId = $details['orderId'];
69
        } elseif (!empty($details['order_id'])) {
70
            $orderId = $details['order_id'];
71
        }
72
73
        $data = array(
74
            "merchant"=> $this->settings->merchantId, //required
75
            "callbackUrl"=> $this->settings->callbackUrl, //required
76
            "amount"=> $toman, //required
77
            "orderId"=> $orderId, //optional
78
        );
79
80
        // Pass current $data array to add existing optional details
81
        $data = $this->checkOptionalDetails($data);
82
83
        $response = $this->client->request(
84
            'POST',
85
            $this->settings->apiPurchaseUrl,
86
            ["json" => $data, "http_errors" => false]
87
        );
88
89
        $body = json_decode($response->getBody()->getContents(), false);
90
91
        if ($body->result != 100) {
92
            // some error has happened
93
            throw new PurchaseFailedException($body->message);
94
        }
95
96
        $this->invoice->transactionId($body->trackId);
97
98
        // return the transaction's id
99
        return $this->invoice->getTransactionId();
100
    }
101
102
    /**
103
     * Pay the Invoice
104
     *
105
     * @return RedirectionForm
106
     */
107
    public function pay() : RedirectionForm
108
    {
109
        $payUrl = $this->settings->apiPaymentUrl.$this->invoice->getTransactionId();
110
111
        if (strtolower($this->settings->mode) == 'direct') {
112
            $payUrl .= '/direct';
113
        }
114
115
        return $this->redirectWithForm($payUrl);
116
    }
117
118
    /**
119
     * Verify payment
120
     *
121
     * @return mixed|void
122
     *
123
     * @throws InvalidPaymentException
124
     * @throws \GuzzleHttp\Exception\GuzzleException
125
     */
126
    public function verify() : ReceiptInterface
127
    {
128
        $successFlag = Request::input('success');
129
        $orderId = Request::input('orderId');
130
        $transactionId = $this->invoice->getTransactionId() ?? Request::input('trackId');
131
132
        if ($successFlag != 1) {
133
            $this->notVerified('پرداخت با شکست مواجه شد');
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);
152
        }
153
154
        /*
155
            for more info:
156
            var_dump($body);
157
        */
158
159
        return $this->createReceipt($orderId);
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
    /**
177
     * Trigger an exception
178
     *
179
     * @param $message
180
     * @throws InvalidPaymentException
181
     */
182
    private function notVerified($message)
183
    {
184
        if (empty($message)) {
185
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.');
186
        } else {
187
            throw new InvalidPaymentException($message);
188
        }
189
    }
190
191
    /**
192
     * Retrieve data from details using its name.
193
     *
194
     * @return string
195
     */
196
    private function extractDetails($name)
197
    {
198
        $detail = null;
199
        if (!empty($this->invoice->getDetails()[$name])) {
200
            $detail = $this->invoice->getDetails()[$name];
201
        } elseif (!empty($this->settings->$name)) {
202
            $detail = $this->settings->$name;
203
        }
204
205
        return $detail;
206
    }
207
208
    /**
209
     * Checks optional parameters existence (except orderId) and
210
     * adds them to the given $data array and returns new array
211
     * with optional parameters for api call.
212
     *
213
     * To avoid errors and have a cleaner api call log, `null`
214
     * parameters are not sent.
215
     *
216
     * To add new parameter support in the future, all that
217
     * is needed is to add parameter name to $optionalParameters
218
     * array.
219
     *
220
     * @param $data
221
     *
222
     * @return array
223
     */
224
    private function checkOptionalDetails($data)
225
    {
226
        $optionalParameters = [
227
            'mobile',
228
            'description',
229
            'allowedCards',
230
            'feeMode',
231
            'percentMode',
232
            'multiplexingInfos'
233
        ];
234
235
        foreach ($optionalParameters as $parameter) {
236
            if (!is_null($this->extractDetails($parameter))) {
237
                $parameterArray = array(
238
                    $parameter => $this->extractDetails($parameter)
239
                );
240
                $data = array_merge($data, $parameterArray);
241
            }
242
        }
243
244
        return $data;
245
    }
246
}
247