Разработка модуля ценовых правил 1С-Битрикс
Менеджер хочет задать акцию: «скидка 15% на все товары бренда X для покупателей из Москвы, у которых сумма заказов за последние 30 дней превышает 10 000 рублей, но только если в корзине нет товаров категории Y». Штатный модуль скидок Битрикс (sale) обрабатывает прямолинейные случаи, однако комбинированные условия с обращением к истории заказов или региональной логикой требуют либо костылей в шаблоне корзины, либо разработки отдельного модуля.
Ограничения штатного механизма
Встроенные скидки в sale работают через таблицу b_discount и b_discount_condition. Условия ограничены предустановленным набором: группа пользователя, сумма заказа, набор товаров. Расширить список условий можно через событие OnGetDiscountConditionTypes, но это решение точечное и не масштабируется при большом числе кастомных правил.
Вторая проблема — приоритеты. При пересечении нескольких скидок результат зависит от порядка применения, который сложно контролировать через стандартный интерфейс.
Архитектура модуля ценовых правил
Модуль строится как надстройка над sale, не заменяя ядро. Это важно: изменения цен регистрируются через стандартный механизм скидок, что обеспечивает совместимость с 1С-синхронизацией и сторонними интеграциями.
Движок правил хранит правила в собственной таблице myvendor_price_rules. Каждое правило — это JSON-структура с набором условий и действий:
{
"conditions": [
{"type": "user_group", "value": [5, 8]},
{"type": "region", "value": ["RU-MOW"]},
{"type": "order_history_sum", "period_days": 30, "min_sum": 10000}
],
"condition_operator": "AND",
"actions": [
{"type": "percent_discount", "value": 15, "target": "brand_X_items"}
],
"priority": 100,
"stackable": false
}
Вычислитель условий — набор классов-стратегий, каждая из которых реализует ConditionInterface::check(int $userId, array $basketItems): bool. Условия, требующие обращения к БД (история заказов, сумма покупок), кешируют результат в рамках одного запроса через статический массив.
Детально: условие по истории заказов
Это самое затратное условие с точки зрения производительности. Запрос к b_sale_order с агрегацией за 30 дней для активного магазина может быть тяжёлым. Решение:
$cacheKey = "order_history_{$userId}";
if (!isset($_SESSION['price_rules_cache'][$cacheKey])) {
$sum = \Bitrix\Sale\OrderTable::getList([
'filter' => [
'=USER_ID' => $userId,
'>=DATE_INSERT' => (new \Bitrix\Main\Type\DateTime())->add('-30D'),
'=CANCELED' => 'N',
],
'runtime' => [
new \Bitrix\Main\Entity\ExpressionField('TOTAL', 'SUM(%s)', 'PRICE'),
],
])->fetch()['TOTAL'] ?? 0;
$_SESSION['price_rules_cache'][$cacheKey] = (float)$sum;
}
Исключающие условия (не применять если в корзине есть товары категории Y) реализованы как отдельный тип ExclusionCondition, который проверяется последним и блокирует применение правила.
Интеграция с корзиной
Модуль подключается к событию OnSaleOrderBeforeSaved и OnBeforeBasketAdd. При добавлении товара в корзину вычислитель прогоняет все активные правила, находит применимые, рассчитывает итоговую скидку с учётом приоритетов и стекуемости, создаёт запись в b_discount / b_discount_coupon программно через \Bitrix\Sale\Discount.
Административный интерфейс
В разделе модуля — визуальный конструктор правил: drag-and-drop для условий, предпросмотр «кому применится это правило» (показывает количество подходящих пользователей из базы), история применений с разбивкой по правилам.
Сроки разработки
| Масштаб | Состав | Срок |
|---|---|---|
| Базовый | До 5 типов условий + % и фиксированные скидки | 3–4 недели |
| Средний | + история заказов + региональная логика + приоритеты | 5–7 недель |
| Полный | + визуальный конструктор + аналитика + A/B тестирование правил | 8–12 недель |
Перед разработкой необходим анализ текущих скидок в b_discount — импорт существующих правил в новую систему часто занимает неожиданно много времени.







