У стандартного компонента битрикса 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",
Если кому-то поможет решить задачу - буду рад :) Если нужна будет помощь - обращайтесь!