1

On every 25€ I wish to offer a product as a gift. With every 25 it increases another gift is added. So for instance, 102,50 will give 4 gifts.

I've allready got this working through cart.phtml. I know it actually should be done in code/local, but I'm having problems finding the proper dispatch event. There are events for adding a product, deleting etc. However, I need to make a definition on every action done in the cart.

I'm looking for an event which triggers as soon as the cart is called. This avoids a lot of hassle.

I've got the basic script working, I only need the direction to where and how I could insert this script.

4 Answers 4

1

You can also do it via the collecttotals hook. Not in front of a pc right now, so will update with example in a few hours. An example is in the config.xml of the core rules module.

The information as promised:

In your module config.xml, in the <global> tag you can place the following, which will allow you to call your model everytime magento does a call to ->collecttotals()

I actually use this in my own gifting module to effect gifting, based on the cart subtotal.

    <sales>
        <quote>
            <totals>
                <giftpromo>
                    <class>giftpromo/promo_gift</class>
                    <after>subtotal</after>
                    <before>tax_subtotal,shipping</before>
                </giftpromo>
            </totals>
        </quote>
    </sales>

This thus calls my model which is defined as such (added so you can see the class inheritance to make this work):

class ProxiBlue_GiftPromo_Model_Promo_Gift extends Mage_Sales_Model_Quote_Address_Total_Abstract
{
}

In this class you need a public method called collect, and to this core will pass the current shipping address object. From this you can get the current quote object.

My method is as such:

public function collect(Mage_Sales_Model_Quote_Address $address)
    {
        parent::collect($address);
        $quote = $address->getQuote();
        $store = Mage::app()->getStore($quote->getStoreId());
        if (!count($quote->getAllVisibleItems())) {
            return $this;
        }
        $this->_validator->init($store->getWebsiteId(), $quote->getCustomerGroupId(), $quote->getCouponCode());
        $this->_validator->processGiftRules($address);
        return $this;
    }

Obviously my method references other objects not part of the answer, but it would give you the general idea of how to use the collect totals.

For a core based example, see the class Mage_SalesRule_Model_Quote_Freeshipping

Have a peek in the core Sales module's config.xml, and you will see other examples of how to set the totals hook.

For completeness, here is that code:

<sales>
            <quote>
                <totals>
                    <freeshipping>
                        <class>salesrule/quote_freeshipping</class>
                        <after>subtotal</after>
                        <before>tax_subtotal,shipping</before>
                    </freeshipping>
                    <discount>
                        <class>salesrule/quote_discount</class>
                        <after>subtotal,shipping</after>
                        <before>grand_total</before>
                    </discount>
                </totals>
                <nominal_totals>
                    <nominal_discount>
                        <class>salesrule/quote_nominal_discount</class>
                        <sort_order>550</sort_order>
                    </nominal_discount>
                </nominal_totals>
            </quote>
        </sales>

Using the collect totals hook (right terminology?) you can easily run some custom code whenever the cart/quote changes totals.

Hope this helps.

3
  • @GeertSamuel - updated the answer as promised.
    – ProxiBlue
    Feb 26, 2014 at 9:19
  • thank you! I'll run through this later today, I will report back on how it's working out. Feb 26, 2014 at 9:42
  • I've added my working code, except for the remove product part, which is not working yet. Feb 26, 2014 at 23:49
0

What about sales_quote_save_before for checking and adding/removing

2
  • I've tried that one, but it didn't work as hoped. I tried a bunch over events, none really worked well. It either didn't update after a quantity update, or when I removed a product. I've gotten it to work after a "add product to cart" however not on the other actions of the cart. Feb 26, 2014 at 8:29
  • If you implement something, share the code and describe your problem, we might fix it. Feb 26, 2014 at 8:49
0

Ok, this is working perfect. I only need a way to remove the product, this doesn't work yet unfortunatelly, getting an error there

Invalid method Mage_Sales_Model_Quote_Item::removeItem

I know what this means, but I'm not sure what to call through the "Mage_Sales_Model_Quote_Item" to remove a product. If I get the base to work I wille expand this with and admin section, for now I'm happy if I got this working properly.

class Custom_FreeProduct_Model_Freeproductrow extends     Mage_Sales_Model_Quote_Address_Total_Abstract
{

public function collect(Mage_Sales_Model_Quote_Address $address)
{

    parent::collect($address); 

    $subtotal = $address->getSubtotalWithDiscount();
    $items = $address->getAllItems();

    $cartHelper = Mage::helper('checkout/cart');
    $freeProdCalc = floor($subtotal / 25);
    $freeProductExists = false;

    $cartItems = $cartHelper->getCart()->getItems(); 
    $cartItemsQty = count($cartItems);
    foreach ($cartItems as $item) 
    {
       $itemId = $item->getProductId();
       if ( $itemId == 10718 ) {
            $freeProductExists = true;
       }
    }

    if ( $subtotal < 25 ) 
    {
        foreach ( $items as $item ) {
            $itemProductId = $item->getProductId();
            $itemId = $item->getId();
            if ( $itemProductId == 10718 ) 
            {
                //$item->removeItem($itemId);
            }       
        }
    }
    elseif ( $freeProductExists ) 
    {
        foreach ( $items as $item ) {
            $itemId = $item->getProductId();
            if ( $itemId == 10718 ) 
            {
                $item->setQty($freeProdCalc);
            }       
        }
    } elseif ( $subtotal > 24.99 ) 
    {
        $_product = Mage::getModel('catalog/product')->load(10718);
        $cart = Mage::getModel('checkout/cart');
        $cart->init();
        $cart->addProduct($_product, array( 'product' => 10718, 'qty' => $freeProdCalc, 'options' => array( 542 => 2741 )));
        $cart->save();
    }

}

}
7
  • Some suggestions: There is no need to instantiate the cart object in your code. The address object comes with the quote object ready for you to use. Rather use the quote object to manipulate the items. your call to $cartItems = $cartHelper->getCart()->getItems(); will return all items, thus child items of complex product types. If you use the quote object you can simply use $quote->getAllVisibleItems() and eliminate the child items. Then later, only once you need to add to cart, can you instantiate the cart model to add your item.
    – ProxiBlue
    Feb 27, 2014 at 2:20
  • To remove an item, you can then soimply use $address->getQuote()->removeItem($quoteItem->getId()); and a call to $address->getQuote()->save(); will save that, bypassing the cart object save (else you end up running collecttotals again via $cart->save())
    – ProxiBlue
    Feb 27, 2014 at 2:27
  • @ProxiBlue Thanks! It worked like a charm. I changed the cartItems to $quote->getAllVisibleItems() and my setQty and removeItem work through there now. It seems everything is working so far. Feb 27, 2014 at 12:39
  • Nice. It is acceptable behaviour to accept my answer ;)
    – ProxiBlue
    Feb 27, 2014 at 14:07
  • @ProxiBlue I'm running into a problem. If the cart is empty and I add the first product the cart totals are messed up (it looks like the product was added with a quantity of 2), and the product line is without VAT. For instance, I add a product of 201,40, my row total is: 166,45 (which is without 21% vat), and subtotal is 137,56, vat is 28,89, total is 375,85. However, my gift product is added properly. Once I refresh, all is fine tho... Mar 2, 2014 at 20:45
0

I would observe the event sales_quote_collect_totals_after which is called everytime the cart has changed and after shopping cart rules are applied and totals recalculated.

It receives the quote as parameter, so that you can retrieve the subtotal as follows:

$subTotal = $observer->getQuote()->getBaseSubTotal();

then add the free gift like this

$product = Mage::getModel('catalog/product')->load(FREE_PRODUCT_ID);
$item = $observer->getQuote()->addProduct($product, floor($subTotal / 25));
$item->setCustomPrice(0);

It's important that you set the following flag to prevent the totals to be collected again after this change which would cause an infinite loop:

$observer->getQuote()->setTotalsCollectedFlag(true);

Your Answer

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

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