1С-Битрикс. Сортировка по цене в системах с разной валютой.
Долгие годы разработчики просили возможность сортировать по цене, там где используется несколько валют. Ведь система позволяет одни цены на товары хранить в рублях, другие в евро и т. д. Это удобно, учитывая, что многие поставщики дают цены в валюте, то проще сохранить ее сразу в валюте и потом на выходе отдавать в рублях, на текущий курс.
И вот случилось чудо, спустя 4-5 лет долгих костылей и просьб на сайте разработчика, в API была добавлена возможность сортировать с учетом валюты.

Использование сортировки цен с валютой в 1C-Bitrix версии 16.0.3 и старше
Для того что бы использовать эту возможность, надо посмотреть в вашей системе, какой тип цены является базовы, для этого идем в Магазин → Настройки → Типы цен

В моем случае это ID = 1
Дальше мы добавляем в вызов компонента возможность сортировать по убыванию цены, например:
"ELEMENT_SORT_FIELD" => "CATALOG_PRICE_SCALE_1", "ELEMENT_SORT_ORDER" => "desc",
Или возрастанию:
"ELEMENT_SORT_FIELD" => "CATALOG_PRICE_SCALE_1", "ELEMENT_SORT_ORDER" => "asc",
Так же, вы можете добавить 2 параметр сортировки с ключем ELEMENT_SORT_FIELD2 и ELEMENT_SORT_ORDER2.
Но что делать тем, у кого версия битрикса младше 16.0.3?
Для этого есть разные способы, я решил использовать дополнительное свойство, в которое я пишу цену в рублях (конвертирую) и уже сортирую по ней. Сейчас я его подробно опишу.
Для начала, нам нужно создать свойство: PRICE_SORT, в название я написал «Цена в рублях для сортировки», тип: число.

Дальше, нам необходимо заполнить его у всех товаров, я это сделал при помощи вот такого скрипта:
function update_catalog_price_sort(){
$count = 0;
try{
$arFilter = Array( "IBLOCK_ID" => 2 );
$res = CIBlockElement::GetList(Array(), $arFilter, false, false, Array("ID", "PROPERTY_PRICE_SORT", 'CATALOG_GROUP_1') );
while($row = $res->GetNext())
{
$price = $row['CATALOG_PRICE_1'];
echo "Start update {$row['ID']}: {$price} {$row['CATALOG_CURRENCY_1']} to ";
if ($row['CATALOG_CURRENCY_1'] != 'RUB'){
$price = CCurrencyRates::ConvertCurrency($price, $row['CATALOG_CURRENCY_1'], 'RUB');
}
if ($price != $row['PROPERTY_PRICE_SORT_VALUE']){
CIBlockElement::SetPropertyValuesEx($row['ID'], 2, array(
'PRICE_SORT' => $price
));
echo "{$price} {RUB} - DONE \n";
$count++;
sleep(0.2);
} else {
echo "{$price} {RUB} - NOT NEED UPDATE \n";
}
}
} catch(Exception $ex) {
smail('Запуск обновления цен-сортировок', 'Провал - обновления:' . $ex->getMessage() );
}
return $count;
}
Вначале мы запрашиваем все товары в системе, у меня около 120 тыс. Из запроса мы получаем:
- ID - индификатор товара
- CATALOG_PRICE_1 — цена товара. Учтите, что если у вас, базовый тип цены другой (смотри выше где можно проверить), то и цифра в конце ключа, будет другой. В любом случае, вы всегда можете сделать print_r($row) и узнать правильность ID базовой цены
- CATALOG_CURRENCY_1 — в какой валюте сохранена цена. Так же как и с ценой, важно учитывать ID в конце ключа
Дальше все просто, если валюта отличается от RUB, делаем конвертацию:
$price = CCurrencyRates::ConvertCurrency($price, $row['CATALOG_CURRENCY_1'], 'RUB');
и потом полученную цену сравниваем с тем, что у нас сохранено в PRICE_SORT (ключ в массиве: PROPERTY_PRICE_SORT_VALUE), если цены различаются, обновляем.
Для отладки я использую вывод информации и отлов исключения, с уведомление на почту. Дальше нам остается функцию update_catalog_price_sort() поместить в агент, который будет обновлять цены. Я его добавил в агент обновляющий валюту. Он у меня запускается раз в сутки, когда на сервере минимальная нагрузка.
Учтите важный момент! Это ресурсоёмкая задача, по-этому агенты должны исполняться на cron.
Ну и самое важное, прописываем наше поле PRICE_SORT в вызове компонента:
"ELEMENT_SORT_FIELD" => 'PROPERTY_PRICE_SORT',
Надеюсь эта статья будет вам полезна, если вы нашли ошибки или опечатки, пишите в комментариях.
Станьте первым!