Выбрать курс
8  /  8

Ограничение скидок в корзине веб-сайта на ЦМС 1С-Битрикс

На сайтах, где установлены модули Торговый каталог и Интернет-магазин есть несколько способов задать скидки:

  1. С помощью правил работы с корзиной.
  2. С помощью скидок на товары.
  3. Есть и иные: накопительные скидки, подарки. Но в данной статье они не взяты в расчет.

Но как ограничить скидку на общую сумму заказа с учетом всех скидок? Не так, чтобы прекращать применять другие скидки, а применить до максимума.

Например:

  • Скидка на товары в корзине по правилу работы равно 20%, а скидка на товар равно 15%.
  • 20 + 15 = 35%. Нужно поставить ограничение = 30%.
  • Полученную скидку снизить до ограничения 35 - 5 = 30%.

В статье рассмотрен пример применения ограничения не к каждому товару, а именно к общей сумме. Для реализации задачи потребуется наш модуль - Произвольное PHP условие правил работы с корзиной. Свои (кастомные) условия в скидках.

Внимание! В статье приведены фрагменты кода, описывающие принцип реализации. Для внедрения отраженного подхода потребуется помощь программистов.

Мы также можем в этом помощь, но за отдельное вознаграждение. Обратиться за помощью можно в наш чат в правом нижнем углу нашего сайта (в рабочее время отвечаем достаточно оперативно). Но оставляем за собой право отказать в доработке без объяснения причин.

Основная идея заключается в том, чтобы вернуть итоговую цену до максимально разрешенной скидки с помощью наценок. Причем приоритет у этих наценок должен быть самый низкий, ниже всех по уровню с остальными скидками.

Шаги для реализации следующие:

  1. С помощью АПИ 1С-Битрикс до вывода корзины (подключения компонента bitrix:sale.basket.basket) определяем какие правила работы применились для текущего покупателя.
  2. Вычисляем итоговую величину скидки в корзине.
  3. Если скидка выше допустимой, накидываем наценку, чтобы привести скидку к максимально допустимой.

    Необходимо будет заготовить правила работы с корзиной с действием "наценка" с шагом единица, т.е. 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), которая вызывается в дополнительных условиях правил работы с корзиной, отвечающих за наценку. Выглядит следующим образом: