22 private $handlerFields =
array();
24 private const FORM_MODE =
'form';
25 private const CHECKOUT_MODE =
'checkout';
26 private const IFRAME_MODE =
'iframe';
38 $request = Context::getCurrent()->getRequest();
41 $mode = $this->getMode();
43 if ($mode === self::CHECKOUT_MODE)
48 if ($mode === self::IFRAME_MODE)
50 return $this->initiateIframePay(
$payment);
62 $actionUri =
$settings[
'CHECKOUT_DATA'][
'ACTION_URI'] ??
null;
63 if (!isset($actionUri))
65 $result->addError(
new Error(Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_ERROR_URI_MISSING')));
76 $requestResult = Rest\Http::sendRequest($actionUri,
$params);
77 if (!$requestResult->isSuccess())
79 $result->addErrors($requestResult->getErrors());
83 $requestData = $requestResult->getData();
84 if (empty($requestData[
'PAYMENT_URL']) || empty($requestData[
'PAYMENT_ID']))
86 if (!empty($requestData[
'PAYMENT_ERRORS']) && is_array($requestData[
'PAYMENT_ERRORS']))
88 foreach ($requestData[
'PAYMENT_ERRORS'] as
$error)
96 $result->addError(
new Error(Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_ERROR_DATA_MISSING')));
100 $result->setPsData([
'PS_INVOICE_ID' => $requestData[
'PAYMENT_ID']]);
101 $url = $requestData[
'PAYMENT_URL'];
105 $qrCode = ((
new PaySystem\BarcodeGenerator())->generate(
$url));
108 $result->setQr(base64_encode($qrCode));
114 if ($this->initiateMode === static::STREAM)
128 $checkoutSettings =
$settings[
'CHECKOUT_DATA'];
129 if (isset($checkoutSettings[
'FIELDS']))
131 return !empty(array_diff_key($checkoutSettings[
'FIELDS'],
$params));
141 $checkoutSettings = $this->getHandlerSettings()[
'CHECKOUT_DATA'];
142 if (isset($checkoutSettings[
'FIELDS']))
144 $params = $this->getQueryDataFromFields(
$payment, $checkoutSettings[
'FIELDS']);
148 foreach ($requestData as $field => $value)
150 if (isset($checkoutSettings[
'FIELDS'][$field]))
159 private function getCheckoutFormTemplate(Payment
$payment): string
162 $formSettings =
$settings[
'CHECKOUT_DATA'];
164 $template =
'<div class="mb-4" id="rest-checkout">';
165 $template .=
'<form name="rest-checkout-form" id="rest-checkout-form">';
167 if (isset($formSettings[
'FIELDS']))
172 $template .=
'<input type="hidden" name="BX_PAYSYSTEM_ID" value="'.$this->service->getField(
'ID').
'">';
173 $template .=
'<input name="button" value="'.Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_BUTTON_PAID').
'" type="submit" class="btn btn-lg btn-success pl-4 pr-4" style="border-radius: 32px;">';
177 $messages = Loc::loadLanguageFile(__FILE__);
180 BX.message(' . \CUtil::PhpToJSObject(
$messages) .
');
190 if (BX.Sale.RestHandler)
195 BX.Sale.RestHandler = {
196 init: function(params)
198 this.formNode = BX(params.formId);
199 this.paysystemBlockNode = BX(params.paysystemBlockId);
200 this.ajaxUrl = params.ajaxUrl;
201 this.paymentId = params.paymentId;
202 this.paySystemId = params.paySystemId;
203 this.isAllowedSubmitting = true;
204 this.returnUrl = params.returnUrl;
209 bindEvents: function()
211 BX.bind(this.formNode, "submit", BX.proxy(this.sendRequest, this));
214 sendRequest: function(e)
218 if (!this.isAllowedSubmitting)
224 formData = this.getAllFormData(),
225 submitButton = this.formNode.querySelector("input[type=\"submit\"]"),
230 submitButton.disabled = true;
232 this.isAllowedSubmitting = false;
235 sessid: BX.bitrix_sessid(),
236 PAYMENT_ID: this.paymentId,
237 PAYSYSTEM_ID: this.paySystemId,
238 RETURN_URL: this.returnUrl,
243 if (formData.hasOwnProperty(i))
245 data[i] = formData[i];
254 onsuccess: BX.proxy(function (result) {
255 if (result.status === "success")
257 this.isAllowedSubmitting = true;
258 this.updateTemplateHtml(result.template);
260 else if (result.status === "error")
262 this.isAllowedSubmitting = true;
263 this.showErrorTemplate(result.buyerErrors);
264 BX.onCustomEvent("onPaySystemAjaxError", [result.buyerErrors]);
270 getAllFormData: function()
272 var prepared = BX.ajax.prepareForm(this.formNode),
275 for (i in prepared.data)
277 if (prepared.data.hasOwnProperty(i) && i === "")
279 delete prepared.data[i];
283 return !!prepared && prepared.data ? prepared.data : {};
286 updateTemplateHtml: function (html)
288 BX.html(this.paysystemBlockNode, html)
291 showErrorTemplate: function(errors)
294 BX.message("SALE_HANDLERS_REST_HANDLER_TEMPLATE_ERROR_MESSAGE_HEADER"),
298 for (var error in errors)
300 if (errors.hasOwnProperty(error))
302 errorsList.push(errors[error]);
307 errorsList.push(BX.message("SALE_HANDLERS_REST_HANDLER_TEMPLATE_ERROR_MESSAGE_FOOTER"));
309 var resultDiv = BX.create("div", {
310 props: {className: "alert alert-danger"},
311 html: errorsList.join("<br />"),
314 this.paysystemBlockNode.innerHTML = "";
315 this.paysystemBlockNode.appendChild(resultDiv);
320 BX.ready(function() {
321 BX.Sale.RestHandler.init({
322 formId: "rest-checkout-form",
323 paysystemBlockId: "rest-checkout",
324 ajaxUrl: "/bitrix/tools/sale_ps_ajax.php",
325 paymentId: "' . \CUtil::JSEscape(
$payment->getId()) .
'",
326 paySystemId: "' . \CUtil::JSEscape(
$payment->getPaymentSystemId()) .
'",
327 returnUrl: "' . $this->service->getContext()->getUrl() .
'",
336 private function getCheckoutPayTemplate($paymentUrl): string
338 $template =
'<a class="btn btn-lg btn-success" style="border-radius: 32px;" href="' . $paymentUrl .
'">';
339 $template .= Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_BUTTON_PAID');
345 private function initiateIframePay(Payment
$payment): ServiceResult
350 if ($this->initiateMode === static::STREAM)
362 private function initiateFormPay(Payment
$payment, ?Request
$request): ServiceResult
369 if ($this->initiateMode === static::STREAM)
388 private function getPaymentUrl(Payment
$payment): string
390 if ($this->isAllowAutoRedirect())
394 if (isset(
$settings[
'FORM_DATA'][
'FIELDS']))
396 $queryParams = $this->getQueryDataFromFields(
$payment,
$settings[
'FORM_DATA'][
'FIELDS']);
400 $queryParams = $this->getQueryDataFromParams(
$payment,
$settings[
'FORM_DATA'][
'PARAMS']);
403 $queryParams[
'BX_PAYSYSTEM_ID'] = $this->service->getField(
'ID');
404 return (
new Uri(
$settings[
'FORM_DATA'][
'ACTION_URI']))->addParams($queryParams)->getLocator();
413 private function isAllowAutoRedirect(): bool
419 if (!empty($formSettings[
'ACTION_URI']) && mb_strtoupper($formSettings[
'METHOD']) ===
'GET')
422 if (isset($formSettings[
'FIELDS']))
424 foreach ($formSettings[
'FIELDS'] as $value)
426 if ((isset($value[
'VISIBLE']) && $value[
'VISIBLE'] ===
'Y') || is_array($value[
'CODE']))
450 if (!is_array($value[
'CODE']) && !empty($value[
'CODE']))
459 private function getIframeTemplate(Payment
$payment): string
461 \CJSCore::Init(
"loader");
464 $formSettings =
$settings[
'IFRAME_DATA'];
466 $iframeData = $this->getIframePayParams(
$payment);
468 $actionUriHost = (
new Uri($formSettings[
'ACTION_URI']))->getHost();
471 <div class='rest-paysystem-wrapper' id='rest-paysystem-wrapper'>
473 src='{$formSettings['ACTION_URI']}'
474 class='rest-payment-frame'
475 name='restPaymentFrame'
476 id='rest-payment-frame'
477 style='border: none; height: 350px; width: 100%'
478 sandbox='allow-forms allow-scripts allow-modals allow-top-navigation allow-same-origin'
480 <div class='alert alert-danger'>" . Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_ERROR_IFRAME') .
"</div>
482 <div class='alert alert-info'>" . Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_TEMPLATE_WARNING_RETURN') .
"</div>
487 BX.ready(function() {
488 var iframe = document.getElementById("rest-payment-frame");
493 loader = new BX.Loader({
494 target: iframe.parentElement,
495 size: iframe.offsetHeight / 2,
500 var parent = iframe.parentElement;
501 iframe.style.width = parent.clientWidth;
503 iframe.onload = function () {
509 var paymentFrame = iframe.contentWindow;
512 var iframeData = ' . \CUtil::PhpToJSObject($iframeData) .
';
513 iframeData.BX_COMPUTED_STYLE = JSON.parse(JSON.stringify(window.getComputedStyle(parent)));
515 paymentFrame.postMessage(iframeData, "' . $formSettings[
'ACTION_URI'] .
'");
518 iframe.onerror = function () {
524 var restPaysystemWrapper = document.getElementById("rest-paysystem-wrapper");
525 restPaysystemWrapper.innerHTML = "";
526 restPaysystemWrapper.appendChild(
528 props: {className: "alert alert-danger"},
529 text: "' . Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_ERROR_IFRAME_LOAD') .
'",
534 window.addEventListener("message", function (event) {
537 var originHost = new URL(event.origin).hostname;
544 if (originHost !== "' . $actionUriHost .
'")
549 if (event.data.width && parseInt(event.data.width) > 0)
551 iframe.style.width = event.data.width + "px";
553 if (event.data.height && parseInt(event.data.height) > 0)
555 iframe.style.height = event.data.height + "px";
569 $formSettings = $this->getHandlerSettings()[
'IFRAME_DATA'];
570 if (isset($formSettings[
'FIELDS']))
572 $params = $this->getQueryDataFromFields(
$payment, $formSettings[
'FIELDS']);
583 private function getDefaultTemplate(Payment
$payment): string
588 $template =
'<form action="'.htmlspecialcharsbx($formSettings[
'ACTION_URI']).
'" method="'.
htmlspecialcharsbx($formSettings[
'METHOD']).
'" name="rest-handler-form">';
590 if (isset($formSettings[
'FIELDS']))
594 elseif (isset($formSettings[
'PARAMS']))
599 $template .=
'<input type="hidden" name="BX_PAYSYSTEM_ID" value="' . $this->service->getField(
'ID') .
'">';
600 $template .=
'<input type="hidden" name="BX_RETURN_URL" value="' . $this->service->getContext()->getUrl() .
'">';
601 $template .=
'<input name="button" value="' . Loc::getMessage(
'SALE_HANDLERS_REST_HANDLER_BUTTON_PAID') .
'" type="submit" class="btn btn-lg btn-success pl-4 pr-4" style="border-radius: 32px;">';
619 $input = $this->getInputParams(
$payment, $value);
631 private function getInputParams(Payment
$payment, $value):
array
643 if (is_array($value[
'CODE']))
647 $result[
'NAME'] = $input[
'NAME'] ??
'';
655 $result[
'NAME'] = $input[
'NAME'] ??
'';
658 if (isset($input[
'INPUT'][
'TYPE']))
660 $result[
'TYPE'] = mb_strtoupper($input[
'INPUT'][
'TYPE']);
663 if (isset($value[
'VISIBLE']) && $value[
'VISIBLE'] ===
'Y')
677 private function createInput(
string $name,
array $input): string
679 if (!in_array($input[
'TYPE'], [
'Y/N',
'STRING',
'ENUM'],
true))
684 if ($input[
'HIDDEN'] ===
'Y')
686 return Input\Manager::getEditHtml(
$name, $input);
690 $input[
'STYLE'] =
"max-width: 300px;";
692 if ($input[
'TYPE'] ===
'Y/N')
694 $input[
'CLASS'] =
"form-check-input";
696 $inputHtml .=
'<div class="form-check">';
697 $inputHtml .= Input\Manager::getEditHtml(
$name, $input);
698 $inputHtml .=
'<label class="form-check-label">'.$input[
'NAME'].
'</label>';
699 $inputHtml .=
'</div>';
701 elseif ($input[
'TYPE'] ===
'STRING' || $input[
'TYPE'] ===
'ENUM')
703 $input[
'CLASS'] =
"form-control";
705 $inputHtml .=
'<div class="form-group">';
706 $inputHtml .=
'<label>'.$input[
'NAME'].
'</label>';
707 $inputHtml .= Input\Manager::getEditHtml(
$name, $input);
708 $inputHtml .=
'</div>';
730 $clientType = (string)(
$settings[
'CLIENT_TYPE'] ??
'');
736 return parent::getClientType($psMode);
741 $fields = $this->getHandlerFields();
745 'NAME' =>
$fields[
'NAME'] ??
'',
746 'SORT' =>
$fields[
'SORT'] ?? 100,
751 private function getHandlerFields():
array
753 if (!$this->handlerFields)
755 $handler = $this->service->getField(
'ACTION_FILE');
756 $dbRes = PaySystemRestHandlersTable::getList([
757 'filter' => [
'=CODE' => $handler]
763 $this->handlerFields =
$data;
767 return $this->handlerFields;
773 private function getHandlerSettings():
array
775 $handlerFields = $this->getHandlerFields();
777 return is_array($handlerFields[
'SETTINGS']) ? $handlerFields[
'SETTINGS'] : [];
780 private function getMode(): string
786 return self::IFRAME_MODE;
791 return self::CHECKOUT_MODE;
794 return self::FORM_MODE;
799 $params[
'BX_SYSTEM_PARAMS'] = [
800 'RETURN_URL' => $this->service->getContext()->getUrl(),
801 'PAYSYSTEM_ID' => $this->service->getField(
'ID'),
804 'CURRENCY' =>
$payment->getField(
'CURRENCY'),
839 'PS_STATUS_CODE' =>
'Y',
844 if ($psInvoiceId =
$request->get(
'PS_INVOICE_ID'))
846 $psData[
'PS_INVOICE_ID'] = $psInvoiceId;
849 if ($psStatusCode =
$request->get(
'PS_STATUS_CODE'))
851 $psData[
'PS_STATUS_CODE'] = $psStatusCode;
854 if ($psStatusDescription =
$request->get(
'PS_STATUS_DESCRIPTION'))
856 $psData[
'PS_STATUS_DESCRIPTION'] = $psStatusDescription;
859 if ($psStatusMessage =
$request->get(
'PS_STATUS_MESSAGE'))
861 $psData[
'PS_STATUS_MESSAGE'] = $psStatusMessage;
864 if ($psSum =
$request->get(
'PS_SUM'))
866 $psData[
'PS_SUM'] = $psSum;
869 if ($psCurrency =
$request->get(
'PS_CURRENCY'))
871 $psData[
'PS_CURRENCY'] = $psCurrency;
874 if ($psRecurringToken =
$request->get(
'PS_RECURRING_TOKEN'))
876 $psData[
'PS_RECURRING_TOKEN'] = $psRecurringToken;
879 if ($psCardNumber =
$request->get(
'PS_CARD_NUMBER'))
881 $psData[
'PS_CARD_NUMBER'] = $psCardNumber;
940 $request = Context::getCurrent()->getRequest();
943 $mode = $this->getMode();
944 if ($mode !== self::CHECKOUT_MODE)
950 $actionUri =
$settings[
'CHECKOUT_DATA'][
'ACTION_URI'] ??
null;
951 if (!isset($actionUri))
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)