Magento – Programatically created order not adding bundle products correctly

apicheckoutmagento-1.7orders

I have an order flow outside of Magento that uses both Magento's direct methods and API SOAP methods to create an order. (The API was used completely at first until we found out it wouldn't pass the payment on order completion) For the most part, it works great, except when it comes to bundle products. Our bundle products have 2 simple products with in, and when the order completes, one of the products is in the bundle, and the other is added separately. I've tracked it down to when my custom class gets the re-fetches the quote instead of using the existing quote, but then the shipping doesn't get added, even though it does go through the shipping methods. I can't figure out what would cause that to happen.

My custom class:

class createOrder{
    // Variables, construct, and address stuff here
    function getParams($item){
        $super_group = array();
        $parentId = $item['parentID'];
        $children = array($item['childID']);
        $child_qty = $item['qty'];
        foreach($children as $child){
            if(intval($child)){
                $super_group[$child] = $child_qty;
            }
        }
        // set params for product
        if (!empty($super_group)) {
            $params = array('super_group' => $super_group);
        }
        else {
            // bundled product
            if ($parentId == 121) { //Product1:
                $params = array(
                    'product' => '121',
                    'related_product' => '',
                    'qty' => "{$item['qty']}",
                    'bundle_option' => array(7=>'3',8=>'14'),
                    'bundle_option_qty' => array(7=>'1',8=>'1'),
                );
            }
            else if ($parentId == 120) { //Product2:
                $params = array(
                    'product' => '120',
                    'related_product' => '',
                    'qty' =>"{$item['qty']}",
                    'bundle_option' => array(5=>"1",6=>"2"),
                );
            }
            else if ($parentId == 146) { //Product3:
                $params = array(
                    'product' => '146',
                    'related_product' => '',
                    'qty' => "{$item['qty']}",
                    'bundle_option' => array(13=>'9',14=>'10'),
                );
            }
            else if($parentId == 382){ //Product4:
                $params = array(
                    'product' => '382',
                    'related_product' => '',
                    'qty' => "{$item['qty']}",
                    'bundle_option' => array(15=>'11',16=>'12'),
                    'bundle_option_qty'=>array(15=>'1',16=>'1'),
                );
            }   
        }
        return $params;
    }

    function completeOrder($shopping_cart_id,$pay,$gift = null,$newOTO = false){
        Mage::log(' -- start completeOrder ---');
        $error = NULL;

        // Get quote and set stuff
        // With this uncommented, products added correctly, but no shipping
        // if(!empty($this->_quote))
            // $quote = $this->_quote;
        // else
            $quote = Mage::getModel('sales/quote')->load($shopping_cart_id);
        $quote->setIsMultiShipping(false);
        $quote->setCheckoutMethod('guest');
        $quote->setCustomerId(null);
        if(isset($_SERVER['REMOTE_ADDR']))
            $quote->setRemoteIp($_SERVER['REMOTE_ADDR']);

        if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
            $quote->setXForwardedFor($_SERVER['HTTP_X_FORWARDED_FOR']);

        $quote->setCustomerGroupId(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID);
        $quote->reserveOrderId();

        // Add shipping
        $quote->getShippingAddress()->setCollectShippingRates(true);
        $quote->getShippingAddress()->collectShippingRates();

        // $quote->collectTotals();
        $quote->save();

        $payment=$quote->getPayment();
        $convertQuote = Mage::getSingleton('sales/convert_quote');
        $order = $convertQuote->addressToOrder($quote->getShippingAddress());

        $order->setPayment($convertQuote->paymentToOrderPayment($payment));
        $order->getPayment()->setCcNumber($pay['cc_number']);
        $order->getPayment()->setCcType($payment->getCcType());
        $order->getPayment()->setCcExpMonth($payment->getCcExpMonth());
        $order->getPayment()->setCcExpYear($payment->getCcExpYear());
        $order->getPayment()->setCcLast4(substr($pay['cc_number'],-4));

        $order->setBillingAddress($convertQuote->addressToOrderAddress($quote->getBillingAddress()));
        $order->setShippingAddress($convertQuote->addressToOrderAddress($quote->getShippingAddress()));
        foreach($quote->getAllItems() as $item){
            $orderItem = $convertQuote->itemToOrderItem($item);
            if ($item->getParentItem()) {
                $orderItem->setParentItem($order->getItemByQuoteItemId($item->getParentItem()->getId()));
            }
            $order->addItem($orderItem);
        }

        try{
            $order->place();
            $order->save();

            $this->orderID = $order->getIncrementId();
            if($newOTO)
                $order->sendNewOrderEmail();
        } catch (Exception $e){
            Mage::log($e->getMessage());
            Mage::log($e->getTraceAsString());
            if($e->getMessage() == "Error in capturing the payment") {
                $error = "A problem has occured with the credit card you are providing. Please try again, or call us at 1-877-371-1807.";
            }
            else {
                $error = "There has been an error placing your order. Please review the information below.";
            }
        }
        return $error;  
    }

These get called with :

Products and Shipping:

foreach ($_SESSION['cart'] as $item) {
    Mage::log('item');
    $params = $OTOrder->getParams($item);
    $parentId = $item['parentID'];
    $parentIDs[] = $parentId;
    if($parentId) {
        try {
            //Get object of main grouped product
            $product = Mage::getModel('catalog/product')->load($parentId);

            //Check product availability
            if (!$product) {
                Mage::log("Error in product! ".$parentId);
                return;
            }

            //Get cart object
            $cart = Mage::getModel('checkout/cart');
            $quote = Mage::getModel('sales/quote')->load($shopping_cart_id);
            if (!$quote) {
                Mage::log("Error in quote! ".$parentId);
                return;
            }
            //Add product to cart with specified parameters and save the cart object
            $quote->addProduct($product, new Varien_Object($params))->save();
            $quote->collectTotals()->save();
            $OTOrder->setQuote($quote);
            Mage::getSingleton('checkout/session')->setCartWasUpdated(true);

        }
        catch (Mage_Core_Exception $e){
            $_SESSION['orderError'] = 'Error in "'.$item['desc'].'"';
            Mage::log("parentID: ".$e->getMessage());
            if (Mage::getSingleton('checkout/session')->getUseNotice(true)){
                header("Location: OrderForm.php?keycode=" . $keystring);
                exit;
            }
            else{
                $messages = array_unique(explode("\n", $e->getMessage()));
                foreach ($messages as $message) {
                    $_SESSION['orderError'] .= "<br />".$message;
                }
                header("Location: OrderForm.php?keycode=" . $keystring);
                exit;
            }
        }
        catch (Exception $e){
            $_SESSION['orderError'] = 'Error in "'.$item['desc'].'"';
            $_SESSION['orderError'] .= "Cannot add the item to shopping cart.";
            Mage::log("Adding product: ".$e->getMessage());
            header("Location: OrderForm.php?keycode=" . $keystring);
            exit;
        } 
    }
}
    $pass = false;
while(!$pass) {
    try{
        $methods = $soap->shoppingCartShippingList($session_id, $shopping_cart_id);
        foreach($methods as $method){
            if($method->method_title != 'Priority')
                $shipCode = $method->code;              
        }
        if(!empty($shipCode))
            $soap->shoppingCartShippingMethod($session_id, $shopping_cart_id, $shipCode);
        $pass = true;
    }
    catch(Exception $e)
    {
        if($e->getMessage() == 'Error Fetching http headers')
            $pass == false;
        else{
            $_SESSION['orderError'] = "Problem with billing or shipping address.";
            $_SESSION['error'] = true;
            Mage::log("shoppingCartShippingList: ".$e->getMessage());
            header("Location: OrderForm.php?keycode=" . $keystring);
            exit;
        }
    }
}

The order completion is called with:

$err = $OTOrder->completeOrder($shopping_cart_id,$paymentMethod,$giftOption);

Best Answer

I was able to create an order with a bundle product using the following code

<?php

require_once 'app/Mage.php';
define('MAGENTO_ROOT', getcwd());

$compilerConfig = MAGENTO_ROOT . '/includes/config.php';
if (file_exists($compilerConfig)) {
    include $compilerConfig;
}

class JLR_Orders_Create {
  public function CreateOrder2() {

        try {
            $storeObject = Mage::getModel('core/store')->load(4); // Store ID
        }
        catch(Exeception $ex)
        {
            echo $ex->getMessage();
        }


        $cart_api = Mage::getModel('checkout/cart_api');
        $quoteId = $cart_api->create($storeObject->getStoreId());
        $quote = Mage::getModel('sales/quote')->loadByIdWithoutStore($quoteId);

        $product = Mage::getModel('catalog/product');
        $productId = $product->getIdBySku('SBTEMP075'); // Bundle Product SKU

        $params = array(
            'product' =>  $productId,
            'related_product' => null,
            'bundle_option' => array(
                    164 => '3235', // Bundle Options
                    165 => '3240',
                    166 => '3241'

                ),
             'bundle_option_qty' => array(
                    164 => 1, // Bundle Quantities
                    165 => 1,
                    166 => 1
                ),
        );

        $request = new Varien_Object();
        $request->setData($params);

        $_value['Email'] = 'ZsdfsXcrtdfert@gmail.com';
        $_value['First Name'] = 'Jeffrey';
        $_value['Last Name'] = 'Roberts';
        $_value['Address'] = 'Biscayne Blvd';
        $_value['City'] = 'Miami';
        $_value['Post Code'] = '33137';
        $_value['Telephone'] = '305-555-1155';

        // create customer
        $customer = Mage::getModel('customer/customer');
        $password = 'stackexchange';

        $customer->setWebsiteId(4); // Set Website ID
        $customer->loadByEmail($_value['Email']);
        $customer->setWebsiteId(4); // Set Website ID AGAIN!

        if(!$customer->getId()) {
            $customer->setEmail($_value['Email']);
            $customer->setFirstname($_value['First Name']);
            $customer->setLastname($_value['Last Name']);
            $customer->setPassword($password);
            $customer->setMode(Mage_Checkout_Model_Cart_Customer_Api::MODE_REGISTER);
        }
        else
        {
            $customer->setMode(Mage_Checkout_Model_Cart_Customer_Api::MODE_CUSTOMER);
        }

        try {
            $customer->save();
            $customer->setConfirmation(null);
            $customer->save();
        }
        catch (Exception $ex) {
            error_log(var_dump($ex));
        }

        if (! $customer->getId() ){
            return $this;                
        }

        $dataShipping = array(
            'firstname'  => $_value['First Name'],
            'lastname'   => $_value['Last Name'],
            'street'     => $_value['Address'],
            'city'       => $_value['City'],
            'region'     => '',
            'region_id'  => '',
            'postcode'   => $_value['Post Code'],
            'country_id' => 'CZ', //todo: un-hardcode this.
            'telephone'  => $_value['Telephone'],
        );

        $customerAddress = Mage::getModel('customer/address');

        if ($defaultShippingId = $customer->getDefaultShipping()){
             $customerAddress->load($defaultShippingId); 
        } else {   
             $customerAddress
                ->setCustomerId($customer->getId())
                ->setIsDefaultShipping('1')
                ->setSaveInAddressBook('1')
             ;
             $customer->addAddress($customerAddress);
        }            

        try {
            $customerAddress
                ->addData($dataShipping)
                ->save()
            ;           
        } catch(Exception $e){
            Mage::log('Address Save Error::' . $e->getMessage());
        }

        $customer->save();

        $product = new Mage_Catalog_Model_Product();
        $product->load($productId);

        $quote->addProduct($product, $request);
        $quote->setCustomer($customer);
        $quote->assignCustomer($customer);
        $quote->getShippingAddress()->addData($dataShipping)->setShippingMethod('tablerate_bestway');
        $quote->getShippingAddress()->setShippingMethod('tablerate_bestway');
        $quote->getShippingAddress()->setCollectShippingRates(true);
        $quote->getShippingAddress()->collectShippingRates(); 
        $quote->setPayment($quote->getPayment()->setMethod('free'));
        $quote->collectTotals();
        $quote->save();

        $convertQuoteObj = Mage::getModel('sales/convert_quote');
        $orderObj = $convertQuoteObj->toOrder($quote);

        $orderPaymentObj=$convertQuoteObj->paymentToOrderPayment($quote->getPayment());

        $orderObj->setBillingAddress($convertQuoteObj->addressToOrderAddress($quote->getBillingAddress()));
        $orderObj->setPayment($convertQuoteObj->paymentToOrderPayment($quote->getPayment()));
        $orderObj->setShippingAddress($convertQuoteObj->addressToOrderAddress($quote->getShippingAddress()));


        $qty=1;
        foreach ($quote->getShippingAddress()->getAllItems() as $item) {
            //@var $item Mage_Sales_Model_Quote_Item
            $item->setQty($qty);
            $orderItem = $convertQuoteObj->itemToOrderItem($item);
            if ($item->getParentItem()) {
                $orderItem->setParentItem($orderObj->getItemByQuoteItemId($item->getParentItem()->getId()));
            }
            $orderObj->addItem($orderItem);
        }

        $orderObj->setCanShipPartiallyItem(false);

        $totalDue=$orderObj->getTotalDue();
        echo "<p>total due: $totalDue</p>";
        $orderObj->place(); //calls _placePayment
        $orderObj->save();
        $orderId=$orderObj->getId();
        echo "<p>orderId: $orderId</p>";

    }
}

Mage::app();

$JLR = new JLR_Orders_Create();
$JLR->CreateOrder2();
Related Topic