I guess this is a cross between a bug and feature request. After adding a coupon, it will only refresh the cart view attached to a pane. This means that if the coupon entry is moved to say the review pane, once added and rules or modules reacting to the price (No Payment comes to mind) do not fire/act because the ajax request targets the line item view specifically.

The coupon module would increase its friendliness by increasing the scope of its refresh to the entire page, or at least offer some sort of Rule plugin to support things that are in direct reliance on the price.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pcambra’s picture

Category: bug » feature

Review pane is out of scope, the "natural" place for placing coupons is the "checkout" step, review should be "read only".

In any case, patches are welcome if there's interest about the feature.

drupalninja99’s picture

Version: 7.x-1.x-dev » 7.x-1.0-beta7

I have an issue where the order total is not updated when rules checks the order balance on the review page. Here is the workflow:

1. Add coupon to checkout page (without the 'add coupon' button), click continue
2. When rules checks the order total on the review page it does not see the new adjusted amount
3. Click back, then continue
4. Now rules sees the correct order total

If I use the ajax 'add coupon' button the order total is correct on the review page. This is a bug bc the review page should have the updated total no matter what method the coupon was added. This is a problem for rules that check the balance to see if the credit card fields should be displayed.

Does that make sense?

pcambra’s picture

Version: 7.x-1.0-beta7 » 7.x-1.x-dev

Are you adding the coupon in the review page? otherwise it's a completely unrelated problem.

drupalninja99’s picture

Sorry, no I am adding to the checkout page

pcambra’s picture

Then please don't comment on unrelated issues and open a new one with your support request.

amberau79’s picture

I would also like to see the ajax refresh scope increased. I want to show the zero total payment method when a coupon covers the entire order amount but I'm stumped for a good method of doing this when a single button only allows a single ajax callback. Would be happy to hear any suggested solutions to this problem. I imagine there are other cases where this would be useful as well.

It seems to me that the primary issue here "Coupon Addition only refreshes cart view" applies equally wherever the coupon is being added. The ajax scope is still too limited.

brogdawg’s picture

Issue summary: View changes

I am also looking for a solution to this. Like amberau79 I will sometimes have coupons for 100% off which makes the total $0. I have conditions for my payment methods to only have CC payment available when total is greater than $0 and a 'No payment required' method to available when total is less than or equal to $0. I have my coupon and payment method all on the checkout page and do not have a review order page.

With that said, if I add a coupon on my checkout page for 100% off I am still shown the credit card payment method even though the total is $0. If I refresh the page then only the 'No payment required' method is available as desired. However, if I remove the coupon then the entire page refreshes and I get the appropriate payment method again. Is there no way to have the entire checkout page refresh when a coupon is added like it does when a coupon is removed. I believe this would also solve this issue https://drupal.org/node/2157177

Gomez_in_the_South’s picture

Add my name to the list of people that could use this.

In my case, we offer free shipping for orders above $80. If a user initially orders $85, he is given free shipping. If he then applies a coupon to reduce the total below the $80 threshold, the free shipping still erroneously applies. A page refresh will apply the correct calculation.

torgosPizza’s picture

We also have a need for this. As an example, I'm toying with the notion of moving the Payment pane to the Checkout page, so users can select PayPal and not be required to enter any billing info. If a user enters a 100% off Coupon, the "Coupon Usage" pane refreshes but not the payment pane, resulting in them still having a Payment Method selection form. They then need to refresh the page for the desired result.

I'll look into this and see if there is any way to easily reload any panes on the current page, outside of refreshing the entire page.

Related:
#1329600: Provide ajax support to reload form after coupon has been added
#1329308: Provide better core support for AJAX reloading of checkout panes / pages (for Commerce)

torgosPizza’s picture

Version: 7.x-1.x-dev » 7.x-2.x-dev
Status: Active » Needs review
FileSize
898 bytes

Here's a small patch for 2.x that refreshes the payment pane if it exists in the $form.

I think it makes sense to do this at the Commerce Coupon level since it is possible to add a coupon that covers 100% of the order.

torgosPizza’s picture

Issue tags: +commerce-sprint

Very small patch and IMO a necessary addition for correctly handling free orders with coupons (and one-page checkout configs).

firewaller’s picture

The above patch does not acknowledge the payment methods rules (ie. rule to toggle paid to free payment method when a $100 order is updated to $0 by a coupon).

Since the use case may differ, I'd recommend leveraging hook_commerce_coupon_add_coupon_ajax_alter(). Below is my approach to truly reloading the pane and overwriting the payment method (FYI I removed a bunch of array isset() checks for readability).

/**
 * Implements hook_commerce_coupon_add_coupon_ajax_alter().
 */
function MY_MODULE_commerce_coupon_add_coupon_ajax_alter(&$commands, &$form, &$form_state) {
  $panes_info = commerce_checkout_panes();
  $payment_pane_info = $panes_info['commerce_payment'];
  $payment_form = drupal_get_form($payment_pane_info['callbacks']['checkout_form'], $payment_pane_info, $form_state['order']);

  // Override existing payment methods.
  $form['commerce_payment']['payment_methods'] = $payment_form['payment_methods'];
  $form['commerce_payment']['payment_method'] = $payment_form['payment_method'];
  $form['commerce_payment']['payment_details'] = $payment_form['payment_details'];

  $output = drupal_render($form['commerce_payment']);

  // Trim $output to prevent extra div wrapper
  $commands[] = ajax_command_replace('.commerce_payment', trim($output));
}
firewaller’s picture

Additionally, to limit overriding any hook_form_FORMID_alter() changes, I added a balance check at the top of the above function.

$balance = commerce_payment_order_balance($form_state['order']);

// Confirm order is free.
if ($balance['amount'] == 0) {
  //...
}
torgosPizza’s picture

@firewaller: Can you re-roll the above patch to utilize your changes? I'd be glad to take a look then.

firewaller’s picture

Please ignore my first comment. I didn't account for the rest of the form to retain legacy pane information (ie. on checkout complete: Notice: Undefined variable: card in commerce_stripe_submit_form_submit().)

Instead, I simply force an ajax reload (and override the other ajax commands) via hook_commerce_coupon_add_coupon_ajax_alter(). Unfortunately, this will cause data loss of any info the user has submitted on that page, so it probably should be added to a custom module instead of patched to the contrib module.

/**
 * Implements hook_commerce_coupon_add_coupon_ajax_alter().
 */
function MY_MODULE_commerce_coupon_add_coupon_ajax_alter(&$commands, &$form, &$form_state) {
  $balance = commerce_payment_order_balance($form_state['order']);

  if ($balance['amount'] == 0) {
    // @url https://www.drupal.org/node/2030561
    ctools_include('ajax');
    ctools_add_js('ajax-responder');

    $commands = array(
      ctools_ajax_command_reload(),
    );

    print ajax_render($commands);

    drupal_exit();
  }
}
sgutta’s picture

issue:

i applied the above patch for '.inc' file and also i have also commented line number 1220 in commerce_coupon.module file(//commerce_coupon_remove_coupon_from_order($order, $coupon, FALSE);) which helps me to render the page on checkout screen.

but after processing the payment when i goto view my order screen, i was not able to see the coupon applied for the payment.

vlad.dancer’s picture

Here is what I'm using to fix this issue:

mymodule.module


/**
 * Implements hook_commerce_coupon_add_coupon_ajax_alter()
 */
function mymodule_commerce_coupon_add_coupon_ajax_alter(&$commands, $form, $form_state) {
  if (isset($form['commerce_payment'])) {
    $commands[] = ajax_command_replace('#commerce-payment-options-ajax-wrapper', drupal_render($form['commerce_payment']['payment_method']));
    $commands[] = ajax_command_replace('#payment-details', drupal_render($form['commerce_payment']['payment_details']));
  }
}

/**
 * Implements hook_form_FORM_ID_alter()
 */
function mymodule_form_commerce_checkout_form_checkout_alter(&$form, &$form_state) {
  $order = $form_state['order'];

  $form['commerce_payment']['payment_method']['#prefix'] = '<div id="commerce-payment-options-ajax-wrapper">';
  $form['commerce_payment']['payment_method']['#suffix'] = '</div>';

  // Rebuild payment pane only when there is at least one aplied coupon.
  if (!empty($order->commerce_coupons) && $form_state['triggering_element']['#ajax']['callback'] == 'commerce_coupon_add_coupon_callback') {
    $panes = commerce_checkout_panes();
    $payment_pane = $panes['commerce_payment'];
    require_once drupal_get_path('module', $payment_pane['module']) . '/' . $payment_pane['file'];

    $payment_form = commerce_payment_pane_checkout_form($form, $form_state, $payment_pane, $order);
    $payment_keys = array_keys($payment_form['payment_methods']['#value']);

    // Set first payment method as default payment,
    // if there is no default payment.
    if (!in_array($payment_form['payment_method']['#default_value'], $payment_keys)) {
      $payment_form['payment_method']['#default_value'] = $payment_keys[0];
    }
    $form['commerce_payment'] = $payment_form;
  }

}