Author: whmcsisg8

3 Oct

WHMCS Merchant Gateway Development

This type of WHMCS gateways can be used for payment using credit card. Let’s create a payment gateway with name test. For that we have to create a file named test.php and then we have to upload it to the folder modules/gateways.

Live mode and test mode.

Each payment gateway provides some test credit card details, we can use that for test payment.
In test mode, for any payment there won’t be any actual transaction.
In live mode, we have to use real credit card details and real transaction will happen in this mode. Payment gateway will give us both live url and test url for real and test payments respectively.

Our gateway module will decide weather we have to do real or test transactions based on the settings in the module config.

'testMode' => array(
            'FriendlyName' => 'Test Mode',
            'Type' => 'yesno',
            'Description' => 'Tick to enable test mode',
        ),

If we select testMode, then only test payments will work. If it’s unselected real transaction will happen.

Initially the test.php file looks like

<?php

if (!defined("WHMCS")) {
    die("This file cannot be accessed directly");
}

function test_MetaData()
{
    return array(
        'DisplayName' => 'Test payment gateway',
        'APIVersion' => '1.0',
        'DisableLocalCredtCardInput' => true,
        'TokenisedStorage' => false,
    );
}

function test_config()
{
    return array(
        'FriendlyName' => array(
            'Type' => 'System',
            'Value' => 'Test payment gateway',
        ),
        'live_url' => array(
            'FriendlyName' => 'Live URL',
            'Type' => 'text',
            'Size' => '25',
            'Default' => '',
            'Description' => 'Enter your live url here',
        ),
        'test_url' => array(
            'FriendlyName' => 'Test URL',
            'Type' => 'text',
            'Size' => '25',
            'Default' => '',
            'Description' => 'Enter your test url here',
        ),
        'testMode' => array(
            'FriendlyName' => 'Test Mode',
            'Type' => 'yesno',
            'Description' => 'Tick to enable test mode',
        ),
        'user_id' => array(
            'FriendlyName' => 'User Id',
            'Type' => 'text',
            'Size' => '25',
            'Default' => '',
            'Description' => 'Enter your user id here',
        ),
    );
}


function test_capture($params) {

        if($params['testMode'] == 'on') { //testmode
          $url = $params['test_url'];
        } else { // live mode
          $url = $params['live_url'];
        }
}
?>

We have to add payment code into the function, test_capture($params).
Inside that we have to use payment transfer code. Each gateway API will be diffrent, so the payment transfer code will be different for each gateway.

Let’s write a payment transfer code for an arbitrary gateway.

function test_capture($params) {
     $postfields = [
        'invoiceid' => $params['invoiceid'],
        'amount' => $params['amount'],
        'currency' => $params['currency'],
        'cardnumber' => $params['cardnum'],
        'cardexpiry' => $params['cardexp'],
        'cardcvv' => $params['cccvv'],
    ];

    if($params['testMode'] == 'on') { //testmode
          $url = 'https://test.myarbitrarygateway/api/payment';
    } else { // live mode
          $url = 'https://myarbitrarygateway/api/payment';
    }

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $response = curl_exec($ch);
    curl_close($ch);

    $data = json_docode($response);

    return array(
        'status' => ($data->success == 1) ? 'success' : 'declined',
        'rawdata' => $data,
        'transid' => $data->transaction_id,
        'fees' => $data->fees,
    ); 
}
25 Sep

What is mean by WHMCS hook?

Standard way of modifying WHMCS features is using hook. WHMCS code is encrypted and we couldn’t change it. In addition to it, modifying core file is a bad idea. When we update WHMCS to the latest version all of our core file changes will be removed. So hook is a nice way to customize WHMCS features.

There are many hooks available in WHMCS. Available WHMCS hooks can be found in the link
https://developers.whmcs.com/hooks/hook-index/

Some of them can be used to run a piece of code just after an action is happened(ClientAdd executes just after a client is added to WHMCS). Some of them can be used used to run a piece of code just before an action(PreDeleteClient executes just before a client is deleted). There are hooks that can be used to run on certain pages(ClientAreaPageHome executes on the client area homepage).

Hooks can be include in the WHMCS in two ways.
1)We can create a php file with any name and can upload to the folder
/includes/hooks/.
2)We can create a file named hooks.php as a part of the addon module.

To get a better idea, let’s go through some examples now.
For now let’s just upload sample files to the folder /includes/hooks/.

Let’s add a hook ‘ClientAreaPage’ to a file named sample.php,
then let’s upload to the folder /includes/hooks/.
(see https://developers.whmcs.com/hooks-reference/client-area-interface/#clientareapage)

<?php
add_hook('ClientAreaPage', 1, function($vars) {
    echo "this is from clieant area hook";
    exit;
});

Then take any page in the client side, you will get a blank page with content
this is from clieant area hook. As we have exit in the code, nothing else will be displayed.

Now let’s modify the hook as shown below.

<?php
add_hook('ClientAreaPage', 1, function($vars) {
    echo "<pre>"; print_r($vars);
    exit;
});

Now the page will display an array.

To remove the hook, just delete the file from the folder /hooks/hook-index/.

Now let’s see another hook, ClientAreaPageCart.
Add the below code to a file named cart_hook.php and then upload to the folder
/includes/hooks/.

<?php
add_hook('ClientAreaPageCart', 1, function($vars) {
        echo "<pre>"; print_r($vars);
        exit;
});

This hook won’t run in all of the client are pages. But it will run in all of the
cart pages. For example take the url /cart.php then you will see an array printed in it.

21 Sep

How to use Smarty if else?

Let’s assign a discount amount from PHP to the tpl file as shown below.

$smarty->assign('discount', 0); 
{if $discount gt 0}
   You have a discount and discount amount is: {$discount}
{else}
	You don't have any discount.
{/if}

Now let’s assign some string to the tpl file as shown below.
Here we compare two strings equality using ‘eq’

$smarty->assign('category', 'Electronics'); 

Then in the tpl file, we can check the category as shown below.

{if $category eq 'Electronics'}
    As you are booking an electronics product, you will get a discount of 15%.
{else}
    For this product, we have a discount of 5%.
{/if}

For detailed explanation regarding the usage of if else in tpl,
go to the link https://www.smarty.net/docsv2/en/language.function.if.tpl

21 Sep

How to use Smarty foreach?

You can pass an array to the smarty tpl file as shown below.

<?php
$user_details = array(
	"name" => "x",
	"address" => "Y",
        "phone" => "Z"
);
$smarty->assign('my_array', $user_details);  //my_array can be replaced with anything

Then in the tpl file you can loop through the array as shown below

<ul>
{*    
   Note: We used my_array here because we passed array as
   assign('my_array', $user_details);
*}

{foreach from=$my_array key=k item=v}
   <li>{$k}: {$v}</li>
{/foreach}
</ul>

If we are passing an array without key in it say

$user_details = array(
	"x", "y", "z"
);
$smarty->assign('my_array', $user_details); 

Then we can display the values in the tpl as shown below

<ul>
{foreach from=$my_array item=v}
   <li>{$v}</li>
{/foreach}
</ul>
20 Sep

WHMCS Addon development

WHMCS addon can be used to develop additional features in your WHMCS.

Here briefly explaining steps required to develop a simple addon, that just print some strings.
That’s enough to get started. After developing this simple addon you can move on to complex addons.

Addon name and folder name

Name of addon do have importance while developing a WHMCS addon.
Let’s name our addon as hello_world.

Then we have to create a folder named hello_world.
Within the folder, develop a file named hello_world.php.
Name used for the folder and file is hello_world, which is the name of the addon.
We have to upload the folder to the WHMCS folder /modules/addons/.

Functions to be defined in hello_world.php

We have to define some functions in the file hello_world.php.
Prefix for those functions should be same as the addon name.
As our addon name is hello_world, prefix for those functions
must be hello_world_.

Those functions are listed below.
1)hello_world_config
2)hello_world_activate
3)hello_world_deactivate
4)hello_world_output
5)hello_world_clientarea

hello_world_config

This function just returns an array.
Here we define addon name, version author etc.

function hello_world_config() {
    $configarray = array(
        "name" => "My first whmcs addon",
        "description" => "Just a sample addon, that just prints some strings",
        "version" => "1.0",
        "author" => "WHMCSTools.com",
        "language" => "english",
    );
    return $configarray;
}

hello_world_activate

This function is called when the addon module is activated from the admin side.
We can write table creation code within the function.

function hello_world_activate () {
    return array(
        'status' => 'success',
        'description' => 'Addon activated'
    );
}

hello_world_deactivate

This function is called when we are deactivating the addon from the admin side.
All addon table drop code should be added here.

function hello_world_deactivate() {
    return array(
        'status' => 'success',
        'description' => 'Addon deactivated'
    );
}

hello_world_output

Code written within this function will be executed when we take the url
www.ourwebsite.com/admin/addonmodules.php?module=hello_world

function hello_world_output($vars) {
    echo "just printing this in admin side";
}

hello_world_clientarea

This function is called when we take the url,
www.ourwebsite.com/index.php?m=hello_world

To display some contents in the client area, we have to create a smarty tpl file.
In the function hello_world_clientarea, we specified tpl file name as
‘templatefile’ => ‘template/clienthome’. So we have to create a folder named
template inside the folder /modules/addons/hello_world.
Then we have to create a file named clienthome.tpl in the folder template.
Note that we specified templatefile as ‘templatefile’ => ‘template/clienthome’, (no extension here) but we created file name as template/clienthome.tpl with the extension .tpl.

We have to pass parameters to the tpl file from the function hello_world_clientarea.
In the function we are passing the smarty key value pair as shown below.

'vars' => array(
            'name' => 'X ',
            'address' => 'Y',
            'phone' => 'Z',
),

Then in the tpl file we just have to write {$name} to display the name.

function hello_world_clientarea($vars) {
 
    $modulelink = $vars['modulelink'];
 
    return array(
        'pagetitle' => 'Addon Module',
        'breadcrumb' => array('index.php?m=hello_world'=>'Hello World Addon'),
        'templatefile' => 'template/clienthome', #smarty file name without .tpl extension
        'requirelogin' => true, # accepts true/false
        'forcessl' => false, # accepts true/false
        'vars' => array(  #smarty key value pair
            'name' => 'X ',
            'address' => 'Y',
            'phone' => 'Z',
        ),
    );
 
}

Content of the file template/clienthome.tpl is

    <h4> My Details </h4>

    <ul>
        <li>My name is : {$name} </li>
       <li>My address is : {$address} </li>
        <li>My phone number is : {$phone} </li>
    </ul>
20 Sep

How to create and drop tables in WHMCS 7 using PHP 7?

We might have to create a table from WHMCS addon while activating the module.
Also we might have to drop the table while deactivating the module.
Here we are going to write PHP 7 compatible codes to create and drop the table.

Create a table

Assume that we have to create a table named sample_table
with the following fields.
a)table_id
It’s an auto increment field, also it’s primary key of the table.

b)age
This field is an integer

c)name
This field should store string and maximum character length is 100.

d)created_at
It’s a date field

c)amount
It’s float field with two decimal points.

d)description
It’s a text field.

Then we can use below code for that.

 use Illuminate\Database\Capsule\Manager as Capsule;
 if (!Capsule::schema()->hasTable('sample_table')) {
        Capsule::schema()->create('sample_table', function($table) {
            $table->increments('table_id');
            $table->integer('age');
            $table->string('name', 100);
            $table->date('created_at');
            $table->float('amount', 8, 2);
            $table->text('description');
        });
    }

Drop the table.

To drop the table we can use the below code.

#add the below line only once in a file
use Illuminate\Database\Capsule\Manager as Capsule;
Capsule::schema()->dropIfExists('sample_table');
21 Aug

WHMCS Report Development

We can easily create a custom report in WHMCS.
First of all we have to create a file with any name and then we have to upload it to the folder modules/reports.

Let’s write a report to list down invoices that are paid between two dates.
Name of the file is invoice_report.php.
And it should be uploaded to the folder, modules/reports.

Th sample report code is below.

<?php

if (!defined("WHMCS")) die("This file cannot be accessed directly");

use Illuminate\Database\Capsule\Manager as Capsule;

# Report Title
$reportdata["title"] = "Invoice Report";

# Report Description
$reportdata["description"] = "";

$start_date = "2017-01-01";
$end_date =  date("Y-m-d");  

$reportdata["tableheadings"] = array(
      "ID", 
      "DATE PAID", 
      "SUBTOTAL",
      "TAX", 
      "TOTAL", 
      "PAYMENT TYPE",
);
 if(!empty($start_date) && !empty($end_date)) {
        $invoices = Capsule::table('tblinvoices')
              ->whereBetween('datepaid', array($start_date, $end_date))
              ->where('status', 'Paid')
              ->get();

        foreach($invoices as $invoice) {
	         $reportdata["tablevalues"][] = array(
                    $invoice->id,
                    $invoice->datepaid,         
                    $invoice->subtotal,
                    $invoice->tax + $invoice->tax2,
                    $invoice->total,
                    $invoice->paymentmethod,
	         );
       }
}

We have a ready made sales total report tool, with one time cost of $25.
Please Contact Us by filling the form. We will get back to you asap.

31 Jul

How to render button in Django base table?

Assume that you have a table as defined below

class CustomerTable(BaseTable):
    pk = ToggleColumn()
    name = tables.LinkColumn('customers:customer', args=[Accessor('customer.id')])
    

    
    class Meta(BaseTable.Meta):
        model = Customer
        fields = ('pk', 'name',  'city', 'state' , 'phone')

Now assume you would like to display a button next to the phone

we can do it as below

class CustomerTable(BaseTable):
    pk = ToggleColumn()
    name = tables.LinkColumn('customers:customer', args=[Accessor('customer.id')])
    edit_button = tables.Column(empty_values=())

    
    class Meta(BaseTable.Meta):
        model = Customer
        fields = ('pk', 'name',  'city', 'state' , 'phone', 'edit_button')

    def render_edit_button(self, record):
        rendered_item = format_html(
            "<a href='{url}' class='btn btn-primary' role='button'>Edit</a>",
            url= reverse('users:user_edit', kwargs={'id':record.id})
        )
        return rendered_item
19 Jul

Useful Linux Tips

#Replace all occurrence of City with Town in every txt file within the current directory.
$sed -i 's/City/Town/g' *.txt

Using vim editor, replace foo with bar from line 23 to 30
:23,30s/foo/bar/g

19 Jul

Useful git commands

#remove files only from local, not from git
$git rm -r --cached myfolder/

#reset back to the head
$git reset --hard my_branch

#make a branch same as master
$git checkout -B new master

#Delete local branch
$git branch -d branch_name

#push a new local branch to remote
$git push -u origin my_branch

#ignore file mode change
$git config core.fileMode false