В общем, если кому понадобится, написал такие обработчики. Пришлось разбираться с D7, опять лезть в исходники, потому, что классические обработчики уже не работают как надо. Обрабатываю события сохранения корзины и сохранения заказа (скидки за купоны в объект корзины записываются только при сохранении заказа).
Функция recalcBasketKitSets считает сумму комплектующих и сравнивает с ценой комплекта, и исправляет то или иное в пользу покупателя. Если на комплект назначена скидка, она распределяется на комплектующие.
Приходится менять BASE_PRICE комплекта, поскольку в корзине (стандартном компоненте sale.basket.basket) выводится именно она, плюс похоже корзина на каждом хите норовит обновить цены товаров в соответствии с каталогом. Возможно нужно как-то пользоваться провайдерами, но в мануале про это нет, а я не ОО-архитектор.
Функция recalcBasketKitSets считает сумму комплектующих и сравнивает с ценой комплекта, и исправляет то или иное в пользу покупателя. Если на комплект назначена скидка, она распределяется на комплектующие.
Приходится менять BASE_PRICE комплекта, поскольку в корзине (стандартном компоненте sale.basket.basket) выводится именно она, плюс похоже корзина на каждом хите норовит обновить цены товаров в соответствии с каталогом. Возможно нужно как-то пользоваться провайдерами, но в мануале про это нет, а я не ОО-архитектор.
Код |
---|
use Bitrix\Main; Main\EventManager::getInstance()->addEventHandler('sale', 'OnSaleBasketBeforeSaved', Array(CKitSetPriceHandlers, basketBeforeSavedHandler)); Main\EventManager::getInstance()->addEventHandler('sale', 'OnSaleOrderBeforeSaved', Array(CKitSetPriceHandlers, orderBeforeSavedHandler)); class CKitSetPriceHandlers { private function recalcBasketKitSets(\Bitrix\Sale\Basket $basket, $changeSetPrice = false) { $arBasketItems = $basket->getBasketItems(); foreach ($arBasketItems as $basketItem) if ($basketItem->isBundleParent() && $basketItem->getFields()->isChanged('PRICE')) { $kitSetPrice = $basketItem->getField('PRICE'); $kitSetBasePrice = $basketItem->getField('BASE_PRICE'); $kitSetCurrency = $basketItem->getField('CURRENCY'); $kitSetQuantity = $basketItem->getField('QUANTITY'); $kitSetDiscount = $kitSetBasePrice > 0 ? $kitSetPrice / $kitSetBasePrice : 1; $setCompTotalBasePrice = 0; $setCompTotalPrice = 0; $bMatchCurrency = true; if (!$kitSetQuantity) continue; $arBundleItems = $basketItem->getBundleCollection()->getBasketItems(); foreach ($arBundleItems as $bundleItem) { if ($bundleItem->getField('CURRENCY') <> $kitSetCurrency) $bMatchCurrency = false; $setCompQuantity = $bundleItem->getField('QUANTITY'); $setCompTotalPrice += $bundleItem->getField('PRICE') * $setCompQuantity / $kitSetQuantity; $setCompTotalBasePrice += $bundleItem->getField('BASE_PRICE') * $setCompQuantity / $kitSetQuantity; } if ($setCompTotalPrice == $kitSetPrice || !$bMatchCurrency || !$setCompTotalBasePrice) // Цены комплекта и комплектующих уже выравнены, или что-то пошло не так continue; elseif (!$changeSetPrice || $setCompTotalPrice > $kitSetPrice) // Пересчитать цены компонентов (округление выполняется классами модуля) foreach ($arBundleItems as $bundleItem) { $bundleItemNewPrice = $kitSetPrice * $bundleItem->getField('BASE_PRICE') / $setCompTotalBasePrice; $bundleItem->setFieldNoDemand('PRICE', $bundleItemNewPrice); } else // Переназначить цену комплекта в меньшую сторону с учетом изначальной скидки (округление выполняется классами модуля) { foreach ($arBundleItems as $bundleItem) { $bundleItemNewPrice = $bundleItem->getField('PRICE') * $kitSetDiscount; $bundleItem->setFieldNoDemand('PRICE', $bundleItemNewPrice); } $kitSetNewPrice = $setCompTotalPrice * $kitSetDiscount; $kitSetNewFields = array( 'PRICE' => $kitSetNewPrice, 'BASE_PRICE' => $setCompTotalPrice, 'DISCOUNT_PRICE' => $setCompTotalPrice - $kitSetNewPrice ); $basketItem->setFieldsNoDemand($kitSetNewFields); } } } function basketBeforeSavedHandler(Main\Event $event) { /** @var Basket $basket */ $basket = $event->getParameter("ENTITY"); self::recalcBasketKitSets($basket, true); return new Main\EventResult(Main\EventResult::SUCCESS); } function orderBeforeSavedHandler(Main\Event $event) { $order = $event->getParameter("ENTITY"); $basket = $order->getBasket(); self::recalcBasketKitSets($basket); return new Main\EventResult(Main\EventResult::SUCCESS); } } |