Magento 2 – How to Add New Item to Existing Order Programmatically

magento-2.2.5order-itemsprogrammaticallysales-order

I have created one virtual product in my Magento2 website. Now, I want to add it programmatically to the existing customer orders on some occasions with its custom price and name.

Can someone please guide step by step to achieve this?

Thanks,

Best Answer

After some goggling and with the help of some core modules I came up with following solution :

/**
* @var \Magento\Sales\Api\OrderRepositoryInterface
*/
protected $orderRepository;

/**
* @var \Magento\Catalog\Api\ProductRepositoryInterface
*/
protected $productRepository;

/**
* @var \Magento\Quote\Api\Data\CartItemInterfaceFactory
*/
protected $cartItemFactory;

/**
* @var \Magento\Quote\Api\CartRepositoryInterface
*/
protected $quoteRepository;

/**
* @var \Magento\Sales\Model\Order\ItemFactory
*/
protected $orderItemFactory;

 public function __construct(
    \Magento\Backend\App\Action\Context $context,        
    \Magento\Sales\Api\OrderRepositoryInterface $orderRepository,
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
    \Magento\Quote\Api\Data\CartItemInterfaceFactory $cartItemFactory,
    \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
    \Magento\Sales\Model\Order\ItemFactory $orderItemFactory
) {
    parent::__construct($context);       
    $this->productRepository    = $productRepository;
    $this->orderRepository      = $orderRepository;
    $this->cartItemFactory      = $cartItemFactory;
    $this->quoteRepository      = $quoteRepository;
    $this->orderItemFactory     = $orderItemFactory;
}

public function execute()
{
    $postData       = $this->getRequest()->getPostValue();
    $productSku     = 'your-product-sku'; // Static Virtual Product created. You may also use static ID.
    $product        = $this->productRepository->get($productSku);
    $order          = $this->orderRepository->get($postData['order_id']);
    $quote          = $this->quoteRepository->get($order->getQuoteId());

    try {
    /* Add Quote Item Start */
    $quoteItem = $this->cartItemFactory->create();
    $quoteItem->setProduct($product);
    $quoteItem->setCustomPrice($postData['custom_price']);
    $quoteItem->setOriginalCustomPrice($postData['custom_price']);
    $quoteItem->getProduct()->setIsSuperMode(true);
    $quote->addItem($quoteItem);
    $quote->collectTotals()->save();
    /* Add Quote Item End */

    /* Add Order Item Start */
    $orderItem = $this->orderItemFactory->create();
    $orderItem
            ->setStoreId($order->getStoreId())
            ->setQuoteItemId($quoteItem->getId())
            ->setProductId($product->getId())
            ->setProductType($product->getTypeId())
            ->setName($product->getName())
            ->setSku($product->getSku())
            ->setQtyOrdered(1)
            ->setPrice($postData['custom_price'])
            ->setBasePrice($postData['custom_price'])
            ->setOriginalPrice($postData['custom_price'])
            ->setBaseOriginalPrice($postData['custom_price'])
            ->setPriceInclTax($postData['custom_price'])
            ->setBasePriceInclTax($postData['custom_price'])
            ->setRowTotal($postData['custom_price'])
            ->setBaseRowTotal($postData['custom_price'])
            ->setRowTotalInclTax($postData['custom_price'])
            ->setBaseRowTotalInclTax($postData['custom_price'])
            ->setWeight(1)
            ->setIsVirtual(1);
    $order->addItem($orderItem);
    /* Add Order Item End */

    /* Update relavant order totals Start */
    $order->setBaseGrandTotal($order->getBaseGrandTotal() + $postData['custom_price']);
    $order->setGrandTotal($order->getGrandTotal() + $postData['custom_price']);
    $order->setBaseSubtotal($order->getBaseSubtotal() + $postData['custom_price']);
    $order->setSubtotal($order->getSubtotal() + $postData['custom_price']);
    $order->setBaseSubtotalInclTax($order->getBaseSubtotalInclTax() + $postData['custom_price']);
    $order->setSubtotalInclTax($order->getSubtotalInclTax() + $postData['custom_price']);
    $order->setTotalItemCount($order->getTotalItemCount() + 1);
    $order->setTotalQtyOrdered($order->getTotalQtyOrdered() + 1);
    $this->orderRepository->save($order);
    /* Update relavant order totals End */
  }
  catch (\Exception $e) {
     $this->messageManager->addError($e->getMessage());
  } 
}