skip to Main Content

I’m developing a procedure that has to programatically create shipment for orders that are already paid and invoiced.

The problem is that even after creating the shipment, the order status remains to ‘processing’ instead of going to ‘complete’.
This does not happen if I manually Ship from the backend.

I found that the problem is that the quantity shipped for the order items is not updated, but remains 0 after saving the shipment and the order.

This is the procedure i’m using.
No exception is issued, and shipment is correctly created.

    $orders = $this->_orderCollectionFactory->create()
        ->addAttributeToSelect('*')
        ->addFieldToFilter( 'entity_id' , array('in' => $ordersIdsArr) )
        ->setOrder('created_at', 'desc' );   

    foreach ($orders as $index => $order) {
        if ($order->canShip()) { 
           $shipment = $this->_convertOrder->toShipment($order);;
           $orderItems = $order->getItemsCollection()->addAttributeToSelect('*')->load();

           foreach ($orderItems as $orderItem) {
                if (! $orderItem->getQtyToShip() || $orderItem->getIsVirtual()) {
                    continue;
                }
                $qtyShipped = $orderItem->getQtyToShip();
                $shipmentItem = $this->_convertOrder->itemToShipmentItem($orderItem)->setQty($qtyShipped);
                $shipment->addItem($shipmentItem); 
            }
            $shipment->register();
            $shipment->getOrder()->setIsInProcess(true);
    
            try {

                $saveTransaction = $this->_transactionFactory->create();
                $saveTransaction->addObject($shipment)
                    ->addObject($shipment->getOrder());
                $saveTransaction->save();
            } catch (Exception $e) {
               
            }
        }
    }

    /*..........*/

3

Answers


  1. Chosen as BEST ANSWER

    After struggling for 2 days on this, trying to understand what the problem was, studying Magento core classes for module-sales, I found someone on Magento community who had similar problems with Magento API and developed a patch.

    The problem is from one year ago, but doesn't seem to have been addressed in subsequent versions of Magento, so I decided to adopt the same solution as the extension does, hence forcing the shipped quantity of order items to be equal to the quantity to ship, and then, save the order again.

    Well, it is just a patch and dunno if it is a general problem, but to me it has been the only way to make this work, and get finally the order in status of 'Complete'.

    I added this code after the first save of the order:

    try {
            $saveTransaction = $this->_transactionFactory->create();
            $saveTransaction->addObject($shipment)
                 ->addObject($shipment->getOrder());
            $saveTransaction->save();
    
            $itemsCheck = $order->getItemsCollection()->addAttributeToSelect('*')->load();
            foreach ($itemsCheck as $item) {
                if (! $item->getQtyToShip() || $item->getIsVirtual()) { 
                       continue;
                }
                $item->setQtyShipped($item->getQtyToShip());
                $item->save();
                $Norder = $shipment->getOrder()->load( $shipment->getOrder()->getId() );
                $Norder->save();
            }
        } 
    

    Hope it can be of help for someone else.


  2. If you take a look at the SOAP API for creating shipments (Mage_Sales_Model_Order_Shipment_Api::create(…)), you see that this is done automatically when you save the order in the same transaction.

        /* @var $shipment Mage_Sales_Model_Order_Shipment */
        $shipment = $order->prepareShipment($itemsQty);
        if ($shipment) {
            $shipment->register();
            $shipment->addComment($comment, $email && $includeComment);
            if ($email) {
                $shipment->setEmailSent(true);
            }
            $shipment->getOrder()->setIsInProcess(true);
            try {
                $transactionSave = Mage::getModel('core/resource_transaction')
                    ->addObject($shipment)
                    ->addObject($shipment->getOrder())
                    ->save();
                $shipment->sendEmail($email, ($includeComment ? $comment : ''));
            } catch (Mage_Core_Exception $e) {
                $this->_fault('data_invalid', $e->getMessage());
            }
            return $shipment->getIncrementId();
        }
    

    I’ve also noted that I can create tracking (Mage_Sales_Model_Order_Shipment_Track) and add it to the shipment before saving, and also add the tracking to the transaction:

        $track = Mage::getModel('sales/order_shipment_track')
            ->setNumber($trackingNumber)
            ->setCarrierCode($carrier)
            ->setTitle($serviceTitle);
    
        $shipment->addTrack($track);
        $transactionSave = Mage::getModel('core/resource_transaction')
            ->addObject($shipment)
            ->addObject($shipment->getOrder())
            ->addObject($track)
            ->save();
    

    So, no need to do that Magento-magic yourself.

    Login or Signup to reply.
  3. I got the same issue, but in my case, I found that after the shipment register, the sales order save the relations again make the qty_shipped to 0.

    So my solution for this is add a plugin to MagentoSalesModelOrderShipment::register() like this:

    public function aroundRegister(
        MagentoSalesModelOrderShipment $subject,
        Closure $proceed
    ) {
        if ($subject->getId()) {
            throw new MagentoFrameworkExceptionLocalizedException(
                __('We cannot register an existing shipment')
            );
        }
    
        $totalQty = 0;
    
        $orderItems = [];
        /** @var MagentoSalesModelOrderShipmentItem $item */
        foreach ($subject->getAllItems() as $item) {
            if ($item->getQty() > 0) {
                $item->register();
                $orderItems[] = $item->getOrderItem();
                if (!$item->getOrderItem()->isDummy(true)) {
                    $totalQty += $item->getQty();
                }
            }
        }
    
        //make sure the updated Item be set in order so the save order relation will be correct
        $subject->getOrder()->setItems($orderItems);
    
        $subject->setTotalQty($totalQty);
    
        return $subject;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search