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

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

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

gregdev
источник

Ответы:

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
Брайан,