На сайтах, где установлены модули Торговый каталог и Интернет-магазин есть несколько способов задать скидки:
Но как ограничить скидку на общую сумму заказа с учетом всех скидок? Не так, чтобы прекращать применять другие скидки, а применить до максимума.
Например:
В статье рассмотрен пример применения ограничения не к каждому товару, а именно к общей сумме. Для реализации задачи потребуется наш модуль - Произвольное PHP условие правил работы с корзиной. Свои (кастомные) условия в скидках.
Основная идея заключается в том, чтобы вернуть итоговую цену до максимально разрешенной скидки с помощью наценок. Причем приоритет у этих наценок должен быть самый низкий, ниже всех по уровню с остальными скидками.
Шаги для реализации следующие:
Необходимо будет заготовить правила работы с корзиной с действием "наценка" с шагом единица, т.е. 1%, 2%, 3%,...100% (вручную или скриптом).
Указать в дополнительных условиях PHP-условие CDev::__check_markup($arOrder, $markup_action), где $markup_action - это величина процента скидки.
Ниже рассмотрен код, который необходимо разместить в init.php. В коде есть множество коммитов, которые отражает техническую сторону реализации и будет очень полезно для ознакомления разработчикам.
Class CDev { public static function OnBeforePrologHandler() { global $APPLICATION; if (CModule::IncludeModule('sale') && CModule::IncludeModule('catalog')) { ///personal/cart/ - если у вас корзина или форма заказа находятся по другому пути, то нужно указать его if (strpos($APPLICATION->GetCurPage(false),"/personal/cart/") === 0 || strpos($APPLICATION->GetCurPage(false),"/personal/order/make/") === 0 ) { CDev::__sc_markup_calculation(); } } } //вспомогательная функция: определяет величину наценки, на котрую нужно поднять получившуюся цену, чтобы получить максимально допустимую цену public static function __sc_markup_calculation() { global $APPLICATION; if (!CModule::IncludeModule('sale') && !CModule::IncludeModule('catalog')) return false; $max_discount = 30; //максимально допустимая скидка, например 30%. Рекомендуем вынести в константу или в опции $fullBasket = \Bitrix\Sale\Basket::loadItemsForFUser(\Bitrix\Sale\Fuser::getId(), \Bitrix\Main\Context::getCurrent()->getSite()); $basketClone = $fullBasket->createClone(); $orderableBasket = $basketClone->getOrderableItems(); unset($basketClone); //Использовать только правила корзины $onlySaleDiscounts = (string) Bitrix\Main\Config\Option::get('sale', 'use_sale_discount_only') == 'Y'; if (!$onlySaleDiscounts) { $orderableBasket->refresh(\Bitrix\Sale\Basket\RefreshFactory::create(\Bitrix\Sale\Basket\RefreshFactory::TYPE_FULL)); } $discounts = \Bitrix\Sale\Discount::buildFromBasket($orderableBasket, new \Bitrix\Sale\Discount\Context\Fuser($orderableBasket->getFUserId(true))); if ($discounts) { $discounts->calculate(); $result = $discounts->getApplyResult(true); $prices = $result['PRICES']['BASKET']; if (!empty($result["PRICES"]["BASKET"])) { $base_price = $price = 0; foreach ($result["PRICES"]["BASKET"] as $item) { $base_price += $item["BASE_PRICE"]; $price += $item["PRICE"]; } if ($price > 0 && $base_price > $price) { $total_discount = ($price * 100) / $base_price; //скидка, которая применилась if ($total_discount > $max_discount) { $max_price = $base_price * (100 - $max_discount) / 100; //определяем какая должны была быть максимально допустимая цена, с учетомт скидок $GLOBALS["SCODER_MARKUP"] = (int) round(($max_price - $price) * 100 / $price); //НАЦЕНКА, на какой процент поднять, чтобы получить максимально допустимую цену } } } } } //вспомогательная функция: определяет, накидывать ли наценку для ограничения скидок public static function __check_markup($arOrder = array(), $markup_action = 0) { $markup_action = (int) $markup_action; if ($markup_action > 0 && $GLOBALS["SCODER_MARKUP"] > 0 ) { //если величины наценок совпадают if ($GLOBALS["SCODER_MARKUP"] == $markup_action) { return true; } } return false; } }
Немного о функции CDev::__check_markup($arOrder, $markup_action), которая вызывается в дополнительных условиях правил работы с корзиной, отвечающих за наценку. Выглядит следующим образом: