When we wrote Commerce 1.x to include the ability to pre-calculate product prices, we enforced a dependency on Rules for all price calculations to ensure we could create a unique key associated with each price. The key corresponded to which pricing rules we know were executed to arrive at an individual price.

However, most sites do not use price pre-calculation. I've only heard of a handful who were using it, and they all required custom code to make use of the pre-calculated prices since we never integrated their utilization into Views or anything else. Therefore, there's no reason we can't open the doors in Commerce 1.14 and beyond for folks to interact with price calculation directly via the API.

Because these features are related, the quickest way to achieve this will be to add a new radio buttons element beneath the sell price pre-calculation radio buttons:

The new element should be named commerce_product_pricing_callback labeled Price calculation process with the following options:

  • rules_invoke: Evaluate pricing rules in order
  • rules_invoke_all: Evaluate pricing rules in order then invoke module based pricing routines

The description should be: "You can only allow modules to directly engage in product pricing when pre-calculation is disabled."

This element should have form state rules on it that only make it appear when "Disabled" is selected for pre-calculation. On submit, this form then needs to ensure that if pre-calculation is enabled the commerce_product_pricing_process is reverted to rules_invoke.

When the form is built, if commerce_product_pricing_process is anything other than rules_invoke, we should disable any options other than "Disabled" for the pre-calculation method. If for some reason we cannot disable individual radio buttons, we'll need to convert that radios element to a static item.

Once this variable is in place, we should alter any place that uses rules_invoke() to determine product prices (outside of code related to price pre-calculation) to use rules_invoke_all().

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

rszrama created an issue. See original summary.

rszrama’s picture

Issue summary: View changes
rszrama’s picture

Issue tags: +release-1.14
jsacksick’s picture

As discussed, I created an API function that wraps the logic required to determine which "callback" is going to be used determining the sell price calculation of a product line item.
I believe this is needed since Commerce Discount and various other contrib modules are directly invoking the "commerce_product_calculate_sell_price" event, so once this is merged, contrib modules should now use "commerce_product_pricing_invoke" instead...

I'm still unsure about the name, I also thought about "commerce_product_pricing_process", suggestions are welcome.

jsacksick’s picture

Issue tags: +Needs change record
rszrama’s picture

The patch looks good and I like the function name as decided. Reading it now, I think we should probably rename the variable from commerce_product_pricing_process to commerce_product_pricing_callback. This will fit better with the "invoke" function. The label for the radio buttons should stay the same, though, as "callback" doesn't make sense in the UI.

rszrama’s picture

Issue summary: View changes
jsacksick’s picture

  • jsacksick committed ea08eee on 7.x-1.x
    Issue #2887385: Allow hook based price calculation when price pre-...
jsacksick’s picture

Status: Needs review » Fixed

Thanks for the feedback, committed the patch from comment #8 (addressed your feedbacks).

Status: Fixed » Closed (fixed)

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

maen’s picture

Sorry, but the hook hook_commerce_product_calculate_sell_price_line_item() is not called. I believe that this is the hook to show the correct price at the add_to_cart form to correct the selling price which is seen by customers, isn't it???

What I did:
I updated commerce to Version: 7.x-1.13+25-dev (before I had the stable version of commerce). I patched the code with https://www.drupal.org/node/1541886#comment-12139654 to integrate the possibility of changing sell price per ajax.
After that, when loading a product page, I saw the correct amount. The base price is 12.00. So I had the correct calculated price, which is either 14.15 or 14.51.
After activating in admin/commerce/config/product-pricing/pre-calculation like so:
UI

the base price is always 0 and I'm not able to revert my settings because of the set states in this form!???

So do I misunderstand anything?

Best wishes,
marc

// Edit: I forgot that I used form_alter() where I Inserted $form_state['default_product']->commerce_price['und'][0]['amount'] = 0; for testing purposes. Forget about my post and sorry!!!!

jsacksick’s picture

@maen: Did you implement the hook yourself in a custom module?? Because Commerce doesn't implement it by default.

maen’s picture

@jsacksick:
Yes I did. With
drush fn-hook commerce_product_calculate_sell_price_line_item
the system shows me that it recognizes my implementation!
I'm just debugging the form from my image above, and I assume that the config from my image just above should give me in commerce_product_pricing_ui.admin in line 162:
$product_pricing_callback == 'module_invoke_all.
In fact $product_pricing_callback gives me "rules_invoke_all" and that seems to be the problem!???

So do I have to give the variable in another location???

If not, I went manually through the patch, and the code seems ok!???

maen’s picture

And:
If I debug commerce_product_pre_calculation_settings_form_submit(...),

$values =
[commerce_product_sell_price_pre_calculation] = string "disabled";
[commerce_product_pricing_callback] = string "rules_invoke_all";

So I believe a take a deeper look at the form again!??

maen’s picture

Sorry again, but what do I miss???

In commerce_product_pricing_ui.admin line 145:

$form['commerce_product_pricing_callback'] = array(
    '#type' => 'radios',
    '#title' => t('Price calculation process'),
    '#description' => t('You can only allow modules to directly engage in product pricing when pre-calculation is disabled.'),
    '#options' => array(
      'rules_invoke_event' => t('Evaluate pricing rules in order'),
      'rules_invoke_all' => t('Evaluate module based pricing routines then invoke pricing rules in order'),
    ),
    '#states' => array(
      'visible' => array(
        ':input[name="commerce_product_sell_price_pre_calculation"]' => array('value' => 'disabled'),
      ),
    ),
    '#default_value' => $product_pricing_callback,
  );
  // If the Product pricing callback configured is set to "module_invoke_all"
  // disable the element and update the description.
  if ($product_pricing_callback == 'module_invoke_all') {
    $form['commerce_product_pricing_callback']['#options']['module_invoke_all'] = t('Only invoke module based pricing routines');
    $form['commerce_product_pricing_callback']['#description'] .= ' ' . t("This value has been set in your site's codebase and cannot be changed via this form.");
    $form['commerce_product_pricing_callback']['#disabled'] = TRUE;
  }

In my opinion there is "show the radio button for "module_invoke_all" only then when you already selected the radio button for "module_invoke_all" which is not possible because you can't select it before!!!

jsacksick’s picture

@maen: The hook should be called hook_commerce_product_calculate_sell_price(), the .api.php was wrong and I just fixed it.
As for "module_invoke_all", this needs to be configured manually (either by setting

$conf['commerce_product_pricing_callback'] =
 'module_invoke_all';

or by setting the variable manually using drush (drush vset commerce_product_pricing_callback "module_invoke_all").

The reason we're not exposing this option by default is that we don't want people to accidentally select that option without being aware of the consequences (Enabling that option will completely bypass Rules).

Hope this helps!

maen’s picture

THIS HELPS A LOT!!!! Thank you so much!