Скидка на отдельную позицию в корзине - правила, купоны, своя цена
Даём скидку на одну позицию корзины и разбираемся, почему своя цена не держится после пересчёта.
Решение
Смотрим, что вообще применилось к позиции:
foreach ($basket as $item) { printf("%-30s цена %8.2f базовая %8.2f своя=%s\n", $item->getField('NAME'), $item->getPrice(), // с учётом скидок $item->getBasePrice(), // без учёта скидок $item->isCustomPrice() ? 'да' : 'нет'); // своя цена означает, что правила корзины эту позицию не трогают}Расхождение между ценой и базовой ценой и есть применённая скидка. Если они равны, ни одно правило корзины на эту позицию не сработало, и дальше смотреть надо условия правил, а не саму позицию.
Ставим свою цену на позицию:
$item->setFields([ 'PRICE' => 800, 'CUSTOM_PRICE' => 'Y', // без флага пересчёт вернёт цену каталога]);$basket->save();Флаг ручной стоимости - единственное, что удерживает цену при пересчёте. Без него ближайший вызов пересчёта корзины вернёт цену из каталога и молча затрёт поставленную.
Считаем скидки по составу корзины:
$order->doFinalAction(true); // применяет правила корзины и купоны$discount = $order->getDiscount();print_r($discount->getApplyResult()); // какие правила сработали и на чтоМетод getApplyResult показывает список сработавших правил по каждой позиции.
Это главный инструмент разбора: он отвечает на вопрос «почему скидки нет»
точнее, чем сравнение цен.
Правила считаются на каждом пересчёте корзины, а пересчёт случается чаще, чем кажется: на добавлении товара, на смене количества, на выборе доставки. Поэтому условия правил держат простыми, а тяжёлые проверки по базе в них не выносят.
Порядок применения задаётся приоритетом правила, и при равном приоритете он не определён. Два правила на одну позицию с одинаковым весом дают разный результат от пересчёта к пересчёту, и такие пары разводят приоритетами сразу.
Применяем купон к текущей корзине:
Bitrix\Sale\DiscountCouponsManager::init();$applied = Bitrix\Sale\DiscountCouponsManager::add($couponCode);echo $applied ? "купон принят\n" : "купон отклонён\n";Купон сам по себе скидки не даёт: он включает привязанное к нему правило. Без активного правила метод вернёт успех, а цена не изменится.
Проверяем скидку по позиции после пересчёта:
$order->doFinalAction(true);foreach ($order->getBasket() as $item) { $discount = $item->getBasePrice() - $item->getPrice(); printf("%-28s скидка %7.2f купон=%s\n", $item->getField('NAME'), $discount, $item->getField('DISCOUNT_NAME') ?: 'нет');}Поле DISCOUNT_NAME называет правило, давшее скидку именно этой позиции. Пустое
поле при ненулевой разнице цен означает скидку каталога, а не правило корзины -
это разные механизмы, и искать их надо в разных местах админки.
Типичные проблемы
Поставленная цена позиции возвращается к прежней.
Не выставлен флаг CUSTOM_PRICE. Любой пересчёт корзины берёт цену из каталога, если позиция не помечена как заданная вручную.
Купон принят, а скидки нет.
Правило, к которому привязан купон, отключено либо его условия не выполняются на текущем составе корзины. Купон только включает правило, а не заменяет его.
Скидка применилась ко всей корзине вместо одной позиции.
В правиле выбрано действие на заказ, а не на позицию. Действия «на товар» и «на заказ» дают разный результат при одинаковом условии.
Скидка в карточке товара не совпадает со скидкой в корзине.
Карточка показывает скидки каталога, корзина - правила корзины. Это два разных механизма, и совпадать они не обязаны.
Частые вопросы
Как сделать наценку на группу товаров?
Правилом корзины с отрицательной скидкой либо отдельным типом цены для нужной группы покупателей. Второй способ предпочтительнее: цена хранится в каталоге, а не вычисляется на каждом пересчёте.
Можно ли дать скидку при комбинации товаров?
Да, условием правила по составу корзины: правило проверяет наличие обоих товаров и применяет действие. Такие правила считаются на каждом пересчёте, поэтому их держат немного.
Почему цену нельзя просто записать в базу?
При работающем обмене её перепишет ближайший сеанс: 1С считает себя источником цен. Своя цена живёт либо в правиле корзины, либо в отдельном типе цены, который обмен не трогает.
Как узнать, какое правило дало скидку?
Методом getApplyResult у объекта скидки заказа после doFinalAction. Он возвращает результат по каждой позиции с идентификаторами сработавших правил.
Смежное
- Цены, скидки и купоны - оглавление подтемы
- Цена на витрине не та: разбор причин - разбор расхождения витрины и корзины
- Каталог: продвинутое - скидки каталога и комплекты
- Каталог и продажи - корзина и заказ
- Правила работы с корзиной: условия, порядок, отладка - механизм скидок целиком
- НДС в каталоге и заказах: ставки, цена с налогом и доставка - как налог считается после скидки
- Купоны: типы, выпуск пачкой, применение и проверка - разбор купонов целиком