Passed
Push — master ( 57db64...5c0b46 )
by mahdi
02:55
created

Zarinpal::purchase()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
eloc 23
c 2
b 1
f 0
dl 0
loc 39
rs 8.9297
cc 6
nc 16
nop 0
1
<?php
2
3
namespace Shetabit\Payment\Drivers\Zarinpal;
4
5
use Shetabit\Payment\Abstracts\Driver;
6
use Shetabit\Payment\Exceptions\InvalidPaymentException;
7
use Shetabit\Payment\Exceptions\PurchaseFailedException;
8
use Shetabit\Payment\Contracts\ReceiptInterface;
9
use Shetabit\Payment\Invoice;
10
use Shetabit\Payment\Receipt;
11
12
class Zarinpal extends Driver
13
{
14
    /**
15
     * Invoice
16
     *
17
     * @var Invoice
18
     */
19
    protected $invoice;
20
21
    /**
22
     * Driver settings
23
     *
24
     * @var object
25
     */
26
    protected $settings;
27
28
    /**
29
     * Zarinpal constructor.
30
     * Construct the class with the relevant settings.
31
     *
32
     * @param Invoice $invoice
33
     * @param $settings
34
     */
35
    public function __construct(Invoice $invoice, $settings)
36
    {
37
        $this->invoice($invoice);
38
        $this->settings = (object) $settings;
39
    }
40
41
    /**
42
     * Purchase Invoice.
43
     *
44
     * @return string
45
     *
46
     * @throws PurchaseFailedException
47
     * @throws \SoapFault
48
     */
49
    public function purchase()
50
    {
51
        if (!empty($this->invoice->getDetails()['description'])) {
52
            $description = $this->invoice->getDetails()['description'];
53
        } else {
54
            $description = $this->settings->description;
55
        }
56
57
        if (!empty($this->invoice->getDetails()['mobile'])) {
58
            $mobile = $this->invoice->getDetails()['mobile'];
59
        }
60
61
        if (!empty($this->invoice->getDetails()['email'])) {
62
            $email = $this->invoice->getDetails()['email'];
63
        }
64
65
        $data = array(
66
            'MerchantID' => $this->settings->merchantId,
67
            'Amount' => $this->invoice->getAmount(),
68
            'CallbackURL' => $this->settings->callbackUrl,
69
            'Description' => $description,
70
            'Mobile' => $mobile ?? '',
71
            'Email' => $email ?? '',
72
            'AdditionalData' => $this->invoice->getDetails()
73
        );
74
75
        $client = new \SoapClient($this->getPurchaseUrl(), ['encoding' => 'UTF-8']);
76
        $result = $client->PaymentRequest($data);
77
78
        if ($result->Status != 100 || empty($result->Authority)) {
79
            // some error has happened
80
            $message = $this->translateStatus($result->Status);
81
            throw new PurchaseFailedException($message);
82
        }
83
84
        $this->invoice->transactionId($result->Authority);
85
86
        // return the transaction's id
87
        return $this->invoice->getTransactionId();
88
    }
89
90
    /**
91
     * Pay the Invoice
92
     *
93
     * @return \Illuminate\Http\RedirectResponse|mixed
94
     */
95
    public function pay()
96
    {
97
        $transactionId = $this->invoice->getTransactionId();
98
        $paymentUrl = $this->getPaymentUrl();
99
100
        if (strtolower($this->getMode()) == 'zaringate') {
101
            $payUrl = str_replace(':authority', $transactionId, $paymentUrl);
102
        } else {
103
            $payUrl = $paymentUrl.$transactionId;
104
        }
105
106
        // redirect using laravel logic
107
        return redirect()->to($payUrl);
108
    }
109
110
    /**
111
     * Verify payment
112
     *
113
     * @return ReceiptInterface
114
     *
115
     * @throws InvalidPaymentException
116
     * @throws \SoapFault
117
     */
118
    public function verify() : ReceiptInterface
119
    {
120
        $authority = $this->invoice->getTransactionId() ?? request()->get('Authority');
121
        $status = request()->get('Status');
122
123
        $data = [
124
            'MerchantID' => $this->settings->merchantId,
125
            'Authority' => $authority,
126
            'Amount' => $this->invoice->getAmount(),
127
        ];
128
129
        if ($status != 'OK') {
130
            throw new InvalidPaymentException('عملیات پرداخت توسط کاربر لغو شد.');
131
        }
132
133
        $client = new \SoapClient($this->getVerificationUrl(), ['encoding' => 'UTF-8']);
134
        $result = $client->PaymentVerification($data);
135
136
        if ($result->Status != 100) {
137
            $message = $this->translateStatus($result->Status);
138
            throw new InvalidPaymentException($message);
139
        }
140
141
        return $this->createReceipt($result->RefID);
142
    }
143
144
    /**
145
     * Generate the payment's receipt
146
     *
147
     * @param $referenceId
148
     *
149
     * @return Receipt
150
     */
151
    public function createReceipt($referenceId)
152
    {
153
        return new Receipt('zarinpal', $referenceId);
154
    }
155
156
    /**
157
     * Convert status to a readable message.
158
     *
159
     * @param $status
160
     *
161
     * @return mixed|string
162
     */
163
    private function translateStatus($status)
164
    {
165
        $translations = array(
166
            "-1" => "اطلاعات ارسال شده ناقص است.",
167
            "-2" => "IP و يا مرچنت كد پذيرنده صحيح نيست",
168
            "-3" => "با توجه به محدوديت هاي شاپرك امكان پرداخت با رقم درخواست شده ميسر نمي باشد",
169
            "-4" => "سطح تاييد پذيرنده پايين تر از سطح نقره اي است.",
170
            "-11" => "درخواست مورد نظر يافت نشد.",
171
            "-12" => "امكان ويرايش درخواست ميسر نمي باشد.",
172
            "-21" => "هيچ نوع عمليات مالي براي اين تراكنش يافت نشد",
173
            "-22" => "تراكنش نا موفق ميباشد",
174
            "-33" => "رقم تراكنش با رقم پرداخت شده مطابقت ندارد",
175
            "-34" => "سقف تقسيم تراكنش از لحاظ تعداد يا رقم عبور نموده است",
176
            "-40" => "اجازه دسترسي به متد مربوطه وجود ندارد.",
177
            "-41" => "اطلاعات ارسال شده مربوط به AdditionalData غيرمعتبر ميباشد.",
178
            "-42" => "مدت زمان معتبر طول عمر شناسه پرداخت بايد بين 30 دقيه تا 45 روز مي باشد.",
179
            "-54" => "درخواست مورد نظر آرشيو شده است",
180
            "101" => "عمليات پرداخت موفق بوده و قبلا PaymentVerification تراكنش انجام شده است.",
181
        );
182
183
        $unknownError = 'خطای ناشناخته رخ داده است.';
184
185
        return array_key_exists($status, $translations) ? $translations[$status] : $unknownError;
186
    }
187
188
    /**
189
     * Retrieve purchase url
190
     *
191
     * @return string
192
     */
193
    protected function getPurchaseUrl() : string
194
    {
195
        $mode = $this->getMode();
196
197
        switch ($mode) {
198
            case 'sandbox':
199
                $url = $this->settings->sandboxApiPurchaseUrl;
200
                break;
201
            case 'zaringate':
202
                $url = $this->settings->zaringateApiPurchaseUrl;
203
                break;
204
            default: // default: normal
205
                $url = $this->settings->apiPurchaseUrl;
206
                break;
207
        }
208
209
        return $url;
210
    }
211
212
    /**
213
     * Retrieve Payment url
214
     *
215
     * @return string
216
     */
217
    protected function getPaymentUrl() : string
218
    {
219
        $mode = $this->getMode();
220
221
        switch ($mode) {
222
            case 'sandbox':
223
                $url = $this->settings->sandboxApiPaymentUrl;
224
                break;
225
            case 'zaringate':
226
                $url = $this->settings->zaringateApiPaymentUrl;
227
                break;
228
            default: // default: normal
229
                $url = $this->settings->apiPaymentUrl;
230
                break;
231
        }
232
233
        return $url;
234
    }
235
236
    /**
237
     * Retrieve verification url
238
     *
239
     * @return string
240
     */
241
    protected function getVerificationUrl() : string
242
    {
243
        $mode = $this->getMode();
244
245
        switch ($mode) {
246
            case 'sandbox':
247
                $url = $this->settings->sandboxApiVerificationUrl;
248
                break;
249
            case 'zaringate':
250
                $url = $this->settings->zaringateApiVerificationUrl;
251
                break;
252
            default: // default: normal
253
                $url = $this->settings->apiVerificationUrl;
254
                break;
255
        }
256
257
        return $url;
258
    }
259
260
    /**
261
     * Retrieve payment mode.
262
     *
263
     * @return string
264
     */
265
    protected function getMode() : string
266
    {
267
        return strtolower($this->settings->mode);
268
    }
269
}
270