You cannot use any event related to the stock item model, because Magento uses an optimized SQL query to decrease stock for all ordered items at once, bypassing the model.
I solved this with a rewrite of Mage_CatalogInventory_Model_Stock where I added an additional event:
<?php /** * Add events to observe stock qty change * * @author Fabian Schmengler * */ class SGH_ShippingExpress_Model_CatalogInventory_Stock extends Mage_CatalogInventory_Model_Stock { const EVENT_CORRECT_STOCK_ITEMS_QTY_BEFORE = 'cataloginventory_stock_item_correct_qty_before'; const EVENT_CORRECT_STOCK_ITEMS_QTY_AFTER = 'cataloginventory_stock_item_correct_qty_after'; /** * (non-PHPdoc) * @see Mage_CatalogInventory_Model_Stock::registerProductsSale() */ public function registerProductsSale($items) { Mage::dispatchEvent(self::EVENT_CORRECT_STOCK_ITEMS_QTY_BEFORE, array( 'stock' => $this, 'items_obj' => (object)array('items' => &$items), 'operator' => '-' )); $result = parent::registerProductsSale($items); Mage::dispatchEvent(self::EVENT_CORRECT_STOCK_ITEMS_QTY_AFTER, array( 'stock' => $this, 'items' => $items, 'fullsave_items' => $result, 'operator' => '-' )); return $result; } /** * (non-PHPdoc) * @see Mage_CatalogInventory_Model_Stock::revertProductsSale() */ public function revertProductsSale($items) { Mage::dispatchEvent(self::EVENT_CORRECT_STOCK_ITEMS_QTY_BEFORE, array( 'stock' => $this, 'items_obj' => (object)array('items' => &$items), 'operator' => '+' )); $result = parent::revertProductsSale($items); Mage::dispatchEvent(self::EVENT_CORRECT_STOCK_ITEMS_QTY_AFTER, array( 'stock' => $this, 'items' => $items, 'fullsave_items' => $result, 'operator' => '+' )); return $result; } }
Then the observer for cataloginventory_stock_item_correct_qty_after can look like this:
/** * @var $items array array($productId => array('qty'=>$qty, 'item'=>$stockItem)) */ $items = $observer->getItems(); foreach ($items as $productId => $item) { $stockItem = $item['item']; $product = $stockItem->getProduct(); // Do anything you need with $stockItem and $product here }
I recommend not to do heavy processing or additional database calls (which are necessary to detect if the product is out of stock for example), but to add the products to a queue that is processed by a cronjob, to minimize additional load time for the user.