Перейти к содержимому

Фильтр по цене и наличию - диапазон, валюта, склад

Разбираемся с двумя самыми частыми условиями умного фильтра: диапазоном цены и наличием товара. Тип цены и валюта, скидки мимо диапазона, доступность и остаток по складу.

Что нужно знать заранее

Диапазон цены строится по конкретному типу цены, а не по «цене товара вообще». Тип задают параметром фильтра, и покупатель без прав на этот тип не увидит ползунок совсем.

В диапазон фильтра попадает цена типа, а не итоговая цена товара со скидкой. Товар с акционной ценой остаётся в старом отрезке, и покупатель находит его по прежней, более высокой границе.

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

Шаги

  1. Определить тип цены фильтра и проверить права всех групп покупателей на этот тип.
  2. Привести валюты к одной, если цены товаров заведены в разных валютах каталога.
  3. Проверить границы диапазона выборкой минимальной и максимальной цены нужного типа.
  4. Включить отбор доступных товаров прямо в параметрах компонента списка товаров.
  5. Добавить своё условие по складу, когда покупателю нужен товар в конкретном пункте выдачи.

Решение

Смотрим настоящие границы диапазона:

\Bitrix\Main\Loader::includeModule('catalog');
$row = \Bitrix\Catalog\PriceTable::getList([
'select' => ['MIN_PRICE', 'MAX_PRICE'],
'filter' => ['=CATALOG_GROUP_ID' => $priceTypeId],
'runtime' => [
new \Bitrix\Main\Entity\ExpressionField('MIN_PRICE', 'MIN(%s)', 'PRICE'),
new \Bitrix\Main\Entity\ExpressionField('MAX_PRICE', 'MAX(%s)', 'PRICE'),
],
])->fetch();
print_r($row); // границы ползунка должны совпадать с этими числами

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

Приводим валюты к одной:

// в параметрах компонента фильтра
'CONVERT_CURRENCY' => 'Y',
'CURRENCY_ID' => 'RUB', // все цены пересчитываются в эту валюту по курсу
// без пересчёта товары в разных валютах попадают в один отрезок как есть

Проверяем, что скидка мимо фильтра:

$optimal = \CCatalogProduct::GetOptimalPrice($productId, 1, $USER->GetUserGroupArray(),
'N', [], SITE_ID, []);
printf("тип цены: %s, итог со скидкой: %s\n", $optimal['PRICE']['PRICE'], $optimal['DISCOUNT_PRICE']);
// в отрезок фильтра попадает первое число, а покупатель видит на витрине второе

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

Включаем отбор доступных товаров:

$APPLICATION->IncludeComponent('bitrix:catalog.section', '', [
'IBLOCK_ID' => $iblockId,
'FILTER_NAME' => 'arrFilter',
'HIDE_NOT_AVAILABLE' => 'Y', // Y - скрыть, L - показать в конце списка
]);

Добавляем своё условие по складу:

global $arrFilter;
$storeId = (int) $request->get('store');
if ($storeId > 0) {
$arrFilter['>=STORE_AMOUNT_' . $storeId] = 1; // ключ выборки по остатку склада
}
// условие добавляют до подключения списка: компонент читает переменную фильтра

Ключ остатка по складу поддерживается выборкой каталога напрямую. Отдельный запрос к таблице складских остатков и последующая фильтрация массива тут не нужны.

Пересобираем фасетный индекс после смены цен:

\Bitrix\Iblock\PropertyIndex\Manager::markAsInvalid($iblockId);
// точечно после правки одного товара: updateElementIndex($iblockId, $elementId)
// пересборку крупного каталога запускают ночью: она читает весь инфоблок

Типичные проблемы

Товар со скидкой не находится по акционной цене.

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

Ползунок показывает границы, которых нет в каталоге.

Фасетный индекс собран до массовой смены цен и хранит прежние границы отрезков. Индекс помечают недействительным и пересобирают его после каждой крупной выгрузки цен.

У части покупателей ползунка цены нет вовсе.

Их группе не выдано право видеть тот тип цены, который указан в параметрах фильтра. Права на тип цены проверяют отдельно от прав группы на сам инфоблок каталога.

Товары в разных валютах смешались в одном отрезке.

Пересчёт валют в параметрах фильтра выключен, и числа разных валют сравниваются напрямую. Включают приведение к одной валюте и указывают её код в параметрах фильтра явно.

Фильтр по складу отбирает не те товары.

Условие добавлено уже после подключения списка либо записано в другую переменную фильтра. Своё условие кладут в ту же переменную и до вызова компонента списка.

Частые вопросы

Почему скидка не влияет на фильтр по цене?

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

Как показать цены в одной валюте?

Включить пересчёт валют в параметрах фильтра и задать целевую валюту. Иначе цены разных валют попадают в общий отрезок без приведения по курсу.

Можно ли фильтровать по остатку склада?

Штатная форма склады не различает, но выборка каталога понимает ключ остатка по складу. Условие добавляют в переменную фильтра до подключения списка товаров.

Чем отличается скрытие недоступных от показа в конце?

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

Как часто пересобирать фасетный индекс?

После каждой массовой правки цен и свойств, обычно ночным заданием. Точечные правки закрывают обновлением индекса одного элемента.

Смежное

Первоисточник