Hello Guys!
Welcome back to my blog. There are many tutorials and stack Exchange answers available for programmatically create a shipment in Magento 2. But today in this article I’ll talk about how we can programmatically create a shipment in multi stock inventory MSI in Magento 2.
For MSI we need to assign a source to shipment. So here is the basic steps to find source with ordered by priority and assgjned to the shipment
- First of all, we need to find stock Id by class
Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface
- Then we need to find the source code ordered by priority by class
Magento\InventoryApi\Api\GetSourcesAssignedToStockOrderedByPriorityInterface
- If there is no source added, it means it has a default source. So we need to assign the default source to the shipment. we can find default source code by class
Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface
- Now we need to assign source code to the shipment extension attributes and save shipment.
Here is the sample code for create shipment
<?php namespace MagePrince\Shipment\Model; use Magento\InventoryApi\Api\GetSourcesAssignedToStockOrderedByPriorityInterface; use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; use Magento\Sales\Model\Convert\Order as ConvertOrder; use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\ShipmentRepository; use Magento\Sales\Model\OrderRepository; use Magento\Shipping\Model\ShipmentNotifier; use Psr\Log\LoggerInterface; use Magento\Framework\Exception\LocalizedException; class CreateShipment { /** * @var LoggerInterface */ private $logger; /** * @var OrderRepository */ private $orderRepository; /** * @var ConvertOrder */ private $convertOrder; /** * @var StockByWebsiteIdResolverInterface */ private $stockByWebsiteIdResolver; /** * @var GetSourcesAssignedToStockOrderedByPriorityInterface */ private $getSourcesAssignedToStockOrderedByPriority; /** * @var DefaultSourceProviderInterface */ private $defaultSourceProvider; /** * @var ShipmentNotifier */ private $shipmentNotifier; /** * @var ShipmentRepository */ private $shipmentRepository; /** * ProcessUpdateOrder constructor. * @param LoggerInterface $logger * @param OrderRepository $orderRepository * @param ConvertOrder $convertOrder * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param GetSourcesAssignedToStockOrderedByPriorityInterface $getSourcesAssignedToStockOrderedByPriority * @param DefaultSourceProviderInterface $defaultSourceProvider * @param ShipmentNotifier $shipmentNotifier * @param ShipmentRepository $shipmentRepository */ public function __construct( LoggerInterface $logger, OrderRepository $orderRepository, ConvertOrder $convertOrder, StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, GetSourcesAssignedToStockOrderedByPriorityInterface $getSourcesAssignedToStockOrderedByPriority, DefaultSourceProviderInterface $defaultSourceProvider, ShipmentNotifier $shipmentNotifier, ShipmentRepository $shipmentRepository ) { $this->logger = $logger; $this->orderRepository = $orderRepository; $this->convertOrder = $convertOrder; $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->getSourcesAssignedToStockOrderedByPriority = $getSourcesAssignedToStockOrderedByPriority; $this->defaultSourceProvider = $defaultSourceProvider; $this->shipmentNotifier = $shipmentNotifier; $this->shipmentRepository = $shipmentRepository; } /** * @param Order $order */ private function createShipment($orderId) { try { $order = $this->orderRepository->get($orderId); $shipment = $this->prepareShipment($order); try { $this->shipmentRepository->save($shipment); } catch (\Exception $e) { throw new LocalizedException(__($e->getMessage())); } //$this->shipmentNotifier->notify($shipment); $order->setStatus(Order::STATE_COMPLETE) ->setState(Order::STATE_COMPLETE) ->addStatusToHistory($order->getStatus()) ->addCommentToStatusHistory('Order Shipped and Completed'); } catch (\Exception $e) { $this->logger->info(__('Cannot create shipment for order #%1', $order->getIncrementId())); $message = 'Cannot create shipment for order #'. $order->getIncrementId() . $e->getMessage(); $order->addCommentToStatusHistory($message); } $this->orderRepository->save($order); } private function prepareShipment($order) { $shipment = $this->convertOrder->toShipment($order); foreach ($order->getAllItems() as $orderItem) { // Check if order item has qty to ship or is virtual if ($orderItem->getIsVirtual()) { continue; } $qtyShipped = $orderItem->getQtyOrdered(); // Create shipment item with qty $shipmentItem = $this->convertOrder->itemToShipmentItem($orderItem) ->setQty($qtyShipped); // Add shipment item to shipment $shipment->addItem($shipmentItem); } $shipment->register(); $shipment->getOrder()->setIsInProcess(true); $websiteId = $order->getStore()->getWebsiteId(); $stockId = $this->stockByWebsiteIdResolver->execute((int)$websiteId) ->getStockId(); $sources = $this->getSourcesAssignedToStockOrderedByPriority->execute((int)$stockId); if (!empty($sources) && count($sources) === 1) { $sourceCode = $sources[0]->getSourceCode(); } else { $sourceCode = $this->defaultSourceProvider->getCode(); } $shipment->getExtensionAttributes()->setSourceCode($sourceCode); return $shipment; } }
So now just use the above class and call function createShipment($orderId)
with order Id.
If you have any questions feel free to comment below.
Thanks for reading. Keep sharing 🙂