In the API doc:

 * Invoking this Rules event / hook does not result in the processing of any
 * return value, so it is not useful for interrupting a cart product add
 * operation outside of a redirect.

... so what is?

I've looked through all the cart hooks and read commerce_cart_product_add() and I don't see anywhere where a hook or a Rules event can block the operation.

Obviously I can doctor the actual add to cart form, but I assumed there would be some way of making this cast-iron robust at the API level.

Comments

rszrama’s picture

Status: Active » Postponed (maintainer needs more info)

As is you have two options:

  1. As you suggest, you can just prevent the Add to Cart form from displaying the possibility of adding the product to the cart. I believe the Stock module may be informative there.
  2. Or you can accomplish the same thing by unsetting the product's price during price calculation. The "Calculating the sell price of a product" event really serves a dual purpose: to ensure a product is purchasable and to tell the system at what price the current user can purchase it. This is why we have a default rule that unsets the price of a product in the cart if it is currently disabled; this unset tells the system that a product is simply not purchasable, and the Add to Cart form will be rendered accordingly.

You can see here the root idea is that we are determining before the form submission whether or not the product on the form is purchasable. From the customer's point of view, I believe this is the best behavior. Why have a submit button advertising an operation that actually isn't possible?

joachim’s picture

Status: Postponed (maintainer needs more info) » Active

Thanks for the quick feeback!

I seem to be hitting several DX problems here.

I've found the hook hook_commerce_product_calculate_sell_price_line_item_alter(), which seems to be where you're saying I need to act.

Changing the metadata with the wrapper doesn't seem to work (that's more a problem with EntityAPI's sparse docs though). But altering the line item directly works and on form submission I'm told I can't add it to the cart:

  // Doesn't work, produces error message
  $line_item_wrapper->commerce_unit_price->set(NULL);

  // Doesn't work.
  $line_item_wrapper->commerce_unit_price->clear();
 
  // Does work.
  $line_item->commerce_unit_price['und'][0]['amount'] = NULL;

But AFAICT this hook only get invoked in commerce_cart_add_to_cart_form_submit(), so as you say, this isn't terribly good UX: the user is misled into submitting the form and only finds out they can't buy it once they've tried to.

So it seems to me I need to be altering the add to cart form.

The $context param is great, but I am wary of relying on the node in there, because an add to cart form can appear in Views AFAIK where presumably that could be empty.

Therefore, alter code has to look at the product(s) involved in the form. However, these are in a different structure depending on whether there's one or many. You can see from this code in commerce_stock that it's a bit awkward:

    // Check to see if product has options (multiple products using
    // the default dropdown)
    if(isset($form['product_id']['#options']) ){
      // Set validation
      $form['#validate'][] = 'commerce_stock_add_to_cart_validate';
      commerce_stock_cart_state_validate_options($form);
    }
    // A single product or uses attributes (like colour & size).
    elseif (isset($form['product_id']['#value'])) {
      // @todo new rules event for handling options - do we need it?
      // Add validation to the add to cart
      $form['#validate'][] = 'commerce_stock_add_to_cart_validate';
      // check if the add to cart form should be enabled (in stock)
      commerce_stock_cart_state_validate($form);
    }

My use case here is that I can operate on the node level, so I can just zap the whole form. But I want the API security too, just in case later on we add other pathways to purchase products.

So several places where DX could be improved here I think:

- make it easier to sniff the commerce_cart_add_to_cart_form to see which products it is listing
- have a single point where adding a product to the cart can be denied (which would then be called both by the the form, and the API function commerce_cart_product_add().

tuccio’s picture

I tried unsetting the line item price, but the Add to Cart button still renders while clicking it causes a PDO exception. My product is a views display, not a node.

jsacksick’s picture

Issue summary: View changes
Status: Active » Closed (won't fix)

D7 is EOL, closing this.

Now that this issue is closed, please review the contribution record.

As a contributor, attribute any organization helped you, or if you volunteered your own time.

Maintainers, please credit people who helped resolve this issue.