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.

Original source