xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Программно добавить скидку или наценку на товар в Commerce

Опубликовано в

Модуль Product Pricing UI входящий в состав Commerce позволяет из админки настраивать правила ценообразования товара. Однако ничто не мешает сделать это из кода. Пример добавления скидки в 500 р. действующей только 31 декабря:

/**
 * Apply discount.
 */
function MODULENAME_apply_discount($line_item) {
  if (date('d.m') == '31.12') {
    module_load_include('rules.inc', 'commerce_line_item');
    $discount_decimal = 500;
    $discount_amount = commerce_currency_decimal_to_amount($discount_decimal, 'RUB') * -1;
    commerce_line_item_unit_price_add($line_item, $discount_amount, 'discount', COMMERCE_ROUND_HALF_UP);
  }
}
/**
 * Implements hook_commerce_product_calculate_sell_price_line_item_alter().
 */
function MODULENAME_commerce_product_calculate_sell_price_line_item_alter($line_item) {
  MODULENAME_apply_discount($line_item);
}
 
/**
 * Implements hook_commerce_cart_line_item_refresh().
 */
function MODULENAME_commerce_cart_line_item_refresh($line_item, $order_wrapper) {
  if (in_array($line_item->type, commerce_product_line_item_types())) {
    MODULENAME_apply_discount($line_item);
  }
}

Комментарии:

В программном способе нужно изменять цену в двух местах — в hook_commerce_product_calculate_sell_price_line_item_alter() и в hook_commerce_cart_line_item_refresh(), потому что первый хук вызывается только при выводе цены товара и добавлении товара в корзину, а второй только при пересчёте цены line item-а в корзине.

В hook_commerce_product_calculate_sell_price_line_item_alter() передаётся "виртуальный" line item (его нет в базе и у него нет line_item_id).

В hook_commerce_product_calculate_sell_price_line_item_alter() у line item-a нет полей, которые пользователь может выбрать в форме добавления товара в корзину, хотя в соответствующем рулсе эти поля уже будут. Если вам нужно высчитывать цену на основе этих полей, то можно после добавления товара в корзину делать принудительный commerce_cart_order_refresh($order), который вызовет hook_commerce_cart_line_item_refresh().

В hook_commerce_cart_line_item_refresh() передаётся реальный line item (он есть в базе, у него есть line_item_id, и присутствуют все пользовательские поля).

Программно добавить скидку к заказу.

Написанное актуально для Commerce 1
Похожие записи

Комментарии RSS

Спасибо, помогло.
До чего полезный блог!

Спасибо, все работает, но почему-то этот компонент цены добавляется в долларах (500 USD), хотя передаю 'RUB'. Что тут может быть?

Тут показана реализация скидки для цены одного товара, а как, таким же образом, применить скидку для суммы всех товаров и суммы товаров одного типа?

Вау, спасибо за быстрый ответ, но есть ли возможность выполнить это в коде, без необходимости править rules?
Кроме того, если честно, то даже с помощью fee не понятно как применить скидку к сумме товаров одного типа.

Точнее даже не товаров одного типа, а просто одного товара. В смысле применять скидку (amount * quantity) - discount, а не (amount - discount) * quantity как в Вашем примере.

Извиняюсь за сумбур, надеюсь внятно изложил суть.

Если скидка в процентах, то без разницы из чего её вычитать - из цены товара или из цены товара с учётом колчества.
Если скидка фиксирована, то дЕлите её на число товаров и вычитаете из стоимости товара получившееся число.
Число товаров лежит в $line_item->quantity

ещё можно добавить скидку прямо в $line_item->commerce_total.
смотрите код функции commerce_line_item_unit_price_add()

Так и делаю, но не всегда получается поделить без остатка, соответственно и цена выходит несколько неточной. Поэтому и ищу другой метод.
А как можно в коде менять общую сумму заказа? Через commerce_cart_line_item_refresh можно менять цену только для commerce_unit_price, неужели только через rules?

В том то и проблема, что $line_item->commerce_total изменить не получается, точнее изменить его можно, но все равно идет пересчет который игнорирует изменение.

попробуйте изменять commerce_total только в hook_commerce_cart_line_item_refresh (т.е. уже после добавления line item-а в базу), а после добавления товара в корзину принудительно вызывайте commerce_cart_order_refresh($order)

Хотя навряд ли поможет. Вообщем вам надо изменять commere_total после вызова line_item_save(). Мне дальше лень копать :)

Да, не помогло.
Жаль, что лень, но спасибо за попытку. Если все таки будет желание то отпишитесь, потому что я, если честно, без понятия как это реализовать, совсем уже отчаялся.

А есть ли возможность делать скидку от количества по каждому товару отдельно? Гуглю уже третий день, все модули что нашел либо не решают проблему, либо не поддерживаются.

Суть примерно такая: посетитель добавляет в корзину товары и, в зависимости от количества каждого товара к каждому товару отдельно применяется скидка.

Товар 1 - 100р. за шт. - 1шт. - скидка не применяется. Сумма - 100р.
Товар 2 - 200р. за шт. - 10 шт. - скидка 10%. Сумма - 1800р.
Товар 2 - 300р. за шт. - 20 шт. - скидка 20%. Сумма - 4800р.
Итого: 100р+1800р+4800р = 6700р.

Как-то так. В том же опенкарте подобный функционал из коробки. В Drupal Commerce такого не нашел - только скидка по всему заказу. Drupal 7, естественно.

Были ли такие кейсы? куда копать?

Код как раз показывает скидку на товар, а не на заказ.

Этот код основывается на дате как условии, а как сделать скидку именно от количества, причем количества конкретной позиции, а не количества всех позиций в заказе (в ванильных модулях только так)?

$line_item->quantity

ОК, спасибо за оперативность, будем попробовать.

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании