1

I am trying to create order programmatically product with customizable options, and it's working but it's created order with one product even I passed two products for me for these I tried below code.

Controller.php Code is below

<?php

namespace Learning\COP\Controller\Index;

use \Magento\Framework\App\Action\Action;
use \Magento\Framework\View\Result\PageFactory;
use \Magento\Framework\App\Action\Context;
use \Magento\Framework\Controller\ResultInterface;
use \Magento\Framework\App\ResponseInterface;
use \Learning\COP\Helper\Data;

class Index extends Action
{

    /**
     * @var PageFactory
     */
    protected $resultPageFactory;

    /**
     * @var Data
     */
    protected $helper;

    /**
     * Index constructor.
     *
     * @param Context $context
     * @param PageFactory $pageFactory
     * @param Data $helper
     */
    public function __construct(
        Context $context,
        PageFactory $pageFactory,
        Data $helper
    )
    {
        $this->helper = $helper;
        $this->resultPageFactory = $pageFactory;
        parent::__construct($context);
    }

    /**
     * @return ResponseInterface|ResultInterface|void
     */
    public function execute()
    {
        $order = [
            'currency_id' => 'USD',
            'email' => '[email protected]',
            'shipping_address' => ['firstname' => 'John',
                'lastname' => 'Doe',
                'street' => '123 Street',
                'city' => 'New York',
                'country_id' => 'US',
                'region' => 'New York',
                'postcode' => '10004',
                'telephone' => '52556542',
                'fax' => '3242322556',
                'region_id' => 43,
                'save_in_address_book' => 1],
            'items' => [
                ['product_id' => '2', 'qty' => 1, 'name' => 'Test Product 1', 'sku' => 'ts1', 'price' => 250 ],
                ['product_id' => '2', 'qty' => 2, 'name' => 'Test Product 2', 'sku' => 'ts2','price' => 15 ]
            ]
        ];

        $result = $this->helper->createOrder($order);
        var_dump($result);
    }

}

Helper class

 <?php

namespace Learning\COP\Helper;

use \Magento\Framework\App\Helper\AbstractHelper;
use \Magento\Framework\App\Helper\Context;
use \Magento\Store\Model\StoreManagerInterface;
use \Magento\Catalog\Model\Product;
use \Magento\Framework\Data\Form\FormKey;
use \Magento\Quote\Model\QuoteFactory;
use \Magento\Quote\Model\QuoteManagement;
use \Magento\Customer\Model\CustomerFactory;
use \Magento\Customer\Api\CustomerRepositoryInterface;
use \Magento\Sales\Model\Service\OrderService;
use \Magento\Catalog\Api\Data\CustomOptionInterface;
use Magento\Catalog\Api\Data\ProductCustomOptionInterface;
use \Magento\Catalog\Model\Product\Option;
use Magento\Quote\Api\Data\ProductOptionInterface;
use \Magento\Quote\Api\CartItemRepositoryInterface;
use Magento\Quote\Api\Data\CartItemInterface;

class Data extends AbstractHelper{

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

    /**
     * @var Product
     */
    protected $product;

    /**
     * @var FormKey
     */
    protected $formkey;

    /**
     * @var QuoteFactory
     */
    protected $quote;

    /**
     * @var QuoteManagement
     */
    protected $quoteManagement;

    /**
     * @var CustomerFactory
     */
    protected $customerFactory;

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

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

    /**
     * @var CustomOptionInterface
     */
    protected $_pOptions;

    /**
     * @var ProductCustomOptionInterface
     */
    protected $_productWithCustomOptions;

    /**
     * @var Option
     */
    protected $_options;

    /**
     * @var ProductOptionInterface
     */
    protected $_productOptionInterface;

    /**
     * @var CartItemRepositoryInterface
     */
    protected $_cartItemRep;

    /**
     * @var CartItemInterface
     */
    protected $_cartItem;

    /**
     * Data constructor.
     *
     * @param Context $context
     * @param StoreManagerInterface $storeManager
     * @param Product $product
     * @param FormKey $formKey
     * @param QuoteFactory $quote
     * @param QuoteManagement $quoteManagement
     * @param CustomerFactory $customerFactory
     * @param CustomerRepositoryInterface $customerRepository
     * @param OrderService $orderService
     * @param CustomOptionInterface $customOption
     * @param ProductCustomOptionInterface $productCustomOption
     * @param Option $productOptions
     * @param ProductOptionInterface $_productOptionInterface
     * @param CartItemRepositoryInterface $cartItemRepository
     * @param CartItemInterface $cartItem
     */
    public function __construct(
        Context $context,
        StoreManagerInterface $storeManager,
        Product $product,
        FormKey $formKey,
        QuoteFactory $quote,
        QuoteManagement $quoteManagement,
        CustomerFactory $customerFactory,
        CustomerRepositoryInterface $customerRepository,
        OrderService $orderService,
        CustomOptionInterface $customOption,
        ProductCustomOptionInterface $productCustomOption,
        Option $productOptions,
        ProductOptionInterface $_productOptionInterface,
        CartItemRepositoryInterface $cartItemRepository,
        CartItemInterface $cartItem
    )
    {
        $this->_pOptions = $customOption;
        $this->storeManager = $storeManager;
        $this->product = $product;
        $this->formkey = $formKey;
        $this->quote = $quote;
        $this->quoteManagement = $quoteManagement;
        $this->customerFactory = $customerFactory;
        $this->customerRepository = $customerRepository;
        $this->orderService = $orderService;
        $this->_productWithCustomOptions = $productCustomOption;
        $this->_options = $productOptions;
        $this->_productOptionInterface = $_productOptionInterface;
        $this->_cartItemRep = $cartItemRepository;
        $this->_cartItem = $cartItem;
        parent::__construct($context);
    }

    public function createOrder($order)
    {
        $store = $this->storeManager->getStore();
        $websiteId = $this->storeManager->getStore()->getWebsiteId();
        $customer = $this->customerFactory->create();
        $customer->setWebsiteId($websiteId);
        $customer->loadByEmail($order['email']);
        if (!$customer->getEntityId()) {
            $customer->setWebsiteId($websiteId)->setStore($store)->setFirstname($order['shipping_address']['firstname'])->setLastname($order['shipping_address']['lastname'])->setEmail($order['email'])->setPassword($order['email']);
            $customer->save();
        }
        $quote = $this->quote->create();
        $quote->setStore($store);
        $customer = $this->customerRepository->getById($customer->getEntityId());
        $quote->setCurrency();
        $quote->assignCustomer($customer);


        $i = 1;
        $optionData = [];
        $optionsArray = [];

        foreach ($order['items'] as $item) {
            $product = $this->product->load($item['product_id']);
            $product->setPrice($item['price']);
            $product->setQty(intval($item['qty']));
            /*foreach ($product->getProductOptionsCollection()->getItems() as $options){
                $this->_productWithCustomOptions->setSku($item['sku']);
                $this->_productWithCustomOptions->setTitle($item['name']);
                $this->_productWithCustomOptions->setPrice($item['price']);
                $this->_productWithCustomOptions->setOptionId($options->getData('option_id'));
                $this->_productWithCustomOptions->setIsRequire(true);
                $this->_productWithCustomOptions->setProductSku($product->getSku());
            }
            $optionsArray[] = array(
                'sku' => $item['sku'],
                'name' => $item['name'],
                'price' => $item['price'],
                'option_id' => $i,
                'product_id' => $product->getId()
            );*/
            $params = array(
                'product' => $product->getId(),
                'qty' => intval($item['qty']),
                'options' => array(
                    '1' => $item['name'],
                    '2' => $item['sku'],
                    '3' => $item['price']
                )
            );
            $requestParams = new \Magento\Framework\DataObject($params);
            //$options = $this->_productWithCustomOptions->getData();
            //$product->setCustomOptions($options);
            $quote->addProduct($product, $requestParams);
            $i++;
        }

       /* $customOptionInterface = \Magento\Framework\App\ObjectManager::getInstance()->create(\Magento\Catalog\Api\Data\CustomOptionInterface::class);
        foreach ($optionsArray as $option) {
            $optionData[] = $customOptionInterface->setdata($option);
        }

        $productOption = $this->_productOptionInterface; // instance of Magento\Quote\Api\Data\ProductOptionInterface
        $extAttribute = $productOption->getExtensionAttributes();
        $extAttribute->setCustomOptions($optionData[0]);
        $productOption->setExtensionAttributes($extAttribute);
        $cartItem = $this->_cartItem;
        $cartItem->setProductOption($productOption);
        $this->_cartItemRep->save($cartItem);*/

        $quote->getBillingAddress()->addData($order['shipping_address']);
        $quote->getShippingAddress()->addData($order['shipping_address']);

        $shippingAddress = $quote->getShippingAddress();
        $shippingAddress->setCollectShippingRates(true)->collectShippingRates()->setShippingMethod('freeshipping_freeshipping');
        $quote->setPaymentMethod('checkmo');
        $quote->setInventoryProcessed(false);
        $quote->save();

        $quote->getPayment()->importData(['method' => 'checkmo']);
        $quote->collectTotals()->save();
        $orderdata = $this->quoteManagement->submit($quote);
        if(isset($orderdata)){
            if ($orderdata->getEntityId()) {
                $result['order_id'] = $orderdata->getRealOrderId();
            } else {
                $result = ['error' => 1, 'msg' => 'Order not created..'];
            }
        }else {
            $result = ['error' => 1, 'msg' => 'Order not created..'];
        } 
        return $result;
    } 
}

Customizable options image here it is.

enter image description here

And created order with only one product see below screenshot.

enter image description here

Could you please suggest me where I went wrong on this process.

1
  • @SohelRana any help on this?
    – Bojjaiah
    Jul 5, 2019 at 7:10

7 Answers 7

1

It seems there are two product passed with the same product_id. It should be different product_id. Please try same code but with different Product Id. e.g.

                ['product_id' => '2', 'qty' => 1, 'name' => 'Test Product 1', 'sku' => 'ts1', 'price' => 250 ],
                ['product_id' => '2', 'qty' => 2, 'name' => 'Test Product 2', 'sku' => 'ts2','price' => 15 ]
            ]

Replace it with

'items' => [
                ['product_id' => '2', 'qty' => 1, 'name' => 'Test Product 1', 'sku' => 'ts1', 'price' => 250 ],
                ['product_id' => '3', 'qty' => 2, 'name' => 'Test Product 2', 'sku' => 'ts2','price' => 15 ]
            ]
1

Finally achieved by following steps.

1) One of the reasons that passing the same product Id as said @KKR, @CoderGeek, and @AdarshM.

2) Product is configured/created with Qty = 0, Price = 0, Stock Maintenance = No and Search = Notvisible.

When I am trying to add the product programmatically it's not added because of Saleable is returning false and not the stock of the product.

for this, I have set the $product->setSkipSaleableCheck(true) and $quote->setIsSuperMode(true) properties for both product and quote and tried the product is created.

and my code is:

$order = [
            'currency_id' => 'USD',
            'email' => '[email protected]',
            'shipping_address' => ['firstname' => 'John',
                'lastname' => 'Doe',
                'street' => '123 Street',
                'city' => 'New York',
                'country_id' => 'US',
                'region' => 'New York',
                'postcode' => '10004',
                'telephone' => '52556542',
                'fax' => '3242322556',
                'region_id' => 43,
                'save_in_address_book' => 1],
            'items' => [
                ['product_id' => '3', 'qty' => 5, 'name' => 'Test Product 1', 'sku' => 'testp1', 'price' => '50' ]
            ]
        ];
$store = $this->storeManager->getStore();
        $websiteId = $this->storeManager->getStore()->getWebsiteId();
        $customer = $this->customerFactory->create();
        $customer->setWebsiteId($websiteId);
        $customer->loadByEmail($order['email']);
        if (!$customer->getEntityId()) {
            $customer->setWebsiteId($websiteId)->setStore($store)->setFirstname($order['shipping_address']['firstname'])->setLastname($order['shipping_address']['lastname'])->setEmail($order['email'])->setPassword($order['email']);
            $customer->save();
        }
        $quote = $this->quote->create();
        $quote->setStore($store);
        $customer = $this->customerRepository->getById($customer->getEntityId());
        $quote->setCurrency();
        $quote->assignCustomer($customer);
        $i = 1;
        foreach ($order['items'] as $item) {
            $product = $this->product->load($item['product_id']);
            $product->setPrice($item['price']);
            $product->setQty(intval($item['qty']));
            $product->setSkipSaleableCheck(true);
            $params = array(
                'product' => $product->getId(),
                'qty' => intval($item['qty']),
                'options' => array(
                    7 => $item['name'],
                    8 => $item['price'],
                    9 => $item['sku']
                )
            );

            $requestParams = new \Magento\Framework\DataObject($params);
            $quote->setIsSuperMode(true);
            $quote->addProduct($product, $requestParams);
            $i++;
        }

        $quote->getBillingAddress()->addData($order['shipping_address']);
        $quote->getShippingAddress()->addData($order['shipping_address']);

        $shippingAddress = $quote->getShippingAddress();
        $shippingAddress->setCollectShippingRates(true)->collectShippingRates()->setShippingMethod('freeshipping_freeshipping');
        $quote->setPaymentMethod('checkmo');
        $quote->setInventoryProcessed(false);
        $quote->save();

        $quote->getPayment()->importData(['method' => 'checkmo']);
        $quote->collectTotals()->save();
        $order_data = $this->quoteManagement->submit($quote);
        if(isset($order_data)){
            if ($order_data->getEntityId()) {
                $result['order_id'] = $order_data->getRealOrderId();
            } else {
                $result = ['error' => 1, 'msg' => 'Order not created..'];
            }
        }else {
            $result = ['error' => 1, 'msg' => 'Order not created..'];
        }
        return $result;

3) If you want to add custom products multiple then try to add one product initially and then save again add one more product until n number of product one by one it will work.

Thanks for all if this is not working feel free to ping me or else if better code please update my thread.

0

Please try with below url :

https://stackoverflow.com/questions/44624568/magento-2-create-order-programmatically-and-add-products-with-custom-options?rq=1

I hope its work for you.

2
  • I post above thread to how to create the order/quote programmatically. Not how to create custom product options? okay
    – Bojjaiah
    Jul 9, 2019 at 6:39
  • Please check with above url, I update my answer. Jul 9, 2019 at 6:47
0

Better use REST API's, I have to give the magento devdoc url: https://devdocs.magento.com/guides/v2.3/rest/tutorials/orders/order-create-quote.html

0
+50

You are passing the same product_id, try changing that and it should add both the products to the order. It is also adding the qty ordered and overwriting the price.

0

You have two products with the same product_id, so the quantity gets added up and the price is overwritten from the final duplicate product.

-1

Your code is too verbose. Why don't use Magento\Sales\Model\Order?

This is my example:

$order = $this->_objectManager->create('Magento\Sales\Model\Order')
                ->setStoreId($store_id)
                ->setQuoteId(0)
                ->addData($orderData);
                ->setBillingAddress($billingAddress)
                ->setShippingAddress($shippingAddress)
                ->setShippingMethod('flatrate_flatrate')
                ->setPayment('checkmo');
foreach ($items as $item) {
    $order->addItem($item);
}
$order->save();

You don't need to declare a Helper class to do it.

1
  • Pretty sure you should not use objectManager directly. Lots of post on here regarding the details of why.
    – B00MER
    Jul 14, 2019 at 19:31

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.