fivestar - Elementos de línea de Drupal Commerce: ¿modificar el precio?
drupal 8 voting api (5)
Luché con este tema todo el día y finalmente descubrí el camino correcto para modificar los precios de las líneas de pedido. El problema es que, incluso si cambia correctamente el precio de la línea de pedido por un valor personalizado, en la próxima página de actualización, el carrito restablecerá las líneas de pedido para que coincidan con el precio del producto original. Eche un vistazo a la función commerce_cart_order_refresh()
para más detalles. Esta función se ejecuta cada vez que se carga un pedido / carrito en la página y no hay forma de evitarlo.
Resulta que la forma correcta de modificar el precio de una línea de pedido es usar Reglas o implementar la función hook_commerce_cart_line_item_refresh()
. De cualquier forma, Drupal Commerce necesita poder aplicar la lógica de alteración cada vez que se carga el carro / orden.
Terminé creando un campo personalizado en el elemento de línea donde almacené el valor de precio personalizado que quería. Luego utilicé una Regla de fijación de precios para copiar el valor del precio personalizado al valor del precio del producto cada vez que se actualiza el carrito.
La siguiente publicación de blog fue muy útil para resolver esto. Le muestra cómo agregar un campo personalizado a un tipo de línea de pedido y cómo configurar una regla de fijación de precios para copiar el importe personalizado al precio unitario.
http://commerceguys.com/blog/using-custom-line-items-provide-donation-feature-drupal-commerce
Tengo que agregar a mi carrito algunas líneas de pedido con una cantidad personalizada. El producto de comercio se guarda con price = 0, y mi módulo calcula el precio y agrega la línea de pedido al carro / pedido, pero no entiendo cómo establecer programáticamente el precio.
He leído sobre el uso de Reglas, pero necesito que mi módulo pueda establecer / modificar el precio, sin invocar reglas .
He intentado con un contenedor de entidades, intenté modificar la línea de pedido creada con commerce_product_line_item_new (), pero nada, cuando la línea de pedido entra en el carro siempre tiene el precio del producto original (en mi caso, 0).
¿Cómo modificar el precio de una línea de pedido programáticamente?
Mi código hasta ahora se ve así:
// 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'';
}
Lo extraño es que intenté adaptar el código de commerce_line_item_unit_price_amount () que se encuentra en commerce / modules / line_item / commerce_line_item.rules.inc, pero esta prueba:
<?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);
?>
aún fallan, el elemento de línea entra en el carro pero con el precio original del producto al que se hace referencia.
¿Alguna idea?
Recientemente tuve que implementar un formulario de donación en Commerce, pero el módulo de Commerce Express Checkout no maneja las líneas de pedido personalizadas. Dado que se trataba de una donación y de todos (¿quién está intentando arruinar la casa?), Sentí que era apropiado pasar el importe de la donación como un tercer parámetro en la URL que proporciona el módulo Express Checkout. Así es como hice piratería del módulo:
Agregué una nueva entrada al enrutador:
$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,
);
Dupliqué y pellizqué la devolución de llamada predeterminada y le añadí ''_extra''. Tenga en cuenta que la propiedad "datos" parece ser un almacén de variables estáticas para ocasiones como esta y persiste la vida útil de la línea de pedido.
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 "";
}
Aquí está la parte que terminó siendo más difícil simplemente debido a la curva de aprendizaje y sin saber qué función usar:
/**
* 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
);
}
}
Cada vez que se modifica el carrito, se actualiza e intenta establecer los productos en el carro a su prototipo dentro del código. A mí también me parece bastante ineficiente, pero me podría estar perdiendo algo.
Si desea ignorar los valores anteriores que se han guardado en una línea de pedido y volver a calcular el total de su nuevo importe, la función que está buscando es commerce_line_item_rebase_unit_price.
Establezca el nuevo valor de cantidad y luego ejecute su línea de pedido hasta allí, guarde la línea de pedido y el pedido:
$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());
Esta publicación me indicó la dirección correcta para modificar programáticamente una línea de pedido de comercio hook_commerce_cart_line_item_refersh()
utilizando hook_commerce_cart_line_item_refersh()
. Sin embargo, algunas de las respuestas aquí son francamente incorrectas, o muy ineficaces y descuidadas.
Esta sería una solución de trabajo correcta para modificar el tipo de línea de pedido en 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();
}
}
Para aquellas personas que no quieren usar reglas y esperan alterar el precio directamente. Aquí está mi solución:
// 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;
}