Author: whmcsisg8

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

#delete a remote branch
git push origin --delete branch_name

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

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

#Fetch a remote branch
$git fetch
$git checkout new_branch

19 Jul

Useful PostgreSQL Queries and Commands

Connecting as root
$sudo -u postgres psql

Connect to database server:
$psql --username=myusername --host=localhost --password

Select a database with name mydatabase:
myusername=>\c mydatabase;

List all tables:
myusername=>\dt;

Get table structure:
myusername=>\d+ my_table;

Take a dump
$pg_dump --username=myusername --host=localhost --password mydatabase > db.sql

Import a database
$psql --username=myusername --host=localhost --password mydatabase < db.sql

5 Jul

Multi Level Product Category (Product Subcategory) in WHMCS

By default in WHMCS, only one level product categories are possible. Assume that you have a category
US and another Category Spain. And under US you have another category California Items
and Under Spain you have another category named Madrid Items.

Then currently you have to create two categories named California Items and Madrid Items as two categories. Then you can add products under California Items and Madrid Items. But there is no way to add subcategory in WHMCS. We developed a module, which allow to add a parent category and then number of child category to it.Anybody looking for such a module, please contact.

 

6 Jun

Hostbill plugin development

1)Create a folder with plugin name.
If plugin name is example, create a folder with name ‘example’.

2)Create a file named
class.example.php. Also a folder named admin in it.

3)In the admin folder create a file named
class.example_controller.php
also can create tpl files here.

Let’s create a tpl named default.tpl here.

4)Let’s create client side basic code in the file class.example.php.


<?php

class example extends OtherModule {

protected $modname = 'Example';
protected $description = 'Sampple Plugin';
protected $version = '0.1';

protected $info = array(
        'haveadmin'    => true,  // is module accessible from adminarea
        'haveuser'     => false, // is module accessible from client area
        'havelang'     => false, // does module support multilanguage
        'havetpl'      => false, // does module have template
        'havecron'     => false, // does module support cron calls
        'haveapi'      => false, // is module accessible via api
        'needauth'     => false, // does module needs authorisation
        'isobserver'   => false, // is module an observer
        'clients_menu' => false, // listing in adminarea->clients menu
        'support_menu' => false, // listing in adminarea->support menu
        'payment_menu' => false, // listing in adminarea->payments menu
        'orders_menu'  => false, // listing in adminarea->orders menu
        'extras_menu'  => true, // listing in extras menu
        'mainpage'     => true, // listing in admin/client home
        'header_js'    => false, // does module have getHeaderJS function
    );

protected $configuration=array(
         'Field1' => array(
            'value' => '',
            'type' => 'input',
            'description' => 'My description'
        ),
        'Field2' => array(
            'value' => '',
            'type' => 'input',
            'description' => 'My description'
        ),
        'Field3' => array(
            'value' => '0',
            'type' => 'check',
            'description' => 'My description'
        )
    );

public function install() {
  echo "Install";
  return true;
}

}

5)

<?php


class example_controller extends HBController {
    /*
	?cmd=example
    */


    function _default($request) {
	//default function, just like our default index.php
        $showheaderandfooter = true;
        $module_type = 'Other';
        $this->template->assign('test', 'test');
        $this->template->render(
                APPDIR_MODULES .
                $module_type . '/example/admin/default.tpl', [], $showheaderandfooter
        );

    }

    /*
	?cmd=example&action=testfunction
    */

    function testfunction($param) {
	//action=testfunction, even for post action we can do like this
        $showheaderandfooter = true;
        $module_type = 'Other';
        $this->template->assign('test', 'test');
        $this->template->render(
                APPDIR_MODULES .
                $module_type . '/example/admin/testfunction.tpl', [], $showheaderandfooter
        );
    }


}

6)The content added to the file admin/default.tpl is
{$test}

16 May

CyberSource Payment Gateway Module for WHMCS

We have to use Cybersource’s SOAP Toolkit for the WHMCS payment gateway module.Using the toolkit we can develop a Merchant Gateway as explained in the link https://developers.whmcs.com/payment-gateways/merchant-gateway/

The SOAP toolkit details can be found in the URL https://www.cybersource.com/developers/getting_started/integration_methods/soap_toolkit_api. Also read the PDF http://apps.cybersource.com/library/documentation/dev_guides/SOAP_Toolkits/SOAP_toolkits.pdf

We are not covering basics of Payment gateway module development for WHMCS in this post. But we are explaining basics of Cybersource’s API here. Sample code with PHP can be downloaded from the URL www.cybersource.com/support_center/implementation/downloads/soap_api/sample_files/sample_php.zip

It’s better to store subscription id, returning from the cybersource and use that for recurring payments.In this way we can avoid repeated entry of credit card details. From the _storeremote($params) function of your WHMCS payment gateway code, we can create the subscription_id. Below briefly explaining code to produce the subscription id.

function cybersourcegateway_storeremote($params) {
    require_once("cybersource_lib/vendor/autoload.php");
    $referenceCode = '<order number>';
    $options = array();
    
    $client = new CybsSoapClient($options, $params);
    $request = $client->createRequest($referenceCode);
    
    $ccAuthService = new stdClass();
    $ccAuthService->run = 'true';
    $request->ccAuthService = $ccAuthService;

    $billTo = new stdClass();
    $billTo->firstName = "<First name here>";
    $billTo->lastName = "<Last name here>";
    $billTo->street1 = "
<address here>";
    $billTo->city = "<city here>";
    $billTo->state = "<State here>";
    $billTo->postalCode = "<Post code here>";
    $billTo->country = "<Country here>";
    $billTo->email = "<Email here>";
    $billTo->ipAddress = "<Ip address here>";
    $request->billTo = $billTo;
 
    
    $card = new stdClass();
    $card->accountNumber = "<card number here>";

    $card->expirationMonth = "<expiry month here>";
    $card->expirationYear = "<expiry year here>";
    $card->cardType = "<card type here>";
    $request->card = $card;

    $purchaseTotals = new stdClass();
    $purchaseTotals->currency = $params['currency'];
    $purchaseTotals->grandTotalAmount = $params['amount'];
    $request->purchaseTotals = $purchaseTotals;

    $recurringSubscriptionInfo = new stdClass();
    $recurringSubscriptionInfo->frequency = "on-demand";
    $request->recurringSubscriptionInfo = $recurringSubscriptionInfo;

    $paySubscriptionCreateService = new stdClass();
    $paySubscriptionCreateService->run = 'true';
    $request->paySubscriptionCreateService = $paySubscriptionCreateService;

    $reply = $client->runTransaction($request);
    $subscription_id = $reply->paySubscriptionCreateReply->subscriptionID;

	

 if ($reply->decision == 'ACCEPT' && $reply->reasonCode == '100') {
    return array(
        "status" => "success",
        "gatewayid" => $subscription_id,
        "rawdata" => json_encode($reply)
    );
 }
else {
        return array(
            "status" => "failed",
            "gatewayid" => $subscription_id,
            "rawdata" => json_encode($reply)
        );
    }
}

Then in your capture function, call API as given below.

function cybersourcegateway_capture($params) {
   require_once("cybersource_lib/vendor/autoload.php");
    $referenceCode = $params['referencecode'];
    $options = array();
    $client = new CybsSoapClient($options, $params);

    $request = $client->createRequest($referenceCode);
    $ccAuthService = new stdClass();
    $ccAuthService->run = 'true';
    $request->ccAuthService = $ccAuthService;

    $ccCaptureService = new stdClass();
    $ccCaptureService->run = 'true';
    $request->ccCaptureService = $ccCaptureService;

    $purchaseTotals = new stdClass();
    $purchaseTotals->currency = $params['currency'];
    $purchaseTotals->grandTotalAmount = $params['amount'];
    $request->purchaseTotals = $purchaseTotals;


    $recurringSubscriptionInfo = new stdClass();
    $recurringSubscriptionInfo->subscriptionID = $params['gatewayid'];
    $request->recurringSubscriptionInfo = $recurringSubscriptionInfo;


    $reply2 = $client->runTransaction($request);

    if ($reply2->decision == 'ACCEPT' && $reply2->reasonCode == '100') {
        return array(
            "status" => "success",
            "transid" => $reply2->requestID,
            "rawdata" => json_encode($reply2)
        );
    } else {
        return array(
            "status" => "failed",
            "transid" => $reply2->requestID,
            "rawdata" => json_encode($reply2)
        );
    }
}

Those who would like to hear more about the gateway development, post a comment. Will reply asap.

And those who are looking for a ready made module, please contact us from the link Request a quote. We will get back to you asap.