3namespace Sale\Handlers\PaySystem;
6 Bitrix\Main\Localization\Loc,
10 Bitrix\Main\Web\HttpClient,
11 Bitrix\Sale\PaymentCollection,
12 Bitrix\Sale\PriceMaths;
14Loc::loadMessages(__FILE__);
24 const PAYMENT_STATUS_FINISHED =
"FINISHED";
26 const INVOICE_ID_DELIMITER =
"#";
41 $result =
new PaySystem\ServiceResult();
43 $invoiceResult = $this->createInvoice(
$payment);
44 if ($invoiceResult->isSuccess())
46 $result->setPsData($invoiceResult->getPsData());
48 $invoiceData = $invoiceResult->getData();
50 "CURRENCY" =>
$payment->getField(
"CURRENCY"),
51 "SUM" => PriceMaths::roundPrecision(
$payment->getSum()),
52 "URL" => $invoiceData[
"paymentPageUrl"],
57 if ($showTemplateResult->isSuccess())
59 $result->setTemplate($showTemplateResult->getTemplate());
63 $result->addErrors($showTemplateResult->getErrors());
73 $result->addErrors($invoiceResult->getErrors());
88 private function createSession(Payment
$payment)
90 $result =
new PaySystem\ServiceResult();
95 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_CLIENT_ID")));
107 if (!$sendResult->isSuccess())
109 $result->addErrors($sendResult->getErrors());
113 $sendData = $sendResult->getData();
115 $validationResult = $this->validationResponse(
$payment, $sendData);
116 if (!$validationResult->isSuccess())
118 $result->addErrors($validationResult->getErrors());
122 $payloadData = self::getPayload($sendData[
"data"][
"token"]);
125 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
129 PaySystem\Logger::addDebugInfo(__CLASS__.
": createSession payload: ".self::encode($payloadData));
131 $result->setData([
"id" => $payloadData[
"id"]]);
145 private function createInvoice(Payment
$payment)
147 $result =
new PaySystem\ServiceResult();
149 $sessionResult = $this->createSession(
$payment);
150 if (!$sessionResult->isSuccess())
152 $result->addErrors($sessionResult->getErrors());
156 $sessionData = $sessionResult->getData();
160 "paySystemId" => $this->service->getField(
"ID"),
164 "sessionId" => $sessionData[
"id"],
165 "systemType" =>
"ECOM"
168 "externalId" =>
$payment->getField(
"ACCOUNT_NUMBER"),
169 "reusability" =>
false,
172 "description" => $this->getPaymentDescription(
$payment),
173 "amount" => (int)PriceMaths::roundPrecision(
$payment->getSum() * 100),
174 "redirectUrl" => $this->getRedirectUrl(
$payment),
175 "extraInfo" => self::encode($extraInfo),
179 if ($userEmail =
$payment->getOrder()->getPropertyCollection()->getUserEmail())
185 if (!$sendResult->isSuccess())
187 $result->addErrors($sendResult->getErrors());
191 $sendData = $sendResult->getData();
193 $validationResult = $this->validationResponse(
$payment, $sendData);
194 if (!$validationResult->isSuccess())
196 $result->addErrors($validationResult->getErrors());
200 $payloadData = self::getPayload($sendData[
"data"][
"token"]);
203 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
207 PaySystem\Logger::addDebugInfo(__CLASS__.
": createInvoice payload: ".self::encode($payloadData));
209 $result->setPsData([
"PS_INVOICE_ID" => $payloadData[
"id"]]);
210 $result->setData($payloadData);
218 private function getRedirectUrl(Payment
$payment)
233 public function refund(Payment
$payment, $refundableSum)
235 $result =
new PaySystem\ServiceResult();
237 $sessionResult = $this->createSession(
$payment);
238 if ($sessionResult->isSuccess())
240 $sessionData = $sessionResult->getData();
242 $psInvoiceId =
$payment->getField(
"PS_INVOICE_ID");
243 $psInvoiceIdList = explode(self::INVOICE_ID_DELIMITER, $psInvoiceId);
244 if (
count($psInvoiceIdList) == 2)
249 "sessionId" => $sessionData[
"id"],
250 "invoiceId" => $psInvoiceIdList[0],
251 "paymentId" => $psInvoiceIdList[1],
256 if (!$sendResult->isSuccess())
258 $result->addErrors($sendResult->getErrors());
261 if ($sendResult->isSuccess())
263 $sendData = $sendResult->getData();
264 $validationResult = $this->validationResponse(
$payment, $sendData);
265 if (!$validationResult->isSuccess())
267 $result->addErrors($validationResult->getErrors());
270 if ($validationResult->isSuccess())
272 $payloadData = self::getPayload($sendData[
"data"][
"token"]);
275 PaySystem\Logger::addDebugInfo(__CLASS__.
": refund payload: ".self::encode($payloadData));
279 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
286 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_PAYMENT_ID")));
291 $result->addErrors($sessionResult->getErrors());
296 $result->setOperationType(PaySystem\ServiceResult::MONEY_LEAVING);
300 PaySystem\Logger::addError(__CLASS__.
": refund: ".join(
"\n",
$result->getErrorMessages()));
319 $result =
new PaySystem\ServiceResult();
320 $httpClient =
new HttpClient();
322 $headers = $this->getHeaders();
323 foreach ($headers as
$name => $value)
325 $httpClient->setHeader(
$name, $value);
332 PaySystem\Logger::addDebugInfo(__CLASS__.
": request data: ".
$postData);
337 $errors = $httpClient->getError();
346 PaySystem\Logger::addDebugInfo(__CLASS__.
": response data: ".
$response);
348 $httpStatus = $httpClient->getStatus();
349 if ($httpStatus !== 200)
351 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_HTTP_STATUS", [
352 "#STATUS_CODE#" => $httpStatus
373 $result =
new PaySystem\ServiceResult();
377 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_RESPONSE")));
383 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_RESPONSE_STATUS")));
395 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_CHECK_SUM")));
405 private function getHeaders()
408 "Content-Type" =>
"application/json",
418 private static function getPayload($token)
420 $tokenPathList = explode(
".", $token);
421 if (
count($tokenPathList) != 3)
426 $payload = self::decode(self::urlSafeBase64Decode($tokenPathList[1]));
435 private function isTokenCorrect($token, Payment
$payment)
439 $tokenPathList = explode(
".", $token);
440 if (
count($tokenPathList) != 3)
445 list($headBase64, $bodyBase64, $cryptoBase64) = $tokenPathList;
446 $signature = self::urlSafeBase64Decode($cryptoBase64);
448 $hash = hash_hmac(
"sha256", $headBase64.
".".$bodyBase64, $signKey,
true);
451 return hash_equals($signature,
$hash);
467 $search = [
"+",
"/",
"="];
468 $replace = [
"-",
"_",
""];
470 $header = self::encode([
"alg" =>
"HS256",
"typ" =>
"JWT"]);
471 $base64UrlHeader = str_replace($search, $replace, base64_encode($header));
473 $payload = self::encode($payload);
474 $base64UrlPayload = str_replace($search, $replace, base64_encode($payload));
476 $signature = hash_hmac(
"sha256", $base64UrlHeader.
".".$base64UrlPayload, $signKey,
true);
477 $base64UrlSignature = str_replace($search, $replace, base64_encode($signature));
478 $jwt = $base64UrlHeader.
".".$base64UrlPayload.
".".$base64UrlSignature;
502 $result =
new PaySystem\ServiceResult();
504 $inputStream = self::readFromStream();
505 $data = self::decode($inputStream);
506 if ($payloadData = self::getPayload(
$data[
"token"]))
508 PaySystem\Logger::addDebugInfo(__CLASS__.
": processRequest payloadData: ".self::encode($payloadData));
511 $paymentId = $payloadData[
"paymentId"] ?? $payloadData[
"id"];
512 if ($payloadData[
"paymentStatus"] === self::PAYMENT_STATUS_FINISHED && $paymentId)
514 $description = Loc::getMessage(
"SALE_HPS_UAPAY_TRANSACTION", [
515 "#ID#" => $payloadData[
"id"],
516 "#PAYMENT_NUMBER#" => $payloadData[
"paymentNumber"]
518 $invoiceId = $payloadData[
"invoiceId"] ?? $payloadData[
"orderId"];
520 "PS_INVOICE_ID" =>
$invoiceId.self::INVOICE_ID_DELIMITER.$paymentId,
521 "PS_STATUS_CODE" => $payloadData[
"paymentStatus"],
523 "PS_SUM" => $payloadData[
"amount"] / 100,
525 "PS_RESPONSE_DATE" =>
new Main\Type\DateTime()
528 if ($this->isSumCorrect(
$payment, $payloadData[
"amount"] / 100))
532 PaySystem\Logger::addDebugInfo(
533 __CLASS__.
": PS_CHANGE_STATUS_PAY=".$this->getBusinessValue(
$payment,
"PS_CHANGE_STATUS_PAY")
538 $result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
543 $error = Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_SUM");
544 $fields[
"PS_STATUS_DESCRIPTION"] .=
" ".$error;
553 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_CHECK_SUM")));
558 $result->addError(
new Main\
Error(Loc::getMessage(
"SALE_HPS_UAPAY_ERROR_PARSE_JWT")));
563 $error = __CLASS__.
": processRequest: ".join(
"\n",
$result->getErrorMessages());
564 PaySystem\Logger::addError(
$error);
581 PaySystem\Logger::addDebugInfo(
582 __CLASS__.
": sum=".PriceMaths::roundPrecision(
$amount).
"; paymentSum=".PriceMaths::roundPrecision(
$payment->getSum())
585 return PriceMaths::roundPrecision(
$amount) === PriceMaths::roundPrecision(
$payment->getSum());
593 public static function isMyResponse(Request
$request, $paySystemId)
595 $inputStream = self::readFromStream();
598 $data = self::decode($inputStream);
601 $payloadData = self::getPayload(
$data[
"token"]);
607 if (isset($payloadData[
"extraInfo"]) && !is_array($payloadData[
"extraInfo"]))
609 $payloadData[
"extraInfo"] = self::decode($payloadData[
"extraInfo"]);
612 if (isset($payloadData[
"extraInfo"][
"paySystemId"]) && ((
int)$payloadData[
"extraInfo"][
"paySystemId"] === (
int)$paySystemId))
626 public function getPaymentIdFromRequest(Request
$request)
628 $inputStream = self::readFromStream();
629 $data = self::decode($inputStream);
630 $payloadData = self::getPayload(
$data[
"token"]);
636 if (isset($payloadData[
"externalId"]))
638 return $payloadData[
"externalId"];
649 $testUrl =
"https://api.demo.uapay.ua/api/";
650 $activeUrl =
"https://api.uapay.ua/api/";
654 self::TEST_URL => $testUrl.
"sessions/create",
655 self::ACTIVE_URL => $activeUrl.
"sessions/create",
657 "invoicesCreate" => [
658 self::TEST_URL => $testUrl.
"invoicer/invoices/create",
659 self::ACTIVE_URL => $activeUrl.
"invoicer/invoices/create",
661 "paymentReverse" => [
662 self::TEST_URL => $testUrl.
"invoicer/payments/reverse",
663 self::ACTIVE_URL => $activeUrl.
"invoicer/payments/reverse",
672 protected function isTestMode(Payment
$payment =
null)
684 private function getPaymentDescription(Payment
$payment)
687 $collection =
$payment->getCollection();
688 $order = $collection->getOrder();
689 $userEmail =
$order->getPropertyCollection()->getUserEmail();
700 $payment->getField(
"ACCOUNT_NUMBER"),
701 $order->getField(
"ACCOUNT_NUMBER"),
704 ($userEmail) ? $userEmail->getValue() :
""
706 $this->getBusinessValue(
$payment,
"UAPAY_INVOICE_DESCRIPTION")
719 return Main\Web\Json::encode(
$data, JSON_UNESCAPED_UNICODE);
726 private static function decode(
$data)
730 return Main\Web\Json::decode(
$data);
732 catch (Main\ArgumentException $exception)
742 private static function urlSafeBase64Decode($input)
744 $remainder = mb_strlen($input) % 4;
747 $padLength = 4 - $remainder;
748 $input .= str_repeat(
"=", $padLength);
750 return base64_decode(strtr($input,
"-_",
"+/"));
756 private static function readFromStream()
758 return file_get_contents(
"php://input");
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
getUrl(Payment $payment=null, $action)
showTemplate(Payment $payment=null, $template='')
setExtraParams(array $values)
getBusinessValue(Payment $payment=null, $code)
</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(!function_exists("bx_hmac")) $amount
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']