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',
Надеюсь эта статья будет вам полезна, если вы нашли ошибки или опечатки, пишите в комментариях.
Станьте первым!