| Project: | Drupal Commerce |
| Version: | 7.x-1.x-dev |
| Component: | Rules integration |
| Category: | feature request |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | closed (won't fix) |
Issue Summary
Due to the shortcoming with the 'Add a product to the cart' action described in #1385818: Ability to specify line item type when adding product to cart using Rules, I'm trying to add a line item to an ordrer through Rules by creating a Line item entity, and then adding this line item entity to the order.
I can create the line item entity without issue, and then I'm using the 'Add item to a list' action to add the newly created and saved entity to site:current-cart-order:commerce-line-items. The rules debuging reports that everything was completed successfully, but no association is made from the order to this line item - no entry is created in field_data_commerce_line_items.
My rule and problem is almost identical to the one described in http://drupal.org/node/1017462#comment-5009590
Comments
#1
When you create your line item, are you forcing an immediate save before trying to add it to the list? If not, there may not be a line item ID to do that.
#2
> When you create your line item, are you forcing an immediate save before trying to add it to the list? If not, there may not be a line item ID to do that.
Yes - I have tried forcing the line item to save before adding it to the list. In fact, without doing that, I get fatal errors. I also tried force saving the order after adding the line item to its list field.
#3
I figured I would try calling commerce_cart_product_add() directly from a PHP Rules action at the end of the Rul, after force saving the newly create line item, and the order and I can't get it work from there. Where as running the following at /devel/php just after running the rule works just fine (note: 238 is the ID of the line item that got created after running the rule.
<?phpglobal $user;
$line_item = commerce_line_item_load(238);
commerce_cart_product_add($user->uid, $line_item, TRUE);
?>
So, how is it that executing this manually just after the rule execution works, but executing it as part of the Rules action chain does not (even after force saving the line item?
#4
Because Rules just aren't as good as straight PHP when you know what you're doing? : )
Theoretically, what you're trying should be possible. I just haven't bothered trying because of my (obvious) preference for a quick bit of code. If you know PHP, is there some other constraint keeping you from enshrining this functionality in code or perhaps creating a custom action for it? Also, this may just be a general Rules issue. I don't know what would be different inside Commerce to make this work / not work.
#5
I'm trying to keep everything in Rules where possible, as it makes it simpler for others to see whats going on and make alterations if need be. It is also nice to keep all of the business logic together in Rules where possible. The php snippet was purely for testing purposes - If I had to use a bit of php like that to make this wqork I would probably just do it in a custom module somewhere.
However, that PHP should ne be needed. It should be enough to create a line item entity, save it, and then add it to the list item on the order entity. Somewhere along the lines the data in the order is getting overritten with data from an earlier state.
My problem looks incredibly similar to #1377872: Change the line item quantity update handler to queue changes instead of sequentially evaluating them
#6
Note: If I use the 'After adding a product to the cart' action instead then the rule works fine. Using 'After saving a new commerce line item' or 'After updating an existing commerce line item' does not work.
#7
Are you trying to add product whose line item type is not "product"?
#8
Hi,
Since this is what I needed, here is a patch that adds a Rules action "Add a line item to the cart".
Testing it seems ok - creating a line item entity, set some data in it in some fields, and then add it to cart.
Ryan, do you think this feature can be added ? Any reason why not ?
Comments are welcome,
Regards,
Shushu
#9
#10
It seems the real issue here is that the order that's being edited via Rules gets out of sync with the order that has been loaded in commerce_cart_product_add(). See for example this code:
<?php
// If no matching line item was found...
if (empty($matching_line_item)) {
// Save the incoming line item now so we get its ID.
commerce_line_item_save($line_item);
// Add it to the order's line item reference value.
$order_wrapper->commerce_line_items[] = $line_item;
}
?>
The event "After saving a new commerce line item" is invoked when the line item is saved, and the rule to create an additional line item for the same order is executed, updating what appears to be a separate copy of the order object than the one in memory in the function. Then after the line item save, the original added line item is added to a copy of the order that does not have the extra line item already in it. This new value for the commerce_line_items field that only has the original added line item is what gets finally saved for the order, even though Rules may have created the additional line item successfully.
I'm not sure there's much we can do about this. My recommendation would likely just be to use code (see my earliest comments in this thread) or else to use a different event. The reason the event "After adding a product to the cart" works as suggested in #6 is that by the time that event is invoked, the originally added line item and the order have been saved, and it's those freshly saved variables that get passed through to Rules at the bottom of commerce_cart_product_add():
<?php// Invoke the product add event with the newly saved or updated line item.
rules_invoke_all('commerce_cart_product_add', $order, $product, $quantity, $line_item);
?>
Regarding shushu's patch, I still don't see this solving the problem of different copies of the order, but more importantly, we already have an action to add a product to an order. I don't think we should add a second one that works on a complete line item. You could just use the existing one and then update the line item after the fact as well, because the action uses Rules' "provides" functionality to make the newly created line item available in the rule.
So at the end of this thread, all I can really think to do is just close this as "won't fix" in favor of these other recommendations. I'm acknowledging there's a problem here, but the issue appears to be out of our control due to how Rules is accessing the referenced order through the Entity API. With viable alternatives in place, I don't consider it worth spending a significant amount of time tracking down at this point in time.
#11
@Ryan, please re-consider my patch.
You can review the details of the task I was working on here in order to understand why I needed it (create a line item and only then add it to the order, and not vice verse).
In fewer words - the existing Rules action works only with "standard" line item. I need to use my "own" line item type, which has a node reference as well, and AFAIK it can't be done with existing action.
Thanks,
Shushu
#12
Hmm, I still don't see this as being necessary. Either you can do the entire operation through code or, if necessary, you could create the line item via Rules (that's what you're doing, right?) and then just use Rules to add it to the order without the need for an additional action. You have access to the current user's cart order ID in the site:current-cart-order:order-id variable that you can use to set the line item's order_id. You can also add items to the cart's commerce_line_items field.
Adding another action for this would seem to just introduce confusion for something we tried to keep intentionally simple, while with the current level of integration I'm under the impression you can still accomplish what you want to do.