Magento – $quote->setHasErrors(true); not working

cartevent-observermagento-1.9quotequoteitem

I am using code from here to add an observer, get qty available from external source, and then set error true/false.

I have the observer set up correctly. I know this as it is doing everything I need it to, except show the fact that there are errors in the cart.

My code inside the observer (using sales_quote_item_qty_set_after) is:

public function cartQtyUpdated(Varien_Event_Observer $observer) {
        if ($action = Mage::app()->getFrontController()->getAction()) {

            /** @var Mage_Sales_Model_Quote_Item $item */
            $item = $observer->getEvent()->getItem();

            if ($item->dataHasChangedFor('qty')) {

                $qty        = (int)$item->getQty();
                $product_id = (int)$item->getProduct()->getId();

                /** @var Mage_Catalog_Model_Product $product */
                $product = Mage::getModel('catalog/product')->load($product_id);

                $product_id = (int)$product->getEntityId();

                if ($product->getTypeId() == "configurable") {
                    $simple_id = (int)$item->getOptionByCode('simple_product')->getProduct()->getId();
                } else {
                    $simple_id = $product_id;
                }

                if (
                    $simple_id != '' &&
                    $qty != ''
                ) {

                    // Logic to get stock levels

                    if ($available['status'] == 'success') {

                        foreach ($options as $option) {
                            if ($option->getCode() == 'additional_options') {
                                $additional_options = unserialize($option->getvalue());
                                foreach ($additional_options as $key => $additional_option) {
                                    if ($additional_option['label'] == "Delivery Estimate") {
                                        $additional_options[$key]['value'] = $available['time'];
                                    }
                                }
                                $option->setValue(serialize($additional_options));
                            }
                        }
                        $item->setOptions($options)->save();
                        Mage::getSingleton('checkout/cart')->save();
                    } else {

                        $item->getQuote()->setHasError(true);
                        $item->addErrorInfo(
                            'checkout',
                            1,
                            Mage::helper('cataloginventory')->__('The requested Qty is not available.')
                        );
                        foreach ($options as $option) {
                            if ($option->getCode() == 'additional_options') {
                                $additional_options = unserialize($option->getvalue());
                                foreach ($additional_options as $key => $additional_option) {
                                    if ($additional_option['label'] == "Delivery Estimate") {
                                        $additional_options[$key]['value'] = "N/A";
                                    }
                                }
                                $option->setValue(serialize($additional_options));
                            }
                        }
                    }
                }
            }
        }
    }

The part that doesn't seem to be working is

$item->getQuote()->setHasError(true);
$item->addErrorInfo(
    'checkout',
    1,
    Mage::helper('cataloginventory')->__('The requested Qty is not available.')
);

I am sure that I have had this working in the last couple of days but for some reason it just won't save the error.

When I put through a qty that I know is not available, and I know returns an the correct error, the cart buttons are still visible and there are no errors on the cart item.

I have added logs at the end of the above script and can safely say that the setHasError() method is doing it's job. Also, I added Mage::log($item->getErrorInfos(), 7, 'cart.log', true); which returns an array containing the exact error I am trying to set.

As everything seems to be setting properly, I am unsure as to why the cart is not showing the errors and why it seems to let me checkout.

Is there anything I can do to find where the errors are being lost between the observer and the cart reloading?

If anyone can give me any thoughts on this it would be very much appreciated; I'm stuck big time on this!

I feel like I'm talking to myself a bit here but here's an update:

Update

I have used $item->getQuoteId() to get the quote ID in the observer method and used

$session        = Mage::getSingleton('checkout/session');
$quote_id       = $session->getQuoteId();

To get the quote ID in the cart.phtml file. Both ID's are the same.

Could really do with some input on this guys and girls…

Best Answer

As you probably saw on my answer for Quote/QuoteItem addErrorInfo is not persistent.

The setHasError in Magento behaves like a success/failure session message. This means once the message has been rendered out on the front-end. The item and the quote itself does not have the error any more.

  1. When loading the quote to render in the cart page, Magento actually revalidates the quote and set error information on the quote and items.
  2. Then in the checkout controller, Magento core has a function to revalidate the quote (and re-set the error information to the quote and items) before letting user checkout (or redirect user back to cart to render the error information).

It seems redundant but if you are to follow Magento core logic, you'll have to implement validation on the checkout controller predispatch.

Otherwise, another way to do it is to store these information in user session and (1) render them at cart page then (2) check those information in the checkout controller predispatch to decide whether user should be able to checkout or not.

Sorry for the wall of text and lack of code reference, I'll try to add more code details in later.

Related Topic