Magento – Programmatically set free shipping from an observer

magento-1shipping

I am programming a module where I need to set shipping to be free of charge if certain conditions are satisfied. These conditions are very specific and cannot be modelled using "Shopping cart price rules". The logic to determine whether a user should get free shipping is done but I don't know how to actually make the shipping free. I have tried this:

$address = $quote->getShippingAddress();
$address->setFreeShipping(true);

I am calling this from event handler of checkout_cart_update_items_after

It is based on the freeshipping sales rule that works with data variable free_shipping. However, it does not work. After updating the cart, shipping keeps its nonzero cost.

I have also tried this:

$address = $quote->getShippingAddress();
$address->setShippingMethod('freeshipping_freeshipping');

It works but the problem is that free shipping must be enabled in backend for this to work. That means a user can pick it in checkout anytime – even if he shouldn't get free shipping based on my conditions.

Is there any good way set free shipping from an observer (event handler)?

Best Answer

So here is how I did it.

First, I have used more appropriate event for that purpose, that is sales_quote_collect_totals_before. And second, I needed to comment out (in local copy of course), one line in Mage_SalesRule_Model_Quote_Freeshipping:

public function collect(Mage_Sales_Model_Quote_Address $address)
{
    parent::collect($address);
    $quote = $address->getQuote();
    $store = Mage::app()->getStore($quote->getStoreId());

    //$address->setFreeShipping(0); # clime: we set this in module
    ...
 }

That is it. The following now works well:

$address = $quote->getShippingAddress();
$address->setFreeShipping(true); # the value must be true, not 1

It works well in single shipping mode. Multishipping is probably going to need some adjustments.

Related Topic