9

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?

1 Answer 1

17

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;
}
9
  • This is better than the events I knew of so far but it is not firing when the customer creates the order with an initial "pending" state. I'm not sure if there are more cases where it is not triggered. By the way, do you know of a complete Magento 2 event list? Mine seems incomplete.
    – Jey DWork
    Commented Jul 11, 2016 at 15:15
  • 1
    Regarding the list, there is already a topic: magento.stackexchange.com/questions/87738/magento-2-events-list
    – Jey DWork
    Commented Jul 11, 2016 at 15:21
  • As far as I know, by default, Magento doesn't have pending state, it's a status. There are some default states: new, pending_payment, processing, complete, closed, canceled, holded, payment_review. We should take a look vendor/magento/module-sales/Model/Order.php Commented Jul 11, 2016 at 15:28
  • You are completely right, the state I was referring to is new ("Pending" is what it says in the Backend). And I'm still having a hard time to react to newly placed orders by customers. sales_order_place_after is not firing and all my other attempts aren't as well. One should guess this is a basic task :/
    – Jey DWork
    Commented Jul 11, 2016 at 19:24
  • 1
    @KhoaTruongDinh how can I get the orders old and new data and get the difference in my custom table?
    – Mohit Rane
    Commented Aug 8, 2019 at 10:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.