партнер компании 1с-битрикс
сайт фрилансера Сергея Эстрина
Войти как пользователь
Вы можете войти на сайт, если вы зарегистрированы на одном из этих сервисов:
Универсальная галерея - модуль для битрикс
Интерфейс создания обработчиков платежных систем в d7 претерпел значительные изменения. В этой статье я расскажу, как создать такой обработчик.
[spoiler]
Пользовательские обработчики платежных систем в d7 могут находится в папке /bitrix/php_interface/include/sale_payment/ или /local/php_interface/include/sale_payment/. В ней нужно создать папку обработчика, которая имеет следующую структуру:



Далее создаем файл handler.php и класс обработчика, который в общих случаях должен наследоваться от класса Bitrix\Sale\PaySystem\ServiceHandler. ВАЖНО: название класса до Handler должно совпадать с именем папки обработчика, иначе обработчик будет работать в режиме совместимости, т.е. не восприниматься битриксом как обработчик на d7!

<?php


namespace Sale\Handlers\PaySystem;

use 
Bitrix\Main\Config;
use 
Bitrix\Main\Error;
use 
Bitrix\Main\Localization\Loc;
use 
Bitrix\Main\Request;
use 
Bitrix\Main\Result;
use 
Bitrix\Main\Text\Encoding;
use 
Bitrix\Main\Type\DateTime;
use 
Bitrix\Main\Web\HttpClient;
use 
Bitrix\Sale\Order;
use 
Bitrix\Sale\PaySystem;
use 
Bitrix\Sale\Payment;
use 
Bitrix\Sale\PriceMaths;

Loc::loadMessages(__FILE__);

class 
MyHandlerHandler extends PaySystem\ServiceHandler// implements PaySystem\IRefundExtended, PaySystem\IHold
{

}

Далее пройдемся по самым важным функциям обработчика, а именно для чего они нужны, не вдаваясь в детали, которые вы можете самостоятельно изучить по исходным кодам системных обработчиков (а они находятся в папке /bitrix/modules/sale/handlers/paysystem/). Итак:

Функция initiatePay

Это самая главная функция в обработчике, в ней можно, например, добавить к параметрам обработчика, которые задаются в административной части, какие-то дополнительные, и вызвать шаблон, который должен находится в подпапке template (перечень параметров обработчика платежей, задаваемых в админке, задается в файле .description.php, его структуру вы можете также изучить по исходным кодам системных обработчиков). Сам шаблон можно скопировать в шаблон сайта в подпапку payment/название_папки_обработчика/template/.

/**

 * @param Payment $payment
 * @param Request|null $request
 * @return PaySystem\ServiceResult
 */
public function initiatePay(Payment $paymentRequest $request null)
{
    
$params = array(
        
'PARAM1' => 'VALUE1',
        
'PARAM2' => 'VALUE2',
    );

    
$this->setExtraParams($params);

    return 
$this->showTemplate($payment"template");
}

Функция getPaymentIdFromRequest


Назначение данной функции - вернуть идентификатор оплаты (не заказа!) из $request при возврате информации ПС на сайт

/**

 * @param Request $request
 * @return mixed
 */
public function getPaymentIdFromRequest(Request $request)
{
    
$paymentId $request->get('ORDER');
    
$paymentId preg_replace("/^[0]+/","",$paymentId);
    return 
intval($paymentId);
}

Функция getCurrencyList

Данная функция должна вернуть массив со списком валют.

/**

 * @return array
 */
public function getCurrencyList()
{
    return array(
'RUB');
}

Функции, связанные с возвратом информации платежной системой

Обычно платежные системы устроены таким образом, что после успешного или неуспешного прохождения платежа, платежная система уведомляет сайт по определенному адресу. Раньше для принятия таких уведомлений существовал отдельный компонент "bitrix:sale.order.payment.receive", в d7 все устроено иначе - вы можете указывать банку стандартный адрес для уведомлений от пс - /bitrix/tools/sale_ps_result.php, а то, что данные предназначаются одному из обработчиков позволено решать самим обработчикам, и для этого существуют функции getIndicativeFields и isMyResponseExtended.

Функция getIndicativeFields должна вернуть массив полей, по которым проверяется принадлежность информации при возврате к данному обработчику, при этом функция может вернуть как ассоциативный массив (т.е. с символьными ключами), при этом проверка будет производится по значениям полей, так и неассоциативный - при этом проверка будет производится только по наличию полей в $request.

/**

 * @return array
 */
public static function getIndicativeFields()
{
    return array(
'PARAM1','PARAM2');
}

Функция isMyResponseExtended осуществляет дополнительную проверку на принадлежность результат пс к обработчику, и она вызывается после getIndicativeFields. Если дополнительные проверки не требуются, вы можете просто вернуть true.

/**

 * @param Request $request
 * @param $paySystemId
 * @return bool
 */
static protected function isMyResponseExtended(Request $request$paySystemId)
{
    return 
true;
}

Функция processRequest выполняет именно обработку результата от платежной системы, и вызов ее произойдет только в том случае, если вы правильно написали предыдущие две функции. В самом упрощенном виде эта функция может выглядеть как-то так:

/**

 * @param Payment $payment
 * @param Request $request
 * @return PaySystem\ServiceResult
 */
public function processRequest(Payment $paymentRequest $request)
{
    
$result = new PaySystem\ServiceResult();
    
$action $request->get('ACTION');
    
$data $this->extractDataFromRequest($request);
    
    
$data['CODE'] = $action;
    
    if(
$action==="1")
    {
        
$result->addError(new Error("Ошибка платежа"));
    }
    elseif(
$action==="0")
    {            
        
$fields = array(
            
"PS_STATUS_CODE" => $action,
            
"PS_STATUS_MESSAGE" => '',
            
"PS_SUM" => $request->get('AMOUNT'),
            
"PS_CURRENCY" => $payment->getField('CURRENCY'),
            
"PS_RESPONSE_DATE" => new DateTime(),
            
"PS_INVOICE_ID" => '',
        );            
        if (
$this->isCorrectSum($payment$request))
        {
            
$data['CODE'] = 0;
            
$fields["PS_STATUS"] = "Y";
            
$fields['PS_STATUS_DESCRIPTION'] = "Оплата произведена успешно";
            
$result->setOperationType(PaySystem\ServiceResult::MONEY_COMING);
        }
        else
        {
            
$data['CODE'] = 200;
            
$fields["PS_STATUS"] = "N";
            
$message "Неверная сумма платежа";
            
$fields['PS_STATUS_DESCRIPTION'] = $message;
            
$result->addError(new Error($message));
        }
        
$result->setPsData($fields);
    }
    else
    {
        
$result->addError(new Error("Неверный статус платежной системы при возврате информации о платеже"));
    }

    
$result->setData($data);

    if (!
$result->isSuccess())
    {
        
PaySystem\ErrorLog::add(array(
            
'ACTION' => "processRequest",
            
'MESSAGE' => join('\n'$result->getErrorMessages())
        ));
    }

    return 
$result;
}

Кроме указанных функций, могут быть еще и другие, здесь я только описал обязательные и самые необходимые. Также вы можете добавить любые свои вспомогательные функции, например, по аналогии с системными обработчиками.

Лог ошибок платежной системы

Еще дополнение. Обычно все сообщения об ошибках при неуспешной оплате и т.д. пишутся в лог (в функции processRequestмы добавляем их через PaySystem\ErrorLog::add, но они могут добавляться и без нашего участия в ядре системы). Саму страницу, где этот лог выводится, лично я не нашел (если вы знаете, напишите в комментариях), но его можно увидеть с помощью следующего кода, например, через командную php строку:

\Bitrix\Main\Loader::IncludeModule("sale");


$rBitrix\Sale\Internals\PaySystemErrLogTable::getList(array('order'=>array('ID'=>'DESC')));

while(
$a=$r->fetch()) 
{
    
print_r($a);
}

Чтобы оставить сообщение, авторизуйтесь, или войдите с помощью:
26.08.2020 19:03:23
Лог ошибок
Посмотреть лог ошибок можно тут http://<your_site_name>/bitrix/admin/perfmon_table.php?lang=ru&table_name=b_sale_pay_system_err_log
16.10.2020 14:02:46
1) Если обработчик находится в папке local, то опция path2user_ps_files должна указывать на папку local, а не на bitrix - Option::get("sale", "path2user_ps_files", "/local/php_interface/include/sale_payment/")
2) регистр класса должен совпадать с регистром названия папки с обработчиком