Create order programmatically in Magento - php

I'm using these two methods to create orders programmatically in Magento.
The first one creates a Quote:
public function prepareCustomerOrder($customerId, array $shoppingCart, array $shippingAddress, array $billingAddress,
$shippingMethod, $couponCode = null)
{
$customerObj = Mage::getModel('customer/customer')->load($customerId);
$storeId = $customerObj->getStoreId();
$quoteObj = Mage::getModel('sales/quote')->assignCustomer($customerObj);
$storeObj = $quoteObj->getStore()->load($storeId);
$quoteObj->setStore($storeObj);
// add products to quote
foreach($shoppingCart as $part) {
$productModel = Mage::getModel('catalog/product');
$productObj = $productModel->setStore($storeId)->setStoreId($storeId)->load($part['PartId']);
$productObj->setSkipCheckRequiredOption(true);
try{
$quoteItem = $quoteObj->addProduct($productObj);
$quoteItem->setPrice(20);
$quoteItem->setQty(3);
$quoteItem->setQuote($quoteObj);
$quoteObj->addItem($quoteItem);
} catch (exception $e) {
return false;
}
$productObj->unsSkipCheckRequiredOption();
$quoteItem->checkData();
}
// addresses
$quoteShippingAddress = new Mage_Sales_Model_Quote_Address();
$quoteShippingAddress->setData($shippingAddress);
$quoteBillingAddress = new Mage_Sales_Model_Quote_Address();
$quoteBillingAddress->setData($billingAddress);
$quoteObj->setShippingAddress($quoteShippingAddress);
$quoteObj->setBillingAddress($quoteBillingAddress);
// coupon code
if(!empty($couponCode)) $quoteObj->setCouponCode($couponCode);
// shipping method an collect
$quoteObj->getShippingAddress()->setShippingMethod($shippingMethod);
$quoteObj->getShippingAddress()->setCollectShippingRates(true);
$quoteObj->getShippingAddress()->collectShippingRates();
$quoteObj->collectTotals(); // calls $address->collectTotals();
$quoteObj->setIsActive(0);
$quoteObj->save();
return $quoteObj->getId();
}
And the second one uses that Quote to create Order:
public function createOrder($quoteId, $paymentMethod, $paymentData)
{
$quoteObj = Mage::getModel('sales/quote')->load($quoteId); // Mage_Sales_Model_Quote
$items = $quoteObj->getAllItems();
$quoteObj->reserveOrderId();
// set payment method
$quotePaymentObj = $quoteObj->getPayment(); // Mage_Sales_Model_Quote_Payment
$quotePaymentObj->setMethod($paymentMethod);
$quoteObj->setPayment($quotePaymentObj);
// convert quote to order
$convertQuoteObj = Mage::getSingleton('sales/convert_quote');
$orderObj = $convertQuoteObj->addressToOrder($quoteObj->getShippingAddress());
$orderPaymentObj = $convertQuoteObj->paymentToOrderPayment($quotePaymentObj);
// convert quote addresses
$orderObj->setBillingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getBillingAddress()));
$orderObj->setShippingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getShippingAddress()));
// set payment options
$orderObj->setPayment($convertQuoteObj->paymentToOrderPayment($quoteObj->getPayment()));
if ($paymentData) {
$orderObj->getPayment()->setCcNumber($paymentData->ccNumber);
$orderObj->getPayment()->setCcType($paymentData->ccType);
$orderObj->getPayment()->setCcExpMonth($paymentData->ccExpMonth);
$orderObj->getPayment()->setCcExpYear($paymentData->ccExpYear);
$orderObj->getPayment()->setCcLast4(substr($paymentData->ccNumber,-4));
}
// convert quote items
foreach ($items as $item) {
// #var $item Mage_Sales_Model_Quote_Item
$orderItem = $convertQuoteObj->itemToOrderItem($item);
$options = array();
if ($productOptions = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct())) {
$options = $productOptions;
}
if ($addOptions = $item->getOptionByCode('additional_options')) {
$options['additional_options'] = unserialize($addOptions->getValue());
}
if ($options) {
$orderItem->setProductOptions($options);
}
if ($item->getParentItem()) {
$orderItem->setParentItem($orderObj->getItemByQuoteItemId($item->getParentItem()->getId()));
}
$orderObj->addItem($orderItem);
}
$orderObj->setCanShipPartiallyItem(false);
try {
$orderObj->place();
} catch (Exception $e){
Mage::log($e->getMessage());
Mage::log($e->getTraceAsString());
}
$orderObj->save();
//$orderObj->sendNewOrderEmail();
return $orderObj->getId();
}
The process works fine, no errors, and the order is created. But the total is 0 and there are no products in it no matter what I put.
I've traced it and I can confirm that the rows are added to the sales_flat_quote and sales_flat_quote_item tables, so that is ok. But when running the createOrder and calling
$items = $quoteObj->getAllItems();
an empty array is always returned, and I have no idea why. I have configurable and simple products in my shop. This happens when I add simple, when I add configurable the error appears as the method
$quoteItem = $quoteObj->addProduct($productObj);
returns null.

It seems to me, you didn't load product collection, therefore, the cart always return empty. Try this link, it will give you more clear help. Create order programmatically
// this is get only one product, you can refactor the code
$this->_product = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('sku', 'Some value here...')
->addAttributeToSelect('*')
->getFirstItem();
// load product data
$this->_product->load($this->_product->getId());

This code worked for me,
public function createorder(array $orderdata)
{
$quoteId = $orderdata['quoteId'];
$paymentMethod = $orderdata['paymentMethod'];
$paymentData = $orderdata['paymentData'];
$quoteObj = Mage::getModel('sales/quote')->load($quoteId);
$items = $quoteObj->getAllItems();
$quoteObj->reserveOrderId();
$quotePaymentObj = $quoteObj->getPayment();
$quotePaymentObj->setMethod($paymentMethod);
$quoteObj->setPayment($quotePaymentObj);
$convertQuoteObj = Mage::getSingleton('sales/convert_quote');
$orderObj = $convertQuoteObj->addressToOrder($quoteObj->getShippingAddress());
$orderPaymentObj = $convertQuoteObj->paymentToOrderPayment($quotePaymentObj);
$orderObj->setBillingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getBillingAddress()));
$orderObj->setShippingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getShippingAddress()));
$orderObj->setPayment($convertQuoteObj->paymentToOrderPayment($quoteObj->getPayment()));
foreach ($items as $item)
{
$orderItem = $convertQuoteObj->itemToOrderItem($item);
$options = array();
if ($productOptions = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct()))
{
$options = $productOptions;
}
if ($addOptions = $item->getOptionByCode('additional_options'))
{
$options['additional_options'] = unserialize($addOptions->getValue());
}
if ($options)
{
$orderItem->setProductOptions($options);
}
if ($item->getParentItem())
{
$orderItem->setParentItem($orderObj->getItemByQuoteItemId($item->getParentItem()->getId()));
}
$orderObj->addItem($orderItem);
}
$quoteObj->collectTotals();
$service = Mage::getModel('sales/service_quote', $quoteObj);
$service->submitAll();
$orderObj->setCanShipPartiallyItem(false);
try
{
$last_order_increment_id = Mage::getModel("sales/order")->getCollection()->getLastItem()->getIncrementId();
return $last_order_increment_id;
}
catch (Exception $e)
{
Mage::log($e->getMessage());
Mage::log($e->getTraceAsString());
return "Exception:".$e;
} }

I had the same problem and delved into the API to find a solution. I changed the way that I loaded a product by using :
$productEntityId = '123456';
$store_code = 'my_store_code';
$product = Mage::helper('catalog/product')->getProduct($productEntityId,Mage::app()->getStore($store_code)->getId());
I found this tutorial to be very useful too :
http://www.classyllama.com/content/unravelling-magentos-collecttotals
If you are looking for a script on order creation this is a very good start :
http://pastebin.com/8cft4d8v
Hope that this helps someone ;)

Related

How to copy an existing order (core, php) with Prestashop 1.6.1

I'm making a script that should make a copy of an existing order.
I can create the overall order, with this code:
$order = new Order($_GET["id_order"]);
$order->add();
But there's no products in the order - I tried with this:
$order_detail = new OrderDetail($_GET["id_order"]);
$order_detail->add();
What am I doing wrong, how can I copy an existing order?
You can duplicate an order using the duplicateObject() method from the ObjectModel class.
Here is a function that should do the trick :
function duplicateOrder($id_order)
{
$order = new Order($id_order);
$duplicatedOrder = $order->duplicateObject();
$orderDetailList = $order->getOrderDetailList();
foreach ($orderDetailList as $detail) {
$orderDetail = new orderDetail($detail['id_order_detail']);
$duplicatedOrderDetail = $orderDetail->duplicateObject();
$duplicatedOrderDetail->id_order = $duplicatedOrder->id;
$duplicatedOrderDetail->save();
}
$orderHistoryList = $order->getHistory(Configuration::get('PS_LANG_DEFAULT'));
foreach ($orderHistoryList as $history) {
$orderHistory = new OrderHistory($history['id_order']);
$duplicatedOrderHistory = $orderHistory->duplicateObject();
$duplicatedOrderHistory->id_order = $duplicatedOrder->id;
$duplicatedOrderHistory->save();
}
}

Magento Split Order via product's attribute manufacturer

I am trying to split order by using product's manufacturer attribute.Like if there are 3 products in cart as 2 lee(manufacturer) products and 1 Levis(manufacturer) product.So when we place order it should generate 2 order one for lee and other one is for levis.
So with some help i am able to split order(problem in total but's it's ok)but it's creating order per product like 5 product 5 orders, so i am just asking is it possible to do as i want?
Here is code for split order which i am using currently
class PMTECH_Splitorder_Model_Checkout_Type_Onepage extends Mage_Checkout_Model_Type_Onepage
{
/**
* Create order based on checkout type. Create customer if necessary.
*
* #return Mage_Checkout_Model_Type_Onepage
*/
public function saveOrder()
{
$this->validate();
$isNewCustomer = false;
switch ($this->getCheckoutMethod()) {
case self::METHOD_GUEST:
$this->_prepareGuestQuote();
break;
case self::METHOD_REGISTER:
$this->_prepareNewCustomerQuote();
$isNewCustomer = true;
break;
default:
$this->_prepareCustomerQuote();
break;
}
$cart = $this->getQuote();
$key=0;
foreach ($cart->getAllItems() as $item)
{
$key= $key+1;
$temparray[$key]['product_id']= $item->getProduct()->getId();
$temparray[$key]['qty']= $item->getQty();
$cart->removeItem($item->getId());
$cart->setSubtotal(0);
$cart->setBaseSubtotal(0);
$cart->setSubtotalWithDiscount(0);
$cart->setBaseSubtotalWithDiscount(0);
$cart->setGrandTotal(0);
$cart->setBaseGrandTotal(0);
$cart->setTotalsCollectedFlag(false);
$cart->collectTotals();
}
$cart->save();
foreach ($temparray as $key => $item)
{
$customer_id = Mage::getSingleton('customer/session')->getId();
$store_id = Mage::app()->getStore()->getId();
$customerObj = Mage::getModel('customer/customer')->load($customer_id);
$quoteObj = $cart;
$storeObj = $quoteObj->getStore()->load($store_id);
$quoteObj->setStore($storeObj);
$productModel = Mage::getModel('catalog/product');
$productObj = $productModel->load($item['product_id']);
$quoteItem = Mage::getModel('sales/quote_item')->setProduct($productObj);
$quoteItem->setBasePrice($productObj->getFinalPrice());
$quoteItem->setPriceInclTax($productObj->getFinalPrice());
$quoteItem->setData('original_price', $productObj->getPrice());
$quoteItem->setData('price', $productObj->getPrice());
$quoteItem->setRowTotal($productObj->getFinalPrice());
$quoteItem->setQuote($quoteObj);
$quoteItem->setQty($item['qty']);
$quoteItem->setStoreId($store_id);
$quoteObj->addItem($quoteItem);
$quoteObj->setBaseSubtotal($productObj->getFinalPrice());
$quoteObj->setSubtotal($productObj->getFinalPrice());
$quoteObj->setBaseGrandTotal($productObj->getFinalPrice());
$quoteObj->setGrandTotal($productObj->getFinalPrice());
$quoteObj->setStoreId($store_id);
$quoteObj->collectTotals();
$quoteObj->save();
$this->_quote=$quoteObj;
$service = Mage::getModel('sales/service_quote', $quoteObj);
$service->submitAll();
if ($isNewCustomer) {
try {
$this->_involveNewCustomer();
} catch (Exception $e) {
Mage::logException($e);
}
}
$this->_checkoutSession->setLastQuoteId($quoteObj->getId())
->setLastSuccessQuoteId($quoteObj->getId())
->clearHelperData();
$order = $service->getOrder();
if ($order) {
Mage::dispatchEvent('checkout_type_onepage_save_order_after',
array('order'=>$order, 'quote'=>$quoteObj));
$quoteObj->removeAllItems();
$quoteObj->setTotalsCollectedFlag(false);
$quoteObj->collectTotals();
}
/**
* a flag to set that there will be redirect to third party after confirmation
* eg: paypal standard ipn
*/
$redirectUrl = $this->getQuote()->getPayment()->getOrderPlaceRedirectUrl();
/**
* we only want to send to customer about new order when there is no redirect to third party
*/
if (!$redirectUrl && $order->getCanSendNewEmailFlag()) {
try {
$order->sendNewOrderEmail();
} catch (Exception $e) {
Mage::logException($e);
}
}
// add order information to the session
$this->_checkoutSession->setLastOrderId($order->getId())
->setRedirectUrl($redirectUrl)
->setLastRealOrderId($order->getIncrementId());
// as well a billing agreement can be created
$agreement = $order->getPayment()->getBillingAgreement();
if ($agreement) {
$this->_checkoutSession->setLastBillingAgreementId($agreement->getId());
}
}
// add recurring profiles information to the session
$profiles = $service->getRecurringPaymentProfiles();
if ($profiles) {
$ids = array();
foreach ($profiles as $profile) {
$ids[] = $profile->getId();
}
$this->_checkoutSession->setLastRecurringProfileIds($ids);
// TODO: send recurring profile emails
}
Mage::dispatchEvent(
'checkout_submit_all_after',
array('order' => $order, 'quote' => $this->getQuote(), 'recurring_profiles' => $profiles)
);
return $this;
}
}
And i think it will be helpful to insert data in flat order quote item so i have that field in this table with product's manufacturer id inserted in it
Thank you in advance for any help.
I found solution on my own, posting answer so may be it can help someone.
i am posting what i made changes in code.
foreach ($cart->getAllItems() as $item)
{
$key= $key+1;
$product = Mage::getModel('catalog/product')->load($item->getProduct()->getId());
$temparray[$product->getManufacturer()][] = array('product_id'=>$item->getProduct()->getId(),'qty'=>$item->getQty());
//added this above line for grouping products by brands
$cart->removeItem($item->getId());
$cart->setSubtotal(0);
$cart->setBaseSubtotal(0);
$cart->setSubtotalWithDiscount(0);
$cart->setBaseSubtotalWithDiscount(0);
$cart->setGrandTotal(0);
$cart->setBaseGrandTotal(0);
$cart->setTotalsCollectedFlag(false);
$cart->collectTotals();
}
$cart->save();
foreach ($temparray as $key => $items)
{ // this ends as it is in my question code
foreach($items as $item){ //added this foreach
$customer_id = Mage::getSingleton('customer/session')->getId();
$store_id = Mage::app()->getStore()->getId();
$customerObj = Mage::getModel('customer/customer')->load($customer_id);
$quoteObj = $cart;
$storeObj = $quoteObj->getStore()->load($store_id);
$quoteObj->setStore($storeObj);
$productModel = Mage::getModel('catalog/product');
$productObj = $productModel->load($item['product_id']);
$quoteItem = Mage::getModel('sales/quote_item')->setProduct($productObj);
$quoteItem->setBasePrice($productObj->getFinalPrice());
$quoteItem->setPriceInclTax($productObj->getFinalPrice());
$quoteItem->setData('original_price', $productObj->getPrice());
$quoteItem->setData('price', $productObj->getPrice());
$quoteItem->setRowTotal($productObj->getFinalPrice() * $item['qty']);
$quoteItem->setQuote($quoteObj);
$quoteItem->setQty($item['qty']);
$quoteItem->setManufacturerName($key);//not sure about this that i need to add this or not
$quoteItem->setStoreId($store_id);
$quoteObj->addItem($quoteItem);
$quoteObj->setBaseSubtotal($productObj->getFinalPrice());
$quoteObj->setSubtotal($productObj->getFinalPrice());
$quoteObj->setBaseGrandTotal($productObj->getFinalPrice());
$quoteObj->setGrandTotal($productObj->getFinalPrice());
$quoteObj->setStoreId($store_id);
$quoteObj->collectTotals();
$quoteObj->save();
$this->_quote=$quoteObj;
}
Okay so by doing this now i am able to split order by brand as i want.

Magento Invalid - method Mage_Sales_Model_Order::assignCustomer

Basically, im trying to make a finance section on magento, I have looked into how to place an order as part of the finance submission, everywhere I look uses the code below (Not exact):
$order = Mage::getModel('sales/order');
$store = Mage::app()->getStore();
$website_id = Mage::app()->getWebsite()->getStoreId();
$quote = Mage::getModel('sales/order')->setStoreId($store->getId());
$customer = Mage::getSingleton('customer/session')->getCustomer();
$quote->assignCustomer($customer);
$quote->setSendCconfirmation(1);
$product_ids = array();
$cart = Mage::getModel('checkout/cart')->getQuote();
foreach($cart->getAllVisibleItems() as $item) {
$quote->addProduct($item->getProduct() , $item->getQty());
}
$shipping = $quote->getShippingAddress();
$shipping->setCollectShippingRates(true)->collectShippingRates()->setShippingMethod('flatrate_flatrate')->setPaymentMethod(array(
'method' => 'checkmo'
));
try {
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
$increment_id = $service->getOrder()->getRealOrderId();
}
catch(Exception $e) {
die($e->getMessage());
}
catch(Mage_Core_Exception $d) {
die($d->getMessage());
}
And for some reason i keep getting this error:
I was loading the customer from session, and not supplying the correct model as an argument , for anyone also looking for this answer;
$customer = Mage::getModel('customer/customer')->loadByEmail(Mage::getSingleton('customer/session')->getCustomer()->getEmail());

Magento BestSeller Module - Summing Configurable Products And Adding Them Back In

This has been bugging me for quite a while. Basically, what we are trying to achieve is in the bestsellers on our front page, to have the products listed in the amount sold. For simple products this works fine, however for configurable products they will be displayed as a quantity ordered of 0.
I somehow need to find a way to get the configurable products, find the simple products attached to them, sum the amount sold of these simple products, add this back to the configurable products ID and feed this information back in so it will list the configurable product with the right amount that has been sold.
I have placed, what I believe, the areas of code that require changing. If anyone could help it would be very much appreciated!
Collection.php
class Luxe_Bestsellers_Model_Mysql4_Product_Collection extends Mage_Reports_Model_Mysql4_Product_Collection
{
public function addOrderedQty($from = '', $to = '', $getComplexProducts=false)
{
$qtyOrderedTableName = $this->getTable('sales/order_item');
$qtyOrderedFieldName = 'qty_ordered';
$productIdFieldName = 'product_id';
if (!$getComplexProducts) {
$compositeTypeIds = Mage::getSingleton('catalog/product_type')->getCompositeTypes();
$productTypes = $this->getConnection()->quoteInto(' AND (e.type_id NOT IN (?))', $compositeTypeIds);
} else {
$productTypes = '';
}
if ($from != '' && $to != '') {
$dateFilter = " AND `order`.created_at BETWEEN '{$from}' AND '{$to}'";
} else {
$dateFilter = "";
}
$this->getSelect()->reset()->from(
array('order_items' => $qtyOrderedTableName),
array('ordered_qty' => "SUM(order_items.{$qtyOrderedFieldName})")
);
$_joinCondition = $this->getConnection()->quoteInto(
'order.entity_id = order_items.order_id AND order.state<>?', Mage_Sales_Model_Order::STATE_CANCELED
);
$_joinCondition .= $dateFilter;
$this->getSelect()->joinInner(
array('order' => $this->getTable('sales/order')),
$_joinCondition,
array()
);
$this->getSelect()
->joinInner(array('e' => $this->getProductEntityTableName()),
"e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}")
->group('e.entity_id')
->having('ordered_qty > 0');
return $this;
}
}
List.php
class Luxe_Bestsellers_Block_List extends Mage_Catalog_Block_Product_List
{
protected $_defaultToolbarBlock = 'bestsellers/list_toolbar';
protected function _beforeToHtml() {
$this->addPriceBlockType('bundle', 'bundle/catalog_product_price', 'bundle/catalog/product/price.phtml');
return parent::_beforeToHtml();
}
public function _toHtml()
{
if ($this->_productCollection->count()) {
return parent::_toHtml();
} else {
return '';
}
}
public function getTimeLimit()
{
if ($this->getData('time_limit_in_days')) {
return intval($this->getData('time_limit_in_days'));
} else {
return intval(Mage::getStoreConfig('bestsellers/bestsellers/time_limit_in_days'));
}
}
public function getBlockTitle()
{
if ($this->getData('title')) {
return $this->getData('title');
} else {
return Mage::getStoreConfig('bestsellers/bestsellers/title');
}
}
public function isShowOutOfStock() {
return (bool)Mage::getStoreConfig('bestsellers/bestsellers/show_out_of_stock');
}
public function getProductsLimit()
{
if ($this->getData('limit')) {
return intval($this->getData('limit'));
} else {
return $this->getToolbarBlock()->getLimit();
}
}
public function getDisplayMode()
{
return $this->getData('display_mode');
}
/**
* Retrieve loaded category collection
*
* #return Mage_Eav_Model_Entity_Collection_Abstract
*/
protected function _getProductCollection()
{
if (is_null($this->_productCollection)) {
$layer = Mage::getModel('catalog/layer');
$bestsellers = Mage::getResourceModel('reports/product_collection');
if ($this->getTimeLimit()) {
$product = Mage::getModel('catalog/product');
$todayDate = $product->getResource()->formatDate(time());
$startDate = $product->getResource()->formatDate(time() - 60 * 60 * 24 * $this->getTimeLimit());
$bestsellers->addOrderedQty($startDate, $todayDate, true);
} else {
$bestsellers->addOrderedQty('', '', true);
}
$bestsellers->addStoreFilter()
->setOrder('ordered_qty', 'desc')
->setPageSize($this->getProductsLimit());
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($bestsellers);
if ($layer->getCurrentCategory()->getId() != Mage::app()->getStore()->getRootCategoryId()) {
$bestsellers->addCategoryFilter($layer->getCurrentCategory());
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($bestsellers);
}
if (!$this->isShowOutOfStock()) {
Mage::getModel('cataloginventory/stock')->addInStockFilterToCollection($bestsellers);
}
$bestsellers->getSelect()->where('order.store_id = ?', Mage::app()->getStore()->getId());
$productIds = array();
foreach ($bestsellers as $p) {
$productIds[] = $p->getId();
}
$collection = Mage::getResourceModel('catalog/product_collection');
Mage::getModel('catalog/layer')->prepareProductCollection($collection);
$attributes = Mage::getSingleton('catalog/config')->getProductAttributes();
$collection->addIdFilter($productIds)
->addAttributeToSelect($attributes)
->addMinimalPrice()
->addFinalPrice();
$this->_productCollection = $collection;
}
return $this->_productCollection;
}
/**
* Translate block sentence
*
* #return string
*/
public function __()
{
$args = func_get_args();
$expr = new Mage_Core_Model_Translate_Expr(array_shift($args), 'Mage_Catalog');
array_unshift($args, $expr);
return Mage::app()->getTranslator()->translate($args);
}
}
Thanks for posting that sample code! I was able to use it to create a solution which should work well for both of us.
I found that configurable product sales are being summed correctly but aren't being included in the results; their child products appear instead. My solution was to include configurable products, do a left join on the catalog_product_super_link table, and filter out anything that has a parent_id. Here are the changes you'll need to make:
Collection.php:
public function addOrderedQty($from = '', $to = '', $getComplexProducts=false, $getComplexChildProducts = true, $getRemovedProducts = true)
{
$qtyOrderedTableName = $this->getTable('sales/order_item');
$qtyOrderedFieldName = 'qty_ordered';
$productIdFieldName = 'product_id';
if (!$getComplexProducts) {
$compositeTypeIds = Mage::getSingleton('catalog/product_type')->getCompositeTypes();
$productTypes = $this->getConnection()->quoteInto(' AND (e.type_id NOT IN (?))', $compositeTypeIds);
} else {
$productTypes = '';
}
if ($from != '' && $to != '') {
$dateFilter = " AND `order`.created_at BETWEEN '{$from}' AND '{$to}'";
} else {
$dateFilter = "";
}
$this->getSelect()->reset()->from(
array('order_items' => $qtyOrderedTableName),
array(
'ordered_qty' => "SUM(order_items.{$qtyOrderedFieldName})",
'order_items_name' => 'order_items.name'
)
);
$_joinCondition = $this->getConnection()->quoteInto(
'order.entity_id = order_items.order_id AND order.state<>?', Mage_Sales_Model_Order::STATE_CANCELED
);
$_joinCondition .= $dateFilter;
$this->getSelect()->joinInner(
array('order' => $this->getTable('sales/order')),
$_joinCondition,
array()
);
// Add join to get the parent id for configurables
$this->getSelect()->joinLeft(
array('cpsl' => $this->getTable('catalog/product_super_link')),
'cpsl.product_id = order_items.product_id',
'cpsl.parent_id'
);
if(!$getComplexChildProducts)
$this->getSelect()->having('parent_id IS NULL');
if($getRemovedProducts)
{
$this->getSelect()
->joinLeft(array('e' => $this->getProductEntityTableName()),
"e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}")
->group('order_items.product_id');
}
else
{
$this->getSelect()
->joinInner(array('e' => $this->getProductEntityTableName()),
"e.entity_id = order_items.{$productIdFieldName} AND e.entity_type_id = {$this->getProductEntityTypeId()}{$productTypes}")
->group('e.entity_id');
}
$this->getSelect()->having('ordered_qty > 0');
// This line is for debug purposes, in case you'd like to see what the SQL looks like
// $x = $this->getSelect()->__toString();
return $this;
}
List.php - Find the following two lines...
$bestsellers->addOrderedQty($startDate, $todayDate, true);
$bestsellers->addOrderedQty('', '', true);
... and change them to:
$bestsellers->addOrderedQty($startDate, $todayDate, true, false, false);
$bestsellers->addOrderedQty('', '', true, false, false);
My changes added two new optional parameters, which both default to true, as to not break existing functionality.
When $getComplexChildProducts is set to false, all child items of the configurable product will be removed from the results.
$getRemovedProducts determines whether or not previously ordered products (which have since been deleted from Magento) should also appear.
Please note that your report statistics will need to be up-to-date in order to get accurate results.
Hope this helps! Let me know if you have any questions.
You can use the following piece of code to get the simple products attached to the configurable product. I'm not sure if this is 100% correct, I haven't tried it myself.
$simpleProducts = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null, $product);

Magento Configurable Product working but not showing until re-saved

I am currently learning how to create configurable product for Magento. Its all working fine, the product was successfully imported using my codes including its associated products. The problem is the product does not show up in front-end. I have to manually go to the back-end, edit the product and save it. Take note I do not have to change anything, I just need to open it, and save. Only then it will show up in front-end. Any idea why is that?
define('MAGENTO', dirname(dirname(__FILE__)));
require_once MAGENTO . '/app/Mage.php';
require_once 'FeedMag.php';
$myFeed = new FeedMag();
Mage::app();
// test data
$sku = "TESTSKU2";
$inventory = "10";
$stockData['qty'] = $inventory;
$stockData['is_in_stock'] = 1;
$simple['Description'] = 'Configurable Product 1';
$simple['ShortDescription'] = 'Short Description';
$simple['LongDescription'] = 'Long Description';
$simple['BrandCode'] = 'Nike';
$attr['color'] = 'Blue';
$attr['size'] = 1;
$price = 11;
// get attribute id
foreach($attr AS $key=>$value) {
$attr_ids[] = $myFeed->attributeValueExists($key, $value);
}
$new = false;
echo "<pre>";
try {
// get product id from SKU
$id = Mage::getModel('catalog/product')->getIdBySku($sku);
// load product if id exist or create a new one
if($id && $id > 0) {
$product = Mage::getModel('catalog/product')->load($id);
}
else {
$product = Mage::getModel('catalog/product')->setSku($sku);
$new = true;
}
// set it to configurable
$product->setTypeId('configurable');
// get attributes' id
$usingAttributeIds = $new_array = array();
foreach( $attr as $key=>$value ) {
$attribute = $product -> getResource() -> getAttribute( $key );
if ( $product -> getTypeInstance() -> canUseAttribute( $attribute ) ) {
if ( $new ) { // fix for duplicating attributes error
$usingAttributeIds[] = $attribute -> getAttributeId();
}
}
}
// if we have attributes' ID, set it to the product
if ( !empty( $usingAttributeIds ) ) {
$product -> getTypeInstance() -> setUsedProductAttributeIds( $usingAttributeIds );
$attributes_array = $product->getTypeInstance()->getConfigurableAttributesAsArray();
foreach($attributes_array as $key => $attribute_value) {
$attributes_array[$key]['label'] = $attribute_value['frontend_label'];
}
$product -> setConfigurableAttributesData($attributes_array);
$product -> setCanSaveConfigurableAttributes( true );
$product -> setCanSaveCustomOptions( true );
}
// set product data
$product->setStoreId(0)
->setAttributeSetId(4)
->setStockData($stockData)
->setPrice($price)
->setName($simple['Description'])
->setShortDescription($simple['ShortDescription'])
->setDescription($simple['LongDescription'])
->setCategoryIds(array(3))
->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
->setBrand($simple['BrandCode'])
->setStatus(1)
->setTaxClassId(2) //Taxable goods
->save();
// get previous children if any
$associated = Mage::getModel('catalog/product_type_configurable')
->getChildrenIds($product->getId());
// add new simple product to configurable product
$associated[0][] = Mage::getModel('catalog/product')->getIdBySku('SIMPLE1');
// add all simple product to configurable product
Mage::getResourceModel('catalog/product_type_configurable')
->saveProducts($product->getId(), array_unique($associated[0]));
}
catch (Mage_Core_Exception $e) {
echo $e->getMessage();
}
catch (Exception $e) {
echo $e;
}
echo "</pre>";
FeedMag is a custom class made by my colleague. There's a lot of method in there but for this purpose I'll be using just one; attributeValueExists to check if said attribute exists and if it does, its ID will be returned.
Simple product already exists so I just need to use it (SIMPLE1).
Its an issue with the indices when importing. You must be missing a field in the export sheet that is required to associate the items and the store. The reason it works when you save is because its rebuilding the table indices which is filling in that missing data.

Categories