재고 변경 감지


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 ()) 조건을 삭제해야했습니다. 이것이 왜 그런가? 싱글 톤 타입을 사용하고 있기 때문입니까? 감사합니다
Moustafa Elqabbany

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

Fabian, 덮어 쓴 함수 자체로 기능을 추가 할 수 있으므로 여기에 사용자 정의 이벤트를 추가하는 목적은 무엇입니까? 이것은 단지 분리하는 것입니까? 안내해주세요.
Magento Learner

@MagentoLearner 예, 다른 기능을 재사용하고 추가하기가 더 쉬워졌습니다. 기술적으로 대신 개인 방법을 도입 할 수도 있습니다
Fabian Schmengler

핵심 클래스를 다시 작성해야 할 수도 있지만 여전히 가장 완벽한 솔루션입니다. 때로는 M1 : P
Brian
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.