Содержание
Организация собственных скидок в Битрикс
Допустим, мы хотим разработать свою систему скидок, которая не укладывается в рамки Битрикса. Например, добавить региональную скидку, которая зависит от места доставки (для каждого места - своя скидка в процентах).
Штатная система скидок предполагает только скидки на товар и скидки на товарную группу.
В этом случае есть смысл хранить свои скидки в отдельно созданных таблицах, а часть бизнес-логики - переписать, делегируя функции скидок классу MyDiscount
:
- изменить цены и скидки при выводе в каталоге
- менять скидку при добавлении в корзину своим обработчиком
- хранить скидку на корзину в отдельной таблице (баг «пересчета» скидок)
Прежнюю систему скидок Битрикс необходимо удалить (иначе в некоторых местах скидки будут считаться дважды):
TRUNCATE b_catalog_discount; TRUNCATE b_catalog_discount_cond;
Скидки в каталоге товаров
Создаем класс MyDiscount
и программируем в нем бизнес-логику, которая выбирает скидки из отдельной таблицы. Новые цены и скидки перед выводом в каталоге можно изменить так:
$arResult["ITEMS"] = MyDiscount::setDiscount($arResult["ITEMS"]);
Добавление скидки в корзину
Обработчик скидок корзины
Для корректной обработки заказа со своей схемой скидок в месте добавления в корзину следует назначить обработчик скидок.
Add2BasketByProductID($iProductID, $iQuantity, array('PRODUCT_PROVIDER_CLASS'=>'CCatalogProductProviderCustom'), $arProductParams);
CCatalogProductProviderCustom
- это унаследованный от CCatalogProductProvider
класс-обработчик корзины:
class CCatalogProductProviderCustom extends CCatalogProductProvider { public static function GetProductData($arParams) { $arResult = CCatalogProductProvider::GetProductData($arParams); // получаем данные из родительского класса $product = CPrice::GetByID($arResult['PRODUCT_PRICE_ID']); // получаем данные о товаре $MyDiscount = new MyDiscount(); // наш класс для обработки скидок $arResult = $MyDiscount->setDiscountCartItem($arResult, $product['PRODUCT_ID']); // модифицируем данные return $arResult; // отдаем модифицированные результаты } public static function OrderProduct($arParams) { $arResult = CCatalogProductProvider::OrderProduct($arParams); $product = CPrice::GetByID($arResult['PRODUCT_PRICE_ID']); $MyDiscount = new MyDiscount(); $arResult = $MyDiscount->setDiscountCartItem($arResult, $product['PRODUCT_ID']); return $arResult; } }
Исправляем баг "пересчета" скидок
Чтобы решить проблему «пересчета» скидок, скидки следует хранить в отдельной таблице:
CREATE TABLE `external_basket_discount` ( `basket_id` int(11) unsigned NOT NULL, `product_id` int(11) unsigned NOT NULL, `my_discount` decimal(5,2) NOT NULL, PRIMARY KEY (`basket_id`,`product_id`) ) ENGINE=InnoDB;
Добавим в класс MyDiscount
три метода:
public function storeDiscount($PRODUCT_ID, $MY_DISCOUNT) { // установить скидку на товар в корзине $basket_id = (int) CSaleBasket::GetBasketUserID(); $product_id = (int) $PRODUCT_ID; $my_discount = (float) $MY_DISCOUNT; $query = "INSERT INTO `external_basket_discount` (`basket_id`, `product_id`, `my_discount`) VALUES ($basket_id, $product_id, '$my_discount') ON DUPLICATE KEY UPDATE `my_discount` = '$my_discount' "; $this->db->Query($query); } public static function extractCartItemDiscount($item) { // получить скидку на товар global $DB; $basket_id = (int) CSaleBasket::GetBasketUserID(); $product_id = (int) $item['PRODUCT_ID']; $query = "SELECT `my_discount` FROM `external_basket_discount` WHERE `basket_id` = $basket_id AND `product_id` = $product_id"; $results = $DB->Query($query); $results = $results->Fetch(); $ret = isset($results['my_discount']) ? $results['my_discount'] : ''; return $ret; } public static function clearDiscount() { // очистить скидки на товары в корзине global $DB; $basket_id = (int) CSaleBasket::GetBasketUserID(); $query = "DELETE FROM `external_basket_discount` WHERE `basket_id` = $basket_id"; $DB->Query($query); }
Где вызывать эти методы:
storeDiscount
- в методеMyDiscount::setDiscountCartItem()
extractCartItemDiscount
- при выводе корзиныclearDiscount
- после оформления заказа