Configuring Cashback Redemption at Payment in 1C-Bitrix
During checkout, the customer sees their available cashback balance and wants to use it partially or in full. The standard sale module has no built-in "pay with bonuses" mechanism — the payment system or cart must be extended. If done incorrectly, cashback is deducted twice, or the order transitions to "paid" with an incorrect amount.
Where Cashback Is Stored
If the cashback system is built on the loyalty module or a custom solution, balances are stored in a dedicated table, e.g. local_cashback_balances. Key fields: USER_ID, AMOUNT, LAST_UPDATED. Operations are recorded in local_cashback_transactions — the accrual and redemption history.
If the standard "Coupon" or "Discount" is used, cashback is expressed through the catalog module's discount mechanism. However, this is an incorrect model for real cashback — discounts are not tied to a specific user through a balance.
Redemption Mechanism
The correct model: cashback is a payment method, not a discount. The b_sale_payment table will contain two payments for an order: one through the payment system (the remaining amount), and a second — "payment with bonuses" (the cashback amount).
Register a custom payment system handler in /local/php_interface/include/sale_payment/cashback/handler.php:
class CashbackPaySystemHandler extends \Bitrix\Sale\PaySystem\ServiceHandler
{
public function initiatePay(
\Bitrix\Sale\Payment $payment,
\Yii\HttpRequest $request = null
): \Bitrix\Sale\PaySystem\ServiceResult
{
$result = new \Bitrix\Sale\PaySystem\ServiceResult();
$userId = $payment->getOrder()->getUserId();
$amount = $payment->getSum();
// Check balance
$balance = CashbackBalanceTable::getBalance($userId);
if ($balance < $amount) {
$result->addError(new \Bitrix\Main\Error('Insufficient cashback'));
return $result;
}
// Reserve
CashbackBalanceTable::reserve($userId, $amount, $payment->getId());
$payment->setPaid('Y');
$payment->save();
return $result;
}
}
Reservation rather than immediate deduction — because the order may be cancelled. Actual deduction occurs when the order status changes to "Fulfilled."
Cancellation Event Handler
AddEventHandler('sale', 'OnSaleOrderCanceled', function(\Bitrix\Sale\Order $order) {
foreach ($order->getPaymentCollection() as $payment) {
if ($payment->getPaySystem()->getField('CODE') === 'cashback') {
CashbackBalanceTable::releaseReserve(
$order->getUserId(),
$payment->getSum(),
$payment->getId()
);
}
}
});
Redemption Amount Limits
Business rules: deduct no more than 30% of the order total, minimum payment in real money — 100 units. Restrictions are implemented in the checkout component (sale.order.ajax or custom) at the form validation level (JS) and server-side check.
$maxCashbackAllowed = min(
$order->getPrice() * 0.30, // 30% of order total
CashbackBalanceTable::getBalance($userId), // actual balance
$order->getPrice() - 100 // minimum cash payment
);
The value is passed to JavaScript via a data-max-cashback attribute on the input field.
Scope of Work
- Development or adaptation of cashback balance and transaction tables
- Custom
cashbackpayment system handler - Reserve/deduct/refund logic on cancellation
- Redemption amount limits in checkout
- Balance display and input field in the order form
Timeline: 1–2 weeks with a ready cashback system. 3–4 weeks if the cashback system is being built from scratch.







