Programmatically Create an Order in Magento 2

This post will demonstrate how to programmatically create an order in Magento 2 Open Source version 2.2 using both guest and registered customers. There is a possibility that the code will work with other versions of Magento 2, however it has not been tested with them.

The code shown below will be contained within a model class within a custom module. The specifics of creating the module will not be described, however you could also modify the code to be used within an external file by bootstrapping the Magento 2 application.

For the purpose of this article, all code will be placed within a model class.

Start off by defining the class and adding the dependencies as shown below.

<?php
namespace Vendor\Module\Model\Order;

use Magento\Framework\App\Helper\Context;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ProductFactory;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterfaceFactory;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Quote\Api\CartManagementInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Sales\Model\Service\OrderService;
use Magento\Store\Model\StoreManagerInterface;

class Create
{
    /**
     * @var ProductRepositoryInterface
     */
    private $productRepository;

    /**
     * @var ProductFactory
     */
    private $productFactory;

    /**
     * @var CustomerRepositoryInterface
     */
    private $customerRepository;

    /**
     * @var CustomerInterfaceFactory
     */
    private $customerInterfaceFactory;

    /**
     * @var CartManagementInterface
     */
    private $cartManagementInterface;

    /**
     * @var CartRepositoryInterface
     */
    private $cartRepositoryInterface;

    /**
     * @var OrderService
     */
    private $orderService;

    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * Create constructor.
     *
     * @param Context $context
     * @param ProductRepositoryInterface $productRepository
     * @param ProductFactory $productFactory
     * @param CustomerRepositoryInterface $customerRepository
     * @param CustomerInterfaceFactory $customerInterfaceFactory
     * @param CartManagementInterface $cartManagementInterface
     * @param CartRepositoryInterface $cartRepositoryInterface
     * @param OrderService $orderService
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        Context $context,
        ProductRepositoryInterface $productRepository,
        ProductFactory $productFactory,
        CustomerRepositoryInterface $customerRepository,
        CustomerInterfaceFactory $customerInterfaceFactory,
        CartManagementInterface $cartManagementInterface,
        CartRepositoryInterface $cartRepositoryInterface,
        OrderService $orderService,
        StoreManagerInterface $storeManager
    ) {
        $this->productRepository        = $productRepository;
        $this->productFactory           = $productFactory;
        $this->customerRepository       = $customerRepository;
        $this->customerInterfaceFactory = $customerInterfaceFactory;
        $this->cartManagementInterface  = $cartManagementInterface;
        $this->cartRepositoryInterface  = $cartRepositoryInterface;
        $this->orderService             = $orderService;
        $this->storeManager             = $storeManager;
    }
}

The code responsible for programmatically creating an order will be held within a create() method.

The method starts off by defining an $orderData array containing customer and product data used to create an order. The array also contains a guest_order array key that can you specify to be either true or false depending if you want to create a guest order or not.

public function create()
{
    $orderData = [
        'currency_id'  => 'GBP',
        'email'        => 'hello123@demo.com',
        'guest_order'  => false,
        'shipping_address'      => [
            'firstname'            => 'John',
            'lastname'             => 'Doe',
            'street'               => 'Street Name',
            'city'                 => 'City Name',
            'country_id'           => 'GB',
            'region'               => 'xxx',
            'postcode'             => 'LN1 1AA',
            'telephone'            => '0777777',
            'save_in_address_book' => 1
        ],
        'items'=> [
            ['product_id' => 1,'qty' => 3],
            ['product_id' => 2,'qty' => 1]
        ]
    ];
}

Next, add the following lines below the $orderData array to initialise an empty cart.

/** @var \Magento\Store\Model\Store $store */
$store = $this->storeManager->getStore();
$websiteId = $this->storeManager->getStore()->getWebsiteId();

// Initialise Cart
$cartId = $this->cartManagementInterface->createEmptyCart();
$cart = $this->cartRepositoryInterface->get($cartId);
$cart->setStore($store);
$cart->setCurrency();

Now check the guest_order flag. If an order is being created for a registered customer, first look to check if the customer’s email address exists from the email address used in $orderData. If not, then create and register the customer programmatically.

// Check if guest order
if ($orderData['guest_order']) {
    $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST);
    $cart->getBillingAddress()->setEmail($orderData['email']);
} else {
    $customer = $this->customerInterfaceFactory->create();
    $customer->setWebsiteId($websiteId);

    // Check if the customer's email address exists
    try {
        $customerEntity = $this->customerRepository->get($orderData['email'], $websiteId);
    } catch (NoSuchEntityException $e) {
        // If it doesn't, create the customer
        $customer
            ->setFirstname($orderData['shipping_address']['firstname'])
            ->setLastname($orderData['shipping_address']['lastname'])
            ->setEmail($orderData['email']);
        $customerEntity = $this->customerRepository->save($customer);
    }

    $customerId = $this->customerRepository->getById($customerEntity->getId());
    $cart->assignCustomer($customerId);
}

The next steps involves adding the items to the cart.

// Add items to cart
foreach ($orderData['items'] as $item) {
    $product = $this->productRepository->getById($item['product_id']);
    $cart->addProduct(
        $product,
        $item['qty']
    );
}

Below this, set the cart’s billing and shipping addresses.

// Set billing and shipping addresses
$cart->getBillingAddress()->addData($orderData['shipping_address']);
$cart->getShippingAddress()->addData($orderData['shipping_address']);

Now set the shipping method using the shipping method’s code. This example will use the default flatrate_flatrate code for the flat rate shipping method.

$shippingAddress = $cart->getShippingAddress();

// Set shipping method
$shippingAddress->setCollectShippingRates(true)
    ->collectShippingRates()
    ->setShippingMethod('flatrate_flatrate');

Finally, set the payment method and save the cart. This example will use the default Check/Money payment option via the checkmo payment mode.

// Set payment method
$cart->setPaymentMethod('checkmo');
$cart->getPayment()->importData(['method' => 'checkmo']);

$cart->collectTotals();
$cart->save();

The order can now be placed. The Magento\Quote\Api\CartManagementInterface interface contains a placeOrder() method that can be used.

// Place the order
$cart = $this->cartRepositoryInterface->get($cart->getId());
$orderId = $this->cartManagementInterface->placeOrder($cart->getId());
return $orderId;

Altogether, the code snippet looks like the below.

<?php
namespace Vendor\Module\Model\Order;

use Magento\Framework\App\Helper\Context;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ProductFactory;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Api\Data\CustomerInterfaceFactory;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Quote\Api\CartManagementInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Sales\Model\Service\OrderService;
use Magento\Store\Model\StoreManagerInterface;

class Create
{
    /**
     * @var ProductRepositoryInterface
     */
    private $productRepository;

    /**
     * @var ProductFactory
     */
    private $productFactory;

    /**
     * @var CustomerRepositoryInterface
     */
    private $customerRepository;

    /**
     * @var CustomerInterfaceFactory
     */
    private $customerInterfaceFactory;

    /**
     * @var CartManagementInterface
     */
    private $cartManagementInterface;

    /**
     * @var CartRepositoryInterface
     */
    private $cartRepositoryInterface;

    /**
     * @var OrderService
     */
    private $orderService;

    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * Create constructor.
     *
     * @param Context $context
     * @param ProductRepositoryInterface $productRepository
     * @param ProductFactory $productFactory
     * @param CustomerRepositoryInterface $customerRepository
     * @param CustomerInterfaceFactory $customerInterfaceFactory
     * @param CartManagementInterface $cartManagementInterface
     * @param CartRepositoryInterface $cartRepositoryInterface
     * @param OrderService $orderService
     * @param StoreManagerInterface $storeManager
     */
    public function __construct(
        Context $context,
        ProductRepositoryInterface $productRepository,
        ProductFactory $productFactory,
        CustomerRepositoryInterface $customerRepository,
        CustomerInterfaceFactory $customerInterfaceFactory,
        CartManagementInterface $cartManagementInterface,
        CartRepositoryInterface $cartRepositoryInterface,
        OrderService $orderService,
        StoreManagerInterface $storeManager
    ) {
        $this->productRepository        = $productRepository;
        $this->productFactory           = $productFactory;
        $this->customerRepository       = $customerRepository;
        $this->customerInterfaceFactory = $customerInterfaceFactory;
        $this->cartManagementInterface  = $cartManagementInterface;
        $this->cartRepositoryInterface  = $cartRepositoryInterface;
        $this->orderService             = $orderService;
        $this->storeManager             = $storeManager;
    }

    public function create()
    {
        $orderData = [
            'currency_id'  => 'GBP',
            'email'        => 'hello123@demo.com',
            'guest_order'  => false,
            'shipping_address'      => [
                'firstname'            => 'John',
                'lastname'             => 'Doe',
                'street'               => 'Street Name',
                'city'                 => 'City Name',
                'country_id'           => 'GB',
                'region'               => 'xxx',
                'postcode'             => 'LN1 1AA',
                'telephone'            => '0777777',
                'save_in_address_book' => 1
            ],
            'items'=> [
                ['product_id' => 1,'qty' => 3],
                ['product_id' => 2,'qty' => 1]
            ]
        ];

        /** @var \Magento\Store\Model\Store $store */
        $store = $this->storeManager->getStore();
        $websiteId = $this->storeManager->getStore()->getWebsiteId();

        // Initialise Cart
        $cartId = $this->cartManagementInterface->createEmptyCart();
        $cart = $this->cartRepositoryInterface->get($cartId);
        $cart->setStore($store);
        $cart->setCurrency();

        // Check if guest order
        if ($orderData['guest_order']) {
            $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST);
            $cart->getBillingAddress()->setEmail($orderData['email']);
        } else {
            $customer = $this->customerInterfaceFactory->create();
            $customer->setWebsiteId($websiteId);

            // Check if the customer's email address exists
            try {
                $customerEntity = $this->customerRepository->get($orderData['email'], $websiteId);
            } catch (NoSuchEntityException $e) {
                // If it doesn't, create the customer
                $customer
                    ->setFirstname($orderData['shipping_address']['firstname'])
                    ->setLastname($orderData['shipping_address']['lastname'])
                    ->setEmail($orderData['email']);
                $customerEntity = $this->customerRepository->save($customer);
            }


            $customerId = $this->customerRepository->getById($customerEntity->getId());
            $cart->assignCustomer($customerId);
        }

        // Add items to cart
        foreach ($orderData['items'] as $item) {
            $product = $this->productRepository->getById($item['product_id']);
            $cart->addProduct(
                $product,
                $item['qty']
            );
        }

        // Set billing and shipping addresses
        $cart->getBillingAddress()->addData($orderData['shipping_address']);
        $cart->getShippingAddress()->addData($orderData['shipping_address']);

        $shippingAddress = $cart->getShippingAddress();

        // Set shipping method
        $shippingAddress->setCollectShippingRates(true)
            ->collectShippingRates()
            ->setShippingMethod('flatrate_flatrate');

        // Set payment method
        $cart->setPaymentMethod('checkmo');
        $cart->getPayment()->importData(['method' => 'checkmo']);

        $cart->collectTotals();
        $cart->save();

        // Place the order
        $cart = $this->cartRepositoryInterface->get($cart->getId());
        $orderId = $this->cartManagementInterface->placeOrder($cart->getId());
        return $orderId;
    }
}

You should now be able to use this code and programmatically create an order in Magento 2. Reading other examples online, the code above may not cater for product custom options, or halt the ability of the order email from being sent out to customers. Therefore you’ll need to modify the code to suit your needs.

However, it should provide a basic template on how to create an order quickly.

Note: This article is based on Magento Open Source version 2.2.