Как известно, в 1С-Битрикс множество разновидностей скидок. Есть и «скидки на товары», и «скидки на заказ», и «купоны скидок», и даже «накопительные скидки». Но вместе они иногда работают не так, как нам нужно.

Рассмотрим пример

В интернет-магазине есть 2 типа скидок:

  • Скидка на товар.
  • Скидка по дисконтной карте, реализованная через купоны.

При оформлении заказа необходимо учитывать бОльшую скидку. Как это сделать? Приоритеты и галочка «Прекратить дальнейшее применение скидок» здесь решением не являются. Например, скидка на товар 10%, а скидки по дисконтным картам от 5% до 20%.

То есть, если клиент кладет в корзину товар с 10% скидкой, вводит номер дисконтной карты (по ней скидка 20%) и карта не считается. Получается, применяется меньшая скидка.

Решим досадное недоразумение парочкой обработчиков событий.

CModule::IncludeModule('catalog');
 
AddEventHandler("catalog", "OnGetDiscount", 
    array("WeProductDiscountHandler", "OnGetDiscount"));
AddEventHandler("catalog", "OnGetDiscountResult", 
    array("WeProductDiscountHandler", "OnGetDiscountResult"));
 
 
class WeProductDiscountHandler{
 
    protected static $productPrice = null;
 
    /**
     * Вызывается в методе CCatalogDiscount::GetDiscount перед получением всех скидок
     * @return bool true
     */
    public function OnGetDiscount($intProductID, $intIBlockID, $arCatalogGroups, 
        $arUserGroups, $strRenewal, $siteID, $arDiscountCoupons, $boolSKU, $boolGetIDS){
 
        // получение текущей цены товара. далее, в обработчике OnGetDiscountResult 
        // цена будет недоступна. поэтому получим её здесь
        $curProductPrice = CPrice::GetBasePrice($intProductID, false, false, false);
        if($curProductPrice != false){
            self::$productPrice = $curProductPrice;
        }
 
        return true;
    }
 
    /**
     * Вызывается в методе CCatalogDiscount::GetDiscount после получения 
     * и обработки всех скидок для товара
     * @return array() возвращаем только нужную нам скидку, 
     * в нашем случае — большую. array(0 => массив с данными скидки)
     */
    public function OnGetDiscountResult(&$arResult){
 
        // если цену товара получили и она больше нуля
        if(is_array(self::$productPrice) 
            && isset(self::$productPrice['PRICE']) 
            && self::$productPrice['PRICE'] > 0){
 
            $discounts = array();
            foreach($arResult as $key_discount => $discount){
 
                // собираем все скидки (тут же будут и скидки по купонам) 
                // складываем сумму в рублях
                switch($discount['VALUE_TYPE']){
 
                    // В процентах
                    case CCatalogDiscount::TYPE_PERCENT:
                        $discounts[$key_discount] = self::$productPrice['PRICE'] 
                            * ($discount['VALUE'] / 100);
                        break;
 
                    // Установить цену на товар    
                    case CCatalogDiscount::TYPE_SALE:
                        $discounts[$key_discount] = self::$productPrice['PRICE'] 
                            - $discount['VALUE'];
                        break;
 
                    // Фиксированная сумма   
                    case CCatalogDiscount::TYPE_FIX:
                        $discounts[$key_discount] = $discount['VALUE'];
                        break;
 
                    default:
                        break;
                }
 
            }
 
            if(!empty($discounts)){
 
                // находим ключ массива с наибольщей скидкой
                $maxs_discounts = array_keys($discounts, max($discounts));
                if(isset($maxs_discounts[0], $arResult[$maxs_discounts[0]]) 
                    && is_array($arResult[$maxs_discounts[0]])){
 
                    // подменяем результирующий массив на наш, с единственной скидкой
                    $neededDiscount = $arResult[$maxs_discounts[0]];
                    $arResult = array($neededDiscount);
 
                }
            }
 
        }
 
        self::$productPrice = null;
    }
 
}

На момент написания статьи, версия модуля «Торговый каталог» (catalog) была 14.0.5. Возможно, в поздних версиях это будет решено «из коробки». А пока довольствуемся тем, что есть.