I've been getting exception logs for this error in production, but I'm unable to reproduce the issue in my local or staging environment, so it's been pretty hard to troubleshoot.
The error originates in Mage_Sales_Model_Service_Quote::_validate()
because the $rate
returned by $rate = $address->getShippingRateByCode($method)
is empty.
I've added in some logging to try and get a better idea of what was going on, and I can see that $method
contains the correct shipping method.
My best guess is that at some point in the process, the shipping rates are being deleted prior to when they should be.
I've noticed that every time this exception occurs, it happens immediately after a legitimate exception, such as an invalid credit card. I've tried to reproduce the issue by using an invalid credit card, then a valid one, but it doesn't reproduce for me - in staging, production, or local.
My initial hunch was that maybe the shipping method was getting lost somewhere after the first valid exception, but that's not the case, because I see that $method
has the correct value at the time that this exception is thrown.
The checkout module that I'm using is AwesomeCheckout - it doesn't really to my knowledge have any custom logic when creating orders that should cause problems here, but might be related.
UPDATE: I've added in some code to attempt to recollect the rates if they are missing.
protected function _validate()
{
if (!$this->getQuote()->isVirtual()) {
$address = $this->getQuote()->getShippingAddress();
$addressValidation = $address->validate();
if ($addressValidation !== true) {
Mage::throwException(
Mage::helper('sales')->__('Please check shipping address information. %s', implode(' ', $addressValidation))
);
}
$method= $address->getShippingMethod();
$rate = $address->getShippingRateByCode($method);
/**
* Start Customization
*/
if (!$this->getQuote()->isVirtual() && !$rate) {
Mage::logException(new Exception("Rate was empty inside quote validate method, trying to forcefully recalculate"));
$this->getQuote()->getShippingAddress()->setCollectShippingRates(true);
$this->getQuote()->setTotalsCollectedFlag(false);
$this->getQuote()->collectTotals();
$rate = $address->getShippingRateByCode($method);
}
/** End Customization **/
if (!$this->getQuote()->isVirtual() && (!$method || !$rate)) {
Mage::throwException(Mage::helper('sales')->__('Please specify a shipping method.'));
}
}