This function just pass the line item to commerce_cart_product_add() which expects the sell price to already be calculated. If you compare this to the normal add to cart form in commerce_cart_add_to_cart_form_submit() you can see that it calculates the sell price before calling commerce_cart_product_add().

What this means is that if you use the rules action "Add a product to the cart" or call commerce_cart_product_add_by_id() directly your product will be added to the cart without taxes, discounts etc. being added to it. commerce_cart_order_refresh() will fix the price on the next page load, but if you have calculations etc. depending on the correct prices in hooks related to add to cart then those won't work.

And we have ajax carts on all our sites so the price shown immediately in the cart will be wrong.

In my opinion this function should look something like this (Based on the code in the normal add to cart form submit handler):

  function commerce_cart_product_add_by_id($product_id, $quantity = 1, $combine = TRUE, $uid = NULL) {
    global $user;
  
    // If the specified product exists...
    if ($product = commerce_product_load($product_id)) {
      // Create a new product line item for it.
      $line_item = commerce_product_line_item_new($product, $quantity);
  
      // Default to the current user if a uid was not passed in.
      if ($uid === NULL) {
        $uid = $user->uid;
      }
      
      // Allow modules to prepare this as necessary. This hook is defined by the
      // Product Pricing module.
      drupal_alter('commerce_product_calculate_sell_price_line_item', $line_item);
  
      // Process the unit price through Rules so it reflects the user's actual
      // purchase price.
      rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
  
      // Only attempt an Add to Cart if the line item has a valid unit price.
      $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
  
      if (!is_null($line_item_wrapper->commerce_unit_price->value())) {
        return commerce_cart_product_add($uid, $line_item, $combine);
      }
      else {
        drupal_set_message(t('%title could not be added to your cart.', array('%title' => $product->title)), 'error');
      }
    }
  
    return FALSE;
  }

Currently it looks like this:

  function commerce_cart_product_add_by_id($product_id, $quantity = 1, $combine = TRUE, $uid = NULL) {
    global $user;
  
    // If the specified product exists...
    if ($product = commerce_product_load($product_id)) {
      // Create a new product line item for it.
      $line_item = commerce_product_line_item_new($product, $quantity);
  
      // Default to the current user if a uid was not passed in.
      if ($uid === NULL) {
        $uid = $user->uid;
      }
  
      return commerce_cart_product_add($uid, $line_item, $combine);
    }
  
    return FALSE;
  }

Comments

TwiiK’s picture

Issue summary: View changes
rszrama’s picture

Title: commerce_cart_product_add_by_id() does not calculate sell price. » Update commerce_cart_product_add_by_id() to calculate sell price
Category: Bug report » Task
Issue tags: +sprint

I'm open to such a patch; I've just never worried about it since it was resolved on the ensuing load. However, since we did recently add the capability to delay the cart order refresh, updating this function accordingly would go nice with that.

mglaman’s picture

It would work on ensuing load, unless the cart was Ajaxified.