Я так понял, пока гуглил, что CUSTOM_PRICE очень "любим" многими за то, что ведёт себя как FINAL_PRICE (которого нет, но суть передаёт лучше). Знаю ситуации, когда такое поведение необходимо. Но так получилось, что чаще мне надо добавить кастомную цену на товар не отключая при этом последующие правила работы с корзиной. И вот я нашёл способ добавлять заранее известную наценку (так можно и понижать цену, но я только про наценку буду говорить) не используя CUSTOM_PRICE. Пропишу основные моменты.
Раз у меня все такие товары всё равно добавляются через кастомный ajax запрос, и наценка известна в момент добавления, то могу спокойно её передавать свойством товара в корзине.
$properties['PRICE_ADD'] = array(
'NAME' => 'Наценка',
'CODE' => 'PRICE_ADD',
'VALUE' => $request->getPost('price_add'),
'SORT' => 500
);
|
Просто в шаблоне корзины её не выводим для пользователя отдельно, раз она уже считается, тогда никого она смущать не будет.
Будем использовать кастомный
CatalogProvider (это слишком легко гуглится, чтобы дополнительно расписывать) и слегка дополним
getProductData.
/**
* @param array $products
*
* @return Sale\Result
*/
public function getProductData(array $products)
{
$result = parent::getProductData($products);
// Во избежании казусов при работе с командной строкой PHP
if(!Bitrix\Main\Context::getCurrent()->getSite())
return $result;
$basket = Sale\Basket::loadItemsForFUser(Sale\Fuser::getId(), Bitrix\Main\Context::getCurrent()->getSite());
$productDataList = array();
foreach($result->getData()['PRODUCT_DATA_LIST'] as $productId => $arProduct)
{
foreach($arProduct['PRICE_LIST'] as $basketItemId => &$arItem)
{
// При добавлении в корзину нет у товара ID, мы не сможем его свойства тут посмотреть
if((int)$basketItemId !== 0)
{
if($basketItem = $basket->getItemById($basketItemId))
{
$properties = $basketItem->getPropertyCollection()->getPropertyValues();
// Если есть наценка, добавляем её к цене
if(!empty($properties['PRICE_ADD']) && isset($properties['PRICE_ADD']['VALUE']))
{
$arItem['BASE_PRICE'] = $arItem['BASE_PRICE'] + (float)$properties['PRICE_ADD']['VALUE'];
$arItem['PRICE'] = $arItem['PRICE'] + (float)$properties['PRICE_ADD']['VALUE'];
}
}
}
}
$productDataList[$productId] = $arProduct;
unset($arItem);
}
$result->setData(['PRODUCT_DATA_LIST' => $productDataList]);
return $result;
}
|
Тут всё просто. При вызове обработчика, в корзине находятся товары со свойством наценки, их цена обновляется. Но если товар только добавили, он игнорируется (не достать его свойства пока что в этой функции, их вообще может ещё не быть у товара). На этом моменте компонент
bitrix:sale.basket.basket при загрузке страницы уже работает как надо. И если раньше (у вас на проекте) обновление количества товара в корзине происходило через
$item->setField('QUANTITY', $value); |
придётся его поменять на
$item->setFieldNoDemand('QUANTITY', $value); |
(у меня переделанный шаблон, скопированный ещё тогда, когда цена пересчитывалась при нажатии кнопки "Пересчитать", и ajax обновление количества ручками писанное)
К сожалению, у меня не получилось заставить компонент плавающей корзины
bitrix:sale.basket.basket.line обновлять цену при добавлении. Но если копировать его в своё пространство имён и наследовать, то в ajax.php перед вызовом компонента добавляем пересчёт корзины
// Не надо нам при удалении ничего пересчитывать здесь. Таков путь.
if(!$_POST['sbblRemoveItemFromCart'])
{
$basket = \Bitrix\Sale\Basket::loadItemsForFUser(\Bitrix\Sale\Fuser::getId(), SITE_ID);
$refreshStrategy = \Bitrix\Sale\Basket\RefreshFactory::create(\Bitrix\Sale\Basket\RefreshFactory::TYPE_FULL);
$result = $basket->refresh($refreshStrategy);
$basket->save();
}
|
И где-нибудь повыше модуль sale подключаем (чего стесняться в компоненте корзины, он всё равно там будет). В стандартном шаблоне SITE_ID задаётся выше, так что он определён. И у меня нельзя в плавающей корзине менять количество, только удалять. Не знаю, как себя поведёт при другом раскладе, но теоретически никаких проблем быть не должно.
Собственно всё. Теперь наша наценка - полноценная часть цены. Без всяких блокирующих скидки CUSTOM_PRICE'ов.
Единственное, что не делает этот способ совсем незаметным, так это вывод свойства наценки в заказе в админке менеджерам. Но лично я могу этим пренебречь.