In Magento 2.3.0, I need to execute a specific function when the order is shipped (the Ship action is triggered).

Basically, I am using the 'sales_order_save_after' event to check what's the current status, but the results are different in two situations as follows:

  1. For a new order, if I generate the invoice first and the shipping process, the observer that is executed following the 'sales_order_save_after' event says that the current status is complete which is correct.
  2. For a new order, if I don't generate the invoice and I just hit the 'Ship' button, the observer that is executed following the 'sales_order_save_after' event says that the current status is processing and not complete.

Why is this happening and how can I get the complete event when I hit the 'Ship' button, without going through preliminary steps such as invoicing?

3 Answers 3


For an order to be in status complete it must be invoiced and shipped.

You can check if an order is shipped by checking if it has a shipment instead of checking the order status. If you have the order object you can try:

if ($order->hasShipments()) {
      // your code here

Thank you, @Kristoffer.

However, the situation is a little bit different and I'm afraid that your answer is not covering the situations I have 100%.

Basically, the configuration area of my custom module settings contains an option that says "Order state when AWB should be generated". Users can choose a state from a dropdown when a third-party API should be called to generate an AWB.

Right now, the option that is set up is "Complete", but they can create a custom state and assign that as the order state where the AWB should be generated.

Coming back to your solution, it's good, but what if they ship ($order->hasShipments() == 1) and suddenly they cancel the order after, a situation when the order still has shipments, right? That call will be executed twice and I don't need that. Of course, I can make some tweaks and mark the AWB as generated for that order. Then, if it already has an AWB, another one shouldn't be generated.

Any solutions to this situation?

PS. For not explaining the whole situation, but things got changed in the past few hours.


It seems that the only situation when $order->getState() is not similar to the selected state is when the selected state is "complete". In this situation, $order->getState() is "processing" and I think I can treat this situation separately by including $order->hasShipments(). The rest of them seems to be ok.

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.