Доброго времени суток.
Столкнулся тут с проблемой: как отсортировать все товары по цене, если каталог имеет торговые предложения?
При этом проблема даже не с решением того, как это реализовать, а с логикой: по какому полю сортировать? у товара может быть много торговых предложений, каждое со своей ценой ...
Выход из данной проблемы был в 12-й версии продукта, в решении eshop. Сейчас почему-то убрали, возможно разработчики знают, почему, но особо времени разбираться нет, поэтому на одном из старых проектов нашел код, решающий данную задачу.
Итак, привожу просто код файла init.php. Те, кто в теме - поймут, кто не в теме - обратитесь лучше к тем, кто в теме
AddEventHandler("iblock", "OnAfterIBlockElementUpdate", "BXIBlockAfterSave");
AddEventHandler("iblock", "OnAfterIBlockElementAdd", "BXIBlockAfterSave");
AddEventHandler("catalog", "OnPriceAdd", "BXIBlockAfterSave");
AddEventHandler("catalog", "OnPriceUpdate", "BXIBlockAfterSave");
function BXIBlockAfterSave($arg1, $arg2 = false)
{
global $USER;
$ELEMENT_ID = false;
$IBLOCK_ID = false;
$OFFERS_IBLOCK_ID = false;
$OFFERS_PROPERTY_ID = false;
$BX_SITE_ID = "s1";
if (CModule::IncludeModule('currency'))
$strDefaultCurrency = CCurrency::GetBaseCurrency();
//Check for catalog event
if (is_array($arg2) && $arg2["PRODUCT_ID"] > 0)
{
//Get iblock element
$rsPriceElement = CIBlockElement::GetList(
array(),
array(
"ID" => $arg2["PRODUCT_ID"],
),
false,
false,
array("ID", "IBLOCK_ID")
);
if ($arPriceElement = $rsPriceElement->Fetch())
{
$arCatalog = CCatalog::GetByID($arPriceElement["IBLOCK_ID"]);
if (is_array($arCatalog))
{
//Check if it is offers iblock
if ($arCatalog["OFFERS"] == "Y")
{
//Find product element
$rsElement = CIBlockElement::GetProperty(
$arPriceElement["IBLOCK_ID"],
$arPriceElement["ID"],
"sort",
"asc",
array("ID" => $arCatalog["SKU_PROPERTY_ID"])
);
$arElement = $rsElement->Fetch();
if ($arElement && $arElement["VALUE"] > 0)
{
$ELEMENT_ID = $arElement["VALUE"];
$IBLOCK_ID = $arCatalog["PRODUCT_IBLOCK_ID"];
$OFFERS_IBLOCK_ID = $arCatalog["IBLOCK_ID"];
$OFFERS_PROPERTY_ID = $arCatalog["SKU_PROPERTY_ID"];
}
} //or iblock which has offers
elseif ($arCatalog["OFFERS_IBLOCK_ID"] > 0)
{
$ELEMENT_ID = $arPriceElement["ID"];
$IBLOCK_ID = $arPriceElement["IBLOCK_ID"];
$OFFERS_IBLOCK_ID = $arCatalog["OFFERS_IBLOCK_ID"];
$OFFERS_PROPERTY_ID = $arCatalog["OFFERS_PROPERTY_ID"];
} //or it's regular catalog
else
{
$ELEMENT_ID = $arPriceElement["ID"];
$IBLOCK_ID = $arPriceElement["IBLOCK_ID"];
$OFFERS_IBLOCK_ID = false;
$OFFERS_PROPERTY_ID = false;
}
}
}
} //Check for iblock event
elseif (is_array($arg1) && $arg1["ID"] > 0 && $arg1["IBLOCK_ID"] > 0)
{
//Check if iblock has offers
$arOffers = CIBlockPriceTools::GetOffersIBlock($arg1["IBLOCK_ID"]);
if (is_array($arOffers))
{
$ELEMENT_ID = $arg1["ID"];
$IBLOCK_ID = $arg1["IBLOCK_ID"];
$OFFERS_IBLOCK_ID = $arOffers["OFFERS_IBLOCK_ID"];
$OFFERS_PROPERTY_ID = $arOffers["OFFERS_PROPERTY_ID"];
}
} elseif (is_array($arg1) && intval($arg1['ID'])>0 && isset($arg1['QUANTITY'])){
$ELEMENT_ID = intval($arg1["ID"]);
$IBLOCK_ID = intval($_REQUEST['IBLOCK_ID']);
}
if ($ELEMENT_ID)
{
static $arPropCache = array();
if (!array_key_exists($IBLOCK_ID, $arPropCache))
{
//Check for MINIMAL_PRICE property
$rsProperty = CIBlockProperty::GetByID("MINIMUM_PRICE", $IBLOCK_ID);
$arProperty = $rsProperty->Fetch();
if ($arProperty)
$arPropCache[$IBLOCK_ID] = $arProperty["ID"];
else
$arPropCache[$IBLOCK_ID] = false;
}
if ($arPropCache[$IBLOCK_ID])
{
//Compose elements filter
if ($OFFERS_IBLOCK_ID)
{
$rsOffers = CIBlockElement::GetList(
array(),
array(
"ACTIVE" => "Y",
"IBLOCK_ID" => $OFFERS_IBLOCK_ID,
"PROPERTY_" . $OFFERS_PROPERTY_ID => $ELEMENT_ID,
),
false,
false,
array("ID")
);
while ($arOffer = $rsOffers->Fetch())
$arProductID[] = $arOffer["ID"];
if (!is_array($arProductID) || empty($arProductID))
$arProductID = array($ELEMENT_ID);
} else
$arProductID = array($ELEMENT_ID);
$minPrice = false;
$maxPrice = false;
//Get prices
foreach ($arProductID as $productID)
{
$arDiscountPrice = CCatalogProduct::GetOptimalPrice($productID, 1, $USER->GetUserGroupArray(), false,
false, $BX_SITE_ID);
if (CModule::IncludeModule('currency')
&& $strDefaultCurrency != $arDiscountPrice['RESULT_PRICE']['CURRENCY'])
$arDiscountPrice['DISCOUNT_PRICE'] = CCurrencyRates::ConvertCurrency(
$arDiscountPrice['DISCOUNT_PRICE'],
$arDiscountPrice['RESULT_PRICE']["CURRENCY"],
$strDefaultCurrency
);
$PRICE = $arDiscountPrice['DISCOUNT_PRICE'];
if ($minPrice === false || $minPrice > $PRICE)
$minPrice = $PRICE;
if ($maxPrice === false || $maxPrice < $PRICE)
$maxPrice = $PRICE;
}
//Save found minimal price into property
if ($minPrice !== false)
{
CIBlockElement::SetPropertyValuesEx(
$ELEMENT_ID,
$IBLOCK_ID,
array(
"MINIMUM_PRICE" => $minPrice,
"MAXIMUM_PRICE" => $maxPrice,
)
);
}
}
}
}
не забудьте в каталоге добавить числовое свойство (или добавить функцию-проверку наличия такого свойства и в случае отсутствия - создание такового):
MINIMUM_PRICE
и
MAXIMUM_PRICE
Update 2019-08-21
Была обнаружена такая особенность: если изменения происходят только по цене, то свойство с минимальной цено не обновлялось (точнее оно затиралось данными из формы товара). Внес правки в код, чтобы исправить эту ситуацию
