Magento – Update Stock Levels Before Displaying Configurable Product Details

configurable-productevent-observerstock

When a product is viewed I need to go to an external system (using a web service), query the actual stock values and update them in magento before displaying the page. This is for a configurable product so I need to handle all the associated simple products.

I've implemented an event observer capturing the catalog_controller_product_init_before event and the Observer.php module has

public function loadBeforeProductObserve(Varien_Event_Observer $observer)   {
    $event = $observer->getEvent();
    $x = $event['controller_action'];
    $id = $x->getRequest()->getParam('id');
    $product = Mage::getModel('catalog/product')->load($id);

    $childProducts = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null,$product);

    foreach($childProducts as $child) {
        $stock = $child->getData("stock_item");

        if ($stock->getData("qty") == 0) {
            $stock->addData(array("qty"=>27, 'is_in_stock' => 1));
            //$stock->save();
        }
    }
}

Clearly this is running just to test the process in that it simply identifies any products with 0 stock and sets them to have 27 items.

My actual code is littered with print statements so I can see that it's finding all the right things and displaying the new values after the addData command (I've also tried setData) shows the values to be there.

When I try activating the save() function, the system fails and I get a 404 error for the page.

Without doing the save the product display is showing details as though the zero stock items are still zero and, indeed, capturing the catalog_controller_product_init_after event shows the value to be unchanged.

So what am I doing wrong?
What things could I be doing better?
How do I save the new stock value so that it will be used for the product display?

Best Answer

I just tried your exact code (with save enabled) on my Magento installation and it just works without modification.

There has to be another issue at your machine when it gives a 404 - maybe the product is disabled automatically (i.e. getting status attribute 0) as it was out of stock?

In addition, I refactored your code to avoid usages of array access ['controller_action'], addData and getData. It is best practice to use the magic methods instead.

Moreover, using the event catalog_controller_product_init passes a loaded product instance in its parameters so you don't have to do the loading yourself.

<events>
    <catalog_controller_product_init>
        <observers>
            <stackday>
                <class>stackday/observer</class>
                <method>updateInventoryOnProduct</method>
                <type>singleton</type>
            </stackday>
        </observers>
    </catalog_controller_product_init>
</events>

Observer:

/**
 * Update inventory on product.
 * 
 * @param Varien_Event_Observer $observer Observer.
 *
 * @throws Exception
 * 
 * @return void
 */
public function updateInventoryOnProduct(Varien_Event_Observer $observer)
{
    /** @var Mage_Catalog_Model_Product $product */
    $product = $observer->getProduct();

    if ($product->getTypeId() != Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE) {
        return;
    }

    $childProducts = Mage::getModel('catalog/product_type_configurable')
        ->getUsedProducts(null, $product);

    foreach ($childProducts as $child) {
        /** @var Mage_Catalog_Model_Product $child */

        /** @var Mage_CatalogInventory_Model_Stock_Item $stock */
        $stock = $child->getStockItem();

        if ($stock->getQty() == 0) {
            $stock->setQty(27);
            $stock->setIsInStock(1);
            $stock->save();
        }
    }
}

But even with this code, the product may be displayed as Out of Stock - as there is an indexer in play here. You would have to run cataloginventory_stock indexer programmatically after updating stock item.

Related Topic