I get the following error (also see screenshot): with D7.7, and Ubercart 7x-3.0-beta4 and the Aug 29, 2011 version of 7.x-3.x-dev

An AJAX HTTP error occurred.
HTTP Result Code: 500
Debugging information follows.
Path: /system/ajax
StatusText: Service unavailable (with message)
ResponseText: PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'amount' cannot be null: UPDATE {uc_order_line_items} SET title=:db_update_placeholder_0, amount=:db_update_placeholder_1
WHERE  (line_item_id = :db_condition_placeholder_0) ; Array
(
[:db_update_placeholder_0] => USPS
[:db_update_placeholder_1] => 
[:db_condition_placeholder_0] => 431
)
in uc_order_update_line_item() (line 77 of /home/musewear/public_html/sites/all/modules/ubercart/uc_order/uc_order.line_item.inc).

Here's how to reproduce:
I have two flat rate shipping options based on Delivery Country. One option for "United States" only, and one for All Other Countries.
On the checkout page, I have 'United States' as the default country.
When I change the Country to something other than "United States" the shipping is updated great.
BUT, when I change it back to "United States", the State/Province is not updated, and when I click on "Click to Update Shipping" I receive the error shown above.
I can change the country to anything else, and the shipping works fine, along with the State/Province select box update. So, it has to do with the shipping matrix set up where the rate is different for the US and 'all other countries'.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

TR’s picture

I can't reproduce this. Following your steps works for me.

nelslynn’s picture

Version: 7.x-3.0-beta4 » 7.x-3.x-dev
Priority: Major » Normal

This might be a rules module issue? Are you using the lated version of rules (7.x-2.0-rc1)? There's a nasty bug with the the new rules module ... http://drupal.org/node/1257580

EDIT: same issue with rules 7.x-2.0-beta3, with Ubercart 7.x-3.x-dev or Ubercart 7.x-3.0-beta4

revnoah’s picture

I'm using 7.x-2.0-rc1 and experiencing this issue.

I have three shipping methods: for Canada, US and international. In Canada, we need to charge HST on orders; elsewhere, we don't.
I added a rule to my taxes to only charge HST when shipping in Canada. The condition is Shipping Quote with the option "Order has a shipping quote from a particular method". I select this and choose 'Canada' from the shipping method drop down.

Sometimes the error occurs when selecting a state/province. It always occurs when changing the postal code, which makes me think that the shipping rule by delivery address and the tax rule based on this value are conflicting with each other. The form data does not get saved correctly if I try to continue to the next page.

Is there another way that the tax rule should be limited by delivery address, or am I doing this correctly?

revnoah’s picture

Version: 7.x-3.x-dev » 7.x-3.0-beta4
Priority: Normal » Major

I would actually consider this a major bug since it prevents users from completing the order. Handling sales tax and shipping costs separately for different countries is a pretty core feature. Running beta4, not dev.

samtherobot’s picture

Version: 7.x-3.x-dev » 7.x-3.0-beta4
Priority: Normal » Major

Having the same issue. I may be able to add a little more light to how to make this happen.

I started with 3 shipping rates. One for each of Ontario, Canada and United States. I set up the rule to look at the delivery address for each and restrict accordingly. This works fine.

However I needed to add another rate that would apply to everyone called "Pickup" which is essentially a shipping rate of $0. As soon as I add this rate which does not have a rule, then I get that error.

As a workaround I added a rule to the Pickup rate to only apply to Ontario. When I added that rule then I no longer get the error. This will work for me however it still seems like an issue. If there is a rate that does not have a rule applied, then we get an error.

revnoah’s picture

I also tried changing the tax rule to be based on the delivery address country, rather than the shipping rule. Same results, almost identical to the error above. One thing to note is that I got this error when changing from Canada to US, though the error mentions the shipping method for Canada.

An AJAX HTTP error occurred.
HTTP Result Code: 500
Debugging information follows.
Path: /tnq/system/ajax
StatusText: Service unavailable (with message)
ResponseText: PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'amount' cannot be null: UPDATE {uc_order_line_items} SET title=:db_update_placeholder_0, amount=:db_update_placeholder_1
WHERE  (line_item_id = :db_condition_placeholder_0) ; Array
(
[:db_update_placeholder_0] => Shipping - Canada
[:db_update_placeholder_1] => 
[:db_condition_placeholder_0] => 93
)
in uc_order_update_line_item() (line 77 of /websites/tnq/sites/all/modules/ubercart/uc_order/uc_order.line_item.inc).
Island Usurper’s picture

Status: Active » Postponed (maintainer needs more info)

I can't reproduce it either. I've got Ubercart 7.x-3.x-dev, Rules 7.x-2.0-rc1. Two flat rate shipping methods, each with a "data comparison" condition on "order:delivery-address:country" equals "United States", with the International one Negated. The only way I've gotten checkout to break is hitting the back button from the review page, but only because the Memcache statistics were being appended to the AJAX response. I have a state-specific tax as well, and changing countries removes and adds it appropriately.

@revnoah, you have a shipping method named "Canada"? I suppose you could, but with the data selectors that Rules provides, I tend to inspect the delivery address directly with the Data Comparison condition.

Ben Howes’s picture

I've been having this issue and it has been lots of fun...

My take is that this occurs under when you use rules on some (or all) of your shipping options, so the availability of the options will as a result of changes to delivery address. This means that you end up with some problems in the quote module as it is trying to use the quote for a rule which has been removed as a result of your address options. This is where you end up trying to insert/update a null value.

The bellow snippet fixes the 500's, but there is still another error that I will mention after.
replace this in uc_quote.module at approx line 676:

$quote_option = explode('---', $form_state['values']['panes']['quotes']['quotes']['quote_option']);
        $order->quote['method'] = $quote_option[0];
        $order->quote['accessorials'] = $quote_option[1];
        $methods = array_filter(module_invoke_all('uc_shipping_method'), '_uc_quote_method_enabled');
        $method = $methods[$quote_option[0]];

        $label = $method['quote']['accessorials'][$quote_option[1]];

        $quote_option = $form_state['values']['panes']['quotes']['quotes']['quote_option'];

        $order->quote['rate'] = $form_state['values']['panes']['quotes']['quotes'][$quote_option]['rate'];

with this:

      $quote_option = $form_state['values']['panes']['quotes']['quotes']['quote_option'];
      if(isset($form_state['values']['panes']['quotes']['quotes'][$quote_option])){ //if the selected option is avaliable
        $quote_option = explode('---', $form_state['values']['panes']['quotes']['quotes']['quote_option']);
        $order->quote['method'] = $quote_option[0];
        $order->quote['accessorials'] = $quote_option[1];
        $methods = array_filter(module_invoke_all('uc_shipping_method'), '_uc_quote_method_enabled');
        $method = $methods[$quote_option[0]];

        $label = $method['quote']['accessorials'][$quote_option[1]];

        $quote_option = $form_state['values']['panes']['quotes']['quotes']['quote_option'];

        $order->quote['rate'] = $form_state['values']['panes']['quotes']['quotes'][$quote_option]['rate'];
      }
      else{ // if the previously selected option is not avaliable (due to rules), select the first option
        $fallback = array_shift(array_keys($form_state['values']['panes']['quotes']['quotes']));

        $form['panes']['quotes']['quotes']['quote_option']['#value'] = $fallback;
        $form['panes']['quotes']['quotes']['quote_option']['#defualt_value'] = $fallback;
        $quote_option = explode('---', $fallback);
        $order->quote['method'] = $quote_option[0];
        $order->quote['accessorials'] = $quote_option[1];
        $methods = array_filter(module_invoke_all('uc_shipping_method'), '_uc_quote_method_enabled');
        $method = $methods[$quote_option[0]];

        $label = $method['quote']['accessorials'][$quote_option[1]];

        $order->quote['rate'] = $form_state['values']['panes']['quotes']['quotes'][$fallback]['rate'];
      }

This prevents you from trying to use a now invalid shipping option by selecting the lightest available one and seems to work fine for me.

The next problem is that when you change into a situation where 2 shipping options are avaliable by changing the address, then clicking get quote, you get 'an invalid choice has been selected', which is because drupal validates the posted data against the form, which has been regenerated to have the new shipping options, but not shown to the user as the current setup of the delievery address stuff does not refresh this.

The solution is to either :
1. (preferred) Make the change of address update the shipping options
2. From the Code I think that not posting a shipping option from the client will make it fallback to default and prevent us from having any problems.

It's home time for me, but I will be on this again tomorrow morning.

Island Usurper’s picture

It's hard to figure out what you're doing without a patch. See http://drupal.org/node/707484 for instructions and tips.

revnoah’s picture

Yeah, I see how that would seem odd. The cart is for a customer that manually ships out products, so the shipping type is named after their internal process. They have one shipping type for Canadian orders, and types for US and other international order. Most of their orders are subscriptions to a literary magazine. So, this isn't really a case where we need to calculate shipping based on package size, shipping company, etc. But there are different shipping rates per product, per destination and sometimes per product.

I changed from basing the tax rule on the shipping method to use the data comparison directly. Same results.

revnoah’s picture

Version: 7.x-3.0-beta4 » 7.x-3.x-dev
Priority: Major » Normal

I believe I've solved the problem but will keep testing to verify.

I updated the ubercart and rules modules to the latest dev versions, cleared the cache, but this didn't fix it. So, I deleted the tax rule and all of the shipping quotes, starting over step-by-step. The issue appeared to be related to the international shipping method, not the taxes.

Here are my shipping rules now:
Canada - order:delivery address:country == Canada
US - order:delivery address:country == United States
International:
order:delivery address:country != Canada
order:delivery address:country != United States

The NOT needed to be on the individual country items, not with an OR and negating the total result or any other combination. I must've had a different variation on this rule. Like I said, until this is thoroughly tested I won't be fully satisfied that it's fixed but I'm not seeing that angry error anymore. Why the error exhibits itself this way, I'm not sure, and maybe more can be done with the way that ubercart is reading the rule logic.

Ben Howes’s picture

FileSize
3.49 KB

#9, sorry didn't think that the patch would really be that useful, but I stand corrected and here you go.

I'm going to see what I can do about getting the shipping options to be rebuilt when you change address (as the used to be in D5 and maybe 6). I shall report back.

Ben

Ben Howes’s picture

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

Okay.

The Problem
=======
When using rules to change the availability of shipping options by _country_, the shipping options section of the form is not replaced on the checkout form, meaning that when you click "Click to calculate shipping" you are actually submitting data for a previous version of the form. If you are moving to a country that has more than one shipping option, the form will not have the selected option available and this will screw up the code that is referencing the selected option which has been removed by rules.

Solution
======
The patch above fixed the problems with referencing the code that no longer existed, however that is not the full story because the submitted data gets validated against the new form, which may not have the selected option giving an "Illegal choice has been detected", which is quite true. I fixed this by making sure that the ajax updater that updates the shipping zones for the newly selected country also updates the shipping options ensuring that you have the newest version of the shipping pane at all times avoiding the issues all together.
It does this by wrapping the normal uc_store ajax callback with another function that adds on the replacement of the shipping option. All of my changes are inside uc_quote and the attached patch gets everything working nicely for me.

So whilst revnoah was able to configure his/her way out of the problem, this fixes the underlying problems with the uc_quote module.

Ben

Ben Howes’s picture

Status: Postponed (maintainer needs more info) » Needs review
revnoah’s picture

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

Great job! Since I had a problem I could work around, I'll hold off on applying the patch. Hopefully, it gets reviewed and committed to the module soon. What a horribly frustrating problem.

Ben Howes’s picture

Yeah, not sure why the automated test hasn't happened yet. I have a set of 12 shipping options with country based rules and its working pretty reliably for me :)

longwave’s picture

Status: Needs review » Needs work
+++ b/sites/all/modules/contrib/ubercart/shipping/uc_quote/uc_quote.module
@@ -673,17 +678,36 @@ function uc_checkout_pane_quotes($op, &$order, $form = NULL, &$form_state = NULL
+        $form['panes']['quotes']['quotes']['quote_option']['#value'] = $fallback;
+        $form['panes']['quotes']['quotes']['quote_option']['#defualt_value'] = $fallback;

Not sure this is correct. Normally you don't set #value directly, and #defualt_value is a typo that means that line does nothing.

I also wonder if instead of overriding $element['delivery_country']['#ajax']['callback'], uc_store_process_address_field() should invoke a hook, so any other module can also have a say in what happens here.

Ben Howes’s picture

Whoops, typo shouldn't have got in there... Setting the #value was quite deliberate though because some of the time the form was being submitted with an invalid value which wouldn't get caught by any validation (and you don't want it to throw an error).

Invoking a hook from uc_store_process_address_field() would be cleaner and more scalable :)

How do you wish to proceed from here?

nelslynn’s picture

Any update on this issue. Still experiencing the original issue with Drupal 7.8, Ubercart 7.x-3.0-rc2, Rules 7.x-2.0

TR’s picture

@Ben Howes: Testbot wasn't working properly until about three weeks ago, but the failure it shows now is real - the patch is in the wrong format. (The way you've made it, it needs to be applied with patch -p6 from the ubercart directory, when it should be -p1). If you can re-roll the patch in the correct format and get the testbot to run green on it, that would be a big help in getting this resolved.

trigop’s picture

Status: Needs work » Needs review

#13: uc_quote-2.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, uc_quote-2.patch, failed testing.

wodenx’s picture

Status: Needs work » Needs review
FileSize
8.5 KB

Here's a slightly different stab at this - makes use of the new 'prepare' checkout pane op to reduce code duplication.

longwave’s picture

+  // The following replaces "uc_store_process_address_field" from uc_store, with a wrapper that will
+  // update the available quotes when the country is changed.
+  if (isset($element['delivery_country'])) {
+    $element['delivery_country']['#ajax']['callback'] = 'uc_quote_country_change_wrapper';
+  }

I would prefer to see a hook or some other mechanism for this, because we're just causing problems later down the line when something else wants to react on country change. Do we even need a more generalised mechanism for reacting to changes anywhere on the checkout page?

longwave’s picture

Status: Needs review » Fixed

OK, so #23 works well for me in testing and fixes the errors reported in this thread, so I committed it.

The issue I mention above can be dealt with separately, if and when a problem arises with it. I had an idea for adding a hook_uc_address_ajax_fields_info() or similar which could register field-level callbacks to provide multiple reactions on address field changes, executed through a common dispatcher, but I guess it isn't necessary right now.

longwave’s picture

Status: Fixed » Closed (fixed)

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