1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
handler.php
См. документацию.
1<?php
2
3namespace Sale\Handlers\PaySystem;
4
5use Bitrix\Main\Application;
6use Bitrix\Main\ArgumentException;
7use Bitrix\Main\Error;
8use Bitrix\Main\Localization\Loc;
9use Bitrix\Main\Request;
10use Bitrix\Main\Type\DateTime;
11use Bitrix\Main\Web;
12use Bitrix\Sale\BusinessValue;
13use Bitrix\Sale\Internals\YandexSettingsTable;
14use Bitrix\Sale\Payment;
15use Bitrix\Sale\PaySystem;
16use Bitrix\Sale\PriceMaths;
17
18Loc::loadMessages(__FILE__);
19
20class YandexInvoiceHandler extends PaySystem\ServiceHandler
21{
27 public function initiatePay(Payment $payment, Request $request = null)
28 {
29 $errors = '';
30
31 if ($request === null)
32 {
33 $instance = Application::getInstance();
34 $context = $instance->getContext();
35 $request = $context->getRequest();
36 }
37
38 $serviceResult = new PaySystem\ServiceResult();
39
40 if ($request->get('phone') !== null)
41 {
42 $payload = array(
43 'payer' => array('phone' => $request->get('phone')),
44 'recipient' => array(
45 'shopId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID'),
46 'shopArticleId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ARTICLE_ID'),
47 ),
48 'order' => array(
49 'clientOrderId' => $this->getBusinessValue($payment, 'PAYMENT_ID'),
50 'customerId' => $request->get('phone'),
51 'amount' => $this->getBusinessValue($payment, 'PAYMENT_SHOULD_PAY'),
52 'currency' => $payment->getField('CURRENCY'),
53 'parameters' => array(
54 'pay_system_id' => $this->service->getField('ID')
55 )
56 ),
57 'schemes' => array($this->service->getField('PS_MODE'))
58 );
59
60 $params = $this->prepareRequest($payment, $payload);
61
62 $http = new Web\HttpClient();
63 $http->setCharset("utf-8");
64
65 $result = $http->post($this->getUrl($payment, 'payments'), array('request' => $params));
66 if ($result)
67 {
68 try
69 {
70 $result = Web\Json::decode($result);
71 }
72 catch (ArgumentException $e)
73 {
74 $errors .= $e->getMessage();
75 }
76
77 if ($errors === '')
78 {
79 if (in_array($result['status'], array('Created', 'Approved')))
80 {
81 $scheme = current($result['schemes']);
82 if ($scheme)
83 {
84 $billUrl = $this->getUrl($payment, 'bill');
85 $payload = array(
86 'payer' => array('phone' => $request->get('phone')),
87 'scheme' => $scheme['scheme'],
88 'orderId' => $result['orderId'],
89 );
90
91 $http = new Web\HttpClient();
92 $http->setCharset("utf-8");
93 $result = $http->post($billUrl, array('request' => $this->prepareRequest($payment, $payload)));
94 if ($result)
95 {
96 try
97 {
98 $result = Web\Json::decode($result);
99 }
100 catch (ArgumentException $e)
101 {
102 $errors .= $e->getMessage();
103 }
104
105 if (in_array($result['status'], array('Authorized', 'Processing')))
106 $serviceResult->setPsData(array('PS_INVOICE_ID' => $result['orderId']));
107 else
108 $errors .= $result['error'];
109 }
110 else
111 {
112 $errors .= implode("\n", $http->getError());
113 }
114 }
115 }
116 else if ($result['status'] == 'Refused')
117 {
118 $errors .= $result['error'];
119 }
120 }
121 }
122 else
123 {
124 $errors .= implode("\n", $http->getError());
125 }
126
127 if ($errors === '')
128 {
129 $templateName = 'success';
130 $this->setExtraParams(array('PAYMENT_SUM' => $payment->getSum()));
131 }
132 else
133 {
134 $serviceResult->addError(new Error($errors));
135 $templateName = 'failure';
136 }
137
138 $template = $this->showTemplate($payment, $templateName);
139 $serviceResult->setTemplate($template->getTemplate());
140 }
141 else
142 {
144 $paymentCollection = $payment->getCollection();
145
147 $order = $paymentCollection->getOrder();
148
149 $this->setExtraParams(
150 array(
151 'ORDER_ID' => $order->getId(),
152 'ACCOUNT_NUMBER' => $order->getField('ACCOUNT_NUMBER'),
153 'PAYSYSTEM_ID' => $this->service->getField('ID')
154 )
155 );
156
157 return $this->showTemplate($payment, 'template');
158 }
159
160 return $serviceResult;
161 }
162
166 public function getCurrencyList()
167 {
168 return array('RUB');
169 }
170
176 public function processRequest(Payment $payment, Request $request)
177 {
178 $serviceResult = new PaySystem\ServiceResult();
179
180 if ($request->get('request') === null)
181 return $serviceResult;
182
183 list($header, $payload, $sign) = explode('.', $request->get('request'));
184 if (!$this->isSignCorrect($payment, $header.'.'.$payload, $sign))
185 {
186 $payload = Web\Json::decode(self::base64Decode($payload));
187
188 $data = array(
189 'notificationType' => 'PaymentAviso',
190 'orderId' => $payload['orderId'],
191 'shopId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID'),
192 'shopArticleId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ARTICLE_ID'),
193 'status' => 'Refused',
194 'error' => 'IllegalSignature'
195 );
196
197 $serviceResult->setData(array('response' => $this->prepareRequest($payment, $data)));
198
199 return $serviceResult;
200 }
201
202 $header = Web\Json::decode(self::base64Decode($header));
203 $payload = Web\Json::decode(self::base64Decode($payload));
204
205 if ($payload['notificationType'] === 'PaymentAviso' && $header['iss'] === 'Yandex.Money')
206 {
207 return $this->processNoticeAction($payment, $payload);
208 }
209
210 $data = array(
211 'notificationType' => 'PaymentAviso',
212 'orderId' => $payload['orderId'],
213 'shopId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID'),
214 'shopArticleId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ARTICLE_ID'),
215 'status' => 'Refused',
216 'error' => 'SyntaxError'
217 );
218
219 $serviceResult->setData(array('response' => $this->prepareRequest($payment, $data)));
220
221 return $serviceResult;
222 }
223
229 private function processNoticeAction(Payment $payment, array $payload)
230 {
231 $serviceResult = new PaySystem\ServiceResult();
232
233 $data = array(
234 'notificationType' => 'PaymentAviso',
235 'orderId' => $payload['orderId'],
236 'shopId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID'),
237 'shopArticleId' => $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ARTICLE_ID'),
238 );
239
240 $paymentPrice = PriceMaths::roundPrecision($this->getBusinessValue($payment, 'PAYMENT_SHOULD_PAY'));
241 $yandexPrice = PriceMaths::roundPrecision($payload['order']['amount']);
242 if ($yandexPrice === $paymentPrice)
243 {
244 $serviceResult->setOperationType($serviceResult::MONEY_COMING);
245 $psData = array(
246 'PS_INVOICE_ID' => $payload['orderId'],
247 'PS_STATUS' => ($payload['status'] == 'Authorized') ? 'Y' : 'N',
248 'PS_SUM' => $payload['order']['amount'],
249 'PS_CURRENCY' => mb_substr($payload['order']['currency'], 0, 3),
250 'PS_RESPONSE_DATE' => new DateTime(),
251 );
252 $serviceResult->setPsData($psData);
253
254 $data['status'] = 'Delivered';
255 }
256 else
257 {
258 $data['status'] = 'Refused';
259 $data['error'] = 'SyntaxError';
260 $serviceResult->addError(new Error(Loc::getMessage('SALE_HPS_YANDEX_INVOICE_ERROR_SUM')));
261 }
262
263 $serviceResult->setData(array('response' => $this->prepareRequest($payment, $data)));
264 return $serviceResult;
265 }
266
271 public function getPaymentIdFromRequest(Request $request)
272 {
273 list($header, $payload, $sign) = explode('.', $request->get('request'));
274 if ($payload)
275 {
276 $payload = Web\Json::decode(self::base64Decode($payload));
277 return $payload['order']['clientOrderId'];
278 }
279
280 return '';
281 }
282
286 protected function getUrlList()
287 {
288
289 return array(
290 'test' => array(
291 self::TEST_URL => 'http://angius.yandex.ru:8082/payment-api/json-api/api/version',
292 self::ACTIVE_URL => 'https://money.yandex.ru/api/v2/version'
293 ),
294 'payments' => array(
295 self::TEST_URL => 'http://angius.yandex.ru:8082/payment-api/json-api/api/payments',
296 self::ACTIVE_URL => 'https://money.yandex.ru/api/v2/payments'
297 ),
298 'bill' => array(
299 self::TEST_URL => 'http://angius.yandex.ru:8082/payment-api/json-api/api/mobileInvoice',
300 self::ACTIVE_URL => 'https://money.yandex.ru/api/v2/payments/mobileInvoice'
301 )
302 );
303 }
304
308 public static function getHandlerModeList()
309 {
310 return array(
311 'Sberbank' => Loc::getMessage('SALE_HPS_YANDEX_INVOICE_SBERBANK'),
312 'Wallet' => Loc::getMessage('SALE_HPS_YANDEX_INVOICE_WALLET')
313 );
314 }
315
322 private function prepareRequest(Payment $payment, array $payload)
323 {
324 $header = array(
325 "alg" => "ES256",
326 "iat" => round(microtime(true) * 1000),
327 "iss" => "shopId:".$this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID'),
328 "aud" => $this->isTestMode($payment) ? 'test' : 'production'
329 );
330
331 $jsonHeader = Web\Json::encode((object)$header);
332 $jsonPayload = Web\Json::encode((object)$payload);
333
334 $data = self::base64Encode($jsonHeader).'.'.self::base64Encode($jsonPayload);
335
336 $sign = '';
337 $shopId = $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID');
338 if ($shopId)
339 {
340 $dbRes = YandexSettingsTable::getById($shopId);
341 if ($settings = $dbRes->fetch())
342 $sign = $this->sign($data, $this->getKeyResource($settings['PKEY']));
343 }
344 return $data.'.'.self::base64Encode($sign);
345 }
346
351 static private function base64Encode($data)
352 {
353 return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
354 }
355
360 static private function base64Decode($data)
361 {
362 return base64_decode(strtr($data, '-_', '+/'));
363 }
364
370 public function sendResponse(PaySystem\ServiceResult $result, Request $request)
371 {
372 global $APPLICATION;
373 $APPLICATION->RestartBuffer();
374
375 $data = $result->getData();
376 echo $data['response'];
377
378 $APPLICATION->FinalActions();
379 die();
380 }
381
388 private function isSignCorrect(Payment $payment, $data, $sign)
389 {
390 $binary = self::base64Decode($sign);
391 list($r, $s) = str_split($binary, (int) (mb_strlen($binary) / 2));
392
393 $r = ltrim($r, "\x00");
394 $s = ltrim($s, "\x00");
395
396 if (ord($r[0]) > 0x7f) $r = "\x00" . $r;
397 if (ord($s[0]) > 0x7f) $s = "\x00" . $s;
398
399 $binary = PaySystem\ASN1::encodeDER(
400 PaySystem\ASN1::SEQUENCE,
401 PaySystem\ASN1::encodeDER(PaySystem\ASN1::INTEGER_TYPE, $r).PaySystem\ASN1::encodeDER(PaySystem\ASN1::INTEGER_TYPE, $s),
402 false
403 );
404
405 $shopId = $this->getBusinessValue($payment, 'YANDEX_INVOICE_SHOP_ID');
406 $dbRes = YandexSettingsTable::getById($shopId);
407 if ($settings = $dbRes->fetch())
408 {
409 $verify = openssl_verify($data, $binary, $settings['PUB_KEY'], 'SHA256');
410 return $verify === 1;
411 }
412
413 return false;
414 }
415
421 private function sign($input, $keyResource)
422 {
423 $signature = null;
424 $signAlgo = OPENSSL_ALGO_SHA256;
425
426 $r = openssl_sign($input, $signature, $keyResource, $signAlgo);
427
428 if ($r === true)
429 {
430 $offset = 0;
431 $offset += PaySystem\ASN1::readDER($signature, $offset, $value);
432 $offset += PaySystem\ASN1::readDER($signature, $offset, $r);
433 $offset += PaySystem\ASN1::readDER($signature, $offset, $s);
434
435 $r = ltrim($r, "\x00");
436 $s = ltrim($s, "\x00");
437
438// $r = str_pad($r, $keyResource->getSize() / 8, "\x00", STR_PAD_LEFT);
439// $s = str_pad($s, $keyResource->getSize() / 8, "\x00", STR_PAD_LEFT);
440
441 $signature = $r . $s;
442 }
443
444 return $signature;
445 }
446
451 private function getKeyResource($key)
452 {
453 if (is_resource($key))
454 return $key;
455
456 return openssl_pkey_get_public($key) ?: openssl_pkey_get_private($key);
457 }
458
463 protected function isTestMode(Payment $payment = null)
464 {
465 return $this->getBusinessValue($payment, 'PS_IS_TEST') == 'Y';
466 }
467
471 static public function getIndicativeFields()
472 {
473 return array('request');
474 }
475
481 protected static function isMyResponseExtended(Request $request, $paySystemId)
482 {
483 list($header, $payload, $sign) = explode('.', $request->get('request'));
484 if ($payload)
485 {
486 $payload = Web\Json::decode(self::base64Decode($payload));
487
488 if (!array_key_exists('parameters', $payload['order']))
489 return false;
490
491 if (!array_key_exists('pay_system_id', $payload['order']['parameters']))
492 return false;
493
494 return $paySystemId == $payload['order']['parameters']['pay_system_id'];
495 }
496
497 return false;
498 }
499
503 public function isTuned()
504 {
505 $personTypeList = PaySystem\Manager::getPersonTypeIdList($this->service->getField('ID'));
506 $personTypeId = array_shift($personTypeList);
507 $shopId = BusinessValue::get('YANDEX_INVOICE_SHOP_ID', $this->service->getConsumerName(), $personTypeId);
508
509 return !empty($shopId);
510 }
511}
global $APPLICATION
Определения include.php:80
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
Определения catalog_reindex.php:36
static encodeDER($type, $value='', $primitive=true, $class=0)
Определения asn1.php:115
const SEQUENCE
Определения asn1.php:55
const INTEGER_TYPE
Определения asn1.php:50
getUrl(Payment $payment=null, $action)
Определения baseservicehandler.php:343
initiatePay(Payment $payment, Request $request=null)
showTemplate(Payment $payment=null, $template='')
Определения baseservicehandler.php:59
getBusinessValue(Payment $payment=null, $code)
Определения baseservicehandler.php:184
$data['IS_AVAILABLE']
Определения .description.php:13
$template
Определения file_edit.php:49
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
$errors
Определения iblock_catalog_edit.php:74
$context
Определения csv_new_setup.php:223
trait Error
Определения error.php:11
$payment
Определения payment.php:14
$order
Определения payment.php:8
$paymentCollection
Определения payment.php:11
$sign
Определения payment.php:69
$settings
Определения product_settings.php:43
$instance
Определения ps_b24_final.php:14
if(empty($signedUserToken)) $key
Определения quickway.php:257
die
Определения quickway.php:367
$shopId
Определения refund.php:14
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$dbRes
Определения yandex_detail.php:168