1

I have a problem with my code that I can't really figure out how to solve.

I have some products that are added programmatically into my cart and when I add them I edit their price with an observer and everything seems fine.

The problem is that when I add the products to the cart programmatically via:

$cart = Mage::getModel("checkout/cart");
$cart->addProduct($print_obj, $myquantity);                                
$cart->save();

Somehow my custom shipping method is called:

class Due_Myship_Model_Carrier extends Mage_Shipping_Model_Carrier_Abstract implements Mage_Shipping_Model_Carrier_Interface
{
    protected $_code = 'due_myship';

    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
        /* @var $result Mage_Shipping_Model_Rate_Result */
        $finalMethods = Mage::getModel('shipping/rate_result');

        //loading libraries
        $obj = Mage::helper('print/cartcheck');
        $obj->doCleanup(); //cleaning up mistakes from carts

        //now we "should" have the cart perfecly clean, lets check if everything works correclty and send data to iMaterialise
        $iMatData = $obj->createCart();

        //any error?
        if($obj->error != NULL)
        {
            $error = Mage::getModel("shipping/rate_result_error");
            $error->setCarrier($this->_code);
            $error->setErrorMessage($obj->error);
            $finalMethods->append($error);
        }
        else
        {
            //no error, continue
            //getting possible shipments
            $methods = array();

            for($j = 0; $j < count($iMatData->shipmentCost->services); $j++)
            {
                $methods[$iMatData->shipmentCost->services[$j]->name] = array('price'=> $iMatData->shipmentCost->services[$j]->value,
                                                                              'title'=> $iMatData->shipmentCost->services[$j]->name,
                                                                              'cost' => $iMatData->shipmentCost->services[$j]->value,
                                                                              'code' => $iMatData->shipmentCost->services[$j]->name);
            }

            foreach($methods as $item)
            {
                $method = Mage::getModel('shipping/rate_result_method');
                $method->setCarrier($this->_code);
                $method->setMethod($item['code']);
                $method->setCarrierTitle('Printed Object Shipment');
                $method->setMethodTitle($item['title']);
                $method->setPrice($item['price']);
                $method->setCost($item['cost']);
                $finalMethods->append($method);
            }

            //saving the newly created cartID for this user
            $obj->saveCartOrder($iMatData->cartID);
        }

        return $finalMethods;
    }
}

The problem is that this is causing a bunch of problems, mostly on price calculation, because... well, I don't know why to be honest.

The function from helpers are mostly API calls or cart sync between our website and a partner one.

I paste here the observer part which is in charge of setting item price based on API response from the partner:

public function modifyPrice(Varien_Event_Observer $obs)
    {
        // Get the quote item
        $item = $obs->getQuoteItem();
        // Ensure we have the parent item, if it has one
        $item = ( $item->getParentItem() ? $item->getParentItem() : $item );

        //is it a fake object?
        $obj = Mage::helper('print/cartcheck');
        if($obj->checkPid($item->getProductId()))
        {
            //before deleting all the data, we save what was the old cart id for changing our values afterwards
            //$obj->saveDeletedId($item->getProductId());
            // Load the custom price
            $price = $this->_getPriceByItem($item);
            // Set the custom price
            $item->setCustomPrice($price);
            $item->setOriginalCustomPrice($price);
            // Enable super mode on the product.
            $item->getProduct()->setIsSuperMode(true);
        }
    }

    protected function _getPriceByItem(Mage_Sales_Model_Quote_Item $item)
    {
        $params = Mage::app()->getRequest()->getParams();

        //single item data
        $pprice = $item->getProduct()->getPrice();
        $quantity = $params['models']['quantity'];
        $iprice = $params['price'];

        //ok, we have removed the object from the cart before this routine, so, we have to load our infos
        $read = Mage::getSingleton('core/resource')->getConnection('core_read');
        $result = $read->fetchAll("SELECT quantity, iMatAPIPrice FROM print_order WHERE pid='" . $item->getProductId() . "' AND uid='" . Mage::getSingleton('customer/session')->getCustomer()->getId() . "'");

        if(count($result) > 0)
        {
            $myquantity = 0;
            $myprice = 0;
            //we have some data saved for this product and user
            for($i = 0; $i < count($result); $i++)
            {
                $myquantity = $myquantity + $result[$i]['quantity'];
                $myprice = $myprice + $result[$i]['iMatAPIPrice'];
            }

            $iprice = $iprice + $myprice;
            $quantity = $quantity + $myquantity;
            //die(print("iprice= " . $iprice . ", quantity =" . $quantity));
        }

        $price = (($pprice * $quantity) + $iprice) / $quantity;

        return $price;
    }

All the code worked great until I added the custom shipment method, then the price in the cart is set as quantity*100 and I can't understand why. Moreover some functions in the shipping method shouldn't be called until last step of the ordering and having them called everytime a product is added is quite painful.

Is there a way to avoid calling the shipping method or at least a workaround?

thank you very much

2
  • 1
    To understand what exactly is going when adding cart and you shipping method being collected see this: classyllama.com/content/unravelling-magentos-collecttotals and you might yourself find a work around. Commented Feb 17, 2014 at 5:47
  • Thank you, I'm reading right now and I'll try to figure out a workaround that still implement what I need!
    – YourTeam
    Commented Feb 17, 2014 at 14:28

1 Answer 1

1

When you do the $cart->save() it will call into this code:

/**
 * Save cart
 *
 * @return Mage_Checkout_Model_Cart
 */
public function save()
{
    Mage::dispatchEvent('checkout_cart_save_before', array('cart'=>$this));

    $this->getQuote()->getBillingAddress();
    $this->getQuote()->getShippingAddress()->setCollectShippingRates(true);
    $this->getQuote()->collectTotals();
    $this->getQuote()->save();
    $this->getCheckoutSession()->setQuoteId($this->getQuote()->getId());
    /**
     * Cart save usually called after changes with cart items.
     */
    Mage::dispatchEvent('checkout_cart_save_after', array('cart'=>$this));
    return $this;
}

This then recalculates the shipping, the totals, etc and because you are mixing cart logic in the shipping its all looping around on top of each other. Wherever possible you should keep the shipping carrier to just be about the shipping calculation.

collectTotals() is a minefield, the only real way to get to bottom of it is to debug in PHPStorm or similar

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.