Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/sale/lib/paysystem/ |
Upload File : |
<?php namespace Bitrix\Sale\PaySystem; use Bitrix\Main\Entity\EntityError; use Bitrix\Main\Error; use Bitrix\Main\Event; use Bitrix\Main\EventResult; use Bitrix\Main\Localization\Loc; use Bitrix\Main\NotSupportedException; use Bitrix\Main\Request; use Bitrix\Main\SystemException; use Bitrix\Main\Type\Date; use Bitrix\Sale; use Bitrix\Sale\Order; use Bitrix\Sale\Payment; use Bitrix\Sale\Registry; use Bitrix\Sale\Result; use Bitrix\Sale\ResultError; use Bitrix\Sale\Cashbox; use Bitrix\Sale\Services\Base\RestrictionInfoCollection; use Bitrix\Sale\Services\Base\RestrictableService; Loc::loadMessages(__FILE__); /** * Class Service * @package Bitrix\Sale\PaySystem */ class Service implements RestrictableService { public const EVENT_ON_BEFORE_PAYMENT_PAID = 'OnSalePsServiceProcessRequestBeforePaid'; public const EVENT_ON_AFTER_PROCESS_REQUEST = 'OnSaleAfterPsServiceProcessRequest'; public const EVENT_BEFORE_ON_INITIATE_PAY = 'onSalePsBeforeInitiatePay'; public const EVENT_INITIATE_PAY_SUCCESS = 'onSalePsInitiatePaySuccess'; public const EVENT_INITIATE_PAY_ERROR = 'onSalePsInitiatePayError'; public const PAY_SYSTEM_PREFIX = 'PAYSYSTEM_'; /** @var ServiceHandler|IHold|IPartialHold|IRefund|IPrePayable|ICheckable|IPayable|IPdf|IDocumentGeneratePdf|IRecurring|Sale\PaySystem\Cashbox\ISupportPrintCheck $handler */ private $handler = null; /** @var array */ private $fields = array(); /** @var bool */ protected $isClone = false; /** @var Context */ protected $context; /** * Service constructor. * @param $fields * @throws \Bitrix\Main\ArgumentNullException * @throws \Bitrix\Main\ArgumentOutOfRangeException */ public function __construct($fields) { [$className, $handlerType] = Manager::includeHandler($fields['ACTION_FILE']); $this->fields = $fields; $this->handler = new $className($handlerType, $this); $this->context = new Context(); } /** * @param Payment $payment * @param Request|null $request * @param int $mode * @return ServiceResult */ public function initiatePay(Payment $payment, Request $request = null, $mode = BaseServiceHandler::STREAM) { $onBeforeInitResult = $this->callEventOnBeforeInitiatePay($payment); if (!$onBeforeInitResult->isSuccess()) { $error = implode("\n", $onBeforeInitResult->getErrorMessages()); Logger::addError(get_class($this->handler) . '. OnBeforeInitiatePay: ' . $error); $this->markPayment($payment, $onBeforeInitResult); return $onBeforeInitResult; } $this->handler->setInitiateMode($mode); $initResult = $this->handler->initiatePay($payment, $request); $psData = $initResult->getPsData(); if ($psData) { $setResult = $payment->setFields($psData); if ($setResult->isSuccess()) { $order = $payment->getCollection()->getOrder(); if ($order) { $saveResult = $order->save(); if (!$saveResult->isSuccess()) { $initResult->addErrors($saveResult->getErrors()); } } } else { $initResult->addErrors($setResult->getErrors()); } } if ($initResult->isSuccess()) { $this->callEventOnInitiatePaySuccess($payment); } else { $error = implode("\n", $initResult->getErrorMessages()); Logger::addError(get_class($this->handler) . '. InitiatePay: ' . $error); $this->markPayment($payment, $onBeforeInitResult); $this->callEventOnInitiatePayError($payment, $initResult); } return $initResult; } private function callEventOnBeforeInitiatePay(Payment $payment): ServiceResult { $result = new ServiceResult(); $event = new Event( 'sale', self::EVENT_BEFORE_ON_INITIATE_PAY, [ 'payment' => $payment, 'service' => $this ] ); $event->send(); foreach($event->getResults() as $eventResult) { if ($eventResult->getType() === EventResult::ERROR) { $parameters = $eventResult->getParameters(); $error = $parameters['ERROR'] ?? null; $result->addError( $error instanceof Error ? $error : Sale\PaySystem\Error::create( Loc::getMessage('SALE_PS_SERVICE_ERROR_ON_BEFORE_INITIATE_PAY') ) ); } } return $result; } private function callEventOnInitiatePaySuccess(Payment $payment) { $event = new Event( 'sale', self::EVENT_INITIATE_PAY_SUCCESS, [ 'payment' => $payment ] ); $event->send(); } private function callEventOnInitiatePayError(Payment $payment, ServiceResult $result) { $event = new Event( 'sale', self::EVENT_INITIATE_PAY_ERROR, [ 'payment' => $payment, 'errors' => $result->getErrorMessages(), ] ); $event->send(); } /** * @return bool */ public function isRefundable() { if ($this->handler instanceof IRefundExtended) { return $this->handler->isRefundableExtended(); } return $this->handler instanceof IRefund; } /** * @param Payment $payment * @param int $refundableSum * @return ServiceResult|Result * @throws SystemException * @throws \Bitrix\Main\ArgumentOutOfRangeException */ public function refund(Payment $payment, $refundableSum = 0) { if ($this->isRefundable()) { $result = new Result(); if (!$payment->isPaid()) { $result->addError(new ResultError(Loc::getMessage('SALE_PS_SERVICE_PAYMENT_NOT_PAID'))); return $result; } if ($refundableSum == 0) $refundableSum = $payment->getSum(); /** @var ServiceResult $result */ $result = $this->handler->refund($payment, $refundableSum); if (!$result->isSuccess()) { Logger::addError(get_class($this->handler).': refund: '.implode("\n", $result->getErrorMessages())); } return $result; } throw new SystemException(); } /** * @param Request $request * @return Result * @throws NotSupportedException * @throws \Bitrix\Main\ArgumentException * @throws \Bitrix\Main\ArgumentNullException * @throws \Bitrix\Main\ArgumentOutOfRangeException * @throws \Bitrix\Main\ArgumentTypeException * @throws \Bitrix\Main\ObjectException * @throws \Bitrix\Main\ObjectNotFoundException */ public function processRequest(Request $request) { $processResult = new Result(); if (!($this->handler instanceof ServiceHandler)) { return $processResult; } $debugInfo = http_build_query($request->toArray(), "", "\n"); if (empty($debugInfo)) { $debugInfo = file_get_contents("php://input"); } Logger::addDebugInfo( get_class($this->handler)." ProcessRequest. paySystemId=".$this->getField("ID").", request=".($debugInfo ? $debugInfo : "empty") ); $paymentId = $this->handler->getPaymentIdFromRequest($request); if (empty($paymentId)) { $processResult->addError(new Error(Loc::getMessage('SALE_PS_SERVICE_PAYMENT_ERROR_EMPTY'))); Logger::addError( get_class($this->handler).'. ProcessRequest: '.Loc::getMessage('SALE_PS_SERVICE_PAYMENT_ERROR_EMPTY') ); return $processResult; } [$orderId, $paymentId] = Manager::getIdsByPayment($paymentId, $this->getField('ENTITY_REGISTRY_TYPE')); if (!$orderId) { $errorMessage = str_replace('#ORDER_ID#', $orderId, Loc::getMessage('SALE_PS_SERVICE_ORDER_ERROR')); $processResult->addError(new Error($errorMessage)); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$errorMessage); return $processResult; } $registry = Registry::getInstance($this->getField('ENTITY_REGISTRY_TYPE')); /** @var Order $orderClassName */ $orderClassName = $registry->getOrderClassName(); $order = $orderClassName::load($orderId); if (!$order) { $errorMessage = str_replace('#ORDER_ID#', $orderId, Loc::getMessage('SALE_PS_SERVICE_ORDER_ERROR')); $processResult->addError(new Error($errorMessage)); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$errorMessage); return $processResult; } if ($order->isCanceled()) { $errorMessage = str_replace('#ORDER_ID#', $orderId, Loc::getMessage('SALE_PS_SERVICE_ORDER_CANCELED')); $processResult->addError(new Error($errorMessage)); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$errorMessage); return $processResult; } /** @var \Bitrix\Sale\PaymentCollection $collection */ $collection = $order->getPaymentCollection(); /** @var \Bitrix\Sale\Payment $payment */ $payment = $collection->getItemById($paymentId); if (!$payment) { $errorMessage = str_replace('#PAYMENT_ID#', $paymentId, Loc::getMessage('SALE_PS_SERVICE_PAYMENT_ERROR')); $processResult->addError(new Error($errorMessage)); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$errorMessage); return $processResult; } /** @var \Bitrix\Sale\PaySystem\ServiceResult $serviceResult */ $serviceResult = $this->handler->processRequest($payment, $request); if ($serviceResult->isSuccess()) { $status = null; $operationType = $serviceResult->getOperationType(); if ($operationType === ServiceResult::MONEY_COMING) { $status = 'Y'; } else if ($operationType === ServiceResult::MONEY_LEAVING) { $status = 'N'; } if ($status !== null) { $event = new Event('sale', self::EVENT_ON_BEFORE_PAYMENT_PAID, array( 'payment' => $payment, 'status' => $status, 'pay_system_id' => $this->getField('ID') ) ); $event->send(); if ($status === 'N') { $payment->setFieldsNoDemand([ 'IS_RETURN' => Payment::RETURN_PS, 'PAY_RETURN_DATE' => new Date(), ]); } $paidResult = $payment->setPaid($status); if (!$paidResult->isSuccess()) { $error = 'PAYMENT SET PAID: '.join(' ', $paidResult->getErrorMessages()); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$error); $serviceResult->setResultApplied(false); } } $psData = $serviceResult->getPsData(); if ($psData) { $res = $payment->setFields($psData); if (!$res->isSuccess()) { $error = 'PAYMENT SET PAID: '.join(' ', $res->getErrorMessages()); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$error); $serviceResult->setResultApplied(false); } } $saveResult = $order->save(); if (!$saveResult->isSuccess()) { $error = 'ORDER SAVE: '.join(' ', $saveResult->getErrorMessages()); Logger::addError(get_class($this->handler).'. ProcessRequest: '.$error); $serviceResult->setResultApplied(false); } PullManager::onSuccessfulPayment($payment); } else { $serviceResult->setResultApplied(false); $processResult->addErrors($serviceResult->getErrors()); $error = implode("\n", $serviceResult->getErrorMessages()); Logger::addError(get_class($this->handler).'. ProcessRequest Error: '.$error); $this->markPayment($payment, $serviceResult); PullManager::onFailurePayment($payment); } $event = new Event( 'sale', self::EVENT_ON_AFTER_PROCESS_REQUEST, [ 'payment' => $payment, 'serviceResult' => $serviceResult, 'request' => $request, ] ); $event->send(); $this->handler->sendResponse($serviceResult, $request); return $processResult; } /** * @return string */ public function getConsumerName() { $id = $this->fields['ID'] ?? 0; return static::PAY_SYSTEM_PREFIX.$id; } /** * @return array */ public function getHandlerDescription() { return $this->handler->getDescription(); } /** * @return bool */ public function isBlockable() { return $this->handler instanceof IHold || $this->handler instanceof IPartialHold; } /** * @param Payment $payment * @return ServiceResult * @throws SystemException */ public function cancel(Payment $payment) { if ($this->isBlockable()) { return $this->handler->cancel($payment); } throw new SystemException(Loc::getMessage('SALE_PS_SERVICE_ERROR_HOLD_IS_NOT_SUPPORTED')); } /** * @param Payment $payment * @param int $sum * @return ServiceResult * @throws SystemException */ public function confirm(Payment $payment, $sum = 0) { if ($this->isBlockable()) { if ($this->handler instanceof IPartialHold) { return $this->handler->confirm($payment, $sum); } else if ($sum > 0) { throw new SystemException(Loc::getMessage('SALE_PS_SERVICE_ERROR_PARTIAL_CONFIRM_IS_NOT_SUPPORTED')); } return $this->handler->confirm($payment); } throw new SystemException(Loc::getMessage('SALE_PS_SERVICE_ERROR_HOLD_IS_NOT_SUPPORTED')); } /** * @param $name * @return mixed */ public function getField($name) { return $this->fields[$name] ?? null; } /** * @return array */ public function getCurrency() { return $this->handler->getCurrencyList(); } /** * The type of client that the handler can work with * * @return string */ public function getClientTypeFromHandler() { return $this->handler->getClientType( $this->fields['PS_MODE'] ?? null ); } /** * The type of client that the payment system can work with * * @return string */ public function getClientType() { return (string)($this->fields['PS_CLIENT_TYPE'] ?? $this->getClientTypeFromHandler()); } /** * @return bool */ public function isCash() { return $this->fields['IS_CASH'] === 'Y'; } /** * @return bool */ public function canPrintCheck(): bool { return $this->fields['CAN_PRINT_CHECK'] === 'Y'; } /** * @param Payment $payment * @return bool */ public function canPrintCheckSelf(Payment $payment): bool { $service = $payment->getPaySystem(); if (!$service || !$this->isSupportPrintCheck() || !$this->canPrintCheck()) { return false; } /** @var Cashbox\CashboxPaySystem $cashboxClass */ $cashboxClass = $this->getCashboxClass(); $kkm = $cashboxClass::getKkmValue($service); $filter = [ '=ACTIVE' => 'Y', '=HANDLER' => $cashboxClass, ]; if (!empty($kkm)) { $filter['=KKM_ID'] = $kkm; } return (bool)Cashbox\Manager::getList([ 'select' => ['ID'], 'filter' => $filter, ])->fetch(); } /** * @param Payment $payment * @return ServiceResult */ public function creditNoDemand(Payment $payment) { return $this->handler->creditNoDemand($payment); } /** * @param Payment $payment * @return ServiceResult */ public function debitNoDemand(Payment $payment) { return $this->handler->debitNoDemand($payment); } /** * @return bool */ public function isPayable() { if ($this->handler instanceof IPayable) return true; if (method_exists($this->handler, 'isPayableCompatibility')) return $this->handler->isPayableCompatibility(); return false; } /** * @return bool */ public function isAffordPdf() { return $this->handler instanceof IPdf; } /** * @return bool */ public function isAffordDocumentGeneratePdf() { return $this->handler instanceof IDocumentGeneratePdf; } /** * @param Payment $payment * @return mixed * @throws NotSupportedException */ public function getPdfContent(Payment $payment) { if ($this->isAffordPdf()) { return $this->handler->getContent($payment); } throw new NotSupportedException('Handler is not implemented interface '.IPdf::class); } /** * @param Payment $payment * @return mixed * @throws NotSupportedException */ public function getPdf(Payment $payment) { if ($this->isAffordPdf()) { return $this->handler->getFile($payment); } throw new NotSupportedException('Handler is not implemented interface '.IPdf::class); } /** * @param Payment $payment * @param $params * @return mixed * @throws NotSupportedException */ public function registerCallbackOnGenerate(Payment $payment, $params) { if ($this->isAffordDocumentGeneratePdf()) { return $this->handler->registerCallbackOnGenerate($payment, $params); } throw new NotSupportedException('Handler is not implemented interface '.IDocumentGeneratePdf::class); } /** * @param Payment $payment * @return mixed * @throws NotSupportedException */ public function isPdfGenerated(Payment $payment) { if ($this->isAffordPdf()) { return $this->handler->isGenerated($payment); } throw new NotSupportedException('Handler is not implemented interface '.IPdf::class); } /** * @param Payment $payment * @return mixed */ public function getPaymentPrice(Payment $payment) { if ($this->isPayable()) return $this->handler->getPrice($payment); return 0; } /** * @param array $params */ public function setTemplateParams(array $params) { $this->handler->setExtraParams($params); } /** * @param Payment|null $payment * @param $templateName * @return ServiceResult */ public function showTemplate(Payment $payment = null, $templateName) { return $this->handler->showTemplate($payment, $templateName); } /** * @return bool */ public function isPrePayable() { return $this->handler instanceof IPrePayable; } /** * @param Payment|null $payment * @param Request $request * @throws NotSupportedException */ public function initPrePayment(Payment $payment = null, Request $request) { if ($this->isPrePayable()) return $this->handler->initPrePayment($payment, $request); throw new NotSupportedException; } /** * @return mixed * @throws NotSupportedException */ public function getPrePaymentProps() { if ($this->isPrePayable()) return $this->handler->getProps(); throw new NotSupportedException; } /** * @param array $orderData * @return mixed * @throws NotSupportedException */ public function basketButtonAction(array $orderData = array()) { if ($this->isPrePayable()) return $this->handler->basketButtonAction($orderData); throw new NotSupportedException; } /** * @param array $orderData * @return mixed * @throws NotSupportedException */ public function setOrderDataForPrePayment($orderData = array()) { if ($this->isPrePayable()) return $this->handler->setOrderConfig($orderData); throw new NotSupportedException; } /** * @param $orderData * @return mixed * @throws NotSupportedException */ public function payOrderByPrePayment($orderData) { if ($this->isPrePayable()) return $this->handler->payOrder($orderData); throw new NotSupportedException; } /** * @return array */ public function getFieldsValues() { return $this->fields; } /** * @return bool */ public function isAllowEditPayment() { return $this->fields['ALLOW_EDIT_PAYMENT'] == 'Y'; } /** * @return bool */ public function isCheckable() { if ($this->handler instanceof ICheckable) return true; if (method_exists($this->handler, 'isCheckableCompatibility')) return $this->handler->isCheckableCompatibility(); return false; } /** * @param Payment $payment * @return ServiceResult */ public function check(Payment $payment) { $result = new ServiceResult(); if ($this->isCheckable()) { /** @var \Bitrix\Sale\PaymentCollection $paymentCollection */ $paymentCollection = $payment->getCollection(); /** @var \Bitrix\Sale\Order $order */ $order = $paymentCollection->getOrder(); if (!$order->isCanceled()) { /** @var ServiceResult $result */ $checkResult = $this->handler->check($payment); if ($checkResult instanceof ServiceResult && $checkResult->isSuccess()) { $psData = $checkResult->getPsData(); if ($psData) { $res = $payment->setFields($psData); if (!$res->isSuccess()) $result->addErrors($res->getErrors()); } if ($checkResult->getOperationType() == ServiceResult::MONEY_COMING) { $res = $payment->setPaid('Y'); if (!$res->isSuccess()) $result->addErrors($res->getErrors()); } $res = $order->save(); if (!$res->isSuccess()) $result->addErrors($res->getErrors()); } elseif (!$checkResult) { $result->addError(new Error(Loc::getMessage('SALE_PS_SERVICE_ERROR_CONNECT_PS'))); } } else { $result->addError(new EntityError(Loc::getMessage('SALE_PS_SERVICE_ORDER_CANCELED', array('#ORDER_ID#' => $order->getId())))); } } return $result; } /** * @param \SplObjectStorage $cloneEntity * * @return Service */ public function createClone(\SplObjectStorage $cloneEntity) { if ($this->isClone() && $cloneEntity->contains($this)) { return $cloneEntity[$this]; } $paySystemServiceClone = clone $this; $paySystemServiceClone->isClone = true; if (!$cloneEntity->contains($this)) { $cloneEntity[$this] = $paySystemServiceClone; } if ($handler = $this->handler) { if (!$cloneEntity->contains($handler)) { $cloneEntity[$handler] = $handler->createClone($cloneEntity); } if ($cloneEntity->contains($handler)) { $paySystemServiceClone->handler = $cloneEntity[$handler]; } } return $paySystemServiceClone; } /** * @return bool */ public function isClone() { return $this->isClone; } /** * @return bool */ public function isCustom() { return in_array($this->handler->getHandlerType(), array('CUSTOM', 'USER')); } /** * @param Payment $payment * @return array */ public function getParamsBusValue(Payment $payment) { return $this->handler->getParamsBusValue($payment); } /** * @return bool */ public function isTuned() { return $this->handler->isTuned(); } /** * @return array */ public function getDemoParams() { return $this->handler->getDemoParams(); } /** * @param $mode */ public function setTemplateMode($mode) { $this->handler->setInitiateMode($mode); } /** * @return Context */ public function getContext(): Context { return $this->context; } /** * @param Payment $payment * @return bool */ public function isRecurring(Payment $payment): bool { return $this->handler instanceof IRecurring && $this->handler->isRecurring($payment); } /** * @param Payment $payment * @param Request|null $request * @return ServiceResult */ public function repeatRecurrent(Payment $payment, Request $request = null): ServiceResult { $result = new ServiceResult(); if ($this->isRecurring($payment)) { return $this->handler->repeatRecurrent($payment, $request); } return $result; } /** * @param Payment $payment * @param Request|null $request * @return ServiceResult */ public function cancelRecurrent(Payment $payment, Request $request = null): ServiceResult { $result = new ServiceResult(); if ($this->isRecurring($payment)) { return $this->handler->cancelRecurrent($payment, $request); } return $result; } /** * Returns true if handler extends ISupportPrintCheck interface * * @return bool */ public function isSupportPrintCheck(): bool { return $this->handler instanceof Sale\PaySystem\Cashbox\ISupportPrintCheck; } /** * Returns class name of cashbox for pay system * * @return string * @throws NotSupportedException */ public function getCashboxClass(): string { if ($this->isSupportPrintCheck()) { $cashboxClassName = $this->handler::getCashboxClass(); if (!Cashbox\Manager::isPaySystemCashbox($cashboxClassName)) { throw new NotSupportedException( 'Cashbox is not extended class '.Cashbox\CashboxPaySystem::class ); } return $cashboxClassName; } throw new NotSupportedException( 'Handler is not implemented interface '.Sale\PaySystem\Cashbox\ISupportPrintCheck::class ); } /** * Returns true if handler extends IFiscalizationAware interface * * @return bool */ public function isFiscalizationAware(): bool { return $this->handler instanceof Sale\PaySystem\Cashbox\IFiscalizationAware; } /** * Returns indicator showing if fiscalization is enabled on the payment system side * * @param Payment $payment * @return bool * @throws NotSupportedException */ public function isFiscalizationEnabled(Payment $payment): bool { if ($this->isFiscalizationAware()) { return $this->handler->isFiscalizationEnabled($payment); } throw new NotSupportedException( 'Handler does not implement interface '.Sale\PaySystem\Cashbox\IFiscalizationAware::class ); } public function getStartupRestrictions(): RestrictionInfoCollection { if ($this->handler instanceof Sale\Services\PaySystem\Restrictions\RestrictableServiceHandler) { return $this->handler->getRestrictionList(); } return (new RestrictionInfoCollection()); } public function getServiceId(): int { return (int)($this->getField('ID') ?? 0); } private function markPayment(Payment $payment, ServiceResult $serviceResult): void { (new PaymentMarker($this, $payment)) ->mark($serviceResult) ->save() ; } }