Накопительная скидка в Битрикс: как менять сумму оплаченных заказов
Как платформа понимает «накопительный» объём
В классической схеме «1С‑Битрикс» для прогрессивной скидки смотрят не на баллы программы лояльности, а на агрегированную сумму уже оплаченных покупок пользователя. Внутренний расчёт сосредоточен около метода CCatalogDiscountSave::__SaleOrderSumm: сначала срабатывает событие catalog::OnSaleOrderSumm (можно подставить свой набор данных вместо стандартного обхода заказов), затем после вычисления вызывается OnSaleOrderSummResult, куда попадают итоговые ключи вида накопленной суммы и суммы для текущего ценового диапазона.
Важно: в свежих ветках магазина часть логики перенесли в новые сервисы и обработчики; перечисленные события могут отсутствовать или вести себя иначе. Перед продакшеном сверьтесь с актуальной документацией и трассировкой на вашей версии.
Стартовый баланс после переноса клиентов
Типичный кейс — миграция с другого движка: на новом сайте история платежей пустая, а у клиента уже был накопленный порог на стороне CRM или старого магазина. Решение простое: добавляете пользователям свойство профиля, например UF_ORDERS_SUMM, заполняете его числом из внешней системы и на событии OnSaleOrderSummResult добавляете это значение к рассчитанным платформой цифрам.
$eventBroker = \Bitrix\Main\EventManager::getInstance();
$eventBroker->addEventHandlerCompatible('catalog', 'OnSaleOrderSummResult', 'mergeSeedTurnoverIntoCumulativeTotals');
function mergeSeedTurnoverIntoCumulativeTotals(&$orderAggregate)
{
global $USER;
if (!$USER->IsAuthorized()) {
return true;
}
$seedRow = \Bitrix\Main\UserTable::getList([
'select' => ['UF_ORDERS_SUMM'],
'filter' => ['=ID' => (int)$USER->GetID()],
'limit' => 1,
])->fetch();
$seedAmount = (int)($seedRow['UF_ORDERS_SUMM'] ?? 0);
if ($seedAmount <= 0) {
return true;
}
$orderAggregate['SUMM'] += $seedAmount;
$orderAggregate['RANGE_SUMM'] += $seedAmount;
return true;
}Если нужно не прибавлять корректирующее число к расчёту ядра, а полностью подменить сумму одним значением из поля, можно присвоить массиву новые числа напрямую — но это лишний раз триггерит пересборку уже посчитанных данных и обычно менее экономно по производительности, чем донастройка на этапе «до результата».
Полностью свой алгоритм на OnSaleOrderSumm
Когда стандартный подсчёт через CSaleOrder::__SaleOrderCount не отражает бизнес‑правила (например, нужно считать только определённые типы заказов, вычитать возвраты или брать сумму из внешнего складского контура), вешайте обработчик на раннее событие OnSaleOrderSumm и возвращайте собственную структуру суммы. Сортировку обработчика ставят высокой (ниже число — раньше исполнение; в примере 99), чтобы переопределить вызов стандартного метода счётчика — конкретное значение уточните по вашей редакции через отладчик.
$eventBroker = \Bitrix\Main\EventManager::getInstance();
$eventBroker->addEventHandlerCompatible(
'catalog',
'OnSaleOrderSumm',
'buildCustomPaidOrderTotalsForLoyalty',
false,
99
);
function buildCustomPaidOrderTotalsForLoyalty($orderFilterSkeleton)
{
/* $orderFilterSkeleton несёт исходный фильтр выборки; здесь считаете
оплаченный оборот по своим таблицам или REST и формируете ответ */
$paidLifetime = /* float|int сумма всего времени */ 0;
$normalizedCurrency = 'RUB';
$lastPaidAt = new \Bitrix\Main\Type\DateTime();
$indexedAt = new \Bitrix\Main\Type\DateTime();
return [
'PRICE' => $paidLifetime,
'CURRENCY' => $normalizedCurrency,
'LAST_ORDER_DATE' => $lastPaidAt,
'TIMESTAMP' => $indexedAt,
];
}Возвращаемый набор полей держите в соответствии с тем, что ожидает ваша сборка после события: при сомнениях откройте реализацию CSaleOrder::__SaleOrderCount на конкретной версии и скопируйте контракт значений один в один.
На что обратить внимание перед выкладкой
- Убедитесь, что валюта агрегата совпадает с валютой правил накопительной скидки, иначе порог будет смещаться.
- Кеши и переиндексация скидок: после изменения логики пересмотрите, не нужно ли вручную обновить тестового пользователя с известными заказами.
- Гостевая покупка — обработчик должен аккуратно выходить, если авторизации нет, чтобы не засорять логи предупреждениями.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии