Passed
Branch master (7f24b0)
by mahdi
25:20 queued 21:10
created

Pasargad::verify()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 51
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 32
c 1
b 0
f 1
dl 0
loc 51
rs 9.408
cc 4
nc 3
nop 0

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\Payment\Drivers\Pasargad;
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\Drivers\Pasargad\Utils\RSAProcessor;
10
use Shetabit\Payment\Invoice;
11
use Shetabit\Payment\Receipt;
12
13
class Pasargad extends Driver
14
{
15
    /**
16
     * Invoice
17
     *
18
     * @var Invoice
19
     */
20
    protected $invoice;
21
22
    /**
23
     * Driver settings
24
     *
25
     * @var object
26
     */
27
    protected $settings;
28
29
    /**
30
     * Prepared invoice's data
31
     *
32
     * @var array
33
     */
34
    protected $preparedData = array();
35
36
    /**
37
     * Pasargad(PEP) constructor.
38
     * Construct the class with the relevant settings.
39
     *
40
     * @param Invoice $invoice
41
     * @param $settings
42
     */
43
    public function __construct(Invoice $invoice, $settings)
44
    {
45
        $this->invoice($invoice);
46
        $this->settings = (object) $settings;
47
    }
48
49
    /**
50
     * Purchase Invoice.
51
     *
52
     * @return string
53
     */
54
    public function purchase()
55
    {
56
        $invoiceData = $this->getPreparedInvoiceData();
57
58
        $this->invoice->transactionId($invoiceData['signed']);
59
60
        // return the transaction's id
61
        return $this->invoice->getTransactionId();
62
    }
63
64
    /**
65
     * Pay the Invoice
66
     *
67
     * @return \Illuminate\Http\RedirectResponse|mixed
68
     */
69
    public function pay()
70
    {
71
        $paymentUrl = $this->settings->apiPaymentUrl;
72
        $data = array_merge($this->getPreparedInvoiceData(), ['submit' => 'Checkout']);
73
74
        // redirect using HTML form
75
        return $this->redirectWithForm($paymentUrl, $data, 'POST');
76
    }
77
78
    /**
79
     * Verify payment
80
     *
81
     * @return ReceiptInterface
82
     *
83
     * @throws InvalidPaymentException
84
     * @throws \GuzzleHttp\Exception\GuzzleException
85
     */
86
    public function verify() : ReceiptInterface
87
    {
88
        $client = new Client();
0 ignored issues
show
Bug introduced by
The type Shetabit\Payment\Drivers\Pasargad\Client was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
89
90
        $response = $client
91
            ->request(
92
                'POST',
93
                $this->settings->apiCheckTransactionUrl,
94
                [
95
                    "form_params" => ['invoiceUID' => request()->input('tref')],
96
                    "http_errors" => false,
97
                ]
98
            );
99
100
        $invoiceDetails = $this->makeXMLTree($response->getBody()->getContents());
101
        $referenceId = $invoiceDetails['resultObj']['transactionReferenceID'];
102
        $traceNumber = $invoiceDetails['resultObj']['traceNumber'];
103
        $referenceNumber = $invoiceDetails['resultObj']['referenceNumber'];
104
105
        $invoiceData = $this->getPreparedInvoiceData();
106
        $fields = array(
107
            'InvoiceNumber' => request()->input('iN'),
108
            'InvoiceDate' => request()->input('tref'),
109
            'MerchantCode' => $invoiceData['merchantCode'],
110
            'TerminalCode' => $invoiceData['terminalCode'],
111
            'amount' => $invoiceData['amount'],
112
            'TimeStamp' => $invoiceData['timeStamp'],
113
            'sign' => $invoiceData['sign']
114
        );
115
116
117
        $response = $client
118
            ->request(
119
                'POST',
120
                $this->settings->apiVerificationUrl,
121
                [
122
                    "form_params" => $fields,
123
                    "http_errors" => false,
124
                ]
125
            );
126
        $verifyResult = $this->makeXMLTree($response->getBody()->getContents());
127
128
        if (empty($verifyResult['actionResult']) || is_null($verifyResult['actionResult']['result'])) {
129
            throw new InvalidPaymentException($this->getDefaultExceptionMessage());
130
        }
131
132
        if ($verifyResult['actionResult']['result'] === false) {
133
            throw new InvalidPaymentException($verifyResult['actionResult']['resultMessage'] ?? $this->getDefaultExceptionMessage());
134
        }
135
136
        return $this->createReceipt($referenceId, $traceNumber, $referenceNumber);
137
    }
138
139
    /**
140
     * Generate the payment's receipt
141
     *
142
     * @param $referenceId
143
     *
144
     * @return Receipt
145
     */
146
    protected function createReceipt($referenceId, $traceNumber, $referenceNumber)
147
    {
148
        $reciept = new Receipt('Pasargad', $referenceId);
149
150
        $reciept->detail('trace_number', $traceNumber);
151
        $reciept->detail('reference_number', $referenceNumber);
152
153
        return $reciept;
154
    }
155
156
    /**
157
     * A default message for exceptions
158
     *
159
     * @return string
160
     */
161
    protected function getDefaultExceptionMessage()
162
    {
163
        return 'مشکلی در دریافت اطلاعات از بانک به وجود آمده است';
164
    }
165
166
    /**
167
     * Sign given data.
168
     *
169
     * @param string $data
170
     *
171
     * @return string
172
     */
173
    public function sign($data)
174
    {
175
        $certificate = $this->settings->certificate;
176
        $certificateType = $this->settings->certificateType;
177
178
        $processor = new RSAProcessor($certificate, $certificateType);
179
180
        return $processor->sign($data);
181
    }
182
183
    /**
184
     * Retrieve prepared invoice's data
185
     *
186
     * @return array
187
     */
188
    protected function getPreparedInvoiceData()
189
    {
190
        if (empty($this->preparedData)) {
191
            $this->preparedData = $this->prepareInvoiceData();
192
        }
193
194
        return $this->preparedData;
195
    }
196
197
    /**
198
     * Prepare invoice data
199
     *
200
     * @return array
201
     */
202
    protected function prepareInvoiceData()
203
    {
204
        $action = "1003"; 	// 1003 : for buy request (bank standard)
205
        $merchantCode = $this->settings->merchantId;
206
        $terminalCode = $this->settings->terminalCode;
207
        $amount = $this->invoice->getAmount() * 10; // convert to toman
208
        $redirectAddress = $this->settings->callbackUrl;
209
        $invoiceNumber = crc32($this->invoice->getUuid()).rand(0, time());
210
        $timeStamp = date("Y/m/d H:i:s");
211
212
        if (!empty($this->invoice->getDetails()['date'])) {
213
            $invoiceDate = $this->invoice->getDetails()['date'];
214
        } else {
215
            $invoiceDate = date("Y/m/d H:i:s");
216
        }
217
218
        $data = "#". $merchantCode ."#". $terminalCode ."#". $invoiceNumber ."#". $invoiceDate ."#". $amount ."#". $redirectAddress ."#". $action ."#". $timeStamp ."#";
219
        $data = sha1($data, true);
220
        $data =  $this->sign($data);
221
        $signedData =  base64_encode($data);
222
223
        return [
224
            'invoiceNumber' => $invoiceNumber,
225
            'invoiceDate' => $invoiceDate,
226
            'amount' => $amount,
227
            'terminalCode' => $terminalCode,
228
            'merchantCode' => $merchantCode,
229
            'redirectAddress' => $redirectAddress,
230
            'timeStamp' => $timeStamp,
231
            'action' => $action,
232
            'signed' => $signedData,
233
        ];
234
    }
235
236
    /**
237
     * Convert XML tree to array
238
     *
239
     * @param $data
240
     *
241
     * @return array
242
     */
243
    protected function makeXMLTree($data)
244
    {
245
        $ret = array();
246
247
        $parser = xml_parser_create();
248
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
249
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
250
        xml_parse_into_struct($parser, $data, $values, $tags);
251
        xml_parser_free($parser);
252
253
        $hash_stack = array();
254
        foreach ($values as $key => $val) {
255
            switch ($val['type']) {
256
             case 'open':
257
                array_push($hash_stack, $val['tag']);
258
             break;
259
             case 'close':
260
                array_pop($hash_stack);
261
             break;
262
             case 'complete':
263
                array_push($hash_stack, $val['tag']);
264
                // uncomment to see what this function is doing
265
                // echo("\$ret[" . implode($hash_stack, "][") . "] = '{$val[value]}';\n");
266
                eval("\$ret[" . implode($hash_stack, "][") . "] = '{$val[value]}';");
0 ignored issues
show
Bug introduced by
'][' of type string is incompatible with the type array expected by parameter $pieces of implode(). ( Ignorable by Annotation )

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

266
                eval("\$ret[" . implode($hash_stack, /** @scrutinizer ignore-type */ "][") . "] = '{$val[value]}';");
Loading history...
Bug introduced by
The constant Shetabit\Payment\Drivers\Pasargad\value was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
introduced by
The use of eval() is discouraged.
Loading history...
267
                array_pop($hash_stack);
268
             break;
269
          }
270
        }
271
272
        return $ret;
273
    }
274
}
275