So I'm trying to use the event 'before adding a product to cart' to check (1) the sku of the product being added (2) the quantity of products in the commerce order (3) the sku's already within the commerce order. If the conditions return true then I wan't to stop the 'add to cart' process.
In the actions I've set a 'show a message on the site' so I know the conditions are working correctly. I've also added a 'set data value' where I set quantity to 0. But this does nothing. I'm surprised there isn't a condition where you can raise an exception which bombs out the whole process. Surely on an event like 'before adding a product to cart' you expect to be able to raise a 'no'.
Unfortunately I don't really know anything about rules or how commerce integrates with it otherwise I would try and write something.
Can anyone shed any light on the logic of this? Is this a reasonable request?
Thanks
Issue fork commerce-1658788
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #1
rszrama commentedThere isn't a clear cut Rules based way to prevent the addition of a product to the cart, because technically modules that know they want to prevent the add to cart should alter the form and disable the submit button (see the Stock module for an example). However, through Rules you should be able to do one of two things:
Please let me know what works (if either).
Comment #3
NecroHill commentedthese 2 solutions do not work for me neither with "Before adding a product to the cart" event.
1. With redirect I see my message together with the "Product xxxxx added to your cart." message and its true - product being added.
2. I receive "Data selector commerce-line-item:commerce-unit-price:amount for parameter data is invalid." error message when I manually add commerce-line-item:commerce-unit-price:amount into Data selector field and click "Continue".
In my case in conditions I check if "Order contains products of particular product types" and if not I'd like to break adding to cart process but I can't.
Comment #4
rszrama commentedYeah, you can't use data selectors that don't exist for your event. You'd have to use a different event. But it may just not be possible, hence my first recommendation to just use hook_form_alter().
Comment #5
jegaudin commentedI struggled quite a bit with this issue so I thought I'll share what I came out with.
Strangely I got the help of the commerce-stock module which is adding a set of handy events and actions to be used in rules.
In my case, I have 2 product types (A & B) and the user should not be allowed to add a product type B if there is already a product type A in his card.
As rszrama said, I found it more logic to alter the "add to cart form" in order to prevent the user from being able to add the "unwanted" products.
So I created the following custom rule :
1. Data comparison (to check if the product page is of a product type B) : Parameter: Data to compare: [commerce-product:type], Data value: Product B
2. "Order contains products of particular product types" and select your other product type.
Of course, another similar rule need to be created if a user should not be able to add product type A to cart if he has already added product type B.
Comment #6
MD3 commentedI'm sorry to reopen this, but I think I have found several situations in which
hook_form_alter()can be bypassed.hook_form_alter()that disables the add to cart button if the cart is not empty.Product B can still be added to the cart because it was rendered before the cart had an item in it and there is no rule to stop it from being added to the cart when the user clicks on add to cart.
Further complicating this is that as far as I can tell, commerce_services is not using Form API to create carts.
When I look at the code for
commerce_cart_product_add()I do not see a way to modify the$orderor$line_itemusing therules_invoke_all('commerce_cart_product_add', ... )hook because$orderand$line_itemare not passed by reference (Sorry I can not provide line numbers: I get errors when trying to view this file in anything but raw format). (As a quick aside, I do not understand how the commerce services APIcommerce_services_set_field_values()function works because those items are not being passed by reference either).My current work-around is to add a custom validation function in my
hook_form_commerce_cart_add_to_cart_form_alter()that loads the order and implements the custom logic for my client. For those of you less familiar with Drupal:In order to make this more robust and fix both issues at the same time, I see two possible strategies moving forward:
Are there any other possible suggestions / ideas? At the end of the day, how is this any different than the Drupal Commerce mantra of products being separate from displays. Business logic should be separate from the displays for the exact same reasons product variations are. If we don't fix this, we're subjecting iPhone / Android / JavaScript / 3rd Party developers to understand and maintain business logic that should be handled by the server and creating holes for customers to bypass our business logic.
Comment #7
anybodyI also required the functionality several times. Here's a clear request for a new rule :) That about a feature request in commerce issues?
Comment #8
MD3 commented@Anybody I guess you're right! This is a feature request. Should we open a new issue?
Comment #9
anybodyYes, please!
Comment #10
rszrama commented@MD3 re: your hook_form_alter() problems, the issue is that you just need to add a validate handler to the Add to Cart form. In the core Add to Cart form, it prevents an Add to Cart if the product does not have a valid unit price, so another thing you could do would be to use a Rule that unsets the unit price for the "do not add" condition.
Comment #11
iwant2fly commentedJust wanted to say that jegaudin's #5 response worked great. It would be nice if it were a bit more strait forward, but this works for now.
Comment #12
kenorb commentedSee if that helps: #2189247: Add rule for counting/limiting the product line items
Comment #13
Channel Islander commented@jegaudin Your instruction were perfect. Clear, detailed, and ACCURATE. Thank you.
I have an issue with the Event "Check if a product add to cart form should be enabled (is in stock)" not getting evaluated on one of my Product Types, but am able to work around it by evaluating the test both ways in one Rule, thanks to Conditional Rules (which allows you to put conditions inside the Action of a Rule).
Comment #14
torgospizzaI was hoping something like this was doable. We sell mostly digital products, and even with a Rule that disables the Add to Cart form when a product is in the cart already, it is still possible for a user to double-click that button before that case, which could result in the addition of multiples of the same product. (Note that we are bypassing the default Product Display system here; I have exposed Product entities' cart forms in a Views block.)
Looking at the Cart API docs, it's obvious that the Commerce developers realized this is a limitation; unfortunately there is no solution. From hook_commerce_cart_product_prepare():
So.. what DOES allow you to interrupt the process? Anything? Again, the issue here is in addition to "prevent the Add to Cart button from working" since that is something we already have implemented. I want to introduce a simple Rule *simpler than the one in #12, which seems to be doing way too much) that just says "Before a product is added to the cart, if it meets certain conditions, prevent it from being added."
Am I missing an obvious solution that already exists, or does a new API method need to be introduced that DOES return a value which prevents cart-addition from happening?
Comment #15
rszrama commentedYou'd basically just need a new event in commerce_cart_add_to_cart_form_validate(), perhaps called "Validating an Add to Cart form." At that point, if you did a redirect to the current page, it would prevent the Add to Cart submit handler from taking place. I think there might be some "force immediately" toggle or something for the action you'd have to take.
The problem is there isn't an equivalent for a validate callback's boolean response in Rules actions. You don't have a return value out of a normal event invocation, so the terminal behavior would have to be a redirect to the current path (or some other path if you preferred, naturally).
Comment #17
megaphonejon commented[I apparently just made a commit via a comment? Someone please remove that.]
I'm a little late to this party, but if anyone else has this issue, here's some code I wrote to remove a line item from an order. Use this with the "After saving a new commerce line item" event. I wish you could prevent it being added on presave but the requisite data isn't available at that time.