Сортировка товаров по цене с учетом скидок 1С-Битрикс

У стандартного компонента битрикса catalog есть один недостаток, отсутствие возможности сортировки товаров по цене со скидкой. Просто по цене можно, а вот со скидкой никак.

Я предлагаю универсально комплексное решение этой проблемы.

Почему универсальное? Потому что будет работать на более ранних версиях (если у вас более новая версия, можно вместо крона будет использовать события на создание скидки с помощью ORM событий).

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

Меньше слов, ближе к делу:

1. Создаем числовое свойство "Минимальная цена со скидкой" (MIN_PRICE_DISCOUNT) . Можно сделать также через дополнительный тип цены, но в моем примере редакция Малый бизнес и нет возможности добавить еще цену, поэтому будем рассматривать свойство.

2. Ставим событие на обновление цены, на котором записываем новое значение этого свойства, а также добавляем обработчики событий на создание, изменение и удаления самих акций.

С обработчиком на удаление акций я конечно немного помучился, пришлось обрабатывать через 2 события и глобальную переменную, но зато работает.

События можно добавить в файл init.php

AddEventHandler("catalog", "OnPriceAdd", "eventChangePrice");
AddEventHandler("catalog", "OnPriceUpdate", "eventChangePrice");
function eventChangePrice($id, $arFields)
{
	if(CModule::IncludeModule("catalog"))
	{
		// нужно для сортировки цены со скидкой
		// Прошу обратить внимание - обязательно указание сайта!!! в моем случае "s1"
		$arPrice = CCatalogProduct::GetOptimalPrice($arFields["PRODUCT_ID"], 1, array(2), "N", array() , "s1");
		CIBlockElement::SetPropertyValueCode($arFields["PRODUCT_ID"], "MIN_PRICE_DISCOUNT", $arPrice["DISCOUNT_PRICE"]);
		// можем поменять на SetPropertyValues, если знаем ID Инфоблока
	}
}

AddEventHandler("catalog", "OnDiscountAdd", "eventChangeDiscount" );
AddEventHandler("catalog", "OnDiscountUpdate", "eventChangeDiscount");
AddEventHandler("catalog", "OnBeforeDiscountDelete", "eventChangeDiscount" );

function eventChangeDiscount ($id, $arFields)
{
	global $arProdsIdsAfterDiscountDelete;
	
	if(CModule::IncludeModule("catalog"))
	{
		
		if(empty($arFields["PRODUCT_IDS"]) && !empty($id)) // при удалении скидки
		{
			// запомним IDшники товаров из акции
			$resDiscount = CCatalogDiscount::GetList(array(), array("ID"=>$id));
			while($obDiscount = $resDiscount->Fetch())
			{
				$arProdsIdsAfterDiscountDelete[] = $obDiscount["PRODUCT_ID"]; // костыльно конечно
			}
		}
		
		
		
		if(!empty($arFields["PRODUCT_IDS"]))
		{
			foreach($arFields["PRODUCT_IDS"] as $prod_id)
			{
				// нужно для сортировки цены со скидкой
				// Прошу обратить внимание - обязательно указание сайта!!! в моем случае "s1"
				$arPrice = CCatalogProduct::GetOptimalPrice($prod_id, 1, array(2), "N", array() , "s1");
				CIBlockElement::SetPropertyValueCode($prod_id, "MIN_PRICE_DISCOUNT", $arPrice["DISCOUNT_PRICE"]);
				// можем поменять на SetPropertyValues, если знаем ID Инфоблока
			}
		}
		
	}
}

AddEventHandler("catalog", "OnDiscountDelete", "eventAfterDiscountDelete" );
function eventAfterDiscountDelete($id)
{
	global $arProdsIdsAfterDiscountDelete;
	
	// и уже после удаления скидки поменяем свойство для сортировки
	if(!empty($arProdsIdsAfterDiscountDelete))
	{
		foreach($arProdsIdsAfterDiscountDelete as $prod_id)
			{
				// нужно для сортировки цены со скидкой
				// Прошу обратить внимание - обязательно указание сайта!!! в моем случае "s1"
				$arPrice = CCatalogProduct::GetOptimalPrice($prod_id, 1, array(2), "N", array() , "s1");
				CIBlockElement::SetPropertyValueCode($prod_id, "MIN_PRICE_DISCOUNT", $arPrice["DISCOUNT_PRICE"]);
				// можем поменять на SetPropertyValues, если знаем ID Инфоблока
			}
	}
}

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

require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php");
if(CModule::IncludeModule("iblock"))
{
// меняем обязательно ваш номер ИБ
    $resElem = CIBlockElement::GetList(Array(), Array("IBLOCK_ID"=>3, "ACTIVE"=>"Y"), false, false, Array("ID","IBLOCK_ID"));
    while($obElem = $resElem->Fetch())
    {
        $arPrice = CCatalogProduct::GetOptimalPrice($obElem["ID"], 1, array(2), "N", array() , "s1");
		
		if($arPrice["DISCOUNT_PRICE"] > 0)
			CIBlockElement::SetPropertyValues($obElem["ID"], $obElem["IBLOCK_ID"], $arPrice["DISCOUNT_PRICE"], "MIN_PRICE_DISCOUNT");
    }
}

Все, теперь можно ставить сортировку по нашему свойству в вашем компоненте, что-то вроде того "ELEMENT_SORT_FIELD" => "PROPERTY_MIN_PRICE_DISCOUNT",

Если кому-то поможет решить задачу - буду рад :) Если нужна будет помощь - обращайтесь!


Возврат к списку