«Из коробки» в 1С-Битрикс при расчете накопительной скидки сумма оплаченных заказов юзера считается из всех заказов, сделанных им, с флагом «Оплачен». И это логично. А что если нужно выбирать заказы по своей логике, например, заказы с определенным статусом? На этот счет есть не документированное событие.

В методе \CAllCatalogDiscountSave::__SaleOrderSumm есть вызов не документированного события OnSaleOrderSumm. По умолчанию на него подписан CSaleOrder::__SaleOrderCount с сортировкой 100. Схитрим и подпишемся на это событие, с сортировкой меньше 100. Тогда наш обработчик вызовется раньше.

Код обработчика:

<?php
\Bitrix\Main\EventManager::getInstance()->addEventHandlerCompatible('catalog', 'OnSaleOrderSumm',
    function ($arFilter, $strCurrency = '') {
        global $USER;
        $mxResult = false;
 
        // Id статуса заказа, по которому считать заказа выполненным.
        $saleStatusId = 'G';
 
        // ID пользователей, кому вообще не надо давать накопительную скидку
        $withoutDiscountUserIds = array(3); 
 
        if (is_array($arFilter) && !empty($arFilter)) {
            if (isset($arFilter['PAYED'])) {
                unset($arFilter['PAYED']);
            }
 
            if (!isset($arFilter['STATUS_ID'])) {
                $arFilter['STATUS_ID'] = $saleStatusId;
            }
 
            $dblPrice = 0;
            $strCurrency = strval($strCurrency);
            $mxLastOrderDate = '';
            $intMaxTimestamp = 0;
            $intTimeStamp = 0;
            $rsSaleOrders = CSaleOrder::GetList(array(), $arFilter, false, false, 
                array('ID', 'PRICE', 'CURRENCY', 'DATE_INSERT'));
            while ($arSaleOrder = $rsSaleOrders->Fetch()) {
                $intTimeStamp = MakeTimeStamp($arSaleOrder['DATE_INSERT']);
                if ($intMaxTimestamp < $intTimeStamp) {
                    $intMaxTimestamp = $intTimeStamp;
                    $mxLastOrderDate = $arSaleOrder['DATE_INSERT'];
                }
                if (empty($strCurrency)) {
                    $dblPrice += $arSaleOrder['PRICE'];
                    $strCurrency = $arSaleOrder['CURRENCY'];
                } else {
                    if ($strCurrency != $arSaleOrder['CURRENCY']) {
                        $dblPrice += $arSaleOrder['PRICE'];
                    } else {
                        $dblPrice += $arSaleOrder['PRICE'];
                    }
                }
            }
 
            if (in_array($arFilter['USER_ID'], $withoutDiscountUserIds)) {
                $dblPrice = 0;
            }
 
            $mxResult = array(
                'PRICE' => $dblPrice,
                'CURRENCY' => $strCurrency,
                'LAST_ORDER_DATE' => $mxLastOrderDate,
                'TIMESTAMP' => $intMaxTimestamp,
            );
        }
        return $mxResult;
    }, false, 10);

В обработчике так же предусмотрен механизм исключения определённых пользователей и подсчета. То есть у них сумма оплаченных заказов всегда будет равна 0. Это полезно, когда заказ менеджер создаёт руками и нужно чтобы скидка не накапливалась и не применялась.

На этом всё. Читайте исходники — там много полезного.