Сортировка по цене в каталоге с торговыми предложениями

Столкнулся тут с проблемкой: как отсортировать все товары по цене, если каталог имеет торговые предложени?

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

Доброго времени суток. 

Столкнулся тут с проблемой: как отсортировать все товары по цене, если каталог имеет торговые предложения? 

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

Выход из данной проблемы был в 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

Была обнаружена такая особенность: если изменения происходят только по цене, то свойство с минимальной цено не обновлялось (точнее оно затиралось данными из формы товара). Внес правки в код, чтобы исправить эту ситуацию

Количество показов: 6097
17.10.2014

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

Если вам была полезна статья можете отблагодарить автора:
Ethereum:

0x16Df809287333C49D3A237296C6248A6c08702Bc

Разработка сайта

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

Сопровождение сайта

Вы можете подать заявку на сопровождение вашего сайта на базе 1С-Битрикс. Сопровождение включает в себя: проверка актуальности обновлений сайта, проверка актуальности резервной копии, консультации по сайту. Опишите в заявке, какие еще объемы планируются на сопровождении и на какой срок вы планируете заключить договор на сопровождение - мы подберем подходящий вам бюджет на сопровождение

Работы по сайту

Вы можете подать заявку на выполнение определенного объема работ по сайту. Опишите в заявке объем работ. Это может быть разработка какого-то нового функционала, доработки по имеющемуся функционалу, доработки под требования сео-специалистов. На основании заявки вам будет сформирован бюджет работ, а также названы сроки на выполнение тех или иных работ.