Détecter la variation d'inventaire


18

Je dois détecter chaque fois que le niveau de stock d'un produit change. J'ai eu un certain succès en utilisant l' cataloginventory_stock_item_save_afterévénement qui est déclenché lorsque l'inventaire est modifié dans le backend, ou lorsqu'une commande est annulée sur le frontend (via Paypal), mais n'est pas déclenchée lorsqu'un produit est acheté sur le frontend.

Je me connecte à l' cataloginventory_stock_item_save_afterévénement comme ceci:

<global>
    <events>
        <cataloginventory_stock_item_save_after>
            <observers>
                <cataloginventory_stock_item_save_after_handler>
                    <type>model</type>
                    <class>stockchange/observer</class>
                    <method>stockChange</method>
                </cataloginventory_stock_item_save_after_handler>
            </observers>
        </cataloginventory_stock_item_save_after>
    </events>

<?php
class FashionBunker_StockChange_Model_Observer {
    public function stockChange(Varien_Event_Observer $observer) {

Dois-je utiliser un autre événement pour capturer la variation de stock lorsqu'un client achète quelque chose, ou y a-t-il un problème avec la façon dont je me suis connecté à l'événement?

Réponses:


26

Il y a quelque temps, je construis quelque chose pour cela, j'ai dû écouter plusieurs observateurs car ils n'étaient pas tous gérés par la sauvegarde de l'inventaire du catalogue, je dois suivre le code:

    <events>
        <cataloginventory_stock_item_save_commit_after>
            <observers>
                <genmato_stockupdate>
                    <class>genmato_stockupdate/observer</class>
                    <method>catalogInventorySave</method>
                </genmato_stockupdate>
            </observers>
        </cataloginventory_stock_item_save_commit_after>
        <sales_model_service_quote_submit_before>
            <observers>
                <genmato_stockupdate>
                    <class>genmato_stockupdate/observer</class>
                    <method>subtractQuoteInventory</method>
                </genmato_stockupdate>
            </observers>
        </sales_model_service_quote_submit_before>
        <sales_model_service_quote_submit_failure>
            <observers>
                <genmato_stockupdate>
                    <class>genmato_stockupdate/observer</class>
                    <method>revertQuoteInventory</method>
                </genmato_stockupdate>
            </observers>
        </sales_model_service_quote_submit_failure>
        <sales_order_item_cancel>
            <observers>
                <genmato_stockupdate>
                    <class>genmato_stockupdate/observer</class>
                    <method>cancelOrderItem</method>
                </genmato_stockupdate>
            </observers>
        </sales_order_item_cancel>
        <sales_order_creditmemo_save_after>
            <observers>
                <genmato_stockupdate>
                    <class>genmato_stockupdate/observer</class>
                    <method>refundOrderInventory</method>
                </genmato_stockupdate>
            </observers>
        </sales_order_creditmemo_save_after>
    </events>

Et dans l'observateur le code suivant:

public function catalogInventorySave(Varien_Event_Observer $observer)
{
    if ($this->isEnabled()) {
        $event = $observer->getEvent();
        $_item = $event->getItem();

        if ((int)$_item->getData('qty') != (int)$_item->getOrigData('qty')) {
            $params = array();
            $params['product_id'] = $_item->getProductId();
            $params['qty'] = $_item->getQty();
            $params['qty_change'] = $_item->getQty() - $_item->getOrigData('qty');
        }
    }
}

public function subtractQuoteInventory(Varien_Event_Observer $observer)
{
    if ($this->isEnabled()) {
        $quote = $observer->getEvent()->getQuote();
        foreach ($quote->getAllItems() as $item) {
            $params = array();
            $params['product_id'] = $item->getProductId();
            $params['sku'] = $item->getSku();
            $params['qty'] = $item->getProduct()->getStockItem()->getQty();
            $params['qty_change'] = ($item->getTotalQty() * -1);
        }
    }
}

public function revertQuoteInventory(Varien_Event_Observer $observer)
{
    if ($this->isEnabled()) {
        $quote = $observer->getEvent()->getQuote();
        foreach ($quote->getAllItems() as $item) {
            $params = array();
            $params['product_id'] = $item->getProductId();
            $params['sku'] = $item->getSku();
            $params['qty'] = $item->getProduct()->getStockItem()->getQty();
            $params['qty_change'] = ($item->getTotalQty());
        }
    }
}

public function cancelOrderItem(Varien_Event_Observer $observer)
{
    if ($this->isEnabled()) {
        $item = $observer->getEvent()->getItem();
        $qty = $item->getQtyOrdered() - max($item->getQtyShipped(), $item->getQtyInvoiced()) - $item->getQtyCanceled();
        $params = array();
        $params['product_id'] = $item->getProductId();
        $params['sku'] = $item->getSku();
        $params['qty'] = $item->getProduct()->getStockItem()->getQty();
        $params['qty_change'] = $qty;
    }
}

public function refundOrderInventory(Varien_Event_Observer $observer)
{
    if ($this->isEnabled()) {
        $creditmemo = $observer->getEvent()->getCreditmemo();
        foreach ($creditmemo->getAllItems() as $item) {
            $params = array();
            $params['product_id'] = $item->getProductId();
            $params['sku'] = $item->getSku();
            $params['qty'] = $item->getProduct()->getStockItem()->getQty();
            $params['qty_change'] = ($item->getQty());
       }
    }
}

J'espère que c'est un peu ce que vous recherchez.


Lorsque je l'ai utilisé tel quel, cela a produit une erreur de serveur 500 lorsque l'annulation des commandes et le placement des commandes ne fonctionnaient pas. J'ai dû supprimer la condition if ($ this-> isEnabled ()) des fonctions pour que cela fonctionne. Une raison pour laquelle c'est le cas? Est-ce parce que j'utilise le type singleton? Merci
Moustafa Elqabbany

5

Vous ne pouvez utiliser aucun événement lié au modèle d'article en stock, car Magento utilise une requête SQL optimisée pour réduire le stock de tous les articles commandés en même temps, en contournant le modèle.

J'ai résolu cela avec une réécriture de l' Mage_CatalogInventory_Model_Stockendroit où j'ai ajouté un événement supplémentaire:

<?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;
    }
}

L'observateur cataloginventory_stock_item_correct_qty_afterpeut alors ressembler à ceci:

    /**
     * @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

    }

Je recommande de ne pas effectuer de traitement lourd ou d'appels de base de données supplémentaires (qui sont nécessaires pour détecter si le produit est en rupture de stock par exemple), mais pour ajouter les produits à une file d'attente qui est traitée par un cronjob, pour minimiser le temps de chargement supplémentaire pour le utilisateur.


$stockItem->canSubtractQty()ne fonctionne pas dans l'observateur ni $stockItem->getId().. aucune astuce? Semble que je ne peux pas accéder aux méthodes
snh_nl

Fabian, quel est le but d'ajouter des événements personnalisés ici car vous pouvez ajouter la fonctionnalité avec la fonction remplacée elle-même? est-ce seulement pour découpler? Veuillez guider.
Magento Learner

@MagentoLearner oui, cela m'a facilité la réutilisation et l'ajout de différentes fonctionnalités. Techniquement, vous pouvez également introduire une méthode privée à la place
Fabian Schmengler

Cela peut impliquer la réécriture d'une classe principale, mais c'est toujours la solution la plus complète ici. Parfois, il vous suffit d'ajouter vos propres événements sur M1: P
Brian
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.