7

In Magento 2 how can I programmatically ship a order? I am currently developing a custom XML order import, which sends requests to a SOAP back office service. This service replies with the order entity_id and order. status.

In the mean while I am loading the order by entity_idvia the \Magento\Sales\Api\OrderRepositoryInterface class. I haven't been able to find any method that ships the order.

1
  • This is for Magento 1 amitbera.com/… But it will help you to get Idea & u can convert code in Magento 2
    – Jackson
    Sep 8, 2016 at 2:56

6 Answers 6

12

This is how i managed to create shipment. Hope this will help:

protected $container;

protected $orderInterface;

/**
 * @var \Magento\Sales\Model\Order\Shipment\TrackFactory
 */
protected $trackingFactory;

/**
 * @var \Magento\Sales\Api\Data\ShipmentCommentCreationInterface
 */
protected $commentInterface;

/**
 * @var \Magento\Sales\Model\ShipOrder
 */
protected $shipOrderService;

/**
 * @var \Magento\Sales\Model\Convert\Order
 */
protected $orderConverter;


/**
 * ShipmentManager constructor.
 */
public function __construct()
{
    //this is instance of my custom class to get instance object manager.
    $this->container = Container::getInstance();


    //order interface
    $this->orderInterface = $this->container->get(
        \Magento\Sales\Api\Data\OrderInterface::class
    );

    //instance of tracking factory to add tracking number in shipment
    $this->trackingFactory = $this->container->get(
        \Magento\Sales\Model\Order\Shipment\TrackFactory::class
    );

    //Comment interface to add comment on the shipment.
    $this->commentInterface = $this->container->get(
        \Magento\Sales\Api\Data\ShipmentCommentCreationInterface::class
    );

    //Shipment order service to create shipment
    $this->shipOrderService = $this->container->get(
        \Magento\Sales\Model\ShipOrder::class
    );

    //Order converter to create shipment items
    $this->orderConverter = $this->container->get(
        \Magento\Sales\Model\Convert\Order::class);
}

/**
 * Prepares tracking data form tracking number.
 *
 * @param $trackingNumber
 *
 * @return \Magento\Sales\Model\Order\Shipment\Track
 */
protected function setTrackingData($trackingNumber)
{
    $track = $this->trackingFactory->create();
    $track->setTrackNumber($trackingNumber);
    //Carrier code can not be null/empty. Default carrier code is used
    $track->setCarrierCode('custom');//Put your carrier code here
    $track->setTitle('');//add your title here
    $trackInfo[] = $track;

    return $trackInfo;
}

/**
 * @param string $comment
 *
 * @return \Magento\Sales\Api\Data\ShipmentCommentCreationInterface
 */
protected function setShipmentComment($comment)
{
    //comment can not be empty
    $comment = !empty($comment) ? $comment : 'Not Available';

    return $this->commentInterface->setComment($comment);
}

/**
 * {@inheritdoc}
 */
public function createShipment($orderIncrementId, array $items, $comment = null, $notify = false,
    $includeComment = false, $trackingNumber = '')
{
    $order = $this->orderInterface->loadOrderByIncrementId($orderIncrementId);

    if ($order->canShip()) {
        try {
            $orderId = $order->getId();
            $tracks = $this->setTrackingData($trackingNumber);
            $comment = $this->setShipmentComment($comment);
            $shippedItems = $this->createShipmentItems($items, $order);

            //creates shipment 
            $shipmentId = $this->shipOrderService->execute($orderId,
                $shippedItems,
                $notify,
                $includeComment,
                $comment,
                $tracks);
        } catch (\Exception $e) {
            echo $e->getMessage();
        }

        return $shipmentId;
    }

    return null;
}

/**
 * Create shipment items required to create shipment.
 *
 * @param array                      $items
 * @param \Magento\Sales\Model\Order $order
 *
 * @return array
 */
protected function createShipmentItems(array $items, $order)
{
    $shipmentItem = [];
    foreach ($order->getAllItems() as $orderItem) {
        if (array_key_exists($orderItem->getId(), $items)) {
            $shipmentItem[] = $this->orderConverter
                ->itemToShipmentItem($orderItem)
                ->setQty($items[$orderItem->getId()]);
        }
    }

    return $shipmentItem;
}
6
  • 1
    After trying multiple other answers to this question, not just here but other stackexchange questions, yours is the only one that worked. I only had to change one thing, loadOrderByIncrementId is now loadByIncrementId. loadOrderByIncrementId doesn't exist anymore.
    – user44406
    Mar 24, 2018 at 10:41
  • 1
    Than you @Wolfe . Sorry the method loadOrderByIncrementId was something i created in my custom order interface class and forgot to change it while i was posted the answer. Anyways good to know my answer helped you May 4, 2018 at 0:53
  • 2
    Check \Magento\Sales\Api\ShipOrderInterface, it is a much simpler way Jul 30, 2018 at 9:48
  • @SarjanGautam where should i put this code, and how to execute it? Apr 9, 2019 at 18:06
  • @KrisWen, in my case i have used this script in integration code to receive order shipment info (tracjking number, items, qty) from external system and create shipment in magento. You might need to create your module or class similar to above one (exact same code might not work in your case). Please note that my class above is to give idea how shipment can be created and what services can be used.Implementation to match your requirement could be different. Apr 23, 2019 at 23:25
5

You can practice more with this until you'll find exactly what you are searching for.

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$_order = $objectManager->create('\Magento\Sales\Model\Order');
$order = $_order->load(1);
if (!$order->canShip()) {
    throw new \Magento\Framework\Exception\LocalizedException(
        __('You can\'t create an shipment.')
    );
}

$packageParams = array();
$packageParams['width'] = 100;
$packageParams['length'] = 100;
$packageParams['height'] = 100;
$packageParams['weight'] = 1;

$convertOrder = $objectManager->create('\Magento\Sales\Model\Convert\Order');
$shipment = $convertOrder->toShipment($order);

$package = array();

$packaging = array(
    'items' => array()
);

$subtotal = 0;
foreach ($order->getAllItems() AS $orderItem) {
    if (! $orderItem->getQtyToShip() || $orderItem->getIsVirtual()) {
        continue;
    }
    $qtyShipped = $orderItem->getQtyToShip();
    $shipmentItem = $convertOrder->itemToShipmentItem($orderItem)->setQty($qtyShipped);
    $packaging['items'][$shipmentItem->getOrderItemId()] = array(
        'qty' => $shipmentItem->getQty(),
        'custom_value' => $shipmentItem->getPrice(),
        'price' => $shipmentItem->getPrice(),
        'name' => $shipmentItem->getName(),
        'weight' => $shipmentItem->getWeight(),
        'product_id' => $shipmentItem->getProductId(),
        'order_item_id' => $shipmentItem->getOrderItemId()
    );
    $subtotal += $shipmentItem->getRowTotal();
    $shipment->addItem($shipmentItem);
}

if(empty($packaging['items']))
{   
    throw new \Magento\Framework\Exception\LocalizedException(__('No items to ship'));
}

$packaging['params'] = array(
            'container' => '',
            'weight' => $packageParams['weight'],
            'custom_value' => $subtotal,
            'length' => $packageParams['length'],
            'width' => $packageParams['width'],
            'height' => $packageParams['height'],
            'weight_units' => 'KILOGRAM',
            'dimension_units' => 'CENTIMETER',
            'content_type' => '',
            'content_type_other' => ''
);
$package[] = $packaging;

$shipment->setPackages($package);
$shipment->register();
$shipment->getOrder()->setIsInProcess(true);
try {
    $shipment->save();
    $shipment->getOrder()->save();
    $notify = $objectManager->create('Magento\Shipping\Model\ShipmentNotifier');
    $notify->notify($shipment);
    $shipment->save();
} catch (\Exception $e) {
    throw new \Magento\Framework\Exception\LocalizedException(
        __($e->getMessage())
    );
}
2
  • can you tell me please how i set the height width and length and weight lke $skuArray[] = array("sku"=>$item['sku'] this ? Mar 3, 2017 at 13:53
  • @catalin lonita this answer is helpful for me. can u please help me how to set custom filed value in shipment items table. same as qty Mar 16, 2019 at 13:03
3

You can use \Magento\Sales\Api\ShipOrderInterface::execute, just pass order_id as first param.

2
  • Best answer.... Mar 26, 2021 at 13:03
  • Thanks it was a very simple way, shipment is creating but the email is not sending. Any Idea?
    – Mujahidh
    Oct 3, 2022 at 6:17
2

To Create partial or complete Shipment with updating shipping qty follow below code

<?php

protected function _prepareShipment($order,$items)
    {
        $shipmentFactory = $objectManager->create('\Magento\Sales\Model\Convert\Order');
        $shipment = $shipmentFactory->create($order,$items);

        if (!$shipment->getTotalQty()) {
            return false;
        }

        return $shipment->register();
    }

    $items = [];
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    $_order = $objectManager->create('\Magento\Sales\Model\Order');
    $order = $_order->load(1);

    foreach ($order->getAllItems() AS $orderItem) {
        if (! $orderItem->getQtyToShip() || $orderItem->getIsVirtual()) {
            continue;
        }
        $qtyShipped = $orderItem->getQtyToShip();
        $items[$orderItem->getId()] = $qtyShipped;
    }

    if($shipment = $this->_prepareShipment($this->_order,$items)) {

        $track = $objectManager->create('\Magento\Sales\Model\Order\Shipment\TrackFactory')->create();
        $track->setNumber('1111111111');
        $track->setCarrierCode('custom');
        $track->setTitle('Shipment Tracking Number');
        $track->setDescription("Description"));
        $track->setUrl($tracking['url']);
        $shipment->addTrack($track);

    }else{
        echo 'Already Processed';
    }

?>
1
  • Tracking url not working after generate the shipment with all tracking information. please advice Feb 7, 2018 at 5:38
0

Sending shipment email loading by shipment id,

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$shipmentModel = $objectManager->get('\Magento\Sales\Model\Order\Shipment');
$shipmentSender = $objectManager->get('\Magento\Sales\Model\Order\Email\Sender\ShipmentSender');
         
$shipment = $shipmentModel->load(ShipmentID);
$shipmentSender->send($shipment, true);
0
//Load the order by increment ID

$order = $this->_objectManager->create('Magento\Sales\Model\Order')->loadByIncrementID($incrementid);

// OR Load the order by increment ID

$order = $this->_objectManager->create('Magento\Sales\Model\Order')
    ->loadByAttribute('increment_id', '000000001');


OR, Load by order ID
$order = $this->_objectManager->create('Magento\Sales\Model\Order')
    ->load('1');

// Check if order can be shipped or has already shipped
if (! $order->canShip()) {
    throw new \Magento\Framework\Exception\LocalizedException(
                    __('You can\'t create an shipment.')
                );
}

// Initialize the order shipment object
$convertOrder = $this->_objectManager->create('Magento\Sales\Model\Convert\Order');
$shipment = $convertOrder->toShipment($order);

// Loop through order items
foreach ($order->getAllItems() AS $orderItem) {
    // Check if order item has qty to ship or is virtual
    if (! $orderItem->getQtyToShip() || $orderItem->getIsVirtual()) {
        continue;
    }

    $qtyShipped = $orderItem->getQtyToShip();

    // Create shipment item with qty
    $shipmentItem = $convertOrder->itemToShipmentItem($orderItem)->setQty($qtyShipped);

    // Add shipment item to shipment
    $shipment->addItem($shipmentItem);
}

// Register shipment
$shipment->register();

$shipment->getOrder()->setIsInProcess(true);

try {
    // Save created shipment and order
    $shipment->save();
    $shipment->getOrder()->save();

    // Send email
    $this->_objectManager->create('Magento\Shipping\Model\ShipmentNotifier')
        ->notify($shipment);

    $shipment->save();
} catch (\Exception $e) {
    throw new \Magento\Framework\Exception\LocalizedException(
                    __($e->getMessage())
                );
}

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.