Налаштування холдирування коштів на 1С-Bitrix
Покупець оплатив замовлення — гроші списані, але замовлення ще не підтверджено. Через два дні виясняється, що товару немає на складі. Повернення — це ще кілька днів. Холдирування (двохстадійна оплата) вирішує цю проблему: банк резервує суму на карті покупця, а фактичне списання відбувається тільки після підтвердження наявності товару.
Двохстадійна оплата: схема роботи
Стадія 1 — Холд (авторизація): магазин відправляє запит у платіжну систему на резервування суми. Гроші не списані, але заблоковані на карті. Банк-еквайер видає pre_auth_code або аналогічний ідентифікатор авторизації.
Стадія 2 — Підтвердження (capture): магазин підтверджує списання, коли товар готовий до відправки. Гроші переходять на рахунок магазину. Або — скасування (void/cancel): якщо товара немає, резерв знімається без комісій.
Bitrix реалізує це через модуль sale, клас \Bitrix\Sale\PaySystem\Manager та конкретні обробники платіжних систем.
Підтримка двохстадійної оплати в модулі sale
Не всі платіжні системи в Bitrix підтримують двохстадійну оплату. Вбудована підтримка є у:
- Сбербанк (через
SberPaymenthandler) - Тинькофф (
TinkoffPayment) - ЮКасса — YooKassa (
YandexMoney) - Альфа-Банк (
AlfaPayment)
Конфігурація платіжної системи в адміністративній панелі: «Магазин» → «Оплата» → обрати платіжну систему → вкладка «Налаштування» → параметр «Двохстадійна оплата» або «Режим холдирування».
Конфігурація холдирування в таблиці бази даних
Параметри платіжної системи зберігаються в таблицях b_sale_pay_system та b_sale_pay_system_handler:
-- Знайти ID платіжної системи
SELECT ID, NAME, HANDLER_TYPE FROM b_sale_pay_system WHERE ACTIVE = 'Y';
-- Параметри конкретної платіжної системи
SELECT PS_ID, CODE, VALUE FROM b_sale_pay_system_params WHERE PS_ID = 5;
Програмна робота з холдируванням
Статуси оплати в b_sale_payment:
-
N— не оплачено -
Y— оплачено (гроші списані)
Кастомні статуси холдирування зазвичай зберігаються у додаткових полях або через b_sale_order_props.
Підтвердження оплати (capture) через API:
use Bitrix\Sale;
// Отримати замовлення
$order = Sale\Order::load($orderId);
// Отримати оплату
$paymentCollection = $order->getPaymentCollection();
foreach ($paymentCollection as $payment) {
if (!$payment->isPaid()) {
// Підтвердити холдировані платіж
$result = Sale\PaySystem\Manager::confirm($payment);
if (!$result->isSuccess()) {
// Обробити помилку
$errors = $result->getErrorMessages();
}
}
}
Скасування холдирування:
foreach ($paymentCollection as $payment) {
$result = Sale\PaySystem\Manager::cancel($payment);
if ($result->isSuccess()) {
// Обнулити суму оплати
$payment->setField('SUM', 0);
}
}
$order->save();
Обробник eventi підтвердження замовлення
Автоматичне підтвердження (capture) при переводі замовлення у статус «Підтверджено»:
// /bitrix/php_interface/init.php
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandler(
'sale',
'OnSaleStatusOrderChange',
function(\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
$value = $event->getParameter('VALUE');
// Статус "підтверджено" — підтвердити холд
if ($value === 'C') { // ID вашого статусу підтвердження
$paymentCollection = $order->getPaymentCollection();
foreach ($paymentCollection as $payment) {
if (!$payment->isPaid()) {
\Bitrix\Sale\PaySystem\Manager::confirm($payment);
}
}
}
// Статус "скасовано" — зняти холд
if ($value === 'F') {
$paymentCollection = $order->getPaymentCollection();
foreach ($paymentCollection as $payment) {
\Bitrix\Sale\PaySystem\Manager::cancel($payment);
}
}
}
);
Термін дії холдирування
Банки обмежують термін холдирування. Сбербанк — до 30 днів, більшість зарубіжних еквайерів — 7 днів. Якщо за цей термін не підтвердити або не скасувати, банк автоматично знімає резерв.
Налаштувати агент Bitrix, який перевіряє просрочені холди:
// Агент: ProccessExpiredHolds()
function ProccessExpiredHolds() {
// Знайти оплати у статусі холд, старші за 5 днів
$cutoffDate = new \Bitrix\Main\Type\DateTime();
$cutoffDate->add('-5D');
$res = \Bitrix\Sale\Internals\PaymentTable::getList([
'filter' => [
'PAID' => 'N',
'<DATE_BILL' => $cutoffDate,
'!SUM' => 0
],
'select' => ['ID', 'ORDER_ID']
]);
while ($row = $res->fetch()) {
// Відправити сповіщення менеджеру про необхідність обробити замовлення
\CEvent::Send('HOLD_EXPIRING', 's1', [
'ORDER_ID' => $row['ORDER_ID']
]);
}
return 'ProccessExpiredHolds();';
}







