Hi!

Right now DrupalCommerce exposes a "Remove all products from an order" action. However it would be nice to also remove just a single item from the cart. In my situation I want to create a rule that looks for two mutually exclusive products and removes one of them from the cart. I've tried doing this with the "Remove an item from a list" action, but that doesn't seem to work. Or maybe I'm just doing it wrong. Let me know.

Thanks!
Ben

Comments

rszrama’s picture

Category: feature » support
Status: Active » Fixed

If you find and delete the line item, it should work just fine. You can do this with the "Delete entity" action. You could also just unset the price of the line item you want deleted during "Calculating the sell price of a product." That's what the "Unset the price of disabled products in the cart" default rule does, so you can refer to it for an example. Unsetting the price just involves setting the amount to NULL (i.e. no value, not 0).

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

skyredwang’s picture

Status: Closed (fixed) » Active

Could someone provide the documentation on how to use "Delete entity" action to delete a product by SKU number (This is the method used for "Add a product to the cart")

skyredwang’s picture

Category: support » feature

After talking to @rszrama, this could be a feature request. Whoever needs this soon enough will write the patch.

ressa’s picture

Thanks @rszrama, I have been trying a lot of ways to remove a single line item, among others with 'Execute Custom PHP code' and commerce_line_item_delete(), but ran into the dreaded EntityMetadataWrapperException - error.

I had actually visited this page some time ago, and tried to set the price to NULL, in stead of just leaving the field empty. I should have read that passage more carefully!

For those trying to remove a line item by entering an empty field, and setting the price to NULL, you do it under 'Add action' -> 'Data' -> 'Set a data value'. Under Data Selector, enter 'commerce-line-item:commerce-unit-price:amount' ... and just leave the 'Value' field empty, don't actually type "NULL" :-)

rszrama’s picture

Oooooh, I can see how that would be confusing. Thanks for letting us know about your trouble; I'll pass it on to joshmiller to make sure we document this process.

joshmiller’s picture

ressa / rszrama,

Message received, but let me further define the problem that we are trying to document:

In terms of a customer's shopping cart, we are trying to delete one item using Rules.

Failed Attempt: You can do this with the "Delete entity" action. You could also just unset the price of the line item you want deleted during "Calculating the sell price of a product." That's what the "Unset the price of disabled products in the cart" default rule does, so you can refer to it for an example. Unsetting the price just involves setting the amount to NULL (i.e. no value, not 0).

Reason for Failure: Not clear that setting the amount to NULL meant literally "nothing"

Way to avoid Failure: For those trying to remove a line item by entering an empty field, and setting the price to NULL, you do it under 'Add action' -> 'Data' -> 'Set a data value'. Under Data Selector, enter 'commerce-line-item:commerce-unit-price:amount' ... and just leave the 'Value' field empty, don't actually type "NULL" :-)

Ryan - I'm thinking this documentation goes under Shopping Cart, Modifying Line Items using Rules. Please correct me if you have the chance.

rszrama’s picture

Hmm, it really sits between the shopping cart refresh and product sell price calculation. In the context of the cart, it will result in a product being removed from the cart. In the context of sell price calculation on a product display, it will result in the "Add to Cart" button being disabled.

And now that I think about it - I wonder if we shouldn't add an action to set the unit price amount to NULL. That would help mitigate the confusing nature of the task.

ressa’s picture

Thanks guys, for all your hard work on Commerce!

EDIT: The project was cancelled, so the below is not relevant any longer.

I have an extra question, which might be due to a shipping line item not being removed in a timely manner, but perhaps you have some insight in how to resolve it, perhaps by doing some clean up in the order via Rules?

I am using a rule to add one subscription for each product in the cart during checkout, and a second rule to remove all subscriptions, if the customer navigates away from the checkout pages. It works fine if you go to another page, like the front page, from both 'checkout/1' and 'checkout/1/shipping' -- the subscriptions are removed from the cart.

But I get this error if I navigate from the last page ('checkout/1/review'), where a shipping line item has been added, to the front:

Fatal error: __clone method called on non-object in /var/www/ck_test_rules/profiles/commerce_kickstart/modules/commerce/modules/cart/commerce_cart.module on line 791

To reproduce the error:
Install a fresh Commerce Kickstart, and enable the 'PHP filter' module. Install Shipping module 7.x-2.0-beta1, modules: commerce_shipping_example, commerce_shipping_ui, commerce_shipping.

Add a new product:
Product SKU: SUB-100
Title: Subscription
Price: 60
...and 'Save product'.

Now import these two rules:

1. Add one subscription to each product at checkout

{ "rules_add_subscriptions_to_products" : {
    "LABEL" : "Add one subscription to each product at checkout",
    "PLUGIN" : "reaction rule",
    "WEIGHT" : "2",
    "REQUIRES" : [ "rules", "php", "commerce_product_reference" ],
    "ON" : [ "commerce_product_calculate_sell_price" ],
    "IF" : [
      { "php_eval" : { "code" : "global $user;\r\n$order = commerce_cart_order_load($user-\u003Euid);\r\nif ($order) {\r\n\/\/ How many subscriptions are there in the order?\r\n$quantity_subscriptions = intval(db_query(\u0027SELECT SUM(quantity) FROM commerce_line_item WHERE commerce_line_item.line_item_label = \\\u0027SUB-100\\\u0027 AND commerce_line_item.type = \\\u0027product\\\u0027 AND commerce_line_item.order_id = :order_id\u0027, array(\u0027:order_id\u0027 =\u003E $order-\u003Eorder_id))-\u003EfetchField());\r\n\r\n\/\/ only need to run if there are products (type=\u0027product\u0027) in the order and no subscriptions yet\r\nif ((arg(0) == \u0027checkout\u0027) \u0026\u0026 (\u0027[commerce-line-item:type]\u0027 == \u0022product\u0022) \u0026\u0026 ($quantity_subscriptions == 0)) {\r\n  return TRUE;\r\n  } else {\r\n  return FALSE;\r\n}\r\n}" } }
    ],
    "DO" : [
      { "drupal_message" : { "message" : "ARG (0) == checkout\r\n[commerce-line-item:quantity]" } },
      { "php_eval" : { "code" : "global $user;\r\n$order = commerce_cart_order_load($user-\u003Euid);\r\n$wrapper = entity_metadata_wrapper(\u0027commerce_order\u0027, $order);\r\n$line_items = $wrapper-\u003Ecommerce_line_items;\r\n\r\n\/\/ how many products are there in this line item order?\r\n$types = array(\u0022product\u0022);\r\n\r\n$quantity = commerce_line_items_quantity($line_items, $types);\r\nprint $quantity;\r\n\r\n\/\/ Create an order\r\n\/\/ from http:\/\/commerceguys.com\/blog\/creating-orders-drupal-commerce-api\r\n\/\/ Load whatever product represents the item the customer will be\r\n\/\/ paying for and create a line item for it.\r\n$product = commerce_product_load(4);\r\n    \/\/ NOTE: $quantity = number of products in the cart\r\n\r\n$line_item = commerce_product_line_item_new($product, $quantity, \u0027[commerce-line-item:order-id]\u0027);\r\n\r\n\/\/ Save the line item to get its ID.\r\ncommerce_line_item_save($line_item);\r\n\r\n\/\/ Add the line item to the order using fago\u0027s rockin\u0027 wrapper.\r\n$order_wrapper = entity_metadata_wrapper(\u0027commerce_order\u0027, $order);\r\n$order_wrapper-\u003Ecommerce_line_items[] = $line_item;\r\n\r\n\/\/ Save the order again to update its line item reference field.\r\ncommerce_order_save($order);\r\n" } }
    ]
  }
}

2. Remove all subscriptions (SUB-100) from cart

{ "rules_remove_all_subscriptions_from_cart" : {
    "LABEL" : "Remove all subscriptions (SUB-100) from cart",
    "PLUGIN" : "reaction rule",
    "WEIGHT" : "1",
    "REQUIRES" : [ "rules", "php", "commerce_product_reference" ],
    "ON" : [ "commerce_product_calculate_sell_price" ],
    "IF" : [
      { "data_is" : { "data" : [ "commerce-line-item:line-item-label" ], "value" : "SUB-100" } },
      { "php_eval" : { "code" : "global $user;\r\n$order = commerce_cart_order_load($user-\u003Euid);\r\n\r\nif ($order) {\r\n  \/\/ Are there any subscriptions?\r\n  $quantity_subscriptions = intval(db_query(\u0027SELECT SUM(quantity) FROM commerce_line_item WHERE commerce_line_item.line_item_label = \\\u0027SUB-100\\\u0027 AND commerce_line_item.type = \\\u0027product\\\u0027 AND commerce_line_item.order_id = :order_id\u0027, array(\u0027:order_id\u0027 =\u003E $order-\u003Eorder_id))-\u003EfetchField());\r\n\r\n  \/\/ are there more than 0 subscriptions, and not checking out? system added because some ajax function caused errors\r\n  if (($quantity_subscriptions \u003E 0) \u0026\u0026 (arg(0) \u003C\u003E \u0022checkout\u0022) \u0026\u0026 (arg(0) \u003C\u003E \u0022system\u0022)) {\r\n    return TRUE;\r\n    } else {\r\n    return FALSE;\r\n  }\r\n}" } }
    ],
    "DO" : [
      { "drupal_message" : { "message" : "This is *NOT* checkout, SUB-100's deleted" } },
      { "data_set" : { "data" : [ "commerce-line-item:commerce-unit-price:amount" ] } }
    ]
  }
}

Add some products to the cart, go to checkout and verify that a similar number of scanners has been added to the cart. Now click on the Drupal logo to go back to the front page (or any other page) and verify that the subscriptions have been removed from the order.

Now do the same, but proceed beyond shipping, and from the review page (checkout/1/review), where the shipping has been added to the order as a line item, click on the Drupal logo and the error message is shown.

Refresh the page, and the order seems fine.

After visiting the shipping page in the checkout process, a row with a 'line_item_label' called 'Standard shipping' is created in the 'commerce_line_item' table. Perhaps that's causing the error, when the 'remove SUB-100' rule is fired and tries to clone a cart, but the 'Standard shipping' is still there, compared to the new state of the cart...? My coding skills are too poor to understand what exactly is going on in commerce_cart.module on line 791 :-)

arun_ms’s picture

Hello all,

I am a newbie to commerce. I need a delete button to delete the items in cart at order reviewpage.
I am using commerce_cart_summary in order review page.so i added a delete button field in the corresponding view.

But when i try to remove the items in cart, the order get placed and redirected to complete page.

How to overcome this issue? please help me.i am using views "7.x-3.3"

Thanks

chefnelone’s picture

#8: very useful for me too. Thanks.

amberau79’s picture

If I try to do this I get an integrity constraint violation error: Integrity constraint violation: 1048 Column 'commerce_unit_price_amount' cannot be null

Tmanagement’s picture

Same here. Have you resolved your issue by now?

Tmanagement’s picture

Version: 7.x-1.x-dev » 7.x-1.7

Trying a whole day to get a product removed from the cart in case a customer input field in a checkout form (commerce_fieldgroup_panes) has a particular value. Since it took me a minute to add a product, I thought removing a product would take another minute. Given I am working with 7.x-1.7 version, the issue has been updated accordingly.

Tried anything but somehow nothing works. For example, leaving the price unset as posted in #7 returns the error in #12. Moreover, not setting the value NULL (leave empty) but setting it at 1 will indeed change the price but it will do so on each line item. In addition, although the product line items got another value, the total of the cart remains unchanged. I also tried to remove a line item all together but this will remove all line items.

Since I have tried so many with no avail, I was hoping that somebody could post a step by step approach for setting a rule that will remove a particular product if a checkout form has a particular value. This will help me and probably others to do it the right way.

Tmanagement’s picture

Is anybody able to point me in the right direction? Perhaps it is not feasible for whatever reason?

rszrama’s picture

Version: 7.x-1.7 » 7.x-1.x-dev

This issue is a feature request for functionality that doesn't exist, so there isn't a solution yet. Moving back to 1.x-dev where all new features would be added to the 1.x branch.

Tmanagement’s picture

Thanks rszrama for your reply. Just out of interest, why is it so much different to remove a single item than it is to add a single item?

rszrama’s picture

I suppose because it's harder to target an existing item in the list? I'm not sure it's really that much harder, it just hasn't been implemented.

bosmaen’s picture

I followed Randy Fay's video from commerce guys and I was able to remove single items using rules. Watch it here.

kenorb’s picture

function foo_webstore_rules_action_info() {
  return array(
    'foo_webstore_remove_line_item_from_cart_action' => array(
      'group' => t('Commerce'),
      'label' => t('Remove line item from the cart'),
      'parameter' => array(
        'commerce_line_item' => array(
          'type' => 'commerce_line_item',
          'label' => t('Commerce Line Item'),
        ),
      ),
    ),
  );
}

/**
 * Rules action. Removes Commerce Line Item from the cart.
 */
function foo_webstore_remove_line_item_from_cart_action($commerce_line_item) {
  commerce_line_item_delete($commerce_line_item->line_item_id);
}
Horroshow’s picture

Issue summary: View changes

Hi kenorb, where do we paste the code? In a module? Thanks

kenorb’s picture

Yes, #20 code you're pasting into a custom module and change 'foo' into the appropriate module name.
Rules, Commerce and Cart modules are enabled.

Horroshow’s picture

Didn't work for me. I created a custom module with .info and .module files. Copy pasted your code and replaced foo by my store name. Activated the module, flushed the cache (just in case) but can't find the action rule in the list. Any hint? I'm on Drupal 7.28 with Commerce 1.9.

maxrossello’s picture

Setting the price amount to NULL didn't work for me. I get:

Integrity constraint violation: 1048 Column 'commerce_price_amount' cannot be null

Donit’s picture

@bosmaen Would you share your rule?