I'm looking to create a module that would invoke the rule to calculate the sell price of the line item using AJAX and then replace the sell price of the item on the page instead of making the customer add it to cart.

Here is my use case: I have different flavors that can be added to a product, and then dependent on the flavor the price is adjusted. The rules are working for adding to cart and thanks to the "custon ajax add to cart" module I have been able to get AJAX working there. Also, using this bit of code from #1300798: Show price in Add To Cart Form. I have been able to display the price on the add to cart form, and it also has a wrapper. So It would seem that all the pieces are aligned to have AJAX work for the radios and checkboxes on the line items, but I can't figure out a couple things:

1) How would I go about having the rule invoked? I know I have to use rules_invoke_event() with the calculate product price, but I am not sure what the second argument to pass to the rule is.
2) What would be the best means of having the price display replaced? Is this even possible with the framework?
3) Has anyone successfully done this before?

Best,
Tim

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

OnkelTem’s picture

Same question.
I want to ajax-update sell price RIGHT on a product display node when a user changes option (which is commerce line item field).
How to do this?

NecroHill’s picture

same question

rszrama’s picture

Title: AJAX Sell Prices » Incorporate line item fields in the AJAX price recalculation on the Add to Cart form
Version: 7.x-1.2 » 7.x-1.x-dev
Component: Price » Cart
Category: support » feature
Status: Active » Postponed

Hmm, you know, I hadn't considered this before, but here's how to do it. Warning: dev speak ahead.

Right now Drupal Commerce actually supports this behavior out of the box, it just only works through attribute fields, not line item fields added to the Add to Cart form. I never really considered adding AJAX support to the line item fields, but it could be done if you alter the Add to Cart form and add #ajax properties to the line item fields injected to the form you could probably make it happen. The only hitch is that the line item used to calculate sell prices on the Add to Cart form doesn't know anything about values coming in through the form state, and I'm not sure there's an appropriate place to alter this information on. You might get away with it by implementing some sort of preprocessor to the parameters passed in to the form - not sure.

Let's just go ahead and mark this as a feature request, but I doubt it'll go in before Commerce 2.x.

sacowan’s picture

Version: 7.x-1.x-dev » 7.x-1.4
Component: Cart » Price
Category: feature » support
Status: Postponed » Active

Has anyone had any luck with this?

rszrama’s picture

Version: 7.x-1.4 » 7.x-1.x-dev
Component: Price » Cart
Category: support » feature
Status: Active » Postponed

The issue would have been updated if so. Please don't change the issue status, as it's still a postponed feature request per my comment above.

MrPeanut’s picture

For the sake of simplicity, is this a duplicate of #1692960: Refresh price field when a product is customized.?

rszrama’s picture

Yep, let's close that one out.

mesch’s picture

+1 for having this functionality in core Commerce. Right now customers must add a product to the cart to see what effect their line item inputs have on the price, which is not ideal.

There seems to be two obstacles to making this happen. First, the field data is not actually added to the line item until the form is submitted. See the following in commerce_cart_add_to_cart_form_submit():

    // Add field data to the line item.
    field_attach_submit('commerce_line_item', $line_item, $form['line_item_fields'], $form_state);    

    // 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);   

Second, I believe the commerce_price field uses the commerce_product_calculate_sell_price function to calculate the sell price. This function creates a generic, unpopulated line item. So even if a way is found to populate the line item in form state, the field will go on using an unpopulated line item.

I really need this functionality for one line item field in particular, so for now my plan is to manually populate $form_state['line_item'], then invoke rule commerce_product_calculate_sell_price, and then manually refresh the price field by name. We'll see how it goes.

griz’s picture

Yes please.
This would solve the main problem with the granular nature of product pricing - if one has several product types with four or five options what is to be done when an additional service needs to be added?

Use case: print shop selling many different products with many options and an image field on the line item for the customer's design.
They then want to add an artwork checking service at a fixed fee per item, so naturally this would be another line item field and common sense might suggest a product reference. Using Rules it is easy enough to add the value of the referenced product onto the value of the referring product and this can be displayed in the cart and checkout through Views, but unfortunately using a product reference results in a dropdown with ugly "SKU - Title" options, no AJAX and not even a basic indication of price.

malberts’s picture

I've started a module that lets you define a field option's price in one place (with a hook) which can then be used to display it on the Add to Cart form and for use in line item unit price calculation.

http://drupal.org/sandbox/malberts/1915570

It can calculate relative prices for options on single value fields and it can AJAX update the newly calculated custom product (line item) price.

Tomorrow I'm going to look at i18n and commerce_multicurrency support in there. Thereafter I have to get rid of any rough edges.

In the meantime, if anyone wants to look at it, go ahead. I'm currently testing it on Kickstart 2 with Entity Reference fields. I can see my prices with Select/Radio/Checkbox widgets and it updates my line item price, both on the product display node and in the cart.

Documentation is lacking, so if you want to test and don't know what's going on, ask me. Line item fields get some new settings (they should be self explanatory) and then 2 rules need to be enabled to test the bundled Entity Reference support.

marcus178’s picture

@malberts Just having a look at your module and I'm a bit stuck on how to use it. I'm assuming I need to use hook_commerce_custom_product_pricing_calculate_option_price_alter to assign a price to the options but not sure what code to use within the hook to achieve this. Is there any chance of an example?

Anybody’s picture

Issue summary: View changes
Related issues: +#2192969: Allow AJAX price preview

I think this issue is related, but also states out, why commerce pricing attributes are not enough for cases where you absolutely require pricing rules power! The request has not lost any of its importance.

This screencast shows a good usage example: http://www.youtube.com/watch?v=j9KsyvQZaAY
So everybody may understand why this is important.

If someone has a working solution / workaround, please tell me!
PS: The module mentioned above does not work for me at all.

Problue Solutions’s picture

This is essential for a dynamic product configurator type system, Commerce can do everything using custom line item fields and pricing rules, but whats missing is a dynamically updated price when the customer changes options, BEFORE they click add to cart.

I was almost thinking I could use Commerce for a project that requires this kind of thing, but unfortunately its back to a separate javascript solution now.

griz’s picture

I just managed to narrowly avoid bodging my way past this problem again by using malberts' module: http://drupal.org/sandbox/malberts/1915570

Despite supposedly being compatible only with option fields, it can be made to work with numeric fields (for multiplying a price by a float value) by adding an Ajax refresh button in a separate hook_form_alter:

function mymodule_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state) {

  $line_item = $form_state['line_item'];
  $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
  $product_type = $line_item_wrapper->commerce_product->type->value();

  if ($product_type == 'my_product_type') {

    // Add an Ajax refresh button :D
    $form['refresh'] = array(
    '#title' => t('Get a quote'),
    '#type' => 'button',
    '#value' => 'Get a quote',
    '#weight' => 50,
    '#ajax' => array(
      'callback' => 'commerce_cart_add_to_cart_form_attributes_refresh',
      'method' => 'replace',
      'effect' => 'fade',
      ),
    );
  }
}

I also had to stop commerce_vat from adding VAT twice, which I did by adding an ANDed group of two conditions: Not my_product_type AND Line item ID Not = 0.

It took me a while to get there, but thank you malberts!

Summit’s picture

Hi Griz, With what you made, is it now possible to handle quantum discounts and show the visitor real time that choosing a different quantity gives a different price?
Greetings, Martijn

griz’s picture

In my use case this time the site owner is selling material by the meter, so we're not using the built-in quantity field. I've just tested it and changing the quantity field doesn't affect the price - the price is displayed based on your choice of formatter in the product type's view mode, and shows the unit price, not the line item total.

If you have Rules set up to alter the unit price based on quantity you may see the discount appear with the price if you've selected 'Formatted amount with components' and configured your Rule to add a 'Discount' price component, and you might be able to theme the output of that table or create your own formatter to show the line item's total as well as the unit price. I haven't tried either,

Or, perhaps preferably, you could show the price in the Add to Cart form using this https://www.drupal.org/node/1300798 which was linked in the OP, but take the quantity and unit price from the $form_state and multiply them.

Failing that, you could add an integer field to your line item to store the quantity, then in Rules you could use it's value to calculate your discount (which would definitely show up, I've tested that) and then populate the line item's built-in quantity field with it so that the discount is shown in the cart as expected.

griz’s picture

Also, if you look at line 250 of malberts' module you'll see:

    $line_item = commerce_product_line_item_new($product, 1 /*$form_state['values']['quantity']*/, 0, $form_state['line_item']->data, $form_state['line_item']->type);

$form_state['values']['quantity'] has been commented out - not sure why, but you could try adding that back in.

I'd love to see this issue set to 'active' as given the code in malberts' sandbox there is definitely a viable way of integrating this functionality into commerce, but I've not even begun to look at commerce core and I have quite a lot left to do on my current project.

Andrew Gorokhovets’s picture

subscribe

fugazi’s picture

are already new opportunities were found to update the price on the product page. I have copied the video https://www.youtube.com/watch?hl=de&gl=DE&v=j9KsyvQZaAY , it all works just the price is not changed.

fugazi’s picture

any help appreciated

ryanfc78’s picture

I am looking for this as well. I hope this feature gets added soon.

trumanru’s picture

Waiting for the solution too. We need it so much!

mmtt’s picture

Are there any patches or goals for the next future to make this price changing by selecting attributes?

joep.hendrix’s picture

I am afraid there will not be a solution before D8/Commerce2

diriy’s picture

hope, we'll find it together...
I suggest to rebuild the "Quantity" widget with select box and the variants "1, 2, 3....". then, I think it is possible to work with Rules module... can it be considered as a solution? anyone tried?

diriy’s picture

Status: Postponed » Needs work

proposed suggestion above. needed to update issue

andyg5000’s picture

Here's a patch to get us started here.

joshmiller’s picture

Tested Andy's patch. Not sure what the "foreach(element_child(" does for the fields on Andy's site, but I had to check for an empty array and just add it to the simple fields I was testing with.

Attached is the updated patch.

Below I've included an animated gif of this working. Please consider including this in the next version of Commerce, Ryan. Pretty please O:)

line item fields demo

joshmiller’s picture

Issue summary: View changes
TheJoker’s picture

FileSize
327.19 KB

joshmiller, it works. Very cool!

But as always, is not without problems. I thought that the problem in the module "Conditional Fields" and wrote there https://www.drupal.org/node/2449311#comment-11053085. Now it seems that it is in a patch that is not working.

When switching between types of price is not set to zero, although given that it happened.

In molude malberts it works. But there can not be read text and numeric fields.

Please see what you can do.

wqmeng’s picture

Hello,

Have you considering to get this patch #28 also work with the field collection module https://www.drupal.org/project/field_collection?
Just testing this and I have a product which have a field collection field in the custom line item, and the field not work with this patch #28.

Thank you.

turbogeek’s picture

Thanks andyg5000 and joshmiller - patch #28 works well after testing. Hopefully this useful bit of code will make it in the next version of Commerce :)

sprucemoose’s picture

I have successfully applied this much needed patch, but the price in my product display is still not updating when selecting the line item (it is updated when I go to cart, so I think that is setup correctly). The ajax spinner appears briefly, but the price does not update.

Is there any additional setup I need to do after patching the cart module? Thanks

turbogeek’s picture

The ajax spinner appears briefly, but the price does not update.

Have you created a new Rule? If not, create one for the event "Calculating the sell price of a product" with your specific conditions and the action "Add an amount to the unit price".

sprucemoose’s picture

Yes I had created the rule as described, and it is running and updating the price in the cart, but the ajax call does not update the price on the product display page. I have tried a fresh install with drupal 7.43, php 5.5 and the latest (patched as per 28) version of commerce and commerce custom product. I have formated line item total and product price to show as 'formatted price with components' etc, but am still not seeing the updated price in the product display. I feel I am probably missing some setting, but am banging my head against the wall trying to figure what it is!

turbogeek’s picture

What about the ajax callback function, does it exist? It sounds like the callback "commerce_cart_add_to_cart_form_line_item_field_refresh" is being called but perhaps it doesn't exist or you need to clear cache. This function returns the product price.

sprucemoose’s picture

I found an error log message from when the "Calculating the sell price of a product" which was 'Unable to get the data value for the variable or parameter amount. Error: Unable to get the data property field_additional_price as the parent data structure is not set.'

I have since tried again with a fresh install. I and am no longer getting the error message, but am still not seeing the updated price on the product display page, but it is updated in the cart. I have flushd all caches, and checked the commerce_cart_add_to_cart_form_line_item_field_refresh function esicts. It exists just in the updated commerce_cart.module file. Is this the only place it needs to be?

turbogeek’s picture

It's difficult to determine what the issue might be so I made the patch into a simple module. It also includes a rules example that you can follow.

https://github.com/deckfifty/commerce-line-item-recalculate

Just enable, setup a rule and you should be good to go!

mglaman’s picture

Issue tags: +commerce-sprint

Marking for the D7 Sprint. Maybe we should promote this as a submodule, or get a patch in. Will want rszrama's feedback.

sprucemoose’s picture

I have discovered my issue was caused by having the 'number of values' field in the 'product reference' field of the product display set to 1. After changing this to unlimited everything is working perfectly now. Thank you andyg5000 for the patch, and to turbogeek for your assistance and the module version. Much appreciated!

mdupree’s picture

Tested via turbogeeks module based off JoshMillers patch. Works! thumbs up from me.
Thanks you guys!

mdupree’s picture

Should we have a few more people test this? or should we update the status.

thejacer87’s picture

Status: Needs review » Reviewed & tested by the community

tested the module by turbogeek. rule works for me

Alexandre360’s picture

+1 for a commit. I think it should be added in core and not in a submodule. The core handle ajax price update for products attributes and it should provide the exact same feature for line items attributes to stay consistent.

Anybody’s picture

Confirming RTBC and +1 :)

turbogeek’s picture

I agree Alexandre360, having the same callback for line items and attributes would be best. Hopefully it's in a future release.

joshmiller’s picture

Status: Reviewed & tested by the community » Needs review

As much as I want to see this in core Commerce, we need the RTBC to be on the actual patch and not a stand-alone module.

thejacer87’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
120.28 KB

Tested the patch, NOT the module!

I sampled a use case similar to what @timodwhit was asking for in the original post. I added a Flavours field to the product line item type. Three choices, and made a rule for each. I think the patch should be committed, but maybe open an other issue to add some documentation to explain how to get this done.

mojiro’s picture

I tried to use this patch/module but I am facing a weird problem.

My price field's html is:

<div class="field field-name-commerce-price field-type-commerce-price field-label-hidden">
  <div class="field-items">
    <div class="field-item even">6,54 €</div>
  </div>
</div>

while the Ajax response is:

<div class="commerce-product-field commerce-product-field-commerce-price field-commerce-price node-1-product-commerce-price">
  <div class="field field-name-commerce-price field-type-commerce-price field-label-hidden">
    <div class="field-items">
      <div class="field-item even">6,54 €</div>
    </div>
  </div>
</div>

.. so my price-field's html is missing one div wrapper!

Do you have any idea why is this happening?

kopeboy’s picture

We have a working patch in #28 no?

rszrama’s picture

Issue tags: +release-1.14
jsacksick’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
5.66 KB

I tested the patch, and wanted to test a usecase where you'd need to build a pricing calculation rule using license fields values... When you use the Commerce License module, an entity reference field is added from the line item to the license.
Using an Inline Entity Form widget, you could expose License fields from the add to cart form directly...

So with the patch from #28, license fields weren't triggering an ajax refresh, problem is, with the attached patch, an ajax request is correctly fired, but you can't actually react to the refresh using Rules because the license itself hasn't been created yet, thus, not accessible from the line item.

I cleaned up the huge loop and now relying on a recursive function for attaching the #ajax property.

Additionally, I added an alter hook (hook_commerce_cart_add_to_cart_form_line_item_field_refresh_alter(), similar to the hook fired when refreshing the attribute refresh one (hook_commerce_cart_attributes_refresh_alter()).

Since the form, $form_state & the line item is passed to the hook, you could use that to alter the price displayed....

mglaman’s picture

  1. +++ b/modules/cart/commerce_cart.api.php
    @@ -206,6 +206,28 @@ function hook_commerce_cart_attributes_refresh_alter(&$commands, $form, $form_st
    + * Line item field refresh on the add to cart form.
    

    s/L/l

  2. +++ b/modules/cart/commerce_cart.api.php
    @@ -206,6 +206,28 @@ function hook_commerce_cart_attributes_refresh_alter(&$commands, $form, $form_st
    + *   The array of AJAX commands used to refresh the cart form with updated form
    + *   elements.
    

    Two lines, should we just say "The array of AJAX commands." to keep it one line?

  3. +++ b/modules/cart/commerce_cart.module
    @@ -2207,6 +2207,12 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
    +      else {
    +        // Recursively set the AJAX callback to each of the line item
    
    @@ -2241,6 +2247,21 @@ function commerce_cart_add_to_cart_form($form, &$form_state, $line_item, $show_q
    +    if (isset($elements[$child]['#type']) && !in_array($elements[$child]['#type'], array('container', 'fieldset'))) {
    +      $elements[$child]['#ajax']['callback'] = 'commerce_cart_add_to_cart_form_line_item_field_refresh';
    +    }
    

    Should we add a matching field setting here that allows opting in for the cart settings?

    So if they enable the cart settings field access, then the states API shows a checkbox "to include in pricing calculation."

    Now we don't need to recurse. It goes on the top level, people alter in as needed.

lukasss’s picture

after #52 I have fatal error:
call to undefined function commerce_product_pricing_invoke()

dylf’s picture

Issue summary: View changes
FileSize
454.87 KB

Did some testing and the patch in #52 looks good to me. I would make the suggested edits in #53, but other than that RTBC +1 from me.

jsacksick’s picture

@lukasss you need to upgrade Commerce to the latest dev as well... (changes were introduced to the way we invoke pricing rules lately).

dtesenair’s picture

FileSize
174.27 KB

First of all, thanks to all who have worked on and contributed to this functionality.

I'm using the module that turbogeek provided in #38 but am having an odd issue...

If my product display node only references a single product, everything works great... the rules fire when line item fields are updated and the price is calculated properly. However, if the display node references more than one product, the price calculation gets a little screwy:
- When selecting a different product the pricing rule that modified the price is not fired.
- When selecting the line item field, the pricing rule changes the display to the price of the first product.

My pricing rule is as follows:
Event:
- Calculating the sell price of a product
Conditions:
- Entity is of bundle = "Custom Print Line Item"
- Entity has field: field_add_frame
- Data comparison = field_add_frame=1
Actions
- Add an amount to the unit price = Amount: 500

Here's an animated GIF of the behavior:

issue example

I apologize in advance if I've missed some simple configuration but any help would be appreciated.

Frederic wbase’s picture

Hello

After testing this patch everything seems to work fine. But I have a use case where there are multiple inline entity forms in the add to cart form. See screenshort: https://www.dropbox.com/s/ysqc58er9tewk5r/Schermafdruk%202017-09-19%2017...

The issue is that the action buttons of those inline entity forms aren't working anymore. My guess is that this is because of the Ajax callback that is replaced, we now have 'commerce_cart_add_to_cart_form_line_item_field_refresh' instead of 'inline_entity_form_get_element' as a callback.

My first guess to solve this is by using the hook_commerce_cart_add_to_cart_form_line_item_field_refresh_alter but I am not 100% sure. Any thoughts?

grts

CProfessionals’s picture

Applied #28 patch to new install of commerce kickstart 2 with (7.x-1.x-dev updated 28 Aug 2017 at 19:14 UTC) release of Commerce module. Does not seem to query the pricing rules every refresh. Pricing stays the same. but when you go to checkout the correct value is on the order.

rszrama’s picture

Status: Needs review » Needs work
Issue tags: -commerce-sprint, -release-1.14

Moving this back to needs work after testing and removing from the 1.14 release plan.

I duplicated the issue in comment #57 - I'm not sure there's a great way to support line item fields in the attribute related refresh, because you don't have the opportunity to pass in a line item or form state information during the rendering of the price field that is replaced into the page. I suppose we'd simply have to calculate the price a second time in the event we detect line item fields on the form and swap it in directly.

That said, I'm not sure it's a great idea to be recursively setting the Ajax callback like this patch does as of #52. There could be line item fields that legitimately need to set their own, even if it's something as simple as adding additional values to an unlimited multi-value field.

I think for this patch to be successful, we'll need to introduce constraints and not attempt to support line item field based price calculation in every instance. I'd be fine with just admitting it won't work for inline entity forms or fields that have their own Ajax callbacks, for example. I'd even be fine with restricting it to products without attributes, but I think that issue is more easily solved than the latter.