Yandex Metrika
sanches.free 1 просмотр

Накопительная скидка в Битрикс: как менять сумму оплаченных заказов

Как платформа понимает «накопительный» объём

В классической схеме «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 дней гарантии