Credit Memos and Stock Availability in Magento

If, like many merchants using Magento, you have configured Magento to manage product stock levels, Magento will automatically return stock to product(s) should a credit memo get created for the product(s) ordered. However, there is a missing feature involving credit memos and stock availability in Magento.

If there is only a qty of 1 of a product and a customer places an order with the product in their basket, Magento will decrease the stock to 0. This happens if within System -> Configuration -> Catalog -> Inventory, the Automatically Return Credit Memo Item to Stock is set to Yesin the admin.

In addition, Magento will set the product’s availability to Out of Stock. Again, this is assuming that the Qty for Item's Status to Become Out of Stock system configuration option is set to 0.

So for that very same order, if a Credit Memo was issued, the item’s qty level would change from 0 to 1. However, the product’s Availability does not change back to In Stock.

This still happens in later versions of Magento 1.9 and above, however a simple custom module can be written to amend the availability.

Magento uses an Observer.php within its CatalogInventory module to return stock quantity to items after a credit memo is created. An observer can also be created within the custom module that changes the availability of products back to In Stock.

Start by adding the module’s declaration file.

<?xml version="1.0"?>
<config>
    <modules>
        <[Vendor]_[Module]>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_CatalogInventory />
            </depends>
        </[Vendor]_[Module]>
    </modules>
</config>   

Add the module’s config.xml that defines the Helper class.

<?xml version="1.0"?>
<config>
    <global>
        <helpers>
            <[vendor]_[module]>
                <class>[Vendor]_[Module]_Helper</class>
            </[vendor]_[module]>
        </helpers>
    </global>
</config>

Now add the module’s helper Data.php file. This doesn’t need to contain any functionality in this example.

<?php
class [Vendor]_[Module]_Helper_Data extends Mage_Core_Helper_Abstract {}

Amend the config.xml to include the observer file used to observe the sales_order_creditmemo_save_after event.

<?xml version="1.0"?>
<config>
    <global>
        <helpers>
            <[vendor]_[module]>
                <class>[Vendor]_[Module]_Helper</class>
            </[vendor]_[module]>
        </helpers>
        <models>
            <[vendor]_[module]>
                <class>[Vendor]_[Module]_Model</class>
            </[vendor]_[module]>
        </models>
        <events>
            <sales_order_creditmemo_save_after>
                <observers>
                    <[vendor]_[module]>
                        <class>[vendor]_[module]/observer</class>
                        <method>refundOrderInventory</method>
                    </[vendor]_[module]>
                </observers>
            </sales_order_creditmemo_save_after>
        </events>
    </global>
</config>

And lastly, create the Observer.php file where the Mage_Catalog_Model_Product object can be retrieved and subsequently, the getStockItem() and isInStock() methods can be used.

<?php
class [Vendor]_[Module]_Model_Observer
{
    /**
     * Return creditmemo items qty to stock
     *
     * @param Varien_Event_Observer $observer
     */
    public function refundOrderInventory($observer)
    {
        $creditmemo = $observer->getEvent()->getCreditmemo();
        foreach ($creditmemo->getAllItems() as $item) {
            $return = false;
            if ($item->hasBackToStock()) {
                if ($item->getBackToStock() && $item->getQty()) {
                    $return = true;
                }
            } elseif (Mage::helper('cataloginventory')->isAutoReturnEnabled()) {
                $return = true;
            }

            if ($return) {
                $productId = $item->getProductId();
                $product = Mage::getModel('catalog/product')->load($productId);

                if (!$product->isConfigurable()) {
                    $stockItem = $product->getStockItem();
                    $stockItem->setIsInStock(1);
                    $stockItem->save();
                }
            }
        }
    }
}

Refresh the Magento cache and test out placing orders and creating credit memos, and you should notice that the product’s Availability correctly changes to In Stock.

Note: This article is based on Magento Community/Open Source version 1.9.