3namespace Sale\Handlers\PaySystem;
7 Bitrix\Main\Localization,
8 Bitrix\Main\Web\HttpClient,
10 Bitrix\Sale\PaySystem,
11 Bitrix\Sale\PriceMaths,
12 Bitrix\Sale\PaymentCollection,
23 protected const PAYMENT_OPERATION_DEPOSITED =
'deposited';
24 protected const PAYMENT_STATUS_SUCCESS = 1;
26 protected const RESPONSE_CODE_SUCCESS = 0;
28 protected const PAYMENT_STATE_CREATED =
'CREATED';
30 protected const PAYMENT_DELIMITER =
'_';
45 public function initiatePay(Payment
$payment, Request
$request =
null): PaySystem\ServiceResult
47 $result =
new PaySystem\ServiceResult();
51 if (
$payment->getField(
'PS_INVOICE_ID'))
53 $checkOrderResult = $this->checkOrder(
$payment);
54 $checkOrderData = $checkOrderResult->getData();
57 if (!isset($checkOrderData[
'URL']))
59 $orderAttemptNumber = 0;
60 if (isset($checkOrderData[
'ORDER_ATTEMPT_NUMBER']))
62 $orderAttemptNumber = $checkOrderData[
'ORDER_ATTEMPT_NUMBER'];
63 $orderAttemptNumber = (int)$orderAttemptNumber + 1;
66 $createOrderResult = $this->createOrder(
$payment, $orderAttemptNumber);
67 if (!$createOrderResult->isSuccess())
69 $result->addErrors($createOrderResult->getErrors());
73 $createOrderData = $createOrderResult->getData();
74 $params[
'URL'] = $createOrderData[
'URL'];
75 $result->setPsData($createOrderResult->getPsData());
79 $params[
'URL'] = $checkOrderData[
'URL'];
82 $urlComponentList = parse_url(
$params[
'URL']);
83 parse_str($urlComponentList[
'query'], $formParams);
84 $params[
'FORM_PARAMS'] = $formParams;
92 if ($showTemplateResult->isSuccess())
94 $result->setTemplate($showTemplateResult->getTemplate());
98 $result->addErrors($showTemplateResult->getErrors());
118 private function checkOrder(Payment
$payment): PaySystem\ServiceResult
120 $result =
new PaySystem\ServiceResult();
122 $orderStatus = $this->getOrderStatus(
$payment);
123 if ($orderStatus->isSuccess())
125 $orderStatusData = $orderStatus->getData();
126 if (isset($orderStatusData[
'paymentAmountInfo'][
'paymentState']))
128 $paymentState = $orderStatusData[
'paymentAmountInfo'][
'paymentState'];
129 if (($paymentState === self::PAYMENT_STATE_CREATED)
130 && ((
int)
$payment->getSum() === (
int)($orderStatusData[
'amount'] / 100))
134 $params[
'URL'] = $formUrl.$payment->getField(
'PS_INVOICE_ID');
161 private function createOrder(Payment
$payment, $orderAttemptNumber): PaySystem\ServiceResult
163 $result =
new PaySystem\ServiceResult();
165 $registerOrderResult = $this->registerOrder(
$payment, $orderAttemptNumber);
166 if (!$registerOrderResult->isSuccess())
168 $result->addErrors($registerOrderResult->getErrors());
172 $sberbankResultData = $registerOrderResult->getData();
173 $result->setPsData([
'PS_INVOICE_ID' => $sberbankResultData[
'orderId']]);
174 $params[
'URL'] = $sberbankResultData[
'formUrl'];
198 public function processRequest(Payment
$payment, Request
$request): PaySystem\ServiceResult
200 $result =
new PaySystem\ServiceResult();
202 $inputJson = self::encode(
$request->toArray());
203 PaySystem\Logger::addDebugInfo(static::class.
': request: '.$inputJson);
206 if ($secretKey && !$this->isCheckSumCorrect(
$request, $secretKey))
208 $result->addError(
new Main\
Error(Localization\Loc::getMessage(
'SALE_HPS_SBERBANK_ERROR_CHECK_SUM')));
212 if (
$request->get(
'operation') === static::PAYMENT_OPERATION_DEPOSITED
213 && (
int)
$request->get(
'status') === static::PAYMENT_STATUS_SUCCESS
216 $orderStatus = $this->getOrderStatus(
$payment);
217 if ($orderStatus->isSuccess())
219 $orderStatusData = $orderStatus->getData();
220 $description = Localization\Loc::getMessage(
'SALE_HPS_SBERBANK_ORDER_ID', [
221 '#ORDER_ID#' =>
$request->get(
'mdOrder')
224 'PS_INVOICE_ID' =>
$request->get(
'mdOrder'),
225 'PS_STATUS_CODE' =>
$request->get(
'operation'),
227 'PS_SUM' => $orderStatusData[
'amount'] / 100,
229 'PS_CURRENCY' => $orderStatusData[
'currency'],
230 'PS_RESPONSE_DATE' =>
new Main\Type\DateTime()
233 if ($this->isSumCorrect(
$payment, $orderStatusData))
237 PaySystem\Logger::addDebugInfo(
243 $result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
248 $error = Localization\Loc::getMessage(
'SALE_HPS_SBERBANK_ERROR_SUM');
249 $fields[
'PS_STATUS_DESCRIPTION'] .=
'. '.$error;
257 $result->addErrors($orderStatus->getErrors());
262 $error = Localization\Loc::getMessage(
'SALE_HPS_SBERBANK_ERROR_OPERATION', [
263 '#OPERATION#' =>
$request->get(
'operation'),
264 '#STATUS#' =>
$request->get(
'status')
276 public function getPaymentIdFromRequest(Request
$request)
278 $paymentId =
$request->get(
'orderNumber');
279 [$paymentId] = explode(self::PAYMENT_DELIMITER, $paymentId);
289 return [
'mdOrder',
'orderNumber',
'checksum',
'operation',
'status'];
297 protected static function isMyResponseExtended(Request
$request, $paySystemId): bool
300 $bxPaySystemCode = (int)
$request->get(
'bx_paysystem_code');
301 if ($bxPaySystemCode)
303 return (
int)$paySystemId === $bxPaySystemCode;
309 $orderNumberPart = explode(self::PAYMENT_DELIMITER,
$orderNumber);
310 $paySystemIdFromOrderNumber = (int)($orderNumberPart[1] ?? 0);
312 return (
int)$paySystemId === $paySystemIdFromOrderNumber;
327 private function isSumCorrect(Payment
$payment,
array $paymentData): bool
329 $sberbankAmount = $paymentData[
'amount'] / 100;
330 PaySystem\Logger::addDebugInfo(
331 static::class.
': requestSum='.PriceMaths::roundPrecision($sberbankAmount).
'; paymentSum='.PriceMaths::roundPrecision(
$payment->getSum())
334 return PriceMaths::roundPrecision($sberbankAmount) === PriceMaths::roundPrecision(
$payment->getSum());
342 protected function isCheckSumCorrect(Request
$request, $secretKey): bool
344 $requestParamList =
$request->toArray();
345 $checksum = $requestParamList[
'checksum'];
347 unset($requestParamList[
'checksum']);
348 ksort($requestParamList);
351 foreach ($requestParamList as $param => $value)
353 $requestParam .= $param.
';'.
$value.
';';
356 $result = hash_hmac(
'sha256' , $requestParam , $secretKey);
363 return (
$result === mb_strtoupper($checksum));
379 protected function registerOrder(Payment
$payment, $attempt = 0): PaySystem\ServiceResult
381 $result =
new PaySystem\ServiceResult();
388 if (!$sendResult->isSuccess())
390 $result->addErrors($sendResult->getErrors());
409 protected function getOrderStatus(Payment
$payment): PaySystem\ServiceResult
411 $result =
new PaySystem\ServiceResult();
418 if (!$sendResult->isSuccess())
420 $result->addErrors($sendResult->getErrors());
440 public function refund(Payment
$payment, $refundableSum): PaySystem\ServiceResult
442 $result =
new PaySystem\ServiceResult();
447 $params[
'amount'] = $refundableSum * 100;
450 if (!$sendResult->isSuccess())
452 $result->addErrors($sendResult->getErrors());
454 $error = static::class.
': refund: '.implode(
"\n", $sendResult->getErrorMessages());
455 PaySystem\Logger::addError(
$error);
460 $result->setOperationType(PaySystem\ServiceResult::MONEY_LEAVING);
477 $result =
new PaySystem\ServiceResult();
479 $httpClient =
new HttpClient();
480 $httpClient->disableSslVerification();
483 PaySystem\Logger::addDebugInfo(
484 static::class.
': request data: '.
$postData
490 $errors = $httpClient->getError();
499 PaySystem\Logger::addDebugInfo(
500 static::class.
': response data: '.
$response
506 if (!empty(
$response[
'errorCode']) && (
int)
$response[
'errorCode'] !== self::RESPONSE_CODE_SUCCESS)
517 $result->addError(
new Main\
Error(Localization\Loc::getMessage(
'SALE_HPS_SBERBANK_ERROR_DECODE_RESPONSE')));
527 protected function isTestMode(Payment
$payment =
null): bool
537 $testUrl =
'https://3dsec.sberbank.ru/payment/';
538 $activeUrl =
'https://securepayments.sberbank.ru/payment/';
542 self::TEST_URL => $testUrl .
'rest/register.do',
543 self::ACTIVE_URL => $activeUrl .
'rest/register.do',
545 'getOrderStatusExtended.do' => [
546 self::TEST_URL => $testUrl .
'rest/getOrderStatusExtended.do',
547 self::ACTIVE_URL => $activeUrl .
'rest/getOrderStatusExtended.do',
550 self::TEST_URL => $testUrl .
'rest/refund.do',
551 self::ACTIVE_URL => $activeUrl .
'rest/refund.do',
554 self::TEST_URL => $testUrl .
'merchants/sbersafe_sberid/payment_ru.html?mdOrder=',
555 self::ACTIVE_URL => $activeUrl .
'merchants/sbersafe_sberid/payment_ru.html?mdOrder=',
564 protected function getMerchantParams(Payment
$payment):
array
583 protected function getRegisterOrderParams(Payment
$payment,
int $attempt):
array
587 'bx_paysystem_code' => $this->service->getField(
'ID'),
588 'bx_label' => $this->getLabelName(),
592 'orderNumber' => $this->getOrderNumber(
$payment, $attempt),
593 'amount' => (int)PriceMaths::roundPrecision(
$payment->getSum() * 100),
594 'returnUrl' => $this->getSuccessUrl(
$payment),
595 'failUrl' => $this->getFailUrl(
$payment),
596 'jsonParams' => self::encode($jsonParams)
599 $currency = Currency\CurrencyTable::getById(
$payment->getField(
'CURRENCY'))->fetch();
605 $params[
'language'] = LANGUAGE_ID;
611 private function getOrderNumber(Payment
$payment,
int $attempt): string
620 $orderNumberPart[] = $attempt;
623 return implode(self::PAYMENT_DELIMITER, $orderNumberPart);
629 private function getLabelName(): string
631 return '1c_bitrix_'.$this->service->getField(
'ACTION_FILE');
638 private function getSuccessUrl(Payment
$payment)
641 ?: $this->service->getContext()->getUrl();
648 private function getFailUrl(Payment
$payment)
651 ?: $this->service->getContext()->getUrl();
663 protected function getOrderDescription(Payment
$payment)
666 $collection =
$payment->getCollection();
667 $order = $collection->getOrder();
668 $userEmail =
$order->getPropertyCollection()->getUserEmail();
679 $payment->getField(
'ACCOUNT_NUMBER'),
680 $order->getField(
'ACCOUNT_NUMBER'),
683 ($userEmail) ? $userEmail->getValue() :
''
685 $this->getBusinessValue(
$payment, static::getDescriptionCode(
'ORDER_DESCRIPTION'))
696 return Main\Web\Json::encode(
$data, JSON_UNESCAPED_UNICODE);
703 private static function decode(
$data)
707 return Main\Web\Json::decode(
$data);
709 catch (Main\ArgumentException $exception)
719 protected static function getDescriptionCode(
string $code): ?string
721 return static::getDescriptionCodesMap()[
$code] ??
null;
727 protected static function getDescriptionCodesMap():
array
730 'LOGIN' =>
'SBERBANK_LOGIN',
731 'PASSWORD' =>
'SBERBANK_PASSWORD',
732 'SECRET_KEY' =>
'SBERBANK_SECRET_KEY',
733 'RETURN_SUCCESS_URL' =>
'SBERBANK_RETURN_SUCCESS_URL',
734 'RETURN_FAIL_URL' =>
'SBERBANK_RETURN_FAIL_URL',
735 'ORDER_DESCRIPTION' =>
'SBERBANK_ORDER_DESCRIPTION',
736 'TEST_MODE' =>
'SBERBANK_TEST_MODE',
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
static loadMessages($file)
getUrl(Payment $payment=null, $action)
showTemplate(Payment $payment=null, $template='')
setExtraParams(array $values)
getBusinessValue(Payment $payment=null, $code)
static getIndicativeFields()
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(Loader::includeModule( 'bitrix24')) elseif(Loader::includeModule('intranet') &&CIntranetUtils::getPortalZone() !=='ru') $description
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']