Setting up cashback debits when paying with 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

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 cashback payment 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.