Magento – Magento 2 create orders programmatically with multiple items

importmagento-2.1.4magento2orders

I want to create orders with the multiple items using XML. I have gone through the below tutorials but it's working fine with the single items but not multiple items.

https://webkul.com/blog/create-quote-and-order-programmatically-in-magento2/

After that I found answer on the stackexchange for create orders, but it's also working with the single item.

How to create order programmatically in Magento 2?

Below is OrderImport.XML code:

<?xml version="1.0" encoding="UTF-8"?>
<order>
    <release_number>TEST-LGAKFX1627L</release_number>
    <cc_number>4486660002638431</cc_number>
    <cc_type>VISA</cc_type>
    <cc_exp>10/31/19</cc_exp>
    <buyer_name>Buyer Name</buyer_name>
    <buyer_phone>0123456789</buyer_phone>
    <buyer_mail>buyer_name@example.com</buyer_mail>
    <company_name>COmpany Name</company_name>
    <billing_address_1>Billing Address 1</billing_address_1>
    <billing_address_2>Billing Address 2</billing_address_2>
    <billing_address_3>Billing Address 3</billing_address_3>
    <billing_address_4>Billing Address 4</billing_address_4>
    <products>
        <product>
            <qty>1</qty>
            <unit_price>9.78</unit_price>
            <vendor_part_no>SKU</vendor_part_no>
            <pay_carrier>PREPAID ( BY SELLER )</pay_carrier>
            <transport_responsibility>DESTINATION ( SHIPPING )</transport_responsibility>
        </product>
        <product>
            <qty>1</qty>
            <unit_price>10.56</unit_price>
            <vendor_part_no>SKU</vendor_part_no>
            <pay_carrier>PREPAID ( BY SELLER )</pay_carrier>
            <transport_responsibility>DESTINATION ( SHIPPING )</transport_responsibility>
        </product>
    </products>
</order>

Also,I have checked in the admin panel both products quantity and both
are In Stock.

Below is Module file helper Data.php:

public function createOrder($data,$import_file)
{   
    self::$_currentReleaseNumber = (string) $data->release_number;
    $name = explode(' ', (string) $data->buyer_name);
    $shipping_firstName = $firstName = $name[0];
    if (count($name) == 3) {
        $shipping_middleName = $middleName = $name[1];
        $shipping_lastName = $lastName = $name[2];
    } else {
        $shipping_middleName = $middleName = '';
        $shipping_lastName = $lastName = $name[1];
    }

    if(isset($data->shipping_name)){
        $shipping_name = explode(' ', (string) $data->shipping_name);
        $shipping_firstName = $shipping_name[0];
        if (count($shipping_name) == 3) {
            $shipping_middleName = $shipping_name[1];
            $shipping_lastName = $shipping_name[2];
        } else {
            $shipping_middleName = '';
            $shipping_lastName = $shipping_name[1];
        }
    }    

    $shipping_countryCode = $countryCode = $this->_getCountryCode((string)$data->billing_address_4); 
    $shipping_addressData = $addressData = $this->_getAddressData((string) $data->billing_address_3, $countryCode);

    if(isset($data->shipping_address_4)){
        $shipping_countryCode = $this->_getCountryCode((string)$data->shipping_address_4); 
    }

    if(isset($data->shipping_address_3)){
        $shipping_addressData = $this->_getAddressData((string)$data->shipping_address_3, $shipping_countryCode);
    }

    $shipping_address_1 = (string) $data->billing_address_1;
    $shipping_address_2 = (string) $data->billing_address_2;

    if(isset($data->shipping_address_1)){
       $shipping_address_1 =  (string)$data->shipping_address_1;
    }
    if(isset($data->shipping_address_2)){
       $shipping_address_2 =  (string)$data->shipping_address_2;
    }
    if(isset($data->transportation_control_number)){
        $shipping_address_2 .= "\n TCN: ".(string)$data->transportation_control_number;
    }

    $shipping_phone = (string)$data->buyer_phone;
    if(isset($data->shipping_phone)){
        $shipping_phone = (string)$data->shipping_phone;
    }

    $productData =array();
    foreach ($data->products->product as $item) {
        $sku = (string) $item->vendor_part_no;
        if ($product = $this->_productFactory->loadByAttribute('sku', $sku)) {
            $productData[] = array(
                'product_id' => $product->getId(),
                'qty' =>  (int)$item->qty,
                'custom_price' => (string) $item->unit_price,
            );
            /*  $orderComments = $orderData['order']['comment']['customer_note']
                ."<br/>".$item->authorization_number."<br/>".$item->pay_carrier."<br/>".
                $item->transport_responsibility; */
        } 
        else {
            //die('No product found with sku '. $sku);
            $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/orderimport.log');
            $logger = new \Zend\Log\Logger();
            $logger->addWriter($writer);
            $logger->info("Error");
            $logger->info('No product found with sku '. $sku);
            $this->errorEmail('No product found with sku '. $sku,$import_file);
            return;
        }
    }

    $orderData=array(
        'currency'  => 'USD',
        'email'        => (string)$data->buyer_mail, //buyer email id
        'billing_address' =>array(
            'prefix'       => '',
            'firstname'    => $firstName, //address Details
            'middlename'   => $middleName,
            'lastname'     => $lastName,
            'suffix'       => '',
            'company'      => (string) $data->company_name,
            'street' => array(
                (string) $data->billing_address_1,
                (string) $data->billing_address_2,
            ),
            'city' => $addressData['city'],
            'country_id' => $countryCode,
            'region_id' => $addressData['region_id'],
            'postcode' => $addressData['postcode'],
            'telephone' => (string) $data->buyer_phone,
            'fax' => '',
            'save_in_address_book' => 1
        ),
        'shipping_address' =>array(
            'prefix'       => '',
            'firstname'    => $shipping_firstName, //address Details
            'middlename'   => $shipping_middleName,
            'lastname'     => $shipping_lastName . ' (' . (string) $data->release_number . ')',
            'suffix'       => '',
            'company'      => (string) $data->company_name,
            'street' => array(
                $shipping_address_1,
                $shipping_address_2,
            ),
            'city' => $shipping_addressData['city'],
            'country_id' => $shipping_countryCode,
            'region_id' => $shipping_addressData['region_id'],
            'postcode' => $shipping_addressData['postcode'],
            'telephone' => $shipping_phone,
            'fax' => '',
            'save_in_address_book' => 1
        ),
       'items'  => $productData
    );

    /* for payment method*/

    $ccMethod = 'authorizenet';
    if ($this->_isPaymentActive('authnetcim')) {
        $ccMethod = 'authnetcim';
    }
    if (isset($data->cc_exp) && $this->_isPaymentActive($ccMethod)) {
        $ccExpData = explode('/', $data->cc_exp);
        if (strlen((string) $ccExpData[2]) <=2) {
            $ccExpData[2] += 2000;
        }
        $orderData['payment'] = array(
            'method'       => $ccMethod,
            'cc_number'    => (string)$data->cc_number,
            'cc_type'      => $this->_mapCardType((string)$data->cc_type),
            'cc_exp_month' => (string)$ccExpData[0],
            'cc_exp_year'  => (string)$ccExpData[2],
        );
    } elseif ($this->_isPaymentActive('purchaseorder')) {
        $orderData['payment'] = array(
            'method' => 'purchaseorder',
            'po_number' => (string)$data->release_number,
        );
    } else {
        $orderData['payment'] = array(
            'method' => 'checkmo',
        );
    }

    $orderData['order']['comment']['customer_note'] = '';

    if (isset($data->mark_for_party)) {
        $orderData['order']['comment']['customer_note'] = "LABEL FOR ULTIMATE CONSIGNEE";
        $orderData['order']['comment']['customer_note'] .= "<br>";
        $orderData['order']['comment']['customer_note'] .= (string) $data->mark_for_party;
    }

    if (isset($data->reference_to)) {
        $orderData['order']['comment']['customer_note'] .= (string)$data->reference_to;
    }
    /* for payment method */

    try{
        $storeId = $this->_getStoreId();
        $store=$this->_storeManager->getStore($storeId);
        $websiteId = $store->getWebsiteId();
        $customer=$this->_customerFactory->create();
        $customer->setWebsiteId($websiteId);
        $customer->loadByEmail($orderData['email']);// load customet by email address

        if(!$customer->getEntityId()){
            //If not avilable then create this customer 
            $customer->setWebsiteId($websiteId)
                ->setStore($store)
                ->setFirstname($orderData['shipping_address']['firstname'])
                ->setLastname($orderData['shipping_address']['lastname'])
                ->setEmail($orderData['email']) 
                ->setPassword($orderData['email']);
            $customer->save();
        }

        //$quote=$this->quote->create(); //Create object of quote
        $cart_id = $this->cartManagementInterface->createEmptyCart();
        $quote = $this->cartRepositoryInterface->get($cart_id);


        $quote->setStore($store); //set store for which you create quote
        // if you have allready buyer id then you can load customer directly 
        $customer= $this->customerRepository->getById($customer->getEntityId());
        $quote->setCurrency();
        //$this->cartRepositoryInterface->save($quote);
        $quote->assignCustomer($customer); //Assign quote to customer

        //add items in quote
        foreach($orderData['items'] as $item){
            $product=$this->_productFactory->load($item['product_id']);
            $product->setPrice($item['custom_price']);
            $quote->addProduct(
                $product,
                intval($item['qty'])
            );
        }       

        //Set Address to quote
        $quote->getBillingAddress()->addData($orderData['billing_address']);
        $quote->getShippingAddress()->addData($orderData['shipping_address']);

        $quote->setReleaseNumber((string)$data->release_number);

         // Collect Rates and Set Shipping & Payment Method
        $this->shippingRate->setCode('freeshipping_freeshipping')->getPrice(1);
        $shippingAddress = $quote->getShippingAddress();
        //@todo set in order data
        $shippingAddress->setCollectShippingRates(true)->collectShippingRates()->setShippingMethod('freeshipping_freeshipping'); //shipping method
        //$quote->getShippingAddress()->addShippingRate($this->rate);
        $quote->setPaymentMethod($orderData['payment']['method']); //payment method
        //$quote->setPaymentMethod('checkmo');

        $quote->setInventoryProcessed(false); //not effetc inventory
        //$quote->save(); //Now Save quote and your quote is ready

        // Set Sales Order Payment
        $quote->getPayment()->importData($orderData['payment']);
        //$quote->getPayment()->importData(['method' => 'checkmo']);

            // Collect Totals & Save Quote
        //$quote->collectTotals()->save();

        $quote->collectTotals(); // replace it with me as we still need to collect totals

        $quote->save();

        // Create Order From Quote
        //$order = $this->quoteManagement->submit($quote);
        $quote = $this->cartRepositoryInterface->get($quote->getId());
        $order_id = $this->cartManagementInterface->placeOrder($quote->getId());

        //$order->setEmailSent(0);
        //$increment_id = $order->getRealOrderId();
        /*if($order->getRealOrderId()){
            $result['order_id']= $order->getRealOrderId();
        }else{
            $result=['error'=>1,'msg'=>'Your custom message'];
        }*/

        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/orderimport.log');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info("Success");
        $logger->info($order_id);

        if(isset($order_id) && $order_id!=''){
            $loadOrder= $this->order->load($order_id);    
            $loadOrder->setReleaseNumber((string)$data->release_number);
            $loadOrder->addStatusHistoryComment($orderData['order']['comment']['customer_note']);
            $loadOrder->setIsCustomerNotified(false);
            $loadOrder->addStatusHistoryComment('ACS Archive # ' . str_replace('.xml', '', self::$_currentFile));

            $loadOrder->save();

            $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/orderimport.log');
            $logger = new \Zend\Log\Logger();
            $logger->addWriter($writer);
            $logger->info("release_number");
            $logger->info($data->release_number);
        }

        return $order_id;
    }
    catch(\Exception $e){
        //die($e->getMessage());
        $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/orderimport.log');
        $logger = new \Zend\Log\Logger();
        $logger->addWriter($writer);
        $logger->info("Error");
        $logger->info($e->getMessage());
        $this->errorEmail($e->getMessage(),$import_file);
        return;
    }
}

When I print_r($orderData['items']) it's output is below:

Array
(
[0] => Array
(
[product_id] => 541564
[qty] => 1
[custom_price] => 9.78
)
[1] => Array
(
[product_id] => 423562
[qty] => 1
[custom_price] => 10.56
)
)

Please help!!!!

Best Answer

I have found the solution at my end after do lots of things and many thanks to Godric Cao.

I have used the below class to create the order with multiple items:

https://gist.github.com/godriccao/de490ca3f0ba96733b0a84c2928f0458

Now, the order import functionality is working fine with multiple items.