Howto: Create “Cash on Delivery” payment Varied from Different Postcodes for Virtuemart

Actually Virtuemart has done a great job on cash on delivery support, but what if cash on delivery cost a fee not only the total amount of purchase but also the different postcode? Here comes a tutorial on how to calculate the different rates based on users’ postcode.

Of course, before doing that, you need to have a workable Virtuemart distribution on joomla. You can find more tutorials on joomla official website or virtuemart website.

There are only two steps of this simple tutorial:

  1. Create a new payment method on Cash on Delivery. Actually the orignal virtuemart comes with an option of “COD”, but at this time I don’t want to ruin its file structure. I prefer to create a new one. Actually creating new payment method helps you to know more about joomla.
  2. Revise “ps_checkout.php” to make it works.

Let’s dive to details.

Create a new payment method on Cash on Delivery.

Sooner or later will you find that creating payment method couldn’t be easier. What you need to do is to create a class, and of course, you write some methods which is recoginzed by joomla framework. You can find bunch of original payment classes on /administrator/components/com_virtuemart/classes/payment/ folder. If you see carefully, you can see each payment class comes with a config file. For instance, you can see a payment class called ps_paypal.php, should come with a config named ps_paypal.cfg.php. I won’t use config file, so I don’t need the cfg.php file. Now here’s my turn on creating such a class:  create a file name “ps_codonpc.php” (which means “Cash On Delivery On PostCodes”), never mind its name, but I think you better follow the naming convention of Virtuemart. Open this file with any kind of text-editor, I recommend to use notepad++. Create a skeleton below.

if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' );
class ps_codonpc{
var $classname = "ps_codonpc";
var $payment_code = "PU";
function show_configuration() {
return false;
function has_configuration() {
return false;
function get_payment_rate($sum, $ship_to_info_id=null) {
function configfile_writeable() {
return true;
function configfile_readable() {
return true;
function write_configuration( &$d ) {
return true;
function process_payment($order_number, $order_total, &$d) {
return true;

I know what you must be thinking.  You must be wondering if there is any necessity to create those functions within the class. Yes, you have to. That’s the weakness as well as fexibility of the characteristic  object-oriented of PHP. Well, it makes senses, because PHP is runtime dynamic language, not compile-time language. The payment classes on /payment folder are dynamically recognized by the framework, they use the same functions naming convention to make the polymorphism works.  I mean the ps_paypal.php and ps_paymate.php are of the same functions’ name, and created by the framework, however the framework doesn’t need to know the existance of payment classes and doesn’t know what they are doing. The framework only knows their functions’ name. Confused? Never mind.  Forget this paragraph. You can do the same thing on java using “reflection”.

You can see a function called “get_payment_rate” in this class. Well, not all the classes in /payment folder have this function. Why? That’s because virtuemart framework will only calculate the payment rate if the “get_payment_rate” function is defined. Actually, there is only one parameter is need: $sum, but since we need to calculate the fee by post code, I add an additional paramter(ship_to_info_id)  and give it a default value(null).

Now you need to fill the “get_payment_rate” logic to make it works. I add a simple logic to calculate the payment rate.

function get_payment_rate($sum, $ship_to_info_id=null) {
		//Get the ship_to_info_id if the parameter is null
		//Normally the item is passed from checkout module
		//We need to change ps_payment_method.php to pass the parameter to this object.
		if( empty( $ship_to_info_id )) {
		    $sdb = new ps_DB();
		    $sdb->setQuery( "SELECT user_info_id FROM #__{vm}_user_info WHERE user_id=".$auth['user_id']." AND address_type='BT'" );
		    $ship_to_info_id = $sdb->loadResult();
		//Get the zip(post code) from user info table
if(!empty( $ship_to_info_id )){
			$sdb = new ps_DB();
			$qry = "SELECT `zip` FROM `#__{vm}_user_info` WHERE user_info_id='".$ship_to_info_id."'";
			$postcode = $sdb->f('zip');
			if($postcode >= '3000' && $postcode < '3050'){
				return 0;  //these areas are free
			}else if($postcode >= '3050' && $postcode < '3150'){
				return floatval( $GLOBALS['CURRENCY']->convert(-5));  //these areas cost $5
				return floatval( $GLOBALS['CURRENCY']->convert(-10)); //the othes cost $10
		}else{ //unknow post code, use default
			return floatval( $GLOBALS['CURRENCY']->convert(-10)); //the othes cost $10

Can you see the return value? it’s negative, that’s because the get_payment_rate function return the payment discount (according to the definition of this function), the name should be changed to get_payment_discount. Otherwise would be a little bit confused. If you return a positive, the users will get a discount from this payment; a negative, the users will pay an extra fee.

OK. That’s fine.

Revise “ps_checkout.php” to make it works.

And now go to ps_checkout.php, and find a line 1673, change “return $_PAYMENT->get_payment_rate($subtotal);” to

$ship_to_info_id = $_REQUEST['ship_to_info_id'];
return $_PAYMENT->get_payment_rate($subtotal, $ship_to_info_id);

Okey dokey, Now add the Cash On Delivery paymethod on your administration page, and then go through the check out process and find out more excitement. Of course, the logic provided here is very simple, you can judge the rate from a post code data table and apply new features.

7 thoughts on “Howto: Create “Cash on Delivery” payment Varied from Different Postcodes for Virtuemart”

  1. Could you assist me in how to apply this to editing the cash on delivery payment option. I would like to grey it out for some products and make it active for others?

  2. this is very good and usefull.
    But what must we do if we don’t want to added a tax (tax=0%) because the negative value included already the tax? Can we have to select an option?

    Thank you very much.

  3. To Mark: Sure we can. Just select the option with VAT id=0 on your product.

    If you are using KImport, you just need to specify the tax column to 0 in your excel sheet.

  4. This really looks interesting, I am wondering if it is possible to adapt this so it either shows or hides the COD module according to country codes at checkout? Such a feature will make alot of people happy, I have looked everywhere to no avail:/

  5. hi,

    i am trying to find from where i can put the fee from COD ( cash on delivery ) to TOTAL and not SUBTOTAL in order NOT to be taxed, and i cant find it.
    Probbably its the ps_checkout.php.
    I would appreciate any help.

  6. • create a HTML Form to send the user to the pages of the payment provider where he/she can pay
    and return to your shop afterwards.?
    please tell me the whole structure?

  7. to soroush, that’s not this article about. There are lots of payment modules available on vmart already, so just simply apply them to your shop.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">