Banging my head against a wall all night, trying to understand why an ajax callback attached to a button element in a checkout pane was not firing properly. This is for #1329600: Provide ajax support to reload form after coupon has been added. Turns out the problem was due to commerce_payment_example_submit_form assuming that $pane_values is an array - when it may not, as is in the case when the form is being rebuilt as part of the ajax callback process.

Attached patch resolves the issue at hand, but I wonder if this is actually a problem further upstream?

Comments

mrfelton’s picture

mrfelton’s picture

Status: Active » Needs review
rszrama’s picture

Issue tags: +1.3 review

Tagging.

helior’s picture

Status: Needs review » Postponed (maintainer needs more info)
StatusFileSize
new1.86 KB

I took a look at the patch you linked to on the Commerce Coupon module – Exactly what part of your ajax callback is not working? I feel reluctant to call this a bug since commerce_payment_pane_checkout_form() IS properly initializing the $pane_values.

Although I could not test your patch on Commerce Coupon (since I can't even install the module without it going WSOD) I went ahead and created a small module that is mimicking this functionality by providing a checkout pane that contains an ajax-enabled submit button. I didn't get any errors/notices regarding $pane_values, and both my element submission handler and ajax callback ran just fine. -- I attached the test module in case you want to grok it.

I tried my best to prove that this is in fact a bug on Drupal Commerce, but to no avail. Can you possibly provide more details as to why you believe the error is coming from commerce_payment_example_submit_form()?

As a side note: It looks like the Coupons pane was designed to exist ONLY on the checkout page. Notice that commerce_coupon_commerce_checkout_pane_info() specifies that it is "locked". Whereas the Payment pane is locked on the review page. Just thought it was worth mentioning.

mrfelton’s picture

Literally, the ajax callback as defined on the button element would not fire at all (dct_pane_checkout_ajax_callback in your example module). I traced it to commerce_payment_example_submit_form by what was in the php error logs, complaining about the concatenation of non-array elements in $pane_values += $order->data['commerce_payment_example']; as $pane_values passed into the function was not an array, but NULL.

We were using the commerce coupon form on the checkout page as designed - but we have a one page checkout process, with the payment pane on the checkout page.

helior’s picture

Interesting. Any chance you can set up your one page checkout process on a fresh install of Drupal Commerce using the test module to possibly isolate the problem? Otherwise, I'm not sure I'll be able to replicate your issue :\

kalabro’s picture

Status: Postponed (maintainer needs more info) » Needs work
StatusFileSize
new7.65 KB

I confirm that patch from #1 fixes my problem.
Ajax error appears if coupon and payment panes were on the same page:
2012-09-28_12-35-41.png

Not critical, because it is example payment method, but annoying.

mrfelton’s picture

Status: Needs work » Needs review

It is fairly critical, because by simply having the example payment method enable, can completely break one page checkout forms because submit handlers may fire before validation has even run. I'm setting this back to needs review, because I'm not sure whats wrong with the patch I first proposed.

rszrama’s picture

Status: Needs review » Postponed (maintainer needs more info)

It's not really that critical, since the example payment method is purely there for testing purposes. It won't screw anyone up in production.

That said, this would need to be fixed upstream. We say that callback received a $pane_values array, so it should always be an array.

However, I'm having a hard time duplicating the problem. This is the code helior was talking about where $pane_values is initialized:

    // Find the default payment method using either the preselected value stored
    // in the order / checkout pane or the first available method.
    $pane_values = !empty($form_state['values'][$checkout_pane['pane_id']]) ? $form_state['values'][$checkout_pane['pane_id']] : array();

This means that if $form_state['values'][$checkout_pane['pane_id']] were NULL, as you're saying it is when it's passed to commerce_payment_example_submit_form(), it wouldn't pass the empty check and would be initialized to an empty array. I have no clue how to recreate a scenario where you get from this line above to the invocation of the payment method's submit form callback a few lines below without $pane_values either being that initialized array or some other non-empty value.

rszrama’s picture

Status: Postponed (maintainer needs more info) » Closed (cannot reproduce)

Marking this closed until we can get steps to reproduce the problem and understand why the initialized value as shown in comment #9 is missing. In other words, the API as designed says modules implementing this callback will receive an array for the $pane_values parameter. If it isn't getting it, then we need to find out why, not just apply a workaround to a module implementing the API - otherwise we'd have to update every payment module to use the same workaround.

What we can't determine is why between:

    // Find the default payment method using either the preselected value stored
    // in the order / checkout pane or the first available method.
    $pane_values = !empty($form_state['values'][$checkout_pane['pane_id']]) ? $form_state['values'][$checkout_pane['pane_id']] : array();

this code, where $pane_values is initialized, and

    if ($callback = commerce_payment_method_callback($payment_method, 'submit_form')) {
      $pane_form['payment_details'] = $callback($payment_method, $pane_values, $checkout_pane, $order);
    }

this code, where $pane_values is passed to the callback is that variable suddenly changing, when nothing in between there even mentions the variable.

kalabro’s picture

Status: Closed (cannot reproduce) » Active

I guess, it is because of line 79 in commerce_payment.checkout_pane.inc (Commerce 1.3):

$pane_values = !empty($form_state['values']) ? $form_state['values'][$checkout_pane['pane_id']] : array();

It is fixed in 1.4. Thanks.

kalabro’s picture

Status: Active » Closed (fixed)