Why does magento remove error info from sales quote when last added quote item has no errors
magento
Solution
I have to post a follow up, My core hack had an unfortunate side effect (another bug):
- Add item to cart with certain quantity (make sure it is stock).
- Go in admin panel and reduce stock so that the remaining quantity is no longer.
- Go back to the cart page and refresh, you get the expected error.
- Try to update the cart and reduce the requested quantity to that which is in fact available, you will notice that the update does not work and the error from #3 is redisplayed.
So apparently this particular logic is necessary for that scenario.
The actual flaw is that the quote error info collection does not differentiate between quote items. So the _removeErrorsFromQuoteAndItem function removes all quantity related errors from the cart including those that came from another quote item (that is still in error).
I found a workaround that works without any core hacks, attach this event observer to the sales_quote_item_qty_set_after event.
public function reinitQuoteErrorState(Varien_Event_Observer $observer)
{
$item = $observer->getEvent()->getItem();
/** @var $item Mage_Sales_Model_Quote_Item */
$quote = $item->getQuote();
/** @var $quote Mage_Sales_Model_Quote */
// Quote not loaded, do nothing since our changes are transient
if (!$quote) return;
// Quote already has error state, nothing to do.
if ($quote->getHasError()) return;
foreach ($quote->getAllItems() as $quoteItem)
{
if ($errorItems = $quoteItem->getErrorInfos())
{
foreach ($errorItems as $errorItem)
{
if ($errorItem['code'] == Mage_CatalogInventory_Helper_Data::ERROR_QTY)
{
$quote->addErrorInfo(
'error',
'cataloginventory',
Mage_CatalogInventory_Helper_Data::ERROR_QTY,
Mage::helper('cataloginventory')->__('Not all products are available in the requested quantity')
);
return;
}
}
}
}
}
Note: The module that has this event handler must add to the tag of the module XML file in /app/etc/modules/ (eg: /app/etc/modules/MyCompany_MyModule.xml) to ensure that this handler is called after Mage_CatalogInventory_Model_Observer::checkQuoteItemQty which has the bug.
The real solution is to fix the quote errorInfo system to maintain quote item identity, but this workaround will do without any core hacks.
<?xml version="1.0" encoding="utf-8"?>
<config>
<modules>
<MyCompany_MyModule>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_CatalogInventory />
</depends>
</MyCompany_MyModule>
</modules>
</config>
Problem
I've been looking over Magento's code (1.6.2 Community Edition), and OMG is it a terribly executed mess, but I won't rant here about that. Looking at this code: ``` // Delete error from item and its quote, if it was set due to qty lack $this->_removeErrorsFromQuoteAndItem($quoteItem, Mage_CatalogInventory_Helper_Data::ERROR_QTY); ``` Which is in Mage_CatalogInventory_Model_Observer class in /app/code/core/Mage/CatalogInventory/Model/Observer.php Line: 489 This produces a peculiar bug to me, try this (make sure "no backorders" is set in backend): - Add a product to the cart - Add another product to the cart. - Go in admin and change first product quantity such that the requested quantity in the cart is not enough. - Go back to shopping cart page. Result The first product added shows the "requested item not available in this quantity" error, but the Checkout methods are still shown ! Continuing forward, eventually gives an ugly js alert saying "Not all items are available in the requested qty". Digging deeper I see that it seems every quote item (cart item) added to the quote (cart) resets the error state for the whole quote. Is this intentional ? Have I stumbled upon a genuine bug ? What does this useless comment mean ? Thanks in advance. EDIT: See answer below for workaround and explanation.