Question

I am using sales_order_save_after event to change order status. It's working fine for all order status except STATE_COMPLETE. when i set the order status STATE_COMPLETE to make order Complete but it changed to Closed instead of being Complete. Other order States is working fine. The issue only happening when i try to use STATE_COMPLETE.

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $order = $observer->getEvent()->getOrder();
       if($order->getState() != 'complete') {
            $order->setState(\Magento\Sales\Model\Order::STATE_COMPLETE)->setStatus(\Magento\Sales\Model\Order::STATE_COMPLETE);
            $order->save();
       }
}

This is what i'm doing

Can anyone help me out to make order status to "Complete" via observer ?

Was it helpful?

Solution

Ok, so the problem was when i set STATE_COMPLETE Magento make the order closed. But if i set STATE_PROCESSING or STATE_PENDING with status Complete then order status show complete but when i view the order details there it show processing/pending. So i tried to figure out when magento make order status complete and it is when a invoice is generated.

So i use checkout_submit_all_after event and create an invoice through my observer. When i create invoice through my observer magento make the order completed because the invoice is generated.

Here's the observer code -

class CheckoutSubmitAllAfter implements ObserverInterface{

protected $_invoiceService;
protected $_transactionFactory;

public function __construct(
  \Magento\Sales\Model\Service\InvoiceService $invoiceService,
  \Magento\Framework\DB\TransactionFactory $transactionFactory
) {
   $this->_invoiceService = $invoiceService;
   $this->_transactionFactory = $transactionFactory;
}

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $order = $observer->getEvent()->getOrder();

    try {
        if(!$order->canInvoice()) {
            return null;
        }
        if(!$order->getState() == 'new') {
            return null;
        }

        $invoice = $this->_invoiceService->prepareInvoice($order);
        $invoice->setRequestedCaptureCase(\Magento\Sales\Model\Order\Invoice::CAPTURE_ONLINE);
        $invoice->register();

        $transaction = $this->_transactionFactory->create()
          ->addObject($invoice)
          ->addObject($invoice->getOrder());

        $transaction->save();

    } catch (\Exception $e) {
        $order->addStatusHistoryComment('Exception message: '.$e->getMessage(), false);
        $order->save();
        return null;
    }
}}

OTHER TIPS

Please try following code:

use \Magento\Sales\Model\Order;

public function execute(\Magento\Framework\Event\Observer $observer)
{
    $order = $observer->getEvent()->getOrder();

    if($order->getState() != Order::STATE_COMPLETE) {

        $orderState = Order::STATE_COMPLETE;

        // set order status to COMPLETE
        $order->setState($orderState)->setStatus(Order::STATE_COMPLETE);

        // Save order
        $order->save();
    }
}

Hope it Works!

Please take note that invoking the the save method of the order would trigger a state check which might explain why you are experiencing the issue.

Magento 2 has a separate class for checking the order state.

In the Magento\Sales\Model\ResourceModel\Order class you will find the save method invoking state check

public function save(\Magento\Framework\Model\AbstractModel $object)
    {
        /** @var \Magento\Sales\Model\Order $object */
        $this->stateHandler->check($object);
        return parent::save($object);
    }

The stateHandler is an instance of Magento\Sales\Model\ResourceModel\Order\Handler\State

I would recommend that you have a look that the method "check" to trace the logic flow.

You could either override the method check or create a plugin aroundCheck to change the state logic flow

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top