Товары торговой позиции Drupal: изменить цену?
Мне нужно добавить в корзину некоторые позиции с пользовательской суммой.
Продукт торговли сохраняется с ценой = 0, а мой модуль вычисляет цену и добавляет позицию в корзину/заказ, но я не понимаю, как установить программную цену.
Я читал об использовании Правил, но мне нужен мой модуль, чтобы иметь возможность устанавливать/изменять цену без вызова правил.
Я попытался с помощью обертки объекта, я попытался изменить позицию, созданную с помощью commerce_product_line_item_new(), но ничего, когда позиция попадает в корзину, всегда имеет исходную цену продукта (в моем случае - 0).
Как программно изменить цену позиции?
Мой код выглядит так:
// For debugging, this function is called by hook_menu()
function mymodule_test($product_id)
{
global $user;
$user = user_load($user->uid);
$order = commerce_cart_order_load($user->uid);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$product = commerce_product_load($product_id);
$line_item = commerce_product_line_item_new(
$product,
1,
0,
array(
),
'cover'
);
$line_item_wrapper = entity_metadata_wrapper("commerce_line_item", $line_item);
$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
$line_item_wrapper->commerce_unit_price->value(),
'base_price',
array(
'amount' => 1234,
'currency_code' => 'EUR',
'data' => array(),
),
TRUE
);
$insert_line_item = commerce_cart_product_add($user->uid, $line_item_wrapper->value(), FALSE);
return 'done';
}
Странная вещь заключается в том, что я попытался адаптировать код commerce_line_item_unit_price_amount(), найденный в торговле /modules/line _item/commerce_line_item.rules.inc, но этот тест:
<?php
global $user;
$product = commerce_product_load(4); // my commerce product for test
$line_item = commerce_product_line_item_new(
$product,
1,
0,
array(
),
'cover' // I do have this line_items type
);
// manually set amount and component name
$amount = 1234;
$component_name = 'base_price'; // tryed with discount, nothing change
$wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$unit_price = commerce_price_wrapper_value($wrapper, 'commerce_unit_price', TRUE);
// Calculate the updated amount and create a price array representing the
// difference between it and the current amount.
$current_amount = $unit_price['amount'];
$updated_amount = commerce_round(COMMERCE_ROUND_HALF_UP, $amount);
$difference = array(
'amount' => $updated_amount - $current_amount,
'currency_code' => $unit_price['currency_code'],
'data' => array(),
);
// Set the amount of the unit price and add the difference as a component.
$wrapper->commerce_unit_price->amount = $updated_amount;
$wrapper->commerce_unit_price->data = commerce_price_component_add(
$wrapper->commerce_unit_price->value(),
$component_name,
$difference,
TRUE
);
$insert_line_item = commerce_cart_product_add($user->uid, $line_item, FALSE);
?>
все еще не удается, line_item попадает в корзину, но с исходной ценой упомянутого продукта.
Любая идея?
Ответы
Ответ 1
Для тех людей, которые не хотят использовать правила и надеются изменить цену напрямую. Вот мое решение:
// Alter the price in list and single product page.
function my_module_commerce_product_calculate_sell_price_line_item_alter($line_item){
$price = 100; //1 dollar
$line_item->commerce_unit_price[LANGUAGE_NONE]['0']['amount'] = $price;
}
// Alter the price in cart & order.
function my_module_commerce_cart_line_item_refresh($line_item, $order_wrapper){
$price = 100; //1 dollar
$line_item->commerce_unit_price[LANGUAGE_NONE]['0']['amount'] = $price;
// Alter the base_price component.
$line_item->commerce_unit_price[LANGUAGE_NONE]['0']['data']['components']['0']['price']['amount'] = $price;
}
Ответ 2
Если вы хотите игнорировать все предыдущие значения, сохраненные в позиции, и пересчитать сумму из вашей новой суммы, то функция, которую вы ищете, - commerce_line_item_rebase_unit_price.
Задайте новое значение суммы, а затем запустите свою позицию, сохраните позицию и порядок:
$line_item_wrapper->commerce_unit_price->amount = 13;
commerce_line_item_rebase_unit_price($line_item_wrapper->value());
commerce_line_item_save($line_item_wrapper->value());
Ответ 3
Я пробовал эту проблему весь день сегодня, и в итоге выяснил правильный путь к изменению цен на позиции. Проблема в том, что даже если вы успешно измените цену позиции на пользовательское значение, на следующей странице обновите корзину, reset позиции, соответствующие исходной цене продукта. Подробнее см. commerce_cart_order_refresh()
. Эта функция выполняется каждый раз, когда на странице загружается заказ/тележка, и вокруг нее нет способа.
Оказывается, что правильный способ изменить цену позиции - либо использовать Правила, либо реализовать функцию hook_commerce_cart_line_item_refresh()
. В любом случае, Drupal Commerce должна иметь возможность применять логику изменений каждый раз, когда загружается корзина/заказ.
В результате я создал настраиваемое поле в элементе позиции, где я сохранил желаемое значение цены, которое я хотел. Затем я использовал правило ценообразования, чтобы скопировать значение пользовательской цены в значение цены продукта, когда корзина обновляется.
Следующее сообщение в блоге было очень полезно в этом. В нем показано, как добавить настраиваемое поле в тип позиции и как настроить правило ценообразования для копирования пользовательской суммы в цену единицы.
http://commerceguys.com/blog/using-custom-line-items-provide-donation-feature-drupal-commerce
Ответ 4
Недавно мне пришлось внедрить форму для пожертвований в Commerce, но Commerce Express Checkout не обрабатывает персонализированные позиции. Поскольку это было пожертвование и все (кто пытается ввернуть дом?), Я счел уместным передать сумму пожертвования в качестве третьего параметра в URL-адресе, который предоставляет модуль Express Checkout. Вот как я начал взламывать модуль:
Я добавил новую запись на маршрутизатор:
$items['commerce-express-checkout/%/%/%'] = array(
'title' => 'Express Checkout w/ extra argument',
// 'page callback' => 'commerce_express_checkout_create_order',
'page callback' => 'commerce_express_checkout_create_order_extra',
'page arguments' => array(1, 2, 3),
'access arguments' => array('access checkout'),
'type' => MENU_CALLBACK,
);
Я продублировал и настраивал обратный вызов по умолчанию и привязывал к нему "_extra". Обратите внимание, что свойство "data" кажется статическим хранилищем переменных для случаев, подобных этому, и сохраняет срок действия позиции.
function commerce_express_checkout_create_order_extra($product_id, $token, $amount) {
if (drupal_hmac_base64($product_id, drupal_get_private_key().drupal_get_hash_salt()) == $token && is_numeric($amount)) {
global $user;
$product = commerce_product_load($product_id);
$product->commerce_price['und'][0]['amount'] = (int)$amount;
$order = ($user->uid) ? commerce_order_new($user->uid, 'checkout_checkout') : commerce_cart_order_new();
commerce_order_save($order);
$price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $amount), 'currency_code' => commerce_default_currency());
$line_item = commerce_product_line_item_new($product, 1, $order->order_id);
$line_item->data = array('und' => array('0' => $price));
commerce_line_item_save($line_item);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$order_wrapper->commerce_line_items[] = $line_item;
$order->data['type'] = 'commerce_express_checkout_order';
commerce_order_save($order);
drupal_goto('checkout/' . $order->order_id);
return "";
}
return "";
}
Вот часть, которая оказалась самой сложной из-за кривой обучения и не зная, какую функцию heck использовать:
/**
* Implements hook_commerce_cart_line_item_refresh().
*/
function commerce_express_checkout_commerce_cart_line_item_refresh($line_item, $order_wrapper) {
if ($line_item->commerce_product['und'][0]['line_item_label'] == 'DONATE' || $line_item->commerce_product['und'][0]['product_id'] == '11') {
$price = array('amount' => commerce_round(COMMERCE_ROUND_HALF_UP, $line_item->data['und'][0]['amount']), 'currency_code' => commerce_default_currency());
$line_item->commerce_unit_price = array('und' => array('0' => $price));
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$line_item_wrapper->commerce_unit_price->data = commerce_price_component_add(
$line_item_wrapper->commerce_unit_price->value(), 'base_price', $price, TRUE
);
}
}
Каждый раз, когда тележка модифицируется, она обновляется и пытается установить продукты в тележке на их прототип внутри кода. Мне тоже кажется неэффективным, но я мог что-то упустить.
Ответ 5
Этот пост указал мне в правильном направлении для программного изменения позиции для торговли в Drupal, используя hook_commerce_cart_line_item_refersh()
. Однако некоторые из ответов здесь либо совершенно ошибочны, либо очень неэффективны и неаккуратные.
Это было бы правильным рабочим решением для изменения типа позиции в Drupal Commerce:
/*
* implements hook_commerce_cart_line_item_refresh()
*
*/
function MYMODULE_commerce_cart_line_item_refresh($line_item, $order_wrapper){
$line_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$new_price = 100; //I use a function to calculate the value of $new_price
if(!empty($new_price)){
$line_wrapper->commerce_unit_price->amount->set($new_price);
$line_wrapper->save();
}
}