Модуль 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, и присутствуют все пользовательские поля).
Комментарии
Спасибо, помогло.
До чего полезный блог!
Спасибо, все работает, но почему-то этот компонент цены добавляется в долларах (500 USD), хотя передаю 'RUB'. Что тут может быть?
Тут показана реализация скидки для цены одного товара, а как, таким же образом, применить скидку для суммы всех товаров и суммы товаров одного типа?
http://xandeadx.ru/blog/drupal/691
Вау, спасибо за быстрый ответ, но есть ли возможность выполнить это в коде, без необходимости править 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
ОК, спасибо за оперативность, будем попробовать.
Добрый день, а функция commerce_line_item_unit_price_add входит в состав какого-то модуля?
нет
Просто у меня почему то вываливается ошибка:
PHP Fatal error: Call to undefined function commerce_line_item_unit_price_add()
А как сделать, чтобы в Order total шла сумма уже с наценкой?
Добавляйте цену в base_price, а не в discount
О, спасибо огромное. Ваш блог бесценен.
Добавить комментарий