Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drupal Commerce Line Items: alter the price?

I have to add to my cart some line items with a custom amount. The commerce product is saved with price = 0, and my module compute the price and add the line item to the cart/order, but i dont understand how to set programmatically the price.

I've read about using Rules, but I need my module to be able to set/alter the price, without invoking rules.

I've tryed with an entity wrapper, i tryed to alter the line item created with commerce_product_line_item_new(), but nothing, when the line item gets into the cart always has the original product price (in my case, 0).

How to alter a line item price programmatically?

My code so far looks like:

// 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';
}

The strange thing, is that I tryed to adapt the code of commerce_line_item_unit_price_amount() found in commerce/modules/line_item/commerce_line_item.rules.inc, but this test:

<?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);
?>

still fail, the line_item get into the cart but with the original price of the referenced product.

Any idea?

like image 818
Strae Avatar asked Nov 21 '12 11:11

Strae


2 Answers

I struggled through this issue all day today and final figured out the correct path to altering line items prices. The problem is that, even if you successfully change the line item price to a custom value, on the next page refresh the cart will reset the line items to match the original product price. Take a look at the commerce_cart_order_refresh() function for details. This function is executed every time an order/cart is loaded on the page and there is no way around it.

It turns out that the proper way to alter a line item price is to either use Rules or to implement the hook_commerce_cart_line_item_refresh() function. Either way, Drupal Commerce need to be able to apply the alteration logic each time the cart/order is loaded.

I ended up creating a custom field in the Line Item where I stored the custom price value I wanted. I then used a Pricing Rule to copy the custom price value to the product price value whenever the cart is refreshed.

The following blog post was very helpful in figuring this out. It shows you how to add a custom field to a line item type and how to setup a pricing rule to copy the custom amount to the unit price.

http://commerceguys.com/blog/using-custom-line-items-provide-donation-feature-drupal-commerce

like image 63
Nathan Rambeck Avatar answered Oct 21 '22 18:10

Nathan Rambeck


For those people who don't want to use rules and hope to alter the price directly. Here is my solution:

// 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;

}
like image 40
Tim Yao Avatar answered Oct 21 '22 18:10

Tim Yao