Magento 2 – Best Event to Listen for All Order State Changes

event-observermagento2order-statusorderssales-order

I want to observe every order state change and react depending on the old and new status. What is the best way to accomplish this in Magento 2?

It looks like there is the event sales_order_state_change_before but unfortunately it does not seem to fire on state changes. There is also a considerable list of other events which fire in some cases of order changes:
sales_order_invoice_pay
sales_order_payment_place_end
sales_order_payment_capture
sales_order_payment_pay
… just to name a few.

However I'm not exactly sure when which of above events fire and it definitely looks like they only fire in very special occasions. But I need a way which guaranteed covers all state changes and allows me to query the old and new status.
What is the best way to achieve this, am I missing an event or is there a better way than registering an observer?

Best Answer

As far as I know, we can use events: sales_order_save_after and sales_order_state_change_before. I refer sales_order_save_after event.

In our observer, we can get the state of order:

Observer/SalesOrderAfterSave.php

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $order = $observer->getEvent()->getOrder();
    if ($order instanceof \Magento\Framework\Model\AbstractModel) {
       if($order->getState() == 'canceled' || $order->getState() == 'closed') {
            //Your code here
       }
    }
    return $this;
}

We can read more about observer : Magento 2 events list

NOTE: We should try with Plugin:

etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <type name="Magento\Sales\Api\OrderRepositoryInterface">
        <plugin name="order_state_plugin"
                type="Company\Module\Model\Plugin\OrderStatePlugin"/>
    </type>

</config>

Plugin:

/**
 * @param \Magento\Sales\Api\OrderRepositoryInterface $subject
 * @param \Magento\Sales\Api\Data\OrderInterface $result
 * @return mixed
 * @throws \Exception
 */
public function afterSave(
    \Magento\Sales\Api\OrderRepositoryInterface $subject,
    $result
) {
    if($result->getState() == Order::STATE_COMPLETE) {
        ......
    }
    return $result;
}
Related Topic