Creating a shipment programmatically - The Magento 2 way
In the last couple of weeks I worked on improving and automating the process of handling orders of the warehouse team. The goal was that the warehouse team is able to handle an order by using a maximum of five clicks / key presses. To archive this, one of my tasks was to create a (UPS) shipment programmatically.
Since I’m relatively new to Magento I did what probably all Magento newbies do: I asked Google and there I came across a surprisingly high number of posts explaining how to do it. Well, most of the posts contained 1:1 the same code but I had a working solution. However this solution used the Object Manager (which I really would like to avoid) to create the shipment, all ordered items had to be added separately to the shipment and the deprecated ‘save’ method of the model class was used. In short: I wasn’t happy with that solution.
Therefore I started to read some Magento core source code and built my own solution which will be explained in the following code snippet.
<?php
class CreateShipment extends \Magento\Backend\App\Action
{
/**
* The OrderRepository is used to load, save and delete orders.
*
* @var \Magento\Sales\Model\OrderRepository
*/
protected $orderRepository;
/**
* The ShipmentFactory is used to create a new Shipment.
*
* @var Order\ShipmentFactory
*/
protected $shipmentFactory;
/**
* The ShipmentRepository is used to load, save and delete shipments.
*
* @var Order\ShipmentRepository
*/
protected $shipmentRepository;
/**
* The ShipmentNotifier class is used to send a notification email to the customer.
*
* @var ShipmentNotifier
*/
protected $shipmentNotifier;
/**
* All specified parameters in the constructor will be injected via dependency injection.
*
* @param \Magento\Backend\App\Action\Context $context
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Sales\Model\OrderRepository $orderRepository,
\Magento\Sales\Model\Order\ShipmentRepository $shipmentRepository,
\Magento\Sales\Model\Order\ShipmentFactory $shipmentFactory,
\Magento\Shipping\Model\ShipmentNotifier $shipmentNotifier,
) {
parent::__construct($context);
$this->orderRepository = $orderRepository;
$this->shipmentFactory = $shipmentFactory;
$this->shipmentRepository = $shipmentRepository;
$this->shipmentNotifier = $shipmentNotifier;
}
/**
* Since our class extends the Magento Action class it *must* have an execute() function.
* This function is automatically called as soon as the request is sent.
* @return void
*/
public function execute()
{
// we are assuming that the order ID passed to this action via the request parameter.
$orderId = $this->getRequest()->getParam('order_id', 0);
if ($orderId <= 0) {
echo 'Order not found.';
return;
}
try {
// load order from database
$order = $this->orderRepository->get($orderId);
if ($order == null) {
echo "Order not loaded from database."
return;
}
$this->createShipment($order);
} catch (\Exception $exception) {
echo 'Error: ' . $exception->getMessage();
}
}
/**
* Creates a new shipment for the specified order.
*
* @param \Magento\Sales\Model\Order $order
*/
protected function createShipment($order)
{
// check if it's possible to ship the items
if ($order->canShip()) {
// create the shipment
$shipment = $this->shipmentFactory->create($order);
// save the nege-php line-nuwly created shipment
$this->shipmentRepository->save($shipment);
// send shipping confirmation e-mail to customer
$this->shipmentNotifier->notify($shipment);
}
}
}
The above presented CreateShipment.php can also be found as Gist on GitHub. You have annotations to my solution? Feel free to contact me on Github!
Image Source: Photo by chuttersnap on Unsplash