card-only

Magento Product Attribute to Disable a Payment Method

In this short tutorial I’m going to show you how to create a new attribute called “card only” that will remove a specific “free” payment method whenever a customer holds this particular product and attribute in their cart.

This may seem a little strange but let me give you an example. Your company accepts cheque/money order payments for all of it’s products – except a certain few. This could possibly be because your company needs to pay upfront for these types of products – therefore you don’t really want to be left out-of-pocket while a cheque is delivered via snail-mail and possible ‘bounced’.

The ideal scenario for this is to check each product in our basket to check to see if it’s card-only attribute is activated (set to ‘yes’). If it is then we’re going to disable our “free” payment method in the checkout.

Creating our “Card-Only” attribute

First of all we need to create our simple attribute. In the Magento admin simply navigate to Catalog > Attributes > Manage Attributes. Add a new one and call make it’s attribute codecard_only‘ with the Catalog Input Type for Store Owner set as Yes/No – keeping the Default Value as No. Also make sure that you select Visible on Product View Page on Front-end as Yes. Make sure you add it into your appropriate attribute set so that you can set it for your products!

Now go into each of the products that you want to be purchased “Card Only” and set this attribute to “Yes”.

Creating our Module

That’s the easy stuff done, next we need to create a module that will disable our “free” method whenever someone has a “Card Only” product in their basket.

If you’ve never created your own Magento extension before – don’t worry – this one is really easy! There’s only 3 files!

First of all we need to create our folder structure so create the following folders:

app > code > local > Creare > CardOnly > etc
app > code > local > Creare > CardOnly > Model

Next we need to create our files – the first one will be our Observer.php. Create the file Observer.php inside the “Model” folder and paste in the following code.

<?php

class Creare_CardOnly_Model_Observer
{
	public function cardOnly(Varien_Event_Observer $observer)
	{
	   $event           = $observer->getEvent();
           $method          = $event->getMethodInstance();
           $result          = $event->getResult();
	   $cardonly	    = false;

		foreach (Mage::getSingleton('checkout/cart')->getQuote()->getAllVisibleItems() as $item)
		{
			if($item->getProduct()->getCardOnly()){
				$cardonly = true;
			}
		}

		if($method->getCode() == "checkmo" && $cardonly){
			$result->isAvailable = false;
		}

	}
}

That code is what helps us identify our “Card Only” products and disable our “Free” payment method (in this case – “checkmo” – check/money order).

The next file we need to create is the config.xml – this is so that Magento know’s where to look for our Observer.php and also where we can set up our Observer to initiate the function cardOnly.

Within our “etc” folder create a file called config.xml and paste in the following code:

<?xml version="1.0"?>
<config>
	<modules>
		<Creare_CardOnly>
			<version>0.1.0</version>
		</Creare_CardOnly>
	</modules>
	<global>
		<events>
			<payment_method_is_active>
				<observers>
					<card_only>
						<type>singleton</type>
						<class>cardonly/observer</class>
						<method>cardOnly</method>
					</card_only>
				</observers>
			</payment_method_is_active>
		</events> 
		<models>
			<cardonly>
				<class>Creare_CardOnly_Model</class>
				<resourceModel>cardonly_mysql4</resourceModel>
			</cardonly>
		</models>
		<sales>
            <quote>
                <item>
                    <product_attributes>
                        <card_only/>
                    </product_attributes>
                </item>
            </quote>
        </sales>
	</global>
</config>

Within this code all we are doing is telling Magento where to find our ‘Models’ and also telling Magento to perform a function when a certain event is triggered – in this case the event we want Magento to call our function on is “payment_method_is_active”.

Thanks to beeplogic for a couple of tips within this code – we’re also telling Magento to send across our “card_only” attribute to our quote object – so we can load it from our Observer.php. This way we do not need to load the product model again to get at the attribute – saving resources.

The last file we need is the Module Configuration file – basically the file that tells Magento to load our module. You need to create the following file in this location:

app > etc > modules > Creare_CardOnly.xml

Then paste in the following code:

<config>
    <modules>
        <Creare_CardOnly>
            <active>true</active>
            <codePool>local</codePool>
        </Creare_CardOnly>
    </modules>
</config>

There you go – such a simple Magento Module! Just make sure that you clear your cache for the module to take effect.

Testing

Now that our module has been created we should test it to make sure it works. I’m using a brand new version of Magento 1.8 CE (because it has just been released today!).

The first really simply thing to check is to make sure our Module has loaded correctly – visit System > Configuration > Advanced and you should see our new module in the list.

Our module is active
Our module is active.

Great – we know it’s loaded – now let’s test the module.

As this is a brand new installation with sample data installed – I’m going to be using the Cellphones attribute set to try my new “Card Only” attribute on. In particular I’m going to make sure that my HTC Touch phone has Card Only set to YES – any other product will either not contain this attribute or will have it set to default (being NO).

The other thing to note is that my “Free” payment gateway is Check/Money Order – this is the one I want to disable if there is a “Card Only” product in my cart.

Test WITHOUT a “Card Only” product

A default test now – I’m going to add the ever-popular “Ottomon sqaure thing” to my cart and make sure that both of my payment options are available.

Without a Card Only product in the cart
Without a Card Only product in the cart.

And within my checkout I can see both payment options.

Both our payment options are available
Both our payment options are available.

Test WITH a “Card Only” product

Now that the default test has been done let’s test it with a product that should remove my “Free” payment method. Let’s add my HTC Touch now and see what happens.

Our Card Only product is now in our cart
Our Card Only product is now in our cart

And in our checkout I can see that my “Free” payment method has been removed! How about that!

Our Free payment option has been disabled
Our Free payment option has been disabled

Conclusion

So, we’ve learned how to create a module for a particular purpose and really easily perform quite a (on the face of it) complicated task with ease. That’s Magento events & Modules in a nutshell.

You can obviously perform some PHP in the Observer.php to disable as many or as few payment methods as you wish (as long as you know the identifiers for them – trick is to check the radio-button fields on the checkout using Firebug or similar) – as well as anything else that takes your fancy.

You can find all the files featured in this tutorial on github.

  • Adam Moss

    I did this exact thing the other week. Nice post Roberto.

  • beeplogic

    You’re promoting a bad habit:

    $product = Mage::getModel(‘catalog/product’)->load($item->getProductId());

    This is a performance killer and just sloppy. It’s possible to load a custom product attribute in the sales quote item product collection:

    The attribute must be set to “Visible on Product View Page on Front-end”, particularly when the flat catalog is enabled.

    In the module’s config.xml file add the following node:

    Once that’s configured it’s possible to call $item->getProduct()->getCardOnly().

    • http://www.creare.co.uk/ Robert Kent

      Hi Beeplogic – excellent suggestion thanks for sharing that – anything to bypass loading another model is a resource-saver you’re right

      • beeplogic

        I’d recommend you update the article accordingly, otherwise people may copy/paste your solution. Don’t perpetuate bad habits.

        • http://www.creare.co.uk/ Robert Kent

          I’ve tested the change and it works – the only difference to the code you supplied was the inclusion of the tag within config.xml – without this the attribute was not being picked up. I’ve updated the article to show the change – thanks for your input

          • beeplogic

            Ah, you’re correct, good catch. Thanks for being open to feedback and criticism.

  • nithin

    not working ! need help

    • http://www.creare.co.uk/ Robert Kent

      Hi Nithin,

      What’s not working about it? Are you seeing any error messages at all?

      • nithin

        payment is still showing ! no error is reporting ! any suggestion..

        • http://www.creare.co.uk/ Robert Kent

          Hi Nithin,

          Couple of things to check first, go to System > Configuration > Advanced and see if the module appears in the list of extensions and is enabled. Second thing – clear your cache. If it’s still not working after that then I suggest running some testing in the Observer.php – to log some data to make sure the function is being called.

          • nithin

            go to System > Configuration > Advanced , it is available

            cache clear – >

            log some data to make sure the function is being called., how to do that ..

  • Dirk

    Is there a possibility that this solution also works with disabling a shipping method for certain products?

  • Khan

    Hi,

    Can you please tell me how can i disable COD payment option for selected products using attributes?

    Thanks

    • http://supermetal.com.gr/ The Fking

      Did you ever find out how to disable COD?

      I guess the only change in the given code is on line 19 of the Observer.php:

      if($method->getCode() == “checkmo” && $cardonly){

      and the thing we need to change is the “checkmo” and replace it with the COD value, but unfortunately I dont know what it is…

  • http://craftlounz.com vipin

    hello…thanks for wonderful article..i tried the same on my website but could not get away with below error after installing it. is any one fmailiar with error..looks to me as something to do with cache ..please help

    ..a:5:{i:0;s:63:”Mage registry key “_singleton/cardonly/observer” already exists”;i:1;s:4089:”#0 /home/craftlou/public_html/app/Mage.php(222): Mage::throwException(‘Mage registry k…’)

    #1 /home/craftlou/public_html/app/Mage.php(476): Mage::register(‘_singleton/card…’, false)

    #2 /home/craftlou/public_html/includes/src/__default.php(21023): Mage::getSingleton(‘cardonly/observ…’)

    #3 /home/craftlou/public_html/app/Mage.php(447): Mage_Core_Model_App->dispatchEvent(‘payment_method_…’, Array)

    #4 /home/craftlou/public_html/includes/src/Mage_Payment_Model_Method_Abstract.php(646): Mage::dispatchEvent(‘payment_method_…’, Array)

    #5 /home/craftlou/public_html/includes/src/Mage_Paypal_Model_Express.

  • Imesh Liyanage

    I need a little help getting this working, I have 4 different payment methods which are handled by different extensions:
    – Visa/Master (Sampath_Pay)
    – Amex (Orbitnet_Amex)
    – Cash on Delivery (Tal_Cashondelivery)
    – Bank Transfer (Magento default payment options)

    I want to hide Cash of Delivery & Bank Transfer, so should I change line 19 to this:
    if($method->getCode() == “Tal_Cashondelivery” && $cardonly){

    And how do I hide 2 options?

    Please help me out if you can!

  • Vasanth Kumar

    Hi, Thanks for your excellent tutorial.

    For COD just change the 19th line in Observer.php

    like this

    if($method->getCode() == “cashondelivery” && $cardonly){

    • Tallal Hassan

      Hi Vasanth did you try this or is this just your guess?

      • Vasanth Kumar

        i tried its working fine for me. Check it out

        • Tallal Hassan

          Ok thanks.I will give it a check :)

  • santosh

    Hi, With out loading product model above code not working

  • Mukund Pehere

    Great and thanks !

  • Sunil Srivastava

    Pl help:
    in my Magento 1.9 everyday the configured Payment Gateways (PayTM and PayUMoney) are disabled automatically and at the same time everyday when these are disabled Saved CC option get enabled automatically on its own.
    How to fix this problem.

  • Diana Licheva

    Thank you very much! Very useful article.

  • Ali Khan

    its not working with 1.9 Kindly Update Code For 1.9.2.4
    great work ! thanks for educating world .

  • Mohammad Anas Siddiquei

    It’s wonderful seeing the code working! Great work! Thanks a lot

  • Fernando Mata Pelaez

    Great stuff!! it worked fine, thanks a lot