|
Introduction
nBill includes the facility for payments to be made online via a
3rd party payment service provider(PSP), such as Paypal. As there are literally
hundreds of PSPs out there, many of which are specialised to a particular
country, nBill has been written in such a way as to allow payment
gateway extensions to be 'plugged in' so that the component can be used with
virtually any PSP.
Free payment gateway extensions for various PSPs are available here. If you want to use
a different PSP, you will need to install a new gateway that has been created
specifically for your PSP. Creating a payment gateway for nBill is
quite a complicated process, requiring a skilled PHP developer. If you are not
an experienced PHP developer, don't try to create a payment gateway! You must
be capable of producing robust PHP code which is impervious to malicious SQL
injection and other cracking methods. If you do not FULLY understand the
instructions given in this document, please do not try to create a payment
gateway - get a professional to do it for you.
In the following instructions, wherever you see [gateway], insert the
name of your payment gateway (avoid spaces or punctuation marks in your
gateway name). Look at the code for the supplied gateways to see how
the following information has been put into practise.
To develop
a new payment gateway:
Create a folder on your computer in which
to develop the gateway. In that folder, create a sub-folder called
'admin.[gateway]'.
Create a new file called '[gateway].php'. This file will
be used to direct the user to the payment service provider.
Add the
following code to the start of the file:
/** ensure this
file is being included by a parent file */
defined( '_VALID_MOS' ) or die(
'Direct Access to this location is not allowed.' );
Create a new
file called '[gateway]_english.php'. If the gateway is to be used in languages
other than English, add an appropriately named language file for each language.
To ensure that the correct language is picked up at runtime based on the
language that Mambo/Joomla is using, add the following code to your [gateway].php file
(after the _VALID_MOS line):
global $mosConfig_lang,
$mosConfig_live_site;
if (file_exists(ADMIN_BASE_PATH .
"/admin.gateway/admin.[gateway]/[gateway]_" . $mosConfig_lang .
".php"))
{
include_once(ADMIN_BASE_PATH .
"/admin.gateway/admin.[gateway]/[gateway]_" . $mosConfig_lang .
".php");
}
else
{
if (file_exists(ADMIN_BASE_PATH .
"/admin.gateway/admin.[gateway]/[gateway]_english.php"))
{
include_once(ADMIN_BASE_PATH .
"/admin.gateway/admin.[gateway]/[gateway]_english.php");
}
}
Use the language files to store constants for any text
that needs to be displayed to the user. This includes explanatory text for the
gateway parameters that will appear in nBill's back end gateway
administration functions (see details about creating the gateway parameter values using
installation file later on...)
When creating a payment gateway for a
particular payment service provider, you typically require some custom
settings that are specific to that payment service provider. For example, you
might need a merchant id, or some kind of authentication code. The values for
these settings can be stored by nBill, and the user can be given the
ability to modify those values through the nBill administrator.
Details about how to define gateway parameters are described later in this
guide.
In addition to gateway parameter values, you will also need some dynamic
values - things such as the amount of the payment, the currency, and possibly
the name and address of the person paying (if known). These values are made
available through built-in variables which will be available to your script at
run-time.
The following variables are available to you to help you construct the
necessary URL to redirect to, or form to post (note: these variables
are defined and populated by nBill before it calls your gateway
script). The most important ones are:
$g_tx_id - The gateway id
for the transaction (this will be needed if the payment gateway posts back to
the merchant's website, to enable Netshine Billing to identify what the payment
is for)
$currency - The 3 character code for the
currency of the transaction (eg. USD, or GBP).
$total_gross - The full amount that needs to be paid
(including any setup fees).
$regular_total_gross -
The full amount that needs to be paid on a recurring basis after the initial
payment (this will only be different from $total_gross
if there is a setup fee defined for an ordered product, or a discount is being applied to the first payment only).
$orders - An array of items that have been ordered:
$orders[<index>]['product_code'] - The SKU of
the item.
$orders[<index>]['product_name']
- The name of the item.
$orders[<index>]['net_price'] - The net price of the
item.
$orders[<index>]['setup_fee'] - The net price of the
setup fee for the item, if applicable.
$orders[<index>]['quantity'] - The
number of units ordered.
$orders[<index>]['tax_amount'] - The amount of tax to be added to the net price.
$orders[<index>]['setup_fee_tax_amount'] - The amount of tax to be added to the setup fee amount.
$payment_frequency - A
2-character code indicating how often to make repeat payments. Possible values
are:
- AA - One-off
- BB - Weekly
- BX - Four Weekly
- CC - Monthly
- DD - Quarterly (every 3 months)
- DX - Semi-Annually (every 6 months)
- EE - Annually (every year)
- FF - Bi-annually (every 2 years)
- GG - Five-yearly
- HH - Ten-yearly
The following variables provide further information that may be
necessary/useful:
$carriage_service - The name of
the carriage option (eg. 'First Class', 'Federal Express').
$total_net - The total price of all ordered items, before
tax.
$total_tax - The total amount of tax added to
the net price of all ordered items.
$total_carriage
- The total amount of carriage fees added to the price of all ordered
items.
$total_carriage_tax - The total amount of tax
added to the carriage fees.
(The above 4 variables, when added together,
should equal the value held in $total_gross)
$expiry_date -
This value (a timestamp integer) is available from nBill 1.1.3 onwards
only. Defaults to zero if no expiry date is specified - always check
that the value is greater than the current time before use.
In
addition, a breakdown of the tax rates and amounts is available:
$tax_rates[<index>]
$tax_amounts[<index>]
(The
indices of the above arrays are calibrated, so for example $tax_rates[2] will hold the percentage that equates to the
amount of tax held in $tax_amounts[2].)
Details
about the person paying may be available, depending on how the gateway was
called and what fields were present on the order form. You can use the following
variables if they are available, but remember to check to make sure they hold a
value (if necessary) before using them. When using $_POST values, always extract the value using the mosGetParam
function (eg. $first_name = mosGetParam($_POST,
'INV_CORE_first_name');)
$billing_name
$billing_address
$_POST['INV_CORE_first_name']
$_POST['INV_CORE_last_name']
$_POST['INV_CORE_address_1']
$_POST['INV_CORE_address_2']
$_POST['INV_CORE_address_3']
$_POST['INV_CORE_town']
$_POST['INV_CORE_state']
$_POST['INV_CORE_postcode']
$_POST['INV_CORE_telephone']
$_POST['INV_CORE_company_name']
$_POST['INV_CORE_country']
$_POST['INV_CORE_email_address']
$_POST['INV_CORE_username']-This is the username that the customer will use for logging into the Joomla
website (only available if order form allows simultaneous user sign-up)
$_POST['INV_CORE_password'] - This is the password that the
customer will use for logging into the Joomla website (only available if order
form allows simultaneous user sign-up)
The 'INV_CORE_' prefix is there in
case the user defines their own form fields with one of those names, to prevent
the values from clashing. There may also be other values present from the order
form.
Use whichever values you need depending on the requirements of the
payment service provider. You probably will not need to use all of the available
values.
To get the gateway parameter values defined by the merchant in nBill for this gateway, use the following code:
global $database;
$sql = "SELECT * FROM #__inv_payment_gateway
WHERE gateway_id =
'[gateway]'";
$database->setQuery($sql);
$gateway_fields =
$database->loadAssocList('g_key');
Unfortunately, on some servers, the loadAssocList function (part of Mambo/Joomla's $database
object) does not seem to work. Therefore, it is necessary to check for
the existence of a key that is known to always be present (such as a
merchant ID), and if not found, construct the associative array
yourself, like so:
if (!array_key_exists('merchant', $[gateway]_fields))
{
//loadAssocList has not worked
$[gateway]_fields = array();
$alt_[gateway]_fields = $database->loadObjectList();
foreach ($alt_[gateway]_fields as $alt_[gateway]_field)
{
$[gateway]_fields[$alt_[gateway]_field->g_key] = array();
$[gateway]_fields[$alt_[gateway]_field->g_key]['g_key'] = $alt_[gateway]_field->g_key;
$[gateway]_fields[$alt_[gateway]_field->g_key]['g_value'] = $alt_[gateway]_field->g_value;
}
}
The values are then
available in the $gateway_fields associative array, for
example $gateway_fields['<name of my
setting>']['g_value']. g_value means 'gateway value', and the 'g_'
prefix is only there because the word 'value' is a reserved word in mySQL (or in
some versions at least).
If you can pass parameters to the payment
service provider in a URL query string, write the necessary PHP code to
construct the URL, and redirect the user using the nbRedirect() function.
If you have to POST the
parameters to the payment service provider and wait for a response without redirecting the user, you can use either the nbPostHTTP() or
the nbPostHTTPS() functions (which are built-in to nBill).
The syntax of
these functions is: nbPostHTTP[S]($host, $page,
$params). The $host parameter refers to the
main website address that you are posting to (eg. 'www.paymentservice.com'), and
the $page parameter is everything after that (eg.
'/onlinepayments/paymentform.html'). Do not prefix with http:// or https:// as
this will not work! The $params parameter is an
associative array of values to pass to the payment service provider. These
functions will return the HTTP response from the payment service provider
(including headers), which you can either echo to the screen, or process in some
other way. If these functions do not work for you (eg. they might not work if you need to submit an xml document to the PSP), you can just create your own functions, perhaps based on sample code provided by your PSP.
Please note that it is not safe to echo sensitive data over HTTP, so
only do that if the Mambo/Joomla site is using SSL (you can check for
port 443). If the site is using HTTP, it will be necessary to
introduce an extra confirmation step so that the values can be posted
directly to the Payment Service Provider's secure server. The
confirmation form can be posted using Javascript (if enabled on the
user's browser), thus removing the necessity for the user to submit an
extra form. See the SECPay gateway for an example of this.
If your gateway script does not redirect
the user, control returns to nBill, which will output a 'thank you
for your order' message. To suppress that message, just set the $abort flag to
true.
NOTE: If you redirect the user, you will need to pass
the value of $g_tx_id to the payment service provider so that they can
quote it when they call you back. Typically, if the PSP allows, you
would use the value as part of the transaction ID. However, please be
careful to ensure that all transaction IDs are unique (if required by
your PSP, which it usually is) - bearing in mind that a merchant might
be using nBill on more than one website, and therefore $g_tx_id might
not be unique for that merchant. For example, you could perform an md5
hash on the value of $mosConfig_live_site and use that as a prefix or
suffix to make $g_tx_id unique.
NOTE: If you need to collect credit card details on
the merchant site (ie. the PSP does not provide a shared service for
secure credit card detail capture), you need to be careful to ensure
that important values cannot be changed by a cracker between form
posts. For example, if you store the payment amount in a hidden field
while capturing card details, you must check that the amount has not
been changed by the user before sending it off for authorisation. One
way to do this would be to run an md5 hash on the important values PLUS
at least one piece of information that cannot be figured out by the
user - such as the license key (this is how it is done in the
authorize.net and eWAY payment gateways). You can then check the hash
again before posting off to the PSP to ensure no hacking has taken
place. Remember: always think like a cracker! Try to look for any
important data that could be changed by the user at every step of the
process, and put measures in place to verify that the data is valid.
If the payment service
provider processes the payment immediately and responds directly to your HTTP
POST, you can also add the relevant code for processing the receipt in the same
file. If the payment service provider provides a 'callback', the processing
code will need to go in a separate file - create a folder (at the same level as
the 'admin.[gateway]' folder), name it [gateway], and add a file called
[gateway].php. That is the file that will be processed when the payment service
provider does a callback. The callback URL would typically be in the format
'http://www.<domain name
here>.com/index.php?option=com_netinvoice&action=gateway&gateway=[gateway]'.
You can use other URL querystring parameters as well if you wish. Use the global
$mosConfig_live_site variable to pick up the appropriate callback domain name,
and use a gateway parameter for the rest of the callback
URL.
Processing receipts
When your gateway
receives notification that a payment has been made (either by a response to your
POST, or by calling you back), your gateway will need to load the associated
order details and process the order.
If using the 'callback' method, you
will have created a separate file ([gateway]/[gateway].php) for this
processing. In this case, make sure you add the following code to the start of
the file:
/* ensure this file is being included by a
parent file */
defined( '_VALID_MOS' ) or die( 'Direct Access to this
location is not allowed.' );
global $mosConfig_lang;
if
(file_exists(ADMIN_BASE_PATH . "/admin.gateway/admin.[gateway]/" .
"[gateway]_$mosConfig_lang.php"))
{
include_once(ADMIN_BASE_PATH .
"/admin.gateway/admin.[gateway]/" .
"[gateway]_$mosConfig_lang.php");
}
else
{
include_once(ADMIN_BASE_PATH . "/admin.gateway/admin.[gateway]/" .
"[gateway]_english.php");
}
If the payment service provider in
question provides various different types of callback (eg. the Paypal gateway
has 2 types: one for the IPN, and the other for redirecting the user to after
payment has been completed), use a switch statement to control the flow
depending on the querystring parameters (see Paypal gateway).
Once
again, use this code to get the gateway parameters:
$sql
= "SELECT * FROM #__inv_payment_gateway WHERE gateway_id =
'[gateway]'";
$database->setQuery($sql);
$gateway_fields =
$database->loadAssocList('g_key');
And check whether you need to rebuild the associative array yourself by verifying the existence of a known parameter:
if (!array_key_exists('merchant', $[gateway]_fields))
{
//loadAssocList has not worked
$[gateway]_fields = array();
$alt_[gateway]_fields = $database->loadObjectList();
foreach ($alt_[gateway]_fields as $alt_[gateway]_field)
{
$[gateway]_fields[$alt_[gateway]_field->g_key] = array();
$[gateway]_fields[$alt_[gateway]_field->g_key]['g_key'] = $alt_[gateway]_field->g_key;
$[gateway]_fields[$alt_[gateway]_field->g_key]['g_value'] = $alt_[gateway]_field->g_value;
}
}
Then perform any processing
that may be required to validate the callback. For example, with Paypal, you
post back to Paypal to confirm the details; with SECPay, you check for an md5
hashed key to authenticate (remember, anyone can post a response to your gateway script, so you should have some process to ensure that the notification is authentic).
Once we are sure we have a valid callback, it
is time to load the nBill order details, and process the payment
according to the selected configuration options.
This may involve the following
steps:
1) Make sure we have not already processed this payment
2)
Verify that the amount is what we are expecting
3) Create a client record (if
applicable)
4) Create an order record (if applicable)
5) Create an
invoice record (if applicable)
6) Create an income record (if
applicable)
From version 1.1.2 onwards, there are 2 built-in functions which will sort out all the
bits that have to be created, and send the relevant e-mails out. They are named gateway_processing() and finish_gateway_processing().
The first function to call is gateway_processing(), which takes the following parameters:
$g_tx_id (this
is the ID number that was passed to the payment service provider at the
time the payment was made, and which should be passed back to you by
them)
$payment_amount
$payment_currency
&$warning_message
(this is an output parameter which needs to be passed to the 2nd
function so that the warning is added to the e-mail to the
administrator)
&$error_message
(another output parameter that is passed to the 2nd function - if
populated, it means the function failed to work - eg. if the ID number
passed in does not exist in the database)
$customer
(optional - used when creating an income item to indicate who the
payment was from. If omitted, nBill will attempt to find a value based
on the client record)
$reference
(optional - if the payment service provider supplies its own reference,
you can pass that in to be stored with the income record)
$notes = (defaults to the value of the INV_AUTO_GENERATED_INCOME constant)
After that call has been made, you can either do some extra processing
(eg. populating your own transaction table with extra information), or
go straight onto the 2nd function: finish_gateway_processing(),
which sends out the relevant e-mails and redirects the user to the
success or failure page (if you pass in a URL), or displays an
appropriate message (if you don't). The parameters for this function
are:
$warning_message (pass in the value that you got back from the gateway_processing() function)
$error_message (pass in the value that you got back from the gateway_processing() function)
$add_debug_info
(optional - indicate whether or not to add extra environmental
information to the administrator's e-mail if there is an error message
- defaults to false, as this debug information can contain sensitive
data about the transaction and the server configuration. You can use a
gateway parameter in your gateway to allow the user to decide whether
or not to allow this)
$redirect_url (optional - a URL to redirect to after sending the e-mails. If not supplied, an appropriate message will be displayed).
Note: If the callback from the payment service
provider happens behind the scenes from the user's point of view (like
Paypal IPN), then of course the user will never see the success or
failure message, nor be redirected to a success or failure URL by the
gateway script. In such cases, the success or failure
URL may be defined by the merchant in the payment service
provider's control panel, or it might be a parameter which can be passed to the PSP at the time of the transaction (in which case you can create gateway parameters for the values).
All of the above will make more sense if read in
conjunction with the existing payment gateways, available here.
That covers the core code that you will need to
write. Now for creating the installation package.
Creating an Installation Package
To enable your gateway to be installed using the gateway installer
in nBill, you need to create an installation file. This is a simple
text file with the file extension .nbe (nBill Extension). In this file,
you create the definition of the gateway parameter values that you want
to store, as well as any other database tables that you want to create,
and PHP files that you want to include.
The basic structure of the file is shown below:
#nbill_extension_installer_1.0
# This is a sample install file for an nBill Payment Gateway - replace any values with your own as indicated
# In all cases where you see <gateway_name>, replace it with your actual gateway name!
# Lines that start with a hash (#) or double slash (//) or that are blank, will be ignored by the installer
# If you need to use a hash or double slash in the data, prefix with a backslash escape character (eg. \// or \#)
# Always start a new setting on a new line.
# If you want a line break within a setting, surround the setting value with square brackets
# When you publish your gateway, you can delete these comment lines from the top of the file!
# The following directive tells the installer whether or not to convert the files in this extension to UTF-8.
# If your files are encoded as ISO-8559-1 (this is usually the default for text editors, so they probably are),
# some CMSs (eg. Joomla 1.5, Mambo 4.6) will require them to be converted to UTF-8. Other CMSs may prefer them
# to be kept as ISO-8559-1, or the user might be able to choose. If the files are NOT encoded using ISO-8559-1,
# you must set this option to C (Don't Convert), as the conversion process will not work with any other encoding.
# In most cases though, it is necessary to set this option to A.
#
# Valid values for this directive are:
# A = Convert if required by CMS
# B = Convert always
# C = Don't Convert
Convert_ISO-8859-1_to_UTF-8=A
type=gateway
#Minimum version of nBill on which this extension installation will work
nbill_version=1.2.0
#If a service pack is required for the above version in order for this installation to work, specify it here
nbill_sp=0
# The name is used for the folder name, so no spaces or punctuation allowed:
name=<gateway_name>
# The title is used as the default human-readable display value (although the user can change it):
title=***Enter Pretty Name Here***
author=***Enter your own name or company name here***
date=***Enter date of this release***
copyright=***Any copyright message***
license=***Licensing information goes here***
author_email=***Contact e-mail address***
author_url=***Website***
version=***Version number of this extension***
description=***Constant that contains the extension description***
file=***Front-end Gateway file (ie. <gateway_name>/<gateway_name>.php)***
admin_file=***Back-end Gateway file (ie. admin.<gateway_name>/<gateway_name>.php)***
admin_file=***Back-end Language file (ie. admin.<gateway_name>/<gateway_name>_english.php***
# If you want to run some code after installation, include an install file - it MUST be named as indicated below
admin_file=admin.<gateway_name>/<gateway_name>.install.php
# If you want to run some code after uninstallation, include an uninstall file - it MUST be named as indicated below
admin_file=admin.<gateway_name>/<gateway_name>.uninstall.php
# For gateway settings, add a line like the following for each parameter:
gateway_parameter=***key***;value=***;label=***;help=***;required=0;editable=0
# Repeat for as many parameters as you want to add...
gateway_parameter=***key***;value=***;label=***;help=***;required=0;editable=0
gateway_parameter=***key***;value=***;label=***;help=***;required=0;editable=0
gateway_parameter=***key***;value=***;label=***;help=***;required=0;editable=0
# You can split the values onto multiple lines by surrounding in square brackets, like this:
gateway_parameter=[
***parameter_key***;
value=***default_value***;
label=***label_constant***; //You can also add comments at the end of a line, like this
help=***help_text_constant***; #or this!
required=***0 or 1***;
editable=***0 or 1***]
# If you want to run an additional database query, you can define it like this:
query=[***Enter your SQL here, on multiple lines if you like***]
# If the database changes you make by running additional queries, above, can be undone by running another query,
# enter the query here (undo queries will be run if the installation fails or when the extension is uninstalled)
undo_query=[***Enter your SQL here, on multiple lines if you like***]
Note that the gateway parameters will be displayed to the user in the same order that they are
defined within the file, so it is probably best to put the most important
items at the top.
If you want to add extra functionality to nBill that relates to your payment gateway, you can do so by including a
couple of extra files in the either the [gateway] or admin.[gateway] folder (or
both): [gateway].functions.php and [gateway].functions.html.php. These will
work in exactly the same way as a normal Mambo/Joomla component (so put all your
program flow control and processing logic in [gateway].functions.php, and all of
your html generation in [gateway].functions.html.php). You can add any other
files you like as well (eg. [gateway].class.php).
To access back-end (admin) functions, an extra menu item
will appear under the 'Extensions' menu in nBill automatically if a
functions file is detected. If your functions file contains more than 1
feature, you should display a menu of options to the user if no parameters are
passed in, and use querystring parameters to allow access to your other
features.
To access front-end functions, the URL should follow this pattern:
index.php?option=com_netinvoice&action=gatewayfunctions&gateway=[gateway]
- you can of course add your own querystring parameters as required by your
script. Your documentation should inform users of how to access any extra
features you have added.
See the installation files that come with
the existing gateways for examples of how to put together the file.
Licensing
If you are donating your payment gateway for general use by the public,
it is recommended to add a license such as the following to the
comments at the start of each file in your gateway:
/**
* This gateway was developed by and is copyright of <Name of your company>.
* Sections of code may be copyrighted to other parties (eg. where sample code was used
* from the <Name of payment service provider> documentation). All parts (of this gateway only)
* written by <Name of your company> are licensed for use in any way you wish, as long as this
* copyright message remains intact, and without any guarantee of any sort - use at your own risk.*/
In order to be accepted as an approved nBill gateway, and
qualify for a free license key, the following guidelines should be
adhered to:
- Code should be properly commented for ease of reading.
- There should be no redundant code - please don't leave artifacts from other gateways that you may have copied from.
- There should be no 'commented out' code in the gateway unless there is a very good reason for it.
- Code
should be properly indented - please do not include excess white space,
and be consistent in the way you use brackets and indentation.
- Any
HTML code that is output must be XHTML and validate with the W3C
validator. Please do not use deprecated syntax like <font>.
- Please
do not introduce any extra unnecessary steps - eg. don't require the
user to click on a link or a button unless it is absolutely necessary.
They have already submitted their form, and submitted a summary page,
and will have to submit their card details - we don't want them to have
to submit anything else. If you must post a form to the PSP, use
Javascript to do it if necessary rather than requiring another click
from the user (if Javascript is disabled on the user's browser, then
they would have to click themselves to submit, but this is no reason to inconvenience the other 99.9% of users).
- When reading posted values or request values, always use the mosGetParam() function.
- If
your gateway involves a callback from the payment service provider
(PSP), always provide some way of checking the authenticity of the
callback - even if it is just an IP address check (which you should
implement as a gateway parameter in the installation file so that the
user can change it).
- It is preferred if base URLs that are
used to call or hand over to the PSP are defined as gateway parameters
in the installation file - in case they change in future (individual
request parameters that are appended to the base URL can of course be
hard-coded).
- If the PSP supports recurring payments, your
gateway must also support them - including whatever development is
necessary to pass the payment frequency to the PSP. Please Note:
If your gateway does not support recurring payments (whether the PSP
supports them or not), you will only be granted a 2-year license key
for nBill rather than an outright license.
|