Довольно часто на интернет-магазинах оптовой торговли можно встретить сразу несколько типов цен — обычно их обозначают как ОПТ1, ОПТ2, ОПТ3 и т.п. В зависимости от того, на какую сумму покупатель набрал добра в корзине и(или) иных условий, для него срабатывает тот или иной тип цен.
К сожалению, не все движки сайтов предусматривают наличие сразу нескольких типов цен для товара, а даже те движки, в которых есть возможность задания более чем одной цены для продукта, зачастую не располагают гибкими механизмами их переключения. К последним относится довольно таки популярный «1С-Битрикс». С одной стороны, в этой CMS уже в «коробочном» варианте(в редакции «Бизнес» и выше) есть поддержка нескольких видов цен, а с другой стороны, совершенно непонятно как настроить динамическое переключение этих цен в зависимости от тех или иных условий. Штатный мануал по этой части тоже хранит гробовое молчание. Надеюсь, что товарищи из Битрикса исправят это досадное недоразумение, но я решил не ждать этого счастливого момента и ясное дело додумался до костыльного решения, чем собственно и решил поделиться с читателим.
Итак, поехали...
В первую очередь, следует обратить внимание на обработчик OnGetOptimalPrice. Несмотря на то, что эта функция в ядре появилась достаточно давно, в онлайн-документации её описание было добавлено совсем недавно. Между тем, этот обработчик срабатывает когда происходит автоматический выбор оптимальной цены для конкретного товара и позволяет переопределять цену для него. Мы же попытаемся использовать его для пересчета всех цен в корзине в зависимости от общей суммы покупки.
Подключаем обработчик в файле /php_interface/init.php (само собой, если этого файла нет, то его необходимо создать — битрикс подключит его автоматически)
AddEventHandler("catalog", "OnGetOptimalPrice", "MyGetOptimalPrice");
Объявление функции MyGetOptimalPrice вместе с входными параметрами будет выглядеть следующим образом:
function MyGetOptimalPrice($productID, $quantity = 1, $arUserGroups = array(), $renewal = "N", $arPrices = array(), $siteID = false, $arDiscountCoupons = false)
Как видно из приведенного кода, функция не получает на вход общую сумму стоимости товаров в корзине, а только данные конкретного товара. А значит, необходимо получить данные корзины запросом в базу данных. Т.к. обработчик вызывается в цикле в зависимости от количества товаров в корзине, то имеет смысл определить глобальную переменную, в которую будем записывать общую сумму содержимого корзины при первом вызове обработчика OnGetOptimalPrice.
На выходе должно получиться, что-то вроде этого:
global $LocalPrice; $LocalPrice = 0; function MyGetOptimalPrice($productID, $quantity = 1, $arUserGroups = array(), $renewal = "N", $arPrices = array(), $siteID = false, $arDiscountCoupons = false) { global $LocalPrice; if($LocalPrice <= 0) { // Выведем актуальную корзину для текущего пользователя $dbBasketItems = CSaleBasket::GetList(false, array( "FUSER_ID" => CSaleBasket::GetBasketUserID(), "LID" => SITE_ID, "ORDER_ID" => "NULL" ), false, false, array("ID", "MODULE", "PRODUCT_ID", "CALLBACK_FUNC", "QUANTITY", "DELAY", "CAN_BUY", "PRICE") ); while ($arItem = $dbBasketItems->Fetch()) { if($arItem['DELAY'] == 'N' && $arItem['CAN_BUY'] == 'Y') { $LocalPrice += $arItem['PRICE']*$arItem['QUANTITY']; } } } //ОПТ 1 при сумме заказа до 10 000 рублей //ОПТ 2 при сумме заказа до 20 000 рублей //ОПТ 3 при сумме заказа более 20 000 рублей // получаем все типы цен, возможные для данного товара $arOptPrices = CCatalogProduct::GetByIDEx($productID); if($LocalPrice < 10000){ $price = $arOptPrices['PRICES'][1]['PRICE']; $catalog_group_id = 1; } elseif($LocalPrice >= 10000 and $LocalPrice < 20000){ $price = $arOptPrices['PRICES'][2]['PRICE']; $catalog_group_id = 2; } elseif($LocalPrice >= 20000){ $price = $arOptPrices['PRICES'][3]['PRICE']; $catalog_group_id = 3; } return array( 'PRICE' => array( "ID" => $productID, 'CATALOG_GROUP_ID' => $catalog_group_id, 'PRICE' => $price, 'CURRENCY' => "RUB", 'ELEMENT_IBLOCK_ID' => $productID, 'VAT_INCLUDED' => "Y", ), 'DISCOUNT' => array( 'VALUE' => $discount, 'CURRENCY' => "RUB", ), ); }
При желании можно оптимизировать код, добавив кеширование для хранения выборки цен, избавиться от хард-кодового задания условий и вынеся условия в конфиг-файлы или в базу данных. В принципе, саму выборку данных из корзины тоже можно вынести за пределы функции обработчика и хранить сумму где-нить в сессии, куках или глобальной переменной(кому как нравится и как считает правильным). Само собой, для учебного примера не стал всего этого делать. Пользуйтесь на здоровье!
Автор: AdamZ