1 | <?php |
||||
2 | |||||
3 | namespace BPT\pay; |
||||
4 | |||||
5 | use BPT\BPT; |
||||
6 | use BPT\constants\callbackTypes; |
||||
7 | use BPT\constants\cryptoCallbackActionTypes; |
||||
8 | use BPT\constants\cryptoCallbackStatus; |
||||
9 | use BPT\constants\cryptoStatus; |
||||
10 | use BPT\constants\fields; |
||||
11 | use BPT\constants\loggerTypes; |
||||
12 | use BPT\database\mysql; |
||||
13 | use BPT\exception\bptException; |
||||
14 | use BPT\logger; |
||||
15 | use BPT\pay\crypto\errorResponseInterface; |
||||
16 | use BPT\pay\crypto\estimatePriceInterface; |
||||
17 | use BPT\pay\crypto\estimateUpdateInterface; |
||||
18 | use BPT\pay\crypto\invoicePaymentInterface; |
||||
19 | use BPT\pay\crypto\invoiceResponseInterface; |
||||
20 | use BPT\pay\crypto\ipnDataInterface; |
||||
21 | use BPT\pay\crypto\paymentInterface; |
||||
22 | use BPT\receiver\callback; |
||||
23 | use BPT\telegram\request; |
||||
24 | use BPT\tools\tools; |
||||
25 | use BPT\types\cryptoCallback; |
||||
26 | use CurlHandle; |
||||
27 | use function BPT\object; |
||||
28 | |||||
29 | class crypto { |
||||
30 | private static string $ipn_secret = ''; |
||||
31 | |||||
32 | private static int $round_decimal = 4; |
||||
33 | |||||
34 | const API_BASE = 'https://api.nowpayments.io/v1/'; |
||||
35 | |||||
36 | private static CurlHandle $session; |
||||
37 | |||||
38 | public static function init (string $api_key = '', string $ipn_secret = '', int $round_decimal = 4): void { |
||||
39 | self::$ipn_secret = $ipn_secret; |
||||
40 | self::$round_decimal = $round_decimal; |
||||
41 | self::$session = curl_init(); |
||||
42 | curl_setopt(self::$session, CURLOPT_RETURNTRANSFER, true); |
||||
43 | curl_setopt(self::$session, CURLOPT_SSL_VERIFYPEER, 1); |
||||
44 | curl_setopt(self::$session, CURLOPT_SSL_VERIFYHOST, 2); |
||||
45 | curl_setopt(self::$session, CURLOPT_HTTPHEADER, [ |
||||
46 | 'X-API-KEY: ' . $api_key, |
||||
47 | 'Content-Type: application/json' |
||||
48 | ]); |
||||
49 | } |
||||
50 | |||||
51 | private static function execute (string $method, string $endpoint, string|array $data = '') { |
||||
52 | if (is_array($data)) { |
||||
53 | foreach ($data as $key => $value) { |
||||
54 | if (empty($value)) { |
||||
55 | unset($data[$key]); |
||||
56 | } |
||||
57 | } |
||||
58 | } |
||||
59 | |||||
60 | $session = self::$session; |
||||
61 | |||||
62 | switch ($method) { |
||||
63 | case 'GET': |
||||
64 | curl_setopt($session, CURLOPT_URL, self::API_BASE . $endpoint . (!empty($data) && is_array($data) ? ('?' . http_build_query($data)) : '')); |
||||
65 | break; |
||||
66 | case 'POST': |
||||
67 | curl_setopt($session, CURLOPT_POST, true); |
||||
68 | curl_setopt($session, CURLOPT_POSTFIELDS, json_encode($data)); |
||||
69 | curl_setopt($session, CURLOPT_URL, self::API_BASE . $endpoint); |
||||
70 | break; |
||||
71 | default: |
||||
72 | return false; |
||||
73 | } |
||||
74 | return json_decode(curl_exec($session)); |
||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||
75 | } |
||||
76 | |||||
77 | /** |
||||
78 | * This is a method to get information about the current state of the API. Receive true if its ok and false in otherwise |
||||
79 | * @return bool |
||||
80 | */ |
||||
81 | public static function status (): bool { |
||||
82 | return self::execute('GET', 'status')->message === 'OK'; |
||||
83 | } |
||||
84 | |||||
85 | /** |
||||
86 | * This is a method for calculating the approximate price in cryptocurrency for a given value in Fiat currency. |
||||
87 | * You will need to provide the initial cost in the Fiat currency (amount, currency_from) and the necessary |
||||
88 | * cryptocurrency (currency_to) Currently following fiat currencies are available: usd, eur, nzd, brl, gbp. |
||||
89 | * |
||||
90 | * @param int|float $amount |
||||
91 | * @param string $currency_from |
||||
92 | * @param string $currency_to |
||||
93 | * |
||||
94 | * @return estimatePriceInterface|errorResponseInterface|mixed |
||||
95 | */ |
||||
96 | public static function getEstimatePrice (int|float $amount, string $currency_from, string $currency_to) { |
||||
97 | return self::execute('GET', 'estimate', [ |
||||
98 | 'amount' => $amount, |
||||
99 | 'currency_from' => $currency_from, |
||||
100 | 'currency_to' => $currency_to |
||||
101 | ]); |
||||
102 | } |
||||
103 | |||||
104 | /** |
||||
105 | * Creates payment. With this method, your customer will be able to complete the payment without leaving your website. |
||||
106 | * |
||||
107 | * @param int|float $price_amount the fiat equivalent of the price to be paid in crypto |
||||
108 | * @param string $price_currency the fiat currency in which the price_amount is specified (usd, eur, etc). |
||||
109 | * @param string $pay_currency the cryptocurrency in which the pay_amount is specified (btc, eth, etc). |
||||
110 | * @param int|float|null $pay_amount the amount that users have to pay for the order stated in crypto |
||||
111 | * @param string|null $ipn_callback_url url to receive callbacks, should contain "http" or "https" |
||||
112 | * @param string|null $order_id inner store order ID |
||||
113 | * @param string|null $order_description inner store order description |
||||
114 | * @param string|null $purchase_id id of purchase for which you want to create aother payment, only used for several payments for one order |
||||
115 | * @param string|null $payout_address usually the funds will go to the address you specify in your Personal account. In case you want to receive funds on another address, you can specify it in this parameter. |
||||
116 | * @param string|null $payout_currency currency of your external payout_address, required when payout_adress is specified. |
||||
117 | * @param string|null $payout_extra_id extra id or memo or tag for external payout_address. |
||||
118 | * @param bool|null $fixed_rate boolean, can be true or false. Required for fixed-rate exchanges. |
||||
119 | * @param bool|null $is_fee_paid_by_user boolean, can be true or false. Required for fixed-rate exchanges with all fees paid by users. |
||||
120 | * |
||||
121 | * @return invoicePaymentInterface|errorResponseInterface|mixed |
||||
122 | */ |
||||
123 | public static function createPayment (int|float $price_amount, string $price_currency, string $pay_currency, int|float $pay_amount = null, string $ipn_callback_url = null, string $order_id = null, string $order_description = null, string $purchase_id = null, string $payout_address = null, string $payout_currency = null, string $payout_extra_id = null, bool $fixed_rate = null, bool $is_fee_paid_by_user = null) { |
||||
124 | return self::execute('POST', 'payment', [ |
||||
125 | 'price_amount' => $price_amount, |
||||
126 | 'price_currency' => $price_currency, |
||||
127 | 'pay_currency' => $pay_currency, |
||||
128 | 'pay_amount' => $pay_amount, |
||||
129 | 'ipn_callback_url' => $ipn_callback_url, |
||||
130 | 'order_id' => $order_id, |
||||
131 | 'order_description' => $order_description, |
||||
132 | 'purchase_id' => $purchase_id, |
||||
133 | 'payout_address' => $payout_address, |
||||
134 | 'payout_currency' => $payout_currency, |
||||
135 | 'payout_extra_id' => $payout_extra_id, |
||||
136 | 'fixed_rate' => $fixed_rate, |
||||
137 | 'is_fee_paid_by_user' => $is_fee_paid_by_user, |
||||
138 | ]); |
||||
139 | } |
||||
140 | |||||
141 | /** |
||||
142 | * Creates payment by invoice. With this method, your customer will be able to complete the payment without leaving your website. |
||||
143 | * |
||||
144 | * @param string $iid invoice id |
||||
145 | * @param string $pay_currency the cryptocurrency in which the pay_amount is specified (btc, eth, etc). |
||||
146 | * @param string|null $purchase_id id of purchase for which you want to create aother payment, only used for several payments for one order |
||||
147 | * @param string|null $order_description inner store order description |
||||
148 | * @param string|null $customer_email user email to which a notification about the successful completion of the payment will be sent |
||||
149 | * @param string|null $payout_address usually the funds will go to the address you specify in your Personal account. |
||||
150 | * @param string|null $payout_extra_id extra id or memo or tag for external payout_address. |
||||
151 | * @param string|null $payout_currency currency of your external payout_address, required when payout_adress is specified. |
||||
152 | * |
||||
153 | * @return invoicePaymentInterface|errorResponseInterface|mixed |
||||
154 | */ |
||||
155 | public static function createInvoicePayment (string $iid, string $pay_currency, string $purchase_id = null, string $order_description = null, string $customer_email = null, string $payout_address = null, string $payout_extra_id = null, string $payout_currency = null) { |
||||
156 | return self::execute('POST', 'invoice-payment', [ |
||||
157 | 'iid' => $iid, |
||||
158 | 'pay_currency' => $pay_currency, |
||||
159 | 'purchase_id' => $purchase_id, |
||||
160 | 'order_description' => $order_description, |
||||
161 | 'customer_email' => $customer_email, |
||||
162 | 'payout_address' => $payout_address, |
||||
163 | 'payout_extra_id' => $payout_extra_id, |
||||
164 | 'payout_currency' => $payout_currency |
||||
165 | ]); |
||||
166 | } |
||||
167 | |||||
168 | /** |
||||
169 | * This endpoint is required to get the current estimate on the payment, and update the current estimate. |
||||
170 | * Please note! Calling this estimate before expiration_estimate_date will return the current estimate, it won’t be updated. |
||||
171 | * |
||||
172 | * @param int $paymentID payment ID, for which you want to get the estimate |
||||
173 | * |
||||
174 | * @return estimateUpdateInterface|errorResponseInterface|mixed |
||||
175 | */ |
||||
176 | public static function updateEstimatePrice (int $paymentID) { |
||||
177 | return self::execute('POST', 'payment/' . $paymentID . '/update-merchant-estimate'); |
||||
178 | } |
||||
179 | |||||
180 | /** |
||||
181 | * Get the actual information about the payment. |
||||
182 | * |
||||
183 | * @param int $paymentID payment ID, for which you want to get the status |
||||
184 | * |
||||
185 | * @return paymentInterface|errorResponseInterface|mixed |
||||
186 | */ |
||||
187 | public static function getPaymentStatus (int $paymentID) { |
||||
188 | return self::execute('GET', 'payment/' . $paymentID); |
||||
189 | } |
||||
190 | |||||
191 | /** |
||||
192 | * Get the minimum payment amount for a specific pair. |
||||
193 | * |
||||
194 | * @param string $currency_from |
||||
195 | * @param string $currency_to |
||||
196 | * |
||||
197 | * @return float |
||||
198 | */ |
||||
199 | public static function getMinimumPaymentAmount (string $currency_from, string $currency_to): float { |
||||
200 | return self::execute('GET', 'min-amount', [ |
||||
201 | 'currency_from' => $currency_from, |
||||
202 | 'currency_to' => $currency_to |
||||
203 | ])->min_amount; |
||||
204 | } |
||||
205 | |||||
206 | /** |
||||
207 | * Creates an invoice. With this method, the customer is required to follow the generated url to complete the payment. |
||||
208 | * |
||||
209 | * @param int|float $price_amount |
||||
210 | * @param string $price_currency |
||||
211 | * @param string|null $pay_currency |
||||
212 | * @param string|null $ipn_callback_url |
||||
213 | * @param string|null $order_id |
||||
214 | * @param string|null $order_description |
||||
215 | * @param string|null $success_url |
||||
216 | * @param string|null $cancel_url |
||||
217 | * |
||||
218 | * @return invoiceResponseInterface|errorResponseInterface|mixed |
||||
219 | */ |
||||
220 | public static function createInvoice (int|float $price_amount, string $price_currency, string $pay_currency = null, string $ipn_callback_url = null, string $order_id = null, string $order_description = null, string $success_url = null, string $cancel_url = null) { |
||||
221 | return self::execute('POST', 'invoice', [ |
||||
222 | 'price_amount' => $price_amount, |
||||
223 | 'price_currency' => $price_currency, |
||||
224 | 'pay_currency' => $pay_currency, |
||||
225 | 'ipn_callback_url' => $ipn_callback_url, |
||||
226 | 'order_id' => $order_id, |
||||
227 | 'order_description' => $order_description, |
||||
228 | 'success_url' => $success_url, |
||||
229 | 'cancel_url' => $cancel_url |
||||
230 | ]); |
||||
231 | } |
||||
232 | |||||
233 | /** |
||||
234 | * This is a method for obtaining information about all cryptocurrencies available for payments. |
||||
235 | * |
||||
236 | * @return array |
||||
237 | */ |
||||
238 | public static function getCurrencies (): array { |
||||
239 | return self::execute('GET', 'currencies')->currencies; |
||||
240 | } |
||||
241 | |||||
242 | /** |
||||
243 | * This is a method to obtain detailed information about all cryptocurrencies available for payments. |
||||
244 | * |
||||
245 | * @return array |
||||
246 | */ |
||||
247 | public static function getFullCurrencies (): array { |
||||
248 | return self::execute('GET', 'full-currencies')->currencies; |
||||
249 | } |
||||
250 | |||||
251 | /** |
||||
252 | * This is a method for obtaining information about the cryptocurrencies available for payments. |
||||
253 | * Shows the coins you set as available for payments in the "coins settings" tab on your personal account. |
||||
254 | * |
||||
255 | * @return array |
||||
256 | */ |
||||
257 | public static function getAvailableCheckedCurrencies (): array { |
||||
258 | return self::execute('GET', 'merchant/coins')->currencies; |
||||
259 | } |
||||
260 | |||||
261 | /** |
||||
262 | * Check remote ip with nowPayments IPN ip |
||||
263 | * |
||||
264 | * @return bool |
||||
265 | */ |
||||
266 | public static function isNowPayments(): bool { |
||||
267 | return in_array(tools::remoteIP(), ['51.89.194.21', '51.75.77.69', '65.21.158.36']); |
||||
268 | } |
||||
269 | |||||
270 | /** |
||||
271 | * Check is IPN valid or not |
||||
272 | * |
||||
273 | * @return bool |
||||
274 | */ |
||||
275 | public static function isIPNRequestValid (): bool { |
||||
276 | if (empty($_SERVER['HTTP_X_NOWPAYMENTS_SIG'])) { |
||||
277 | return false; |
||||
278 | } |
||||
279 | if (!self::isNowPayments()) { |
||||
280 | return false; |
||||
281 | } |
||||
282 | $request_json = file_get_contents('php://input'); |
||||
283 | if (empty($request_json)) { |
||||
284 | return false; |
||||
285 | } |
||||
286 | $request_data = json_decode($request_json, true); |
||||
287 | ksort($request_data); |
||||
288 | $hmac = hash_hmac('sha512', json_encode($request_data, JSON_UNESCAPED_SLASHES), trim(self::$ipn_secret)); |
||||
289 | return $hmac == $_SERVER['HTTP_X_NOWPAYMENTS_SIG']; |
||||
290 | } |
||||
291 | |||||
292 | /** |
||||
293 | * First it will check if IPN is valid or not, if its valid , then it will return IPN data |
||||
294 | * |
||||
295 | * @return ipnDataInterface|mixed |
||||
296 | */ |
||||
297 | public static function getIPN () { |
||||
298 | if (!self::isIPNRequestValid()) { |
||||
299 | return false; |
||||
300 | } |
||||
301 | return json_decode(file_get_contents('php://input')); |
||||
302 | } |
||||
303 | |||||
304 | protected static function createOrder (float|int $amount, int $user_id, string $description): int|string { |
||||
305 | if (!mysql::getMysqli()) { |
||||
306 | logger::write("crypto::ezPay function used\ncreating order needed mysql connection in our mysql class", loggerTypes::ERROR); |
||||
307 | throw new bptException('MYSQL_CONNECTION_NEEDED'); |
||||
308 | } |
||||
309 | |||||
310 | mysql::insert('orders', ['user_id', 'type', 'amount', 'description'], [$user_id, callbackTypes::CRYPTO, $amount, $description]); |
||||
311 | |||||
312 | return mysql::insertId(); |
||||
313 | } |
||||
314 | |||||
315 | protected static function getOrder (int $order_id): bool|object { |
||||
316 | if (!mysql::getMysqli()) { |
||||
317 | logger::write("crypto::ezPay function used\ncreating order needed mysql connection in our mysql class", loggerTypes::ERROR); |
||||
318 | throw new bptException('MYSQL_CONNECTION_NEEDED'); |
||||
319 | } |
||||
320 | $order = mysql::select('orders', '*', ['id' => $order_id], 1); |
||||
321 | if ($order->num_rows < 1) { |
||||
322 | return false; |
||||
323 | } |
||||
324 | return $order->fetch_object(); |
||||
325 | } |
||||
326 | |||||
327 | /** |
||||
328 | * An easy way to create invoice |
||||
329 | * |
||||
330 | * Processing and authorization of ipn callbacks will be done by library |
||||
331 | * |
||||
332 | * Note : You must activate ipn in your nowPayment account, and you must set ipn_secret in the settings |
||||
333 | * |
||||
334 | * The related callback will be sent to your cryptoCallback method in handler class |
||||
335 | * |
||||
336 | * @param float|int $amount |
||||
337 | * @param int|null $user_id |
||||
338 | * @param string $currency |
||||
339 | * @param string $description |
||||
340 | * @param bool $direct_url |
||||
341 | * @param bool $one_time_url |
||||
342 | * |
||||
343 | * @return bool|string |
||||
344 | * @throws bptException |
||||
345 | */ |
||||
346 | public static function ezPay (float|int $amount, int $user_id = null, string $currency = 'usd', string $description = 'Invoice created by BPT library', bool $direct_url = false, bool $one_time_url = true): bool|string { |
||||
347 | if (empty(self::$ipn_secret)) { |
||||
348 | logger::write("crypto::ezPay function used\nyou must set ipn_secret to use this", loggerTypes::ERROR); |
||||
349 | return false; |
||||
350 | } |
||||
351 | if ($amount < 0) { |
||||
352 | logger::write("crypto::ezPay function used\namount must be bigger then 0", loggerTypes::ERROR); |
||||
353 | return false; |
||||
354 | } |
||||
355 | $user_id = $user_id ?? request::catchFields(fields::USER_ID); |
||||
356 | $order_id = self::createOrder($amount, $user_id, $description); |
||||
357 | $data = ['type' => callbackTypes::CRYPTO, 'action_type' => cryptoCallbackActionTypes::CALLBACK, 'amount' => $amount, 'currency' => $currency, 'user_id' => $user_id, 'order_id' => $order_id]; |
||||
358 | $callback_url = 'https://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] . '?data='.urlencode(callback::encodeData($data)); |
||||
359 | |||||
360 | $data = ['type' => callbackTypes::CRYPTO, 'action_type' => cryptoCallbackActionTypes::SUCCESS, 'amount' => $amount, 'currency' => $currency, 'user_id' => $user_id, 'order_id' => $order_id]; |
||||
361 | $success_url = 'https://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] . '?data='.urlencode(callback::encodeData($data)); |
||||
362 | |||||
363 | $invoice_id = self::createInvoice($amount, $currency, null, $callback_url, $order_id, $description, $success_url)->id; |
||||
364 | |||||
365 | $extra_info = [ |
||||
366 | 'invoice_id' => $invoice_id, |
||||
367 | 'currency' => $currency, |
||||
368 | 'related_payments' => [], |
||||
369 | 'total_paid' => 0, |
||||
370 | ]; |
||||
371 | if (!$direct_url && $one_time_url) { |
||||
372 | $extra_info['redirected'] = false; |
||||
373 | } |
||||
374 | |||||
375 | mysql::update('orders', [ |
||||
376 | 'extra_info' => json_encode($extra_info), |
||||
377 | ], ['id' => $order_id], 1); |
||||
378 | |||||
379 | if ($direct_url) { |
||||
380 | return 'https://nowpayments.io/payment/?iid='. $invoice_id; |
||||
381 | } |
||||
382 | |||||
383 | $data = ['type' => callbackTypes::CRYPTO, 'action_type' => cryptoCallbackActionTypes::REDIRECT, 'amount' => $amount, 'currency' => $currency, 'user_id' => $user_id, 'order_id' => $order_id]; |
||||
384 | return 'https://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] . '?data='.urlencode(callback::encodeData($data)); |
||||
385 | } |
||||
386 | |||||
387 | /** |
||||
388 | * @internal Only for BPT self usage , Don't use it in your source! |
||||
389 | */ |
||||
390 | public static function callbackProcess (array $data) { |
||||
391 | if (!isset($data['action_type'])) { |
||||
392 | return false; |
||||
393 | } |
||||
394 | |||||
395 | if (!isset($data['order_id'])) { |
||||
396 | return false; |
||||
397 | } |
||||
398 | |||||
399 | $action_type = $data['action_type']; |
||||
400 | $order_id = $data['order_id']; |
||||
401 | |||||
402 | if ($action_type === cryptoCallbackActionTypes::REDIRECT) { |
||||
403 | $order = self::getOrder($order_id); |
||||
404 | $extra_info = json_decode($order->extra_info); |
||||
405 | if (isset($extra_info->redirected)) { |
||||
406 | if ($extra_info->redirected) { |
||||
407 | BPT::exit('This link is one time only, Receive another link'); |
||||
408 | } |
||||
409 | } |
||||
410 | $url = 'https://nowpayments.io/payment/?iid='. $extra_info->invoice_id; |
||||
411 | |||||
412 | @header('Location: ' . $url); |
||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
header() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() Are you sure the usage of
header('Location: ' . $url) is correct as it seems to always return null .
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||
413 | die("<meta http-equiv='refresh' content='0; url=$url' /><script>window.location.href = '$url';</script>"); |
||||
0 ignored issues
–
show
|
|||||
414 | } |
||||
415 | |||||
416 | if ($action_type === cryptoCallbackActionTypes::CALLBACK) { |
||||
417 | $ipn = self::getIPN(); |
||||
418 | |||||
419 | if ($ipn->payment_status !== cryptoStatus::FINISHED && $ipn->payment_status !== cryptoStatus::PARTIALLY_PAID ) { |
||||
420 | die(); |
||||
0 ignored issues
–
show
|
|||||
421 | } |
||||
422 | |||||
423 | $payment_id = $ipn->payment_id; |
||||
424 | |||||
425 | $payment = self::getPaymentStatus($payment_id); |
||||
426 | |||||
427 | if (isset($payment->status) && !$payment->status) { |
||||
428 | die(); |
||||
0 ignored issues
–
show
|
|||||
429 | } |
||||
430 | |||||
431 | if ($payment->payment_status !== cryptoStatus::FINISHED && $payment->payment_status !== cryptoStatus::PARTIALLY_PAID) { |
||||
432 | die(); |
||||
0 ignored issues
–
show
|
|||||
433 | } |
||||
434 | |||||
435 | $order = self::getOrder($order_id); |
||||
436 | $extra_info = json_decode($order->extra_info, true); |
||||
437 | if (isset($extra_info['related_payments'][$payment_id])) { |
||||
438 | die(); |
||||
0 ignored issues
–
show
|
|||||
439 | } |
||||
440 | |||||
441 | $paid = round(isset($payment->actually_paid_at_fiat) && $payment->actually_paid_at_fiat > 0 ? $payment->actually_paid_at_fiat : $payment->actually_paid/$payment->pay_amount*$payment->price_amount, self::$round_decimal); |
||||
442 | $extra_info['related_payments'][$payment_id] = $paid; |
||||
443 | $extra_info['total_paid'] += $paid; |
||||
444 | mysql::update('orders', ['extra_info' => json_encode($extra_info)], ['id' => $order_id], 1); |
||||
445 | |||||
446 | $callback_data = [ |
||||
447 | 'status' => 'unknown', |
||||
448 | 'order_id' => $order_id, |
||||
449 | 'user_id' => $order->user_id, |
||||
450 | 'description' => $order->description, |
||||
451 | 'real_amount' => $order->amount, |
||||
452 | 'currency' => $extra_info['currency'], |
||||
453 | 'paid_amount' => $paid, |
||||
454 | 'total_paid' => $extra_info['total_paid'] |
||||
455 | ]; |
||||
456 | |||||
457 | if ($payment->payment_status === cryptoStatus::PARTIALLY_PAID) { |
||||
458 | $callback_data['status'] = $extra_info['total_paid'] > $order->amount ? cryptoCallbackStatus::EXTRA_PAID : ($extra_info['total_paid'] == $order->amount ? cryptoCallbackStatus::FINISHED : cryptoCallbackStatus::PARTIALLY_PAID); |
||||
459 | } |
||||
460 | |||||
461 | if ($payment->payment_status === cryptoStatus::FINISHED) { |
||||
462 | $callback_data['status'] = $extra_info['total_paid'] <= $order->amount ? cryptoCallbackStatus::FINISHED : cryptoCallbackStatus::EXTRA_PAID; |
||||
463 | } |
||||
464 | |||||
465 | $callback_data = object(...$callback_data); |
||||
466 | $callback_data = new cryptoCallback($callback_data); |
||||
467 | |||||
468 | callback::callHandler('cryptoCallback', $callback_data); |
||||
469 | return true; |
||||
470 | } |
||||
471 | |||||
472 | if ($action_type === cryptoCallbackActionTypes::SUCCESS) { |
||||
473 | if (!isset($_GET['NP_id'])) { |
||||
474 | return false; |
||||
475 | } |
||||
476 | |||||
477 | if (!is_numeric($_GET['NP_id'])) { |
||||
478 | return false; |
||||
479 | } |
||||
480 | |||||
481 | $payment_id = $_GET['NP_id']; |
||||
482 | |||||
483 | $payment = self::getPaymentStatus($payment_id); |
||||
484 | |||||
485 | if (isset($payment->status) && !$payment->status) { |
||||
486 | return false; |
||||
487 | } |
||||
488 | |||||
489 | if ($payment->payment_status !== cryptoStatus::FINISHED) { |
||||
490 | return false; |
||||
491 | } |
||||
492 | |||||
493 | $order = self::getOrder($order_id); |
||||
494 | $extra_info = json_decode($order->extra_info); |
||||
495 | |||||
496 | $callback_data = [ |
||||
497 | 'status' => cryptoCallbackStatus::SUCCESS, |
||||
498 | 'order_id' => $order_id, |
||||
499 | 'user_id' => $order->user_id, |
||||
500 | 'description' => $order->description, |
||||
501 | 'real_amount' => $order->amount, |
||||
502 | 'currency' => $extra_info->currency, |
||||
503 | 'paid_amount' => round(isset($payment->actually_paid_at_fiat) && $payment->actually_paid_at_fiat > 0 ? $payment->actually_paid_at_fiat : $payment->actually_paid/$payment->pay_amount*$payment->price_amount, self::$round_decimal), |
||||
504 | 'total_paid' => $extra_info->total_paid |
||||
505 | ]; |
||||
506 | $callback_data = object(...$callback_data); |
||||
507 | $callback_data = new cryptoCallback($callback_data); |
||||
508 | |||||
509 | callback::callHandler('cryptoCallback', $callback_data); |
||||
510 | return true; |
||||
511 | } |
||||
512 | |||||
513 | return false; |
||||
514 | } |
||||
515 | } |