Surprisingly one of the trickiest parts of “under the hood” Magento is how to create order programmatically. At least for me, this was/is the most complex area of Magento development. Reason why it is so difficult is that the order creation process is all but not straightforward. You cannot simply instantiate order model, set some data and call upon the save() method. If you ask me, this is how it should be done.
So why cannot we apply approach like generic one show below?
//$order = new Mage_Sales_Model_Order();
$order = Mage::getModel('sales/order');
$order->setQuote($quoteModelInstance);
$order->setCustomer($customerModelInstance);
$order->setPayment($paymentModelInstance);
$order->setShipping($customerModelInstance->getShippingRelatedInfo());
//...
$order->save();
As it turns out, there are two “types” of order creation process. One is called One Page Checkout or as I like to call it “frontend order creation” and other one is “admin order creation”. Frontend order creation relies heavily on AJAX-ed approach for almost anything, from getting shipping calculations from shipping gateways to handling credit card processing from payment gateways. On one hand it’s a simple, yet extremely complex process to trace and try to simulate into straight forward order creation by your custom code. Little less complex is the admin order creation, or at least it looks like less complex.
Basically if you as an admin try to create an order from Magento, you have these certain steps where you first choose the customer for which you wish to create order, then you choose store, then you choose product, shipping method, payment method, etc. Each of this steps actually manipulates current session values as we are talking about AJAX-ed behavior. So basically Magento models internally use session reading for setting the necessary values in place of having the direct methods by which you yourself can set those values like customer id, store id, etc.
With enough time on your side, strong will and determination one can monitor, analyze and trace the process of such order creation in order to try to execute it with it’s own custom code.
Below you will find an example of code that does exactly that, it programmatically creates order in Magento.
< ?php
class Company_Module_Model_HandleOrderCreate extends Mage_Core_Model_Abstract
{
private $_storeId = '1';
private $_groupId = '1';
private $_sendConfirmation = '0';
private $orderData = array();
private $_product;
private $_sourceCustomer;
private $_sourceOrder;
public function setOrderInfo(Varien_Object $sourceOrder, Mage_Customer_Model_Customer $sourceCustomer)
{
$this->_sourceOrder = $sourceOrder;
$this->_sourceCustomer = $sourceCustomer;
//You can extract/refactor this if you have more than one product, etc.
$this->_product = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('sku', 'Some value here...')
->addAttributeToSelect('*')
->getFirstItem();
//Load full product data to product object
$this->_product->load($this->_product->getId());
$this->orderData = array(
'session' => array(
'customer_id' => $this->_sourceCustomer->getId(),
'store_id' => $this->_storeId,
),
'payment' => array(
'method' => 'checkmo',
),
'add_products' =>array(
$this->_product->getId() => array('qty' => 1),
),
'order' => array(
'currency' => 'USD',
'account' => array(
'group_id' => $this->_groupId,
'email' => $this->_sourceCustomer->getEmail()
),
'billing_address' => array(
'customer_address_id' => $this->_sourceCustomer->getCustomerAddressId(),
'prefix' => '',
'firstname' => $this->_sourceCustomer->getFirstname(),
'middlename' => '',
'lastname' => $this->_sourceCustomer->getLastname(),
'suffix' => '',
'company' => '',
'street' => array($this->_sourceCustomer->getStreet(),''),
'city' => $this->_sourceCustomer->getCity(),
'country_id' => $this->_sourceCustomer->getCountryId(),
'region' => '',
'region_id' => $this->_sourceCustomer->getRegionId(),
'postcode' => $this->_sourceCustomer->getPostcode(),
'telephone' => $this->_sourceCustomer->getTelephone(),
'fax' => '',
),
'shipping_address' => array(
'customer_address_id' => $this->_sourceCustomer->getCustomerAddressId(),
'prefix' => '',
'firstname' => $this->_sourceCustomer->getFirstname(),
'middlename' => '',
'lastname' => $this->_sourceCustomer->getLastname(),
'suffix' => '',
'company' => '',
'street' => array($this->_sourceCustomer->getStreet(),''),
'city' => $this->_sourceCustomer->getCity(),
'country_id' => $this->_sourceCustomer->getCountryId(),
'region' => '',
'region_id' => $this->_sourceCustomer->getRegionId(),
'postcode' => $this->_sourceCustomer->getPostcode(),
'telephone' => $this->_sourceCustomer->getTelephone(),
'fax' => '',
),
'shipping_method' => 'flatrate_flatrate',
'comment' => array(
'customer_note' => 'This order has been programmatically created via import script.',
),
'send_confirmation' => $this->_sendConfirmation
),
);
}
/**
* Retrieve order create model
*
* @return Mage_Adminhtml_Model_Sales_Order_Create
*/
protected function _getOrderCreateModel()
{
return Mage::getSingleton('adminhtml/sales_order_create');
}
/**
* Retrieve session object
*
* @return Mage_Adminhtml_Model_Session_Quote
*/
protected function _getSession()
{
return Mage::getSingleton('adminhtml/session_quote');
}
/**
* Initialize order creation session data
*
* @param array $data
* @return Mage_Adminhtml_Sales_Order_CreateController
*/
protected function _initSession($data)
{
/* Get/identify customer */
if (!empty($data['customer_id'])) {
$this->_getSession()->setCustomerId((int) $data['customer_id']);
}
/* Get/identify store */
if (!empty($data['store_id'])) {
$this->_getSession()->setStoreId((int) $data['store_id']);
}
return $this;
}
/**
* Creates order
*/
public function create()
{
$orderData = $this->orderData;
if (!empty($orderData)) {
$this->_initSession($orderData['session']);
try {
$this->_processQuote($orderData);
if (!empty($orderData['payment'])) {
$this->_getOrderCreateModel()->setPaymentData($orderData['payment']);
$this->_getOrderCreateModel()->getQuote()->getPayment()->addData($orderData['payment']);
}
$item = $this->_getOrderCreateModel()->getQuote()->getItemByProduct($this->_product);
$item->addOption(new Varien_Object(
array(
'product' => $this->_product,
'code' => 'option_ids',
'value' => '5' /* Option id goes here. If more options, then comma separate */
)
));
$item->addOption(new Varien_Object(
array(
'product' => $this->_product,
'code' => 'option_5',
'value' => 'Some value here'
)
));
Mage::app()->getStore()->setConfig(Mage_Sales_Model_Order::XML_PATH_EMAIL_ENABLED, "0");
$_order = $this->_getOrderCreateModel()
->importPostData($orderData['order'])
->createOrder();
$this->_getSession()->clear();
Mage::unregister('rule_data');
return $_order;
}
catch (Exception $e){
Mage::log("Order save error...");
}
}
return null;
}
protected function _processQuote($data = array())
{
/* Saving order data */
if (!empty($data['order'])) {
$this->_getOrderCreateModel()->importPostData($data['order']);
}
$this->_getOrderCreateModel()->getBillingAddress();
$this->_getOrderCreateModel()->setShippingAsBilling(true);
/* Just like adding products from Magento admin grid */
if (!empty($data['add_products'])) {
$this->_getOrderCreateModel()->addProducts($data['add_products']);
}
/* Collect shipping rates */
$this->_getOrderCreateModel()->collectShippingRates();
/* Add payment data */
if (!empty($data['payment'])) {
$this->_getOrderCreateModel()->getQuote()->getPayment()->addData($data['payment']);
}
$this->_getOrderCreateModel()
->initRuleData()
->saveQuote();
if (!empty($data['payment'])) {
$this->_getOrderCreateModel()->getQuote()->getPayment()->addData($data['payment']);
}
return $this;
}
}
Usage would go something like:
$flatOrderDataObject = new Varien_Object(); $flatOrderDataObject->set(...); //... $order = new Company_Module_Model_HandleOrderCreate() $order->setOrderInfo($flatOrderDataObject); $order->create();
Please study the above code well. Code covers only one “combination”, adding simple product with one custom option to cart, using “Check/Money” payment method and flat rate shipping.
There are far more complex combinations you might need. Hope this code serves you as a good starting point.
Cheers.








Hi,
I am Successfully able to add Sale Order for Bundle Products.
But In Created Order,price for the sale order line is not coming.I have used addproduct() function.
Please give me solution.
Did anyone knows,what value for ‘uenc’ needs to pass in the requestinfo.
I think I am missing that parameter.
Thanks.
How can i add custom shipping price, custom tax amount and custom discount to new order pro-grammatically
what we pass here $flatOrderDataObject->set(…);
@Vinai
[SOLVED - STORE EXCEPTION]
I kept running into a STORE EXCEPTION all over the place with Vinai’s code, in the end it turned out that I had to set the STORE not the STOREID on the quote
So i replaced the 1st line of code with:
$store = Mage::getModel(‘core/store’)->load(1);
$quote = Mage::getModel(‘sales/quote’)
->setStore($store);
Hi, I am trying to run your code to create order by Programmatically, but I don’t have a good experience in Magento.
I am not getting understand how to use these below lines and what will be the parameters of set function.
$flatOrderDataObject = new Varien_Object();
$flatOrderDataObject->set(…);
//…
$order = new Company_Module_Model_HandleOrderCreate()
$order->setOrderInfo($flatOrderDataObject);
$order->create();
Would you please explain a little bit from where I could start.
Thanks
Good tut! Better code than most out there although Vinai’s is def better.
Could you please install a better code highlighter though?
Also, where’s the sendConfirmation method at? Right now it does nothing…
Also, here’s the code to process an actual cc number as opposed to checkmo method:
I was following Vinai and had some additions for freeshipping shipping method and details about adding bundled products. I figured it would save someone a few hours that I spent.
Cheers:
http://pastebin.com/zb8Y2w1p
Hi there,
I used Vinais code to create an order and it works fine for me.
I have to assign a coupon code but it’s not accepted.
I tried the code in the checkout cart and it’s working.
When adding it to the created order it doesn’t.
Here’s what I done at the end:
$customer = $this->getCustomerSession()->getCustomer(); if ($customer) { $this->getQuote()->assignCustomer($customer); } $this->getQuote()->setCustomerEmail($data['email']); $this->getQuote()->addProduct(Mage::helper('my_catalogorder')->getProduct(), new Varien_Object(array('qty' => 1))); $addressData = array( 'prefix' => $data['prefix'], 'firstname' => $data['firstname'], 'lastname' => $data['lastname'], 'company' => $data['company'], 'street' => $data['street'], 'city' => $data['city'], 'postcode' => $data['postcode'], 'telephone' => $data['telephone'], 'country_id' =>$data['country_id'], ); /* @var $billingAddress Mage_Sales_Model_Quote_Address */ $billingAddress = $this->getQuote()->getBillingAddress()->addData($addressData); /* @var $shippingAddress Mage_Sales_Model_Quote_Address */ $shippingAddress = $this->getQuote()->getShippingAddress()->addData($addressData); $shippingAddress ->collectTotals() ->setCollectShippingRates(true) ->collectShippingRates() ->setShippingMethod(Mage::getStoreConfig(My_Catalogorder_Helper_Data::XML_PATH_SHIPPING_METHOD)) ->setPaymentMethod(Mage::getStoreConfig(My_Catalogorder_Helper_Data::XML_PATH_PAYMENT_METHOD)) ; $this->getQuote()->getPayment()->importData(array('method' => Mage::getStoreConfig(My_Catalogorder_Helper_Data::XML_PATH_PAYMENT_METHOD))); /* * add coupon code */ $couponCode = array_key_exists('code', $data) ? trim($data['code']) : false; if($couponCode && strlen($couponCode)) { $this->getQuote()->getShippingAddress()->setCollectShippingRates(true); $this->getQuote()->setCouponCode($couponCode)->collectTotals()->save(); if ($couponCode != $this->getQuote()->getCouponCode($couponCode)) { throw new Exception('Coupon code is not valid.'); } } $this->getQuote()->collectTotals()->save(); /* @var $service Mage_Sales_Model_Service_Quote */ $service = Mage::getModel('sales/service_quote', $this->getQuote()); $service->submitAll(); $order = $service->getOrder(); return $this;what we pass here $flatOrderDataObject->set(…);
Great article,
So how do you set the product price using Vinais code? I get order, but products have no prices…please help..?
Thanks!
For some more information about this topic, please check ours Inchoo Demostore extension on Magento Connect: http://www.magentocommerce.com/magento-connect/inchoo-demostore-5050.html
Ahh…nevermind i was trying to place an order with a disabled product…oops
I’m implementing your solution but I’m having a problem with the shipping method. I get the following error.
“Please specify a shipping method.” probably because in Sales/Model/Service/Quote when
$rate = $address->getShippingRateByCode($method);
rate is empty and the following statement gets executed:
if (!$this->getQuote()->isVirtual() && (!$method || !$rate)) {
Mage::throwException(Mage::helper(‘sales’)->__(‘Please specify a shipping method.’));
}
Any help will be really appreciated
Thanks! This all helped a lot, comments included.
Hi! Thank’s for article. I have question – how I can show checkout programmatically with paypal payment?