Bitrix

Фильтрация по цене с учетом валюты в компоненте bitrix:catalog.section

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

Я сделал инфоблок, для заказчики могли бы хранить курс валют нехитрым образом, написал такой скриптик в компоненте catalog.section для выгрузки валюты из инфоблока и использования ее:

// считываем обменный курс из инфоблока

$arSelect = Array();

$arFilter = Array(«IBLOCK_ID»=>4, «ACTIVE_DATE»=>»Y», «ACTIVE»=>»Y»);

$res = CIBlockElement::GetList(Array(), $arFilter, false, Array(), $arSelect);

while($ob = $res->GetNextElement())

{

$arProps = $ob->GetProperties();

$exchange[$arProps[«id_valuta»][«VALUE»]] = $arProps[«rate»][«VALUE»];

}

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

// Сохраняем старый фильтр

// и приводим цены к рублевым эквивалентам

$arrFilter_price = $arrFilter;

$arrFilter_price[«PROPERTY»][«>=price»] = $arrFilter_price[«PROPERTY»][«>=price»] * $exchange[$arrFilter_price[«PROPERTY»][«valuta»]];

$arrFilter_price[«PROPERTY»][«<=price»] = $arrFilter_price[«PROPERTY»][«<=price»] * $exchange[$arrFilter_price[«PROPERTY»][«valuta»]];

Затем я перешел к фильтрации. Когда я только открывал код, я подумал, что напишу какое-то, пусть сложное условие здесь:

$arFilter = array(

«IBLOCK_ID» => $arParams[«IBLOCK_ID»],

«IBLOCK_LID» => SITE_ID,

«IBLOCK_ACTIVE» => «Y»,

«ACTIVE_DATE» => «Y»,

«ACTIVE» => «Y»,

«CHECK_PERMISSIONS» => «Y»,

«INCLUDE_SUBSECTIONS» => $arParams[«INCLUDE_SUBSECTIONS»],

);

и на этом все благополучно закончится.

Но посидев приличное время над кодом компонента, я осознал, что просто не представляю как это сделать при помощи API Битрикс и поэтому пришлось лепить безумные костыли в компоненте catalog.section дабы эта штукуевина заработала этот функционал заработал.

Сначала, перед запросом кеша, пришлось все поубирать из фильтра, связанное с ценами, потому что фильтрация по ценам не будет средствами API Битрикс.

// Удаляем из фильтра все связанное с ценами

$arDiff = Array(«>=price»=>NULL, «<=price»=>NULL, «valuta»=>NULL);

$arrFilter[«PROPERTY»] = array_diff_key($arrFilter[«PROPERTY»], $arDiff);

Затем, там где идет собственно выборка элементов, пришлось дописать свою фильтрацию по ценам:

// цену элемента приводим к рублевому эквиваленту

if (isset($arrFilter_price[«PROPERTY»][«valuta»])) {

$price_rub = $arItem[«PROPERTIES»][«price»][«VALUE»] * $exchange[$arItem[«PROPERTIES»][«valuta»][«VALUE_ENUM_ID»]];

}

// проверяем цену на вхождение в диапазон

$invalid_price = false;

if ($arrFilter_price[«PROPERTY»][«>=price»]!=0 && $arrFilter_price[«PROPERTY»][«<=price»]==0) {

if (! ($price_rub >= $arrFilter_price[«PROPERTY»][«>=price»])) {

$invalid_price = true;

}

}

if ($arrFilter_price[«PROPERTY»][«<=price»]!=0 && $arrFilter_price[«PROPERTY»][«>=price»]==0) {

if (! ($price_rub <= $arrFilter_price[«PROPERTY»][«<=price»])) {

$invalid_price = true;

}

}

if ($arrFilter_price[«PROPERTY»][«<=price»]!=0 && $arrFilter_price[«PROPERTY»][«>=price»]!=0) {

if (! (($price_rub >= $arrFilter_price[«PROPERTY»][«>=price»]) && ($price_rub <= $arrFilter_price[«PROPERTY»][«<=price»]))) {

$invalid_price = true;

}

}

Выглядит не блестяще, но работает… Но.. стоп. А как же постраничная навигация? В ней же мы никак не учитываем, что элементов меньше, чем в выборке через API Битрикс.

Ну что ж, на этот случай тоже можно сделать костыль. Дописываем код в обработку выборки элементов:

if (! $invalid_price)

$quant_all++;

// если цена не входит, то выкидываем элемент из выборки

if (! $invalid_price && ( $start_elem <= $quant_all && $end_elem >= $quant_all ))

$arResult[«ITEMS»][]=$arItem;

И после выборки, перед вызовом метода $rsElements->GetPageNavStringEx пишем:

$rsElements->NavNum = 2;

$rsElements->bNavStart = true;

$rsElements->bShowAll = $arParams[«PAGER_SHOW_ALL»];

if (floor($quant_all / $arParams[«PAGE_ELEMENT_COUNT»]) != $quant_all / $arParams[«PAGE_ELEMENT_COUNT»])

$rsElements->NavPageCount = floor($quant_all / $arParams[«PAGE_ELEMENT_COUNT»]) + 1;

else

$rsElements->NavPageCount = floor($quant_all / $arParams[«PAGE_ELEMENT_COUNT»]);

if (isset($_REQUEST[«PAGEN_2»]))

$rsElements->NavPageNomer = $_REQUEST[«PAGEN_2»];

else

$rsElements->NavPageNomer = 1;

$rsElements->NavRecordCount = $quant_all;

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

Комментариев: 4

  1. Я просто не верю, что это нельзя сделать через Битрикс API…
    Наверняка есть какой-то обходной путь, но не такими костылями же.

  2. Почему не подходит такой вариант:
    $arrFilter[] = array(
    «LOGIC» => «OR»,
    array(«>=CATALOG_PRICE_1» => «10», «CATALOG_CURRENCY_1» => «RUB»),
    array(«>=CATALOG_PRICE_1» => «30», «CATALOG_CURRENCY_1» => «USD»)
    );

Отставить комментарий

Ваш электронный адрес не будет опубликован.Обязательные для заполнения поля отмечены *

четырнадцать − двенадцать =