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/p开发者_如何学Croduct')->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');
}
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
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');
}
What about next flow:
Remove items in observer on
sales_quote_save_before
and add some flag to registry:Mage::register('ooops_we_need_a_redirect', $url)
In observer on
sales_quote_save_after
do redirect if needed:if (Mage::registry('ooops_we_need_a_redirect')) { // do redirect }
精彩评论