Как вывести все товары со скидкой в 1С-битрикс (catalog.section)

Добрый день!

На одном проекте потребовалось вывести на определенной странице все товары со скидкой, проставленной в Правилах работой с корзиной.

К сожалению, в данный момент для этого нет готового решения. Т.е. нельзя например в фильтре компонента или GetList-а задать определенный параметр и таким образом получить все нужные товары.

Погуляв по форумам в поисках готового решения не нашел ничего подходящего для меня, пришлось делать всё ручками с нуля :)

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

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

Почему не используем метод "на лету" - из-за потенциальных проблем с производительностью такого способа.

Итак, что делаем:

Заводим для нашего основного инфоблока свойство типа Список (можно и простую строку, у меня просто оно уже было). Ставим там одно единственное возможное значение (у меня это "yes"). У меня свойство имеет код SPECIALOFFER.

Далее в какой-нибудь служебной папочке добавляем скрипт следующего содержания, где меняем входные параметры на свои, а именно: код инфоблока, значение свойства, сам код свойства (если у вас он другой)

require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php");

CModule::IncludeModule("iblock");
CModule::IncludeModule("catalog");

// меняем под себя эти значения
$iblock_id = 10; // основной инфоблок
$idPropSale = 22; // ID значения свойства отвечающего за Акцию

$oldPropsSale = $arNewSale = array();

// перебираем все активные элементы нашего инфоблока
$resItem = CIBlockElement::GetList(
	array("ID"=>"asc"),
	array( "ACTIVE"=>"Y", "IBLOCK_ID"=>$iblock_id),
	false,
	false,
	array("ID", "IBLOCK_ID", "PROPERTY_SPECIALOFFER")
);
while($arItem = $resItem->Fetch())
{
	// запишем текущее значение свойства скидки
	$oldPropsSale[$arItem["ID"]] = $arItem["PROPERTY_SPECIALOFFER_VALUE"];
	
	// смотрим есть ли у нашего товара SKU
	$offersExist = CCatalogSKU::getExistOffers($arItem["ID"], $arItem["IBLOCK_ID"]);
	
	// для товаров с SKU
	if($offersExist[$arItem["ID"]] == 1)
	{
		// получим все SKU
		$resSku = CCatalogSKU::getOffersList(
			$arItem["ID"],
			$arItem["IBLOCK_ID"],
			array("ACTIVE"=>"Y") // дополнительный фильтр предложений. по умолчанию пуст.
		);
		
		// Если нашли SKU
		if(!empty($resSku[$arItem["ID"]]))
		{
			// Перебираем их
			foreach($resSku[$arItem["ID"]] as $sku)
			{
				// смотрим есть ли для текущего предложения скидка
				$arDiscounts = CCatalogDiscount::GetDiscountByProduct($sku["ID"], array(2), "N", 1, SITE_ID);// ID, группа пользователей, пр.подписки, Группа цены, сайт
				
				// если нашлась скидка
				if(!empty($arDiscounts))
				{
					// ставим для родителя флаг наличия скидки
					$arNewSale[$sku["PARENT_ID"]] = "Y";
					// если нашли останавливаем цикл
					break;
				}
			}
		}
	}
	else // для простых товаров
	{
		// смотрим есть ли для текущего предложения скидка
		$arDiscounts = CCatalogDiscount::GetDiscountByProduct($arItem["ID"], array(2), "N", 1, SITE_ID);// ID, группа пользователей, пр.подписки, Группа цены, сайт
		// если нашлась скидка
		if(!empty($arDiscounts))
		{
			// ставим для родителя флаг наличия скидки
			$arNewSale[$arItem["ID"]] = "Y";
		}
	}
}

// теперь проставляем свойство где нужно
foreach($arNewSale as $prodId => $propVal)
{
	// ставим значение только если оно уже не установлено
	if($oldPropsSale[$prodId] != "yes" && $propVal == "Y")
	{
		//echo "Значение для товара $prodId добавлено \r\n";
		CIBlockElement::SetPropertyValuesEx($prodId, $iblock_id, array("SPECIALOFFER" => $idPropSale));
	}
}

// теперь очистим устаревшие значения свойства Акция
foreach($oldPropsSale as $prodId => $propVal)
{
	// ставим значение только если оно уже не установлено
	if($oldPropsSale[$prodId] == "yes" && $arNewSale[$prodId] != "Y")
	{
		//echo "Значение у товара $prodId удалено \r\n";
		CIBlockElement::SetPropertyValuesEx($prodId, $iblock_id, array("SPECIALOFFER" => false));
	}
}

Всё, теперь нам только остается добавить фильтрацию по нашему свойству где это необходимо.

Предупреждение!! Если каталог у вас довольно большой - скрипт лучше повесить на крон во время наименьшей нагрузки, т.к. выполнятся он может долгое время.

Надеюсь кому-нибудь будет полезно.


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