1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
handler.php
См. документацию.
1<?php
2
3namespace Sale\Handlers\PaySystem;
4
5use Bitrix\Main\Error;
6use Bitrix\Main\Localization\Loc;
7use Bitrix\Main\Request;
8use Bitrix\Main\Type\DateTime;
9use Bitrix\Main\Web\HttpClient;
10use Bitrix\Sale\BusinessValue;
11use Bitrix\Sale\PaySystem;
12use Bitrix\Sale\Payment;
13
14Loc::loadMessages(__FILE__);
15
20class YandexHandler
23{
29 public function initiatePay(Payment $payment, Request $request = null)
30 {
31 $params = array(
32 'URL' => $this->getUrl($payment, 'pay'),
33 'PS_MODE' => $this->service->getField('PS_MODE'),
34 'BX_PAYSYSTEM_CODE' => $this->service->getField('ID'),
35 );
36
37 $this->setExtraParams($params);
38
39 return $this->showTemplate($payment, "template");
40 }
41
45 public static function getIndicativeFields()
46 {
47 return array('BX_HANDLER' => 'YANDEX');
48 }
49
55 static protected function isMyResponseExtended(Request $request, $paySystemId)
56 {
57 $id = $request->get('BX_PAYSYSTEM_CODE');
58 return (int)$id === (int)$paySystemId;
59 }
60
66 public function refund(Payment $payment, $refundableSum)
67 {
68 $result = new PaySystem\ServiceResult();
69 $error = '';
70 $requestDT = date('c');
71 $currency = $this->isTestMode($payment) ? 10643 : 643;
72 $cause = Loc::getMessage('SALE_HPS_YANDEX_CUSTOMER_REJECTION');
73
74 $shopId = $this->getBusinessValue($payment, 'YANDEX_SHOP_ID');
75 $request = '
76 <returnPaymentRequest
77 clientOrderId=\''.$payment->getId().'\'
78 requestDT=\''.$requestDT.'\'
79 invoiceId=\''.$payment->getField('PS_INVOICE_ID').'\'
80 shopId=\''.$shopId.'\'
81 amount=\''.number_format($refundableSum, 2, '.', '').'\'
82 currency=\''.$currency.'\'
83 cause=\''.$cause.'\'
84 />';
85
86 $url = $this->getUrl($payment, 'return');
87
88 $signResult = $this->signRequest($payment, $request);
89 if ($signResult->isSuccess())
90 {
91 $data = $signResult->getData();
92 $pkcs7 = $data['PKCS7'];
93
94 $CertPem = PaySystem\YandexCert::getValue('CERT', $shopId);
95 $PkeyPem = PaySystem\YandexCert::getValue('PKEY', $shopId);
96
97 $cert = self::createTmpFile($CertPem);
98 $pkey = self::createTmpFile($PkeyPem);
99
100 $ch = curl_init($url);
101 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
102 curl_setopt($ch, CURLOPT_HEADER, 0);
103 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
104 curl_setopt($ch, CURLOPT_ENCODING, "");
105 curl_setopt($ch, CURLOPT_USERAGENT, "1C-Bitrix");
106 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120);
107 curl_setopt($ch, CURLOPT_TIMEOUT, 120);
108 curl_setopt($ch, CURLOPT_POST, 1);
109 curl_setopt($ch, CURLOPT_POSTFIELDS, $pkcs7);
110 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
111 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
112 curl_setopt($ch, CURLOPT_SSLCERT, $cert);
113 curl_setopt($ch, CURLOPT_SSLKEY, $pkey);
114 $content = curl_exec($ch);
115 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
116 $curlError = curl_error($ch);
117 curl_close($ch);
118
119 PaySystem\Logger::addDebugInfo('Yandex: returnPaymentResponse: '.$content);
120
121 if ($content !== false)
122 {
123 $element = $this->parseXmlResponse('returnPaymentResponse', $content);
124 $status = (int)$element->getAttribute('status');
125 if ($status == 0)
126 {
127 $result->setOperationType(PaySystem\ServiceResult::MONEY_LEAVING);
128 }
129 else
130 {
131 $error .= Loc::getMessage('SALE_HPS_YANDEX_REFUND_ERROR').' '.Loc::getMessage('SALE_HPS_YANDEX_REFUND_ERROR_INFO', array('#STATUS#' => $status, '#ERROR#' => $element->getAttribute('error')));
132 }
133 }
134 else
135 {
136 $error .= Loc::getMessage('SALE_HPS_YANDEX_REFUND_CONNECTION_ERROR', array('#URL#' => $url, '#ERROR#' => $curlError, '#CODE#' => $httpCode));
137 }
138 }
139 else
140 {
141 $error .= implode("\n", $signResult->getErrorMessages());
142 }
143
144 if ($error !== '')
145 {
146 $result->addError(new Error($error));
147
148 $error = 'Yandex: returnPaymentRequest: '.join('\n', $result->getErrorMessages());
149 PaySystem\Logger::addError($error);
150 }
151
152 return $result;
153 }
154
163 private function isCorrectHash(Payment $payment, Request $request)
164 {
165 $hash = md5(
166 implode(";", array(
167 $request->get('action'),
168 $request->get('orderSumAmount'),
169 $request->get('orderSumCurrencyPaycash'),
170 $request->get('orderSumBankPaycash'),
171 $this->getBusinessValue($payment, 'YANDEX_SHOP_ID'),
172 $request->get('invoiceId'),
173 $this->getBusinessValue($payment, 'PAYMENT_BUYER_ID'),
174 $this->getBusinessValue($payment, 'YANDEX_SHOP_KEY')
175 )
176 )
177 );
178
179 PaySystem\Logger::addDebugInfo(
180 'Yandex: calculatedHash='.mb_strtoupper($hash)."; yandexHash=".mb_strtoupper($request->get('md5'))
181 );
182
183 return mb_strtoupper($hash) === mb_strtoupper($request->get('md5'));
184 }
185
194 private function isCorrectSum(Payment $payment, Request $request)
195 {
196 $sum = $request->get('orderSumAmount');
197 $paymentSum = $this->getBusinessValue($payment, 'PAYMENT_SHOULD_PAY');
198
199 PaySystem\Logger::addDebugInfo(
200 'Yandex: yandexSum='.round($sum, 2)."; paymentSum=".round($paymentSum, 2)
201 );
202
203 return round($paymentSum, 2) == round($sum, 2);
204 }
205
211 public function sendResponse(PaySystem\ServiceResult $result, Request $request)
212 {
213 global $APPLICATION;
214 $APPLICATION->RestartBuffer();
215
216 $data = $result->getData();
217
218 if (!$result->isResultApplied() && $data['CODE'] === 0)
219 {
220 $data['CODE'] = 200;
221 }
222
223 $dateISO = date("Y-m-d\TH:i:s").mb_substr(date("O"), 0, 3).":".mb_substr(date("O"), -2, 2);
224 header("Content-Type: text/xml");
225 header("Pragma: no-cache");
226 $text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
227
228 if ($data['HEAD'] <> '')
229 {
230 $text .= "<".$data['HEAD']." performedDatetime=\"".$dateISO."\"";
231 $text .= " code=\"".$data['CODE']."\" shopId=\"".$data['SHOP_ID']."\" invoiceId=\"".$data['INVOICE_ID']."\"";
232
233 if ($data['TECH_MESSAGE'] <> '')
234 $text .= " techMessage=\"".$data['TECH_MESSAGE']."\"";
235
236 $text .= "/>";
237 }
238
239 PaySystem\Logger::addDebugInfo('Yandex: response: '.$text);
240
241 echo $text;
242 die();
243 }
244
249 public function getPaymentIdFromRequest(Request $request)
250 {
251 return $request->get('orderNumber');
252 }
253
259 private function processCheckAction(Payment $payment, Request $request)
260 {
261 $result = new PaySystem\ServiceResult();
262 $data = $this->extractDataFromRequest($request);
263
264 if ($this->isCorrectSum($payment, $request))
265 {
266 $data['CODE'] = 0;
267 }
268 else
269 {
270 $data['CODE'] = 100;
271 $errorMessage = 'Incorrect payment sum';
272 $result->addError(new Error($errorMessage));
273
274 PaySystem\Logger::addError('Yandex: checkOrderResponse: '.$errorMessage);
275 }
276
277 $result->setData($data);
278
279 return $result;
280 }
281
286 private function extractDataFromRequest(Request $request)
287 {
288 return array(
289 'HEAD' => $request->get('action').'Response',
290 'SHOP_ID' => $request->get('shopId'),
291 'INVOICE_ID' => $request->get('invoiceId')
292 );
293 }
294
300 private function processNoticeAction(Payment $payment, Request $request)
301 {
302 $result = new PaySystem\ServiceResult();
303 $data = $this->extractDataFromRequest($request);
304 $modeList = static::getHandlerModeList();
305 $description = Loc::getMessage('SALE_HPS_YANDEX_TRANSACTION').": ".$request->get('invoiceId')."; ";
306 if ($request->get('paymentDatetime'))
307 {
308 $description .= Loc::getMessage('SALE_HPS_YANDEX_DATE_PAYED').": ".$request->get('paymentDatetime');
309 }
310
311 $fields = array(
312 "PS_STATUS_CODE" => mb_substr($data['HEAD'], 0, 5),
313 "PS_STATUS_DESCRIPTION" => $description,
314 "PS_STATUS_MESSAGE" => $modeList[$request->get('paymentType')],
315 "PS_SUM" => $request->get('orderSumAmount'),
316 "PS_CURRENCY" => mb_substr($request->get('orderSumCurrencyPaycash'), 0, 3),
317 "PS_RESPONSE_DATE" => new DateTime(),
318 "PS_INVOICE_ID" => $request->get('invoiceId')
319 );
320
321 if ($this->isCorrectSum($payment, $request))
322 {
323 $data['CODE'] = 0;
324 $fields["PS_STATUS"] = "Y";
325
326 PaySystem\Logger::addDebugInfo(
327 'Yandex: PS_CHANGE_STATUS_PAY='.$this->getBusinessValue($payment, 'PS_CHANGE_STATUS_PAY')
328 );
329
330 if ($this->getBusinessValue($payment, 'PS_CHANGE_STATUS_PAY') == 'Y')
331 {
332 $result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
333 }
334 }
335 else
336 {
337 $data['CODE'] = 200;
338 $fields["PS_STATUS"] = "N";
339 $errorMessage = 'Incorrect payment sum';
340 $result->addError(new Error($errorMessage));
341
342 PaySystem\Logger::addError('Yandex: paymentAvisoResponse: '.$errorMessage);
343 }
344
345 $result->setData($data);
346 $result->setPsData($fields);
347
348 return $result;
349 }
350
356 private function processCancelAction(Payment $payment, Request $request)
357 {
358 $result = new PaySystem\ServiceResult();
359 $data = $this->extractDataFromRequest($request);
360
361 if ($this->isCorrectHash($payment, $request))
362 {
363 $data['CODE'] = 0;
364 $result->setOperationType(PaySystem\ServiceResult::MONEY_LEAVING);
365 }
366 else
367 {
368 $data['CODE'] = 1;
369
370 $errorMessage = 'Incorrect payment hash sum';
371 $result->addError(new Error($errorMessage));
372
373 PaySystem\Logger::addError('Yandex: cancelOrderResponse: '.$errorMessage);
374 }
375
376 $result->setData($data);
377
378 return $result;
379 }
380
384 protected function getUrlList()
385 {
386 return array(
387 'pay' => 'https://yoomoney.ru/eshop.xml',
388 'confirm' => array(
389 self::ACTIVE_URL => 'https://penelope.yamoney.ru/webservice/mws/api/confirmPayment',
390 self::TEST_URL => 'https://penelope-demo.yamoney.ru:8083/webservice/mws/api/confirmPayment'
391 ),
392 'cancel' => array(
393 self::ACTIVE_URL => 'https://penelope.yamoney.ru/webservice/mws/api/cancelPayment',
394 self::TEST_URL => 'https://penelope-demo.yamoney.ru:8083/webservice/mws/api/cancelPayment'
395 ),
396 'return' => array(
397 self::ACTIVE_URL => 'https://penelope.yamoney.ru/webservice/mws/api/returnPayment',
398 self::TEST_URL => 'https://penelope-demo.yamoney.ru:8083/webservice/mws/api/returnPayment',
399 )
400 );
401 }
402
408 public function processRequest(Payment $payment, Request $request)
409 {
410 $result = new PaySystem\ServiceResult();
411 $action = $request->get('action');
412
413 if ($this->isCorrectHash($payment, $request))
414 {
415 if ($action == 'checkOrder')
416 {
417 return $this->processCheckAction($payment, $request);
418 }
419 else if ($action == 'cancelOrder')
420 {
421 return $this->processCancelAction($payment, $request);
422 }
423 else if ($action == 'paymentAviso')
424 {
425 return $this->processNoticeAction($payment, $request);
426 }
427 else
428 {
429 $data = $this->extractDataFromRequest($request);
430 $data['TECH_MESSAGE'] = 'Unknown action: '.$action;
431 $result->setData($data);
432 $result->addError(new Error('Unknown action: '.$action.'. Request='.join(', ', $request->toArray())));
433 }
434 }
435 else
436 {
437 $data = $this->extractDataFromRequest($request);
438 $data['TECH_MESSAGE'] = 'Incorrect hash sum';
439 $data['CODE'] = 1;
440
441 $result->setData($data);
442 $result->addError(new Error('Incorrect hash sum'));
443 }
444
445 if (!$result->isSuccess())
446 {
447 $error = 'Yandex: processRequest: '.$action.': '.join('\n', $result->getErrorMessages());
448 PaySystem\Logger::addError($error);
449 }
450
451 return $result;
452 }
453
458 protected function isTestMode(Payment $payment = null)
459 {
460 return ($this->getBusinessValue($payment, 'PS_IS_TEST') == 'Y');
461 }
462
467 public function confirm(Payment $payment)
468 {
469 $result = new PaySystem\ServiceResult();
470 $httpClient = new HttpClient();
471
472 $url = $this->getUrl($payment, 'confirm');
473 $requestDT = date('c');
474
475 $request = array(
476 'orderId' => $this->getBusinessValue($payment, 'PAYMENT_ID'),
477 'amount' => $this->getBusinessValue($payment, 'PAYMENT_SHOULD_PAY'),
478 'currency' => $this->getBusinessValue($payment, 'PAYMENT_CURRENCY'),
479 'requestDT' => $requestDT
480 );
481 $responseString = $httpClient->post($url, $request);
482
483 if ($responseString !== false)
484 {
485 $element = $this->parseXmlResponse('confirmPaymentResponse', $responseString);
486 $status = (int)$element->getAttribute('status');
487 if ($status == 0)
488 $result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
489 else
490 $result->addError(new Error('Error on try to confirm payment. Status: '.$status));
491 }
492 else
493 {
494 $result->addError(new Error("Error sending request. URL=".$url." PARAMS=".join(' ', $request)));
495 }
496
497 if (!$result->isSuccess())
498 {
499 $error = 'Yandex: confirmPayment: '.join('\n', $result->getErrorMessages());
500 PaySystem\Logger::addError($error);
501 }
502
503 return $result;
504 }
505
510 public function cancel(Payment $payment)
511 {
512 $result = new PaySystem\ServiceResult();
513 $httpClient = new HttpClient();
514
515 $url = $this->getUrl($payment, 'cancel');
516 $requestDT = date('c');
517 $request = array(
518 'orderId' => $this->getBusinessValue($payment, 'PAYMENT_ID'),
519 'requestDT' => $requestDT
520 );
521 $responseString = $httpClient->post($url, $request);
522
523 if($responseString !== false)
524 {
525 $element = $this->parseXmlResponse('cancelPaymentResponse', $responseString);
526 $status = (int)$element->getAttribute('status');
527 if ($status == 0)
528 $result->setOperationType(PaySystem\ServiceResult::MONEY_LEAVING);
529 else
530 $result->addError(new Error('Error on try to cancel payment. Status: '.$status));
531 }
532 else
533 {
534 $result->addError(new Error('Error sending request. URL='.$url.' PARAMS='.join(' ', $request)));
535 }
536
537 if (!$result->isSuccess())
538 {
539 $error = 'Yandex: cancelPayment: '.join('\n', $result->getErrorMessages());
540 PaySystem\Logger::addError($error);
541 }
542
543 return $result;
544 }
545
551 private function parseXmlResponse($operation, $requestString)
552 {
553 $xmlParser = new \CDataXML();
554
555 $xmlParser->LoadString($requestString);
556 $tree = $xmlParser->GetTree();
557 $elements = $tree->elementsByName($operation);
558
559 return $elements[0];
560 }
561
568 private function signRequest(Payment $payment, $xml)
569 {
570 $result = new PaySystem\ServiceResult();
571
572 $dataFile = self::createTmpFile($xml);
573 $signedFile = self::createTmpFile();
574
575 $shopId = $this->getBusinessValue($payment, 'YANDEX_SHOP_ID');
576 $CertPem = PaySystem\YandexCert::getValue('CERT', $shopId);
577 $PkeyPem = PaySystem\YandexCert::getValue('PKEY', $shopId);
578
579 if ($PkeyPem && $CertPem)
580 {
581 if (openssl_pkcs7_sign($dataFile, $signedFile, $CertPem, $PkeyPem, array(), PKCS7_NOCHAIN + PKCS7_NOCERTS))
582 {
583 $signedData = explode("\n\n", file_get_contents($signedFile));
584 $pkcs7 = "-----BEGIN PKCS7-----\n".$signedData[1]."\n-----END PKCS7-----";
585 $result->setData(array('PKCS7' => $pkcs7));
586 }
587 else
588 {
589 $result->addError(new Error(Loc::getMessage('SALE_HPS_YANDEX_REFUND_ERROR')));
590 }
591 }
592 else
593 {
594 $result->addError(new Error(Loc::getMessage('SALE_HPS_YANDEX_REFUND_ERROR')));
595 }
596
597 return $result;
598 }
599
604 private static function createTmpFile($data = null)
605 {
606 $filePath = tempnam(sys_get_temp_dir(), 'YaMWS');
607 if ($data !== null)
608 file_put_contents($filePath, $data);
609
610 return $filePath;
611 }
612
613
617 public function getCurrencyList()
618 {
619 return array('RUB');
620 }
621
625 public static function getHandlerModeList()
626 {
627 return array(
628 "PC" => Loc::getMessage("SALE_HPS_YANDEX_YMoney"),
629 "AC" => Loc::getMessage("SALE_HPS_YANDEX_Cards"),
630 "GP" => Loc::getMessage("SALE_HPS_YANDEX_Terminals"),
631 "MC" => Loc::getMessage("SALE_HPS_YANDEX_Mobile"),
632 "SB" => Loc::getMessage("SALE_HPS_YANDEX_Sberbank"),
633 "MP" => Loc::getMessage("SALE_HPS_YANDEX_mPOS"),
634 "AB" => Loc::getMessage("SALE_HPS_YANDEX_AlphaClick"),
635 "MA" => Loc::getMessage("SALE_HPS_YANDEX_MasterPass"),
636 "PB" => Loc::getMessage("SALE_HPS_YANDEX_Promsvyazbank"),
637 "QW" => Loc::getMessage("SALE_HPS_YANDEX_Qiwi"),
638// "KV" => Loc::getMessage("SALE_HPS_YANDEX_TinkoffBank"),
639 "QP" => Loc::getMessage("SALE_HPS_YANDEX_YKuppiRu"),
640 "" => Loc::getMessage("SALE_HPS_YANDEX_Smart")
641 );
642 }
643
647 public function isRefundableExtended()
648 {
649 $whiteList = array('PC', 'AC', 'MC', 'MP', 'AB', 'MA', 'QW', 'KV', 'QP');
650 return in_array($this->service->getField('PS_MODE'), $whiteList);
651 }
652
656 public function isTuned()
657 {
658 $personTypeList = PaySystem\Manager::getPersonTypeIdList($this->service->getField('ID'));
659 $personTypeId = array_shift($personTypeList);
660 $shopId = BusinessValue::get('YANDEX_SHOP_ID', $this->service->getConsumerName(), $personTypeId);
661
662 return !empty($shopId);
663 }
664
669 public static function findMyDataRefundablePage(array $paySystemList)
670 {
671 $result = array();
672 $personTypeList = BusinessValue::getPersonTypes();
673 $handler = PaySystem\Manager::getFolderFromClassName(get_called_class());
674 $description = PaySystem\Manager::getHandlerDescription($handler);
675
676 foreach ($paySystemList as $data)
677 {
678 foreach ($personTypeList as $personType)
679 {
680 $shopId = BusinessValue::get('YANDEX_SHOP_ID', PaySystem\Service::PAY_SYSTEM_PREFIX.$data['ID'], $personType['ID']);
681 if ($shopId && !isset($result[$shopId]))
682 {
683 $cert = PaySystem\YandexCert::getCert($shopId);
685 'EXTERNAL_ID' => $shopId,
686 'NAME' => $description['NAME'],
687 'HANDLER' => 'yandex',
688 'LINK_PARAMS' => 'shop_id='.$shopId,
689 'CONFIGURED' => ($cert) ? 'Y' : 'N'
690 );
691 }
692 }
693 }
694
695 return $result;
696 }
697}
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
Определения catalog_reindex.php:36
getUrl(Payment $payment=null, $action)
Определения baseservicehandler.php:343
showTemplate(Payment $payment=null, $template='')
Определения baseservicehandler.php:59
getBusinessValue(Payment $payment=null, $code)
Определения baseservicehandler.php:184
$data['IS_AVAILABLE']
Определения .description.php:13
</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
if(Loader::includeModule( 'bitrix24')) elseif(Loader::includeModule('intranet') &&CIntranetUtils::getPortalZone() !=='ru') $description
Определения .description.php:24
$status
Определения session.php:10
trait Error
Определения error.php:11
$payment
Определения payment.php:14
$shopId
Определения refund.php:14
$currency
Определения template.php:266
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$error
Определения subscription_card_product.php:20
$action
Определения file_dialog.php:21
$url
Определения iframe.php:7