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

19.11.2014

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

/**
 * Calculate line item price.
 */
function MODULENAME_calculate_line_item_price($line_item) {
  $line_item_wrap = entity_metadata_wrapper('commerce_line_item', $line_item);

  // Discount
  if (date('d.m') == '31.12') {
    $line_item_unit_price = commerce_price_wrapper_value($line_item_wrap, 'commerce_unit_price', TRUE);
    $discount = array('amount' => 50000, 'currency_code' => 'RUB');
    $discount['amount'] = commerce_currency_convert($discount['amount'], $discount['currency_code'], $line_item_unit_price['currency_code']);
    $discount['currency_code'] = $line_item_unit_price['currency_code'];

    module_load_include('rules.inc', 'commerce_line_item');
    commerce_line_item_unit_price_add($line_item, $discount['amount'] * -1, '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_calculate_line_item_price($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_calculate_line_item_price($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). Так же у 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
Похожие записи

Комментарии

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

Спасибо, все работает, но почему-то этот компонент цены добавляется в долларах (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(). Мне дальше лень копать :)

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

Гость
30.11.2016, 14:21

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

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

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

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

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

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

Гость
30.11.2016, 14:30

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

Гость
30.11.2016, 14:32

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

Евгений
29.12.2016, 13:55

Добрый день, а функция commerce_line_item_unit_price_add входит в состав какого-то модуля?

Евгений
29.12.2016, 14:01

Просто у меня почему то вываливается ошибка:
PHP Fatal error: Call to undefined function commerce_line_item_unit_price_add()

Гость
24.05.2017, 11:14

А как сделать, чтобы в Order total шла сумма уже с наценкой?

Добавляйте цену в base_price, а не в discount

Гость
24.05.2017, 12:04

О, спасибо огромное. Ваш блог бесценен.

Добавить комментарий