Обнаружить изменение инвентаря


18

Мне нужно обнаруживать всякий раз, когда уровень запасов продукта изменяется. У меня был некоторый успех при использовании cataloginventory_stock_item_save_afterсобытия, которое срабатывает, когда инвентарь изменяется в бэкэнде или когда заказ отменяется на внешнем интерфейсе (через Paypal), но не срабатывает, когда продукт приобретается у внешнего интерфейса.

Я подключаюсь к cataloginventory_stock_item_save_afterтакому событию:

<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) {

Нужно ли использовать другое событие, чтобы зафиксировать изменение инвентаря, когда клиент что-то покупает, или что-то не так с тем, как я подключился к событию?

Ответы:


26

Некоторое время назад я что-то строил для этого, мне приходилось слушать нескольких наблюдателей, потому что они не все обрабатывались при сохранении каталога, мне нужен следующий код:

    <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>

И в обозревателе следующий код:

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());
       }
    }
}

Надеюсь, это то, что вы ищете.


Когда я использовал это как есть, он выдавал ошибку 500, когда отмена заказов и размещение заказов не работали. Мне пришлось удалить условие if ($ this-> isEnabled ()) из функций, чтобы это работало. Любая причина, почему это так? Это потому, что я использую тип Singleton? Спасибо
— Мустафа Элькаббани

5

Вы не можете использовать любое событие, связанное с моделью товара на складе, потому что Magento использует оптимизированный SQL-запрос, чтобы уменьшить запас для всех заказанных товаров одновременно, минуя модель.

Я решил это с переписать, Mage_CatalogInventory_Model_Stockгде я добавил дополнительное событие:

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

Тогда наблюдатель cataloginventory_stock_item_correct_qty_afterможет выглядеть так:

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

    }

Я рекомендую не выполнять тяжелую обработку или дополнительные вызовы базы данных (которые необходимы для определения, например, отсутствия товара на складе), а добавлять продукты в очередь, обрабатываемую cronjob, чтобы минимизировать дополнительное время загрузки для пользователь.


$stockItem->canSubtractQty()не работает в наблюдателе, ни есть $stockItem->getId().. какие-либо советы? Кажется, я не могу получить доступ к методам
— snh_nl

Фабиан, какова цель добавления пользовательских событий, поскольку вы можете добавить функцию с самой перезаписанной функцией? это только для развязки? Пожалуйста, руководство.
— Magento Learner

@MagentoLearner да, мне было проще использовать и добавлять различные функции. Технически вы могли бы также ввести частный метод вместо этого
— Фабиан Шменглер,

Это может включать переписывание базового класса, но это все еще самое полное решение здесь. Иногда вам просто нужно добавить свои собственные события на M1: P
— Брайан,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.