This took a while to pinpoint but the problem lies in commerce_cart_order_refresh();

Take the following simple rule

{ "rules_change_line_item_price" : {
    "LABEL" : "Change line Item price",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "commerce_line_item", "rules", "commerce_cart" ],
    "ON" : [ "commerce_cart_product_add" ],
    "DO" : [
      { "commerce_line_item_unit_price_subtract" : {
          "commerce_line_item" : [ "commerce_line_item" ],
          "amount" : "40000",
          "component_name" : "discount",
          "round_mode" : "1"
        }
      },
      { "entity_save" : { "data" : [ "commerce-line-item" ], "immediate" : 1 } },
      { "entity_save" : { "data" : [ "commerce-line-item:order" ], "immediate" : 1 } }
    ]
  }
}

It does the following when adding a product added to the cart

  • Removes $400 from the product cart
  • Invoked Entity Save on the "line_item"
  • Invoked Entity Save on the "order"

I've verified this in the database, and the prices are saved correctly.

The problems is when the cart is refreshed and the commerce_cart_order_refresh() gets called.
The way the line_item is refreshed is Commerce re-creates the line item by creating a new line item by simulating an "adding to cart", and replacing the newly created line with a new one. Discarding all the rules changes made to the original line_item.

This effectively wipes out all the changes done to the pricing of the line item via rules when it was previously added to the cart!

Comments

rszrama’s picture

Category: bug » support
Status: Active » Closed (works as designed)

This is the way the system was designed; every time a shopping cart order is loaded, its product prices are recalculated from scratch. This means instead of altering the price on the product add event, you should be doing it on the "Calculating the sell price of a product" event. If you only know the price at the point of the add to cart, then the solution is to add a price field to your line item type that can hold the unique price for that customer and then add a sell price calculation rule that swaps the value of that field in for the unit price. If I'm not mistaken, there should be a video at http://vimeo.com/channels/commerceguys that demonstrates this using donations as an example (though in the case of donations it isn't a hidden price field but a customer editable price field on the add to cart form).

yfreeman’s picture

Thanks Ryan,
Perhaps there should be an event called "On line item refresh/recalculate" to intercept the process. The problem with "Calculating the sell price of a product" event is the the "line_item" is not yet in scope b/c it hasn't been created for Rules to play with.

yfreeman’s picture

Title: Cloning line_item mechanism when refreshing card removes all "Commerce Line Item" action rules » Cloning line_item mechanism when refreshing cart removes all "Commerce Line Item" action rules
rszrama’s picture

It hasn't been saved yet, but it has been created and will eventually be saved as the line item added to the cart. You can follow the progress of this line item object in the function commerce_cart_add_to_cart_form_submit() in commerce_cart.module. Hope that helps.