Problem I came across:
While working on the migration of the last batch of data from Magento 1 to Magento 2, I came across a situation where I had to migrate specific 2-3 orders. I could not use the magento migration tool as it was used earlier and there were issues that cropped up, mainly distorted attributes of products and customers.
Solution Derived:
I solved it by a simple 2 step approach to create order programmatically in Magento 2 that saved time and effort. I created an array to fetch order details from Magento 1. This was further imported in M2 using module helper file that I created.
Step by step approach:
Here’s the step by step approach I followed.
It is worth noting these two points here first:
1. This script works only with shipping and payment method enabled. While there is some commented code in helper class that can be used to work with ‘not enabled’ payment method as well. However, in this case you will not be able to see payment method information in order- view in admin, because magento does load substitute block and template saying “payment info not available”.
2. In this script you can also set increment_id for order so once order is created that given id will be assigned to order.
Here are the steps:
Step 1) Use the following to create order:
ordercreate = $ordercreate;
}
private function getOrderDetails(){
return [
'currency_id' => 'GBP',
'email' => 'marcus*****@msn.com', //customer email id
'is_guest' => '1',
'customer' => [
'firstname' => 'Marcus',
'lastname' => '*****'
],
'address' =>[
'billing' => [
'firstname' => 'Marcus',
'lastname' => '*****',
'company' => 'Mrs',
'street' => ['** An***r ****', '*****'],
'city' => 'An****',
'country_id' => 'GB',
'region' => '',
'postcode' => 'Sp*****',
'telephone' => '0*****48577',
'fax' => ''
],
'shipping' => [
'firstname' => 'Select *****',
'lastname' => 'Eshe *****',
'prefix' => '',
'suffix' => '',
'street' => ['5a ***** Road', '*******'],
'city' => '*****',
'country_id' => 'GB',
'region' => '',
'postcode' => 'K****',
'telephone' => '0208******',
'fax' => '020*******'
]
],
'shipping'=>[
'shipping_method'=> 'shqpickup_collect',
'shipping_description' => 'Collect from Store',
],
'items'=> [
['product_id'=>'4***','qty'=>1],
['product_id'=>'4***','qty'=>2]
],
'increment_id' => '10001****',
'payment' => [
'method' => 'braintree_paypal',
'transaction_id' => '44M1*******090F',
'additional_information' => 'a:12:{s:39:"paypal_express_checkout_shipping_method";s:0:"";s:15:"paypal_payer_id";s:13:"36UN******EBJ";s:18:"paypal_payer_email";s:19:"marcusbyrne@msn.com";s:19:"paypal_payer_status";s:8:"verified";s:21:"paypal_address_status";s:9:"Confirmed";s:21:"paypal_correlation_id";s:13:"13073eb441925";s:32:"paypal_express_checkout_payer_id";s:13:"36U******QEBJ";s:29:"paypal_express_checkout_token";s:20:"EC-407676********2361D";s:41:"paypal_express_checkout_redirect_required";N;s:29:"paypal_protection_eligibility";s:8:"Eligible";s:21:"paypal_payment_status";s:9:"completed";s:21:"paypal_pending_reason";s:4:"None";}'
]
];
}
/**
* Post user question
*
* @return Redirect
*/
public function execute()
{
$orderinfo = $this->getOrderDetails();
$this->ordercreate->createOrder($orderinfo);
}
}
Step 2) Write order create function in module helper file
storeManager = $storeManager;
$this->customerFactory = $customerFactory;
$this->productRepository = $productRepository;
$this->customerRepository = $customerRepository;
$this->quote = $quote;
$this->quoteManagement = $quoteManagement;
$this->orderSender = $orderSender;
parent::__construct($context);
}
/*
* create order programmatically
*/
public function createOrder($orderInfo)
{
//error_reporting(E_ALL);
//ini_set('display_errors',1);
try{
$store = $this->storeManager->getStore();
$storeId = $store->getStoreId();
$websiteId = $this->storeManager->getStore()->getWebsiteId();
if($orderInfo['is_guest']==0){
$customer = $this->customerFactory->create();
$customer->setWebsiteId($websiteId);
$customer->loadByEmail($orderInfo['email']); // load customer by email address
if (!$customer->getId()) {
//For if customer not exists then create
$customer->setWebsiteId($websiteId)
->setStore($store)
->setFirstname($orderInfo['customer']['firstname'])
->setLastname($orderInfo['customer']['lastname'])
->setEmail($orderInfo['email'])
->setPassword($orderInfo['email']);
$customer->save();
}
}
$quote = $this->quote->create();
$quote->setStore($store); //set store for our quote
if($orderInfo['is_guest']==0){
/* for registered customer */
$customer = $this->customerRepository->getById($customer->getId());
$quote->assignCustomer($customer); //Assign quote to customer
} else {
/* for guest customer */
$quote->setCustomerEmail($orderInfo['email']);
$quote->setCustomerFirstname($orderInfo['customer']['firstname']);
$quote->setCustomerLastname($orderInfo['customer']['lastname']);
$quote->setCustomerIsGuest(1);
}
$quote->setCurrency(); //set null so that it auto pick currency of store or you can set currency object
//add items in quote
foreach ($orderInfo['items'] as $item) {
$product = $this->productRepository->getById($item['product_id']);
$item['qty'] = intval($item['qty']);
$buyRequest = new \Magento\Framework\DataObject($item);
$quote->addProduct($product, $buyRequest);
}
//Set Billing and shipping Address
$quote->getBillingAddress()->addData($orderInfo['address']['billing']);
$quote->getShippingAddress()->addData($orderInfo['address']['shipping']);
//var_dump($orderInfo['shipping']['shipping_method']); die;
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setCollectShippingRates(true)
->collectShippingRates()
->setShippingMethod($orderInfo['shipping']['shipping_method']); // assign shipping method
unset($orderInfo['shipping']['shipping_method']);
$shippingAddress->addData($orderInfo['shipping']); //shipping method, please verify that shipping must be enable
$quote->setPaymentMethod($orderInfo['payment']['method']);
$quote->setInventoryProcessed(false); //decrease item stock equal to qty or you can make it true to not to process inventory
$quote->save();
// Set Sales Order Payment
if('braintree_paypal'==$orderInfo['payment']['method']){
$additional_info = unserialize($orderInfo['payment']['additional_information']);
} else {
$additional_info = json_decode($orderInfo['payment']['additional_information'], true);
}
//var_dump($additional_info); die;
$orderInfo['payment']['additional_information'] = $additional_info;
/*$method = $quote->getPayment()->getMethodInstance();
$data = new \Magento\Framework\DataObject($orderInfo['payment']);
$method->assignData($data);*/
if('braintree_paypal'==$orderInfo['payment']['method']){
$quote->getPayment()->setMethod('checkmo');
//$method = $quote->getPayment()->getMethodInstance();
//$data = new \Magento\Framework\DataObject($orderInfo['payment']);
//$method->assignData($data);
} else {
$quote->getPayment()->setMethod($orderInfo['payment']['method']);
$quote->getPayment()->importData(['method' => $orderInfo['payment']['method'],'additional_data'=>$additional_info, 'additional_information'=>$additional_info]);
}
// Collect Quote Totals & Save
$quote->collectTotals()->save();
// Create Order From Quote Object
$order = $this->quoteManagement->submit($quote);
if('braintree_paypal'==$orderInfo['payment']['method']){
$order->getPayment()->setMethod('braintree_paypal');
}
$order->getPayment()->setTransactionId($orderInfo['payment']['transaction_id']);
$order->getPayment()->setLastTransId($orderInfo['payment']['transaction_id']);
$order->getPayment()->setAdditionalInformation($additional_info);
/* for send order email to customer email id */
//$this->orderSender->send($order);
/* check if order was created */
$orderId = $order->getIncrementId();
if ($orderId) {
//chaneg order increment_id as given
$order->setIncrementId($orderInfo['increment_id']);
$order->save();
$result['success'] = $order->getIncrementId();
} else {
$result = ['error' => true, 'msg' => 'Error occurs for Order placed'];
}
} catch(\Exception $e){
echo $e->__toString();
}
echo '<pre>';
var_dump($result); die;
}
}
Some additional details:
You can use this for simple product:
['product_id'=>'4066','qty'=>2]
For configurable product:
['product_id'=>'4066','qty'=>2, 'super_attribute' => array(93=>52,142=>167)]
and with custom price
['product_id'=>'4066','qty'=>2, 'custom_price'=>10.92]
In payment array you can use ‘braintree_paypal’ or ‘paypal_express’, and change condition accordingly in helper class file inside if condition.
For trancation_id and additional_information you can get these information of order from table ‘sales_flat_order_payment’, for paypal it usually in serialized form while for sagepay you can get this from ‘sapgepay_oder_payment‘ then you need to make a json in this format.
for eg:
'payment' => [
'method' => 'sagepaysuiteserver',
'transaction_id' => '613450B5-*************CF4ACDA06C',
'additional_information' => '{"vendor_tx_code":"10001858**************8-16-52","vps_protocol":"3.00","integration":"server","vendorname":"aboutroofingsup","mode":"live","trn_currency":"GBP","tx_type":"PAYMENT","security_key":"HQ******MS","VPSTx_id":"{6134************2DEB-54CF4ACDA06C}","tx_auth_no":"90242831","avscv2":"ALL MATCH","address_result":"MATCHED","postcode_result":"MATCHED","cv2result":"MATCHED","threed_secure_status":"OK","cavv":"AAABBk*************VSCEdXNwhA=","address_status":null,"payer_status":null,"card_type":"DELTA","last_four_digits":"4**6","vps_signature":"6619073A8180CED***********4E9B","status":"OK","status_detail":"0000 : The Authorisation was Successful.","giftaid":null,"canceled":null,"voided":null,"aborted":null,"released":null,"authorised":null,"token":null,"trndate":"2019-04-03 09:16:52","customer_contact_info":"074*******79","customer_cc_holder_name":null,"quote_id":"91090","store_id":"1","card_expiry_date":null,"parent_trn_id":null,"payment_system_details":null,"eci":null,"tx_state_id":null,"acsurl":null,"md":null,"pareq":null,"pares":null,"red_fraud_response":null,"surcharge_amount":null,"bank_auth_code":"81*****","decline_code":"0","created_at":"2019-**-** 13:46:52","trn_amount":"12***.3200","batch_id":null,"updated_at":"2019-**-** 12:47:41","nickname":null,"euro_payments_status":null,"server_success_arrived":"1","server_session":null,"server_notify_arrived":"1","server_order_comments":null,"order_email":null}'
]
You can get the transaction id from VPSTx_id, eg: 613450B5-9C9C-04********************6C
Setting up transaction_id is important for online payment orders because it will set last tran_id and transaction_id in order in backend that can be used for future reference of payments. Even in case of sagepay you can click on ‘sync from api’ button to fetch details of transactions based on this transaction_id.
By following the above instructions, one can easily create orders programmatically in the Magento 2 store.
Hope it helps! If you face any problems while implementing, feel free to ask us by leaving a comment below.