1С-Битрикс. Применение только одной, самой большой скидки на товар
Как известно, в 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. Возможно, в поздних версиях это будет решено «из коробки». А пока довольствуемся тем, что есть.
5 комментариев
Добрый день, как сделать, чтобы у товаров в корзине у которых нет скидок, к ним применялась скидка на сумму в 5%? А если у товара уже есть скидка на Бренд и тд и тд Чтобы она не суммировалась
Роман, нужно допиливать метод WeProductDiscountHandler::OnGetDiscountResult или присмотреться к этому способу: http://olegorestov.ru/this/discount_contolrs/
Добрый день! Спасибо за решение. В каталоге товаров без проблем показывает большую скидку, из двух установленных. А вот в корзине, все равно, странная "комбинация" из скидок: 60%+50%=80% ))). Можете подсказать что добавить в Ваш обработчик для применения в корзине? Спасибо.
Не нужно это все писать, достаточно, комбинировать приоритеты скидок соответствующие их размерам, разрешить дальнейшее применение правил, но в настройке каждой скидке выбрать условие применение скидки к товару "были применены скидки" к товару установить на "нет". Тогда на каждый товар установится только максимальная скидка
Запилил на форум решение от 21 августа 2019 года
https://dev.1c-bitrix.ru/community/webdev/user/274551/forum/124225/