Йо-йо! Сейчас я занимаюсь созданием одного очень интересного для меня сайта. Интересен он тем, что в нём есть довольно обширная система лояльности клиентов. Там есть и скидки по дисконтным картам, которые хранятся в 1С, и несколько групп служб доставок, на каждую из которых есть своя скидка. А ещё есть особая группа служб доставок, на которые нужно дать особую скидку.
Есть несколько служб доставок, которые ограничены регионами. В том случае, если сумма товаров с учётом скидок более 20.000 рублей и если цена на доставку меньше или равно 10% от стоимости товаров, то дать скидку на доставку 50%, а если больше, то дать скидку на доставку равную 10% от стоимости товаров.
Давайте запишем в виде формулы
$basketPrice = цена товаров $deliveryPrice = цена на доставку $maxDeliveryPrice = $basketPrice * (10 / 100); максимально возможная скидка на доставку $newValue = новое значение цены на доставку - то, что мы в итоге считаем if($basketPrice > 20000){ $prepareValue = $deliveryPrice / 2; - 50% от стоимости доставки if($prepareValue >= $maxDeliveryPrice){ $newValue = $deliveryPrice - $maxDeliveryPrice; } else { $newValue = $prepareValue; } }
Думаю сейчас вам стало понятно, что конкретно нужно вычислить.
Мы же говорим о битриксе, да… Так вот, для того чтобы применить новую цену на доставку, нужно использовать событие «onSaleDeliveryServiceCalculate«. Но фишка в том, что это событие не содержит объект корзины или заказа, чтобы из него получить сумму товаров. Я попробовал использовать метод для получения корзины:
$basket = Sale\Basket::loadItemsForFUser(Sale\Fuser::getId(), Bitrix\Main\Context::getCurrent()->getSite());
Из статьи «Работа с корзиной в битрикс d7» я увидел, что сильно замедлился расчёт стоимости доставки. Поэтому решил делать иначе.
Мне понадобиться обработать 2 события: «OnSaleComponentOrderCreated» и «onSaleDeliveryServiceCalculate». На OnSaleComponentOrderCreated я получу цену на товары, а на onSaleDeliveryServiceCalculate я получу цену на доставку, посчитаю скидку и применю новую цену на доставку.
// Получить цену товаров при создании корзины AddEventHandler("sale", "OnSaleComponentOrderCreated", "xakpl_OnSaleComponentOrderCreated"); function xakpl_OnSaleComponentOrderCreated($order, &$arUserResult, $request, &$arParams, &$arResult, &$arDeliveryServiceAll, &$arPaySystemServiceAll){ $_SESSION['XAKPL_ORDER_BASKET_PRICE'] = $order->getBasket()->getPrice(); }
Я получил из события объект заказа, из него объект корзины и цену на товары со скидками и наценками. Если вам будет нужен результат без учёта скидок и наценок, то взамен getPrice() используйте getBasePrice().
// Изменить цену доставки после получения расчёта стоимости AddEventHandler("sale", "onSaleDeliveryServiceCalculate", "xakpl_onSaleDeliveryServiceCalculate"); function xakpl_onSaleDeliveryServiceCalculate($result, $shipment, $deliveryID){ if(isset($_SESSION['XAKPL_ORDER_BASKET_PRICE']) ) { $basketPrice = $_SESSION['XAKPL_ORDER_BASKET_PRICE']; // Получаем цену доставки $deliveryPrice = $result->getDeliveryPrice(); // Считаем максимально возможную цену на доставку $maxDeliveryPrice = intval($basketPrice) * (10 / 100); // 10% $newValue = $deliveryPrice; if($basketPrice > 20000){ // Считаем цену на доставку со скидкой 50% $prepareValue = $deliveryPrice / 2; if($prepareValue >= $maxDeliveryPrice){ $newValue = $deliveryPrice - $maxDeliveryPrice; } else { $newValue = $prepareValue; } // Записываем новое значение цены на доставку $shipment->setBasePriceDelivery($newValue, true); } } }
Тут пояснение излишне, комментарии говорят сами за себя.
На этом можно было бы остановиться, но нужно ещё учесть, что надо применять скидку только к определённым службам доставки.
Для идентификации службы доставки у нас в событии есть переменная $deliveryID. Сам идентификатор нужной службы доставки мы можем найти в админке, в списке служб доставки. Ну и я не стал заморачиваться и получилось в итоге вот что:
// Изменить цену доставки после получения расчёта стоимости AddEventHandler("sale", "onSaleDeliveryServiceCalculate", "xakpl_onSaleDeliveryServiceCalculate"); function xakpl_onSaleDeliveryServiceCalculate($result, $shipment, $deliveryID){ // Проверка id службы доставки if($deliveryID == 61 || $deliveryID == 75 || $deliveryID == 67 || $deliveryID == 94 || $deliveryID == 76 ){ if(isset($_SESSION['XAKPL_ORDER_BASKET_PRICE']) ) { $basketPrice = $_SESSION['XAKPL_ORDER_BASKET_PRICE']; // Получаем цену доставки $deliveryPrice = $result->getDeliveryPrice(); // Считаем максимально возможную цену на доставку $maxDeliveryPrice = intval($basketPrice) * (10 / 100); // 10% $newValue = $deliveryPrice; if($basketPrice > 20000){ // Считаем цену на доставку со скидкой 50% $prepareValue = $deliveryPrice / 2; if($prepareValue >= $maxDeliveryPrice){ $newValue = $deliveryPrice - $maxDeliveryPrice; } else { $newValue = $prepareValue; } // Записываем новое значение цены на доставку $shipment->setBasePriceDelivery($newValue, true); } } } }