Developing custom discount logic for 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

Developing Custom Discount Logic in 1C-Bitrix

The standard Bitrix discount constructor covers most typical scenarios. But when you need a discount that depends on external CRM, order history for a quarter, competitor inventory, or time of day — standard tools run out. Then custom logic is written.

Two levels of extension

Level 1: Custom basket event handler

The OnBeforeSaleOrderFinalAction event allows intervening at the moment of basket calculation before final discount application. The OnSaleBasketItemAdd event allows intercepting product addition.

Example: 5% discount on entire order if customer already made a purchase this month:

AddEventHandler('sale', 'OnBeforeSaleOrderFinalAction', function(&$order) {
    $userId = $order->getUserId();
    $currentMonth = date('Y-m');

    $prevOrders = \Bitrix\Sale\Order::load(/* filter by userId and month */);

    if (!empty($prevOrders)) {
        // apply programmatic discount
        $basket = $order->getBasket();
        foreach ($basket as $item) {
            $price = $item->getPrice();
            $item->setField('PRICE', $price * 0.95);
            $item->setField('DISCOUNT_PRICE', $price * 0.05);
        }
    }
});

Level 2: Custom discount provider

A cleaner approach — implement the \Bitrix\Sale\Discount\DiscountProviderInterface interface and register your own provider. The provider receives the basket as input and returns a list of applied discounts in standard format. Standard rules from b_sale_discount continue to work in parallel or replace completely — depends on configuration.

Custom conditions in rule constructor

You can extend the list of available conditions in the marketing rules constructor without replacing the entire mechanism. Create an inheriting class of \Bitrix\Sale\Discount\Actions\Base or a condition inheritor of \Bitrix\Sale\Discount\Condition\Base:

namespace MyModule\Discount\Condition;

class PreviousOrdersCount extends \Bitrix\Sale\Discount\Condition\Base
{
    public function check(\Bitrix\Sale\Order $order): bool
    {
        // check logic
    }
}

The class is registered via the module's events.php, and a new "Number of previous orders" condition appears in the rules constructor.

Custom discounts from external systems

For integration with external CRM or ERP where individual customer discounts are stored:

  1. When user logs in, request their discount profile from external system
  2. Save in session or in user UF_ fields
  3. Basket event handler reads this data and applies the discount

Caching the response from external system is mandatory — each request on every basket change to external API creates unacceptable delays. Cache in Redis/Memcached with TTL 15–60 minutes.

Debugging custom discount logic

Logging applied discounts: b_sale_order_discount stores all rules applied to an order. For debugging custom discounts, add a record to this journal with "custom rule" identifier so that in the admin panel you can see exactly what was applied.

Estimated timeframes

Task Timeframe
Custom event handler for one rule 1–2 days
New condition in marketing rules constructor 2–3 days
Full custom discount provider 1–2 weeks
External CRM discount integration with caching 3–5 days