Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magento recalculate cart total in observer

I have an observer that removes items from the cart if they are out of stock (i.e. customer returns to their cart ofter x time, and an item in the cart has gone out of stock), and shows a message to the user.

Removing the item(s) works, but updating the cart total does not. Any help would be much appreciated!

My observer observes the sales_quote_save_before event:

public function checkStockStatus($observer)
{
    // return if disabled or observer already executed on this request
    if (!Mage::helper('stockcheck')->isEnabled() || Mage::registry('stockcheck_observer_executed')) {
        return $this;
    }

    $quote = $observer->getEvent()->getQuote();
    $outOfStockCount = 0;

    foreach ($quote->getAllItems() as $item) {
        $product = Mage::getModel('catalog/product')->load($item->getProductId());
        $stockItem = $product->getStockItem();
        if ($stockItem->getIsInStock()) {
            // in stock - for testing only
            $this->_getSession()->addSuccess(Mage::helper('stockcheck')->__('in stock'));
            $item->setData('calculation_price', null);
            $item->setData('original_price', null);
        }
        else {
            //remove item 
            $this->_getCart()->removeItem($item->getId());
            $outOfStockCount++; 
            $this->_getSession()->addError(Mage::helper('stockcheck')->__('Out of Stock'));
        }
    }

    if ($outOfStockCount) > 0) {       
        $quote->setTotalsCollectedFlag(false)->collectTotals();
    } 

    Mage::register('stockcheck_observer_executed', true);

    return $this;         
}

protected function _getCart()
{
    return Mage::getSingleton('checkout/cart');
}

protected function _getSession()
{
    return Mage::getSingleton('checkout/session');
}  
like image 815
Toby Hemmerling Avatar asked Oct 03 '11 18:10

Toby Hemmerling


2 Answers

Tip for the day: by observing the *_save_after and trying to force the same object to change will normally call save again and you will end up in endless loop .oO

However if you observe the collectTotals() method in quote class then you'll notice that you are missing a important flag ->setTotalsCollectedFlag(false)->collectTotals() to make the calculation possible once it has been already calculated.

Life would be something different if there were not some bugs in your path to glory so be aware of the following issue in Magento: Issue #26145

like image 176
Anton S Avatar answered Nov 09 '22 06:11

Anton S


Thank you @Anton for your help!

The answer that ended up working for me was to make a call to session_write_close(); before the redirect (in the observer):

if (// products are out-of-stock and were removed...) {
    $this->_getSession()->addError('Error message here.');
    $this->_getSession()->getQuote()->setTotalsCollectedFlag(false)->collectTotals();
    session_write_close();
    Mage::app()->getResponse()->setRedirect('index');
}
like image 45
Toby Hemmerling Avatar answered Nov 09 '22 07:11

Toby Hemmerling