Payment gateway modules

From ISPWiki
Jump to: navigation, search

General information

A gateway module allows to connect a third party payment gateway, configure settings and interface of the payment form, as well as payment procedure on the User side. Besides, the payment module implements invoice generation and payment processing. You may add a custom payment procedure depending on your specific needs: either redirect clients to a gateway's web-site to make payments, or generate invoices.

How it works

The payment procedure in BILLmanager includes the following steps:

  1. The module is installed
  2. The module is connected to the payment gateway
  3. The client makes a payment
  4. The client pays the invoice generated by the billing system
  5. The system handles or cancels his payment

The module can be installed either manually (if it is a list of files), or from repository using the package manager. Once installed, you can choose the payment gateway when creating a new payment method in BILLmanager.

Each module sends requests to BILLmanager for supported features and required parameters. This operation is performed each time BILLmanager starts and a call is sent to the payment module, and allows to improve BILLmanager performance, exclude unsupported calls, and define behavior of BILLmanager forms when the client makes a new payment.

Module structure

A payment gateway module consists of two to unlimited files. The main files are XML description, and the main script that sends module configuration to BILLmanager. Alternatively, two CGI scripts can be used: to redirect a client to the gateway's web-site, and receive notifications from the gateway reporting payment status changes.

If integration with the payment gateway requires additional parameters, or depending on a developer's needs, additional files can be added (for example, files that handle additional forms, verify payment parameters, print invoices, check payment statuses, etc.).

The following is a standard list of files (paths are relative to the location of BILLmanager installation directory):

  • etc/xml/billmgr_mod_pmXXX.xml - XML description of the payment module. Be sure to provide a standard filename format
  • paymethods/pmXXX - the main script. Be sure to provide a standard filename format
  • cgi/XXXpayment - the payment script. Optional file, which can have any name
  • cgi/XXXresult - the notification processing script. Optional file, which can have any name
  • cgi/XXXrecurring - recurrent payments activation script. An optional file, which can have any name
  • cgi/XXXrecurringresult - recurrent payments notifications script. An optional file, which can have any name

Where XXX is the name of your payment method in Latin characters. If the name of the main module contains a file extension, it will be included into the name. For example, if your script name is pmpay.php, the module name will be pay.php, rather than pay.

XML description

A file name can look like the following - billmgr_mod_pmXXX.xml, where XXX - is a module name. The file is copied into the etc/xml directory relative to the BILLmanager installation directory. The file contains description of the module (it is described as a plugin) and additional forms and messages.

Example of the XML file:

<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
  <plugin name="XXX">
    <group>payment_method</group>
    <msg name="desc_short" lang="ru">XXX модуль</msg>
    <msg name="desc_short" lang="en">XXX module</msg>
    <msg name="desc_full" lang="ru">XXX модуль</msg>
    <msg name="desc_full" lang="en">XXX module</msg>
  </plugin>

  <metadata name="paymethod.edit.XXX" type="form">
    <form>
      <page name="methodprops">
        <field name="prop1">
          <input name="prop1" required="yes" type="text" />
        </field>
        <field name="prop2">
          <input name="prop2" private="yes" required="yes" type="text" />
        </field>
      </page>
      <page name="recurring">
        <field name="recurring">
         <input type="checkbox" name="recurring">
           <if value="off" hide="recurringprop1"/>
           <if value="off" hide="recurringprop2"/>
         </input>
        </field>
        <field name="recurringprop1">
          <input name="recurringprop1" required="yes" type="text" />
        </field>
        <field name="recurringprop2">
          <input name="recurringprop2" private="yes" required="yes" type="text" />
        </field>
      </page>
      <page name="refundpage">
        <field name="allowrefund">
         <input type="checkbox" name="allowrefund">
           <if value="off" hide="refundprop1"/>
           <if value="off" hide="refundprop2"/>
         </input>
        </field>
        <field name="refundprop1">
          <input name="refundprop1" required="yes" type="text" />
        </field>
        <field name="refundprop2">
          <input name="refundprop2" private="yes" required="yes" type="text" />
        </field>
      </page>
    </form>
  </metadata>

  <metadata name="payment.edit.xxx" type="form">
    <form>
      <field name="payment_prop">
        <input type="text" name="payment_prop" required="yes"/>
      </field>
    </form>
  </metadata>

  <metadata name="paymethod.transfer.XXX" type="form">
    <form>
      <field name="param">
        <input type="text" name="param" required="yes"/>
      </field>
    </form>
  </metadata>

  <lang name="en">
    <messages name="label_paymethod">
      <msg name="pmXXX">XXX module</msg>
      <msg name="module_pmXXX">XXX module</msg>
    </messages>

    <messages name="paymethod.edit.XXX">
      <msg name="prop1">Prop 1</msg>
      <msg name="hint_prop1">Hint for prop 1</msg>
      <msg name="prop2">Prop 2</msg>
      <msg name="hint_prop2">Hint for prop 2</msg>

      <msg name="recurringprop1">Recurring prop 1</msg>
      <msg name="hint_recurringprop1">Hint for recurring prop 1</msg>
      <msg name="recurringprop2">Recurring prop 2</msg>
      <msg name="hint_recurringprop2">Hint for recurring prop 2</msg>

      <msg name="refundprop1">Refund prop 1</msg>
      <msg name="hint_refundprop1">Hint for refund prop 1</msg>
      <msg name="refundprop2">Refund prop 2</msg>
      <msg name="hint_refundprop2">Hint for refund prop 2</msg>
    </messages>

    <messages name="paymethod.transfer.XXX">
      <msg name="param">Param</msg>
      <msg name="hint_param">Hint param</msg>
    </messages>

    <messages name="payment.edit.XXX">
      <msg name="payment_prop">Prop</msg>
      <msg name="hint_payment_prop">Hint for prop</msg>
      <msg name="placeholder_payment_prop">prop</msg>
    </messages>
  </lang>

  <lang name="ru">
     <messages name="label_paymethod">
      <msg name="pmXXX">XXX module</msg>
      <msg name="module_pmXXX">XXX module</msg>
    </messages>

    <messages name="paymethod.edit.XXX">
      <msg name="prop1">Property 1</msg>
      <msg name="hint_prop1">Hint for property 1</msg>
      <msg name="prop2">Property 2</msg>
      <msg name="hint_prop2">Hint for property 2</msg>
    </messages>

    <messages name="paymethod.transfer.XXX">
      <msg name="param">Property</msg>
      <msg name="hint_param">Hint for property</msg>
    </messages>

    <messages name="payment.edit.XXX">
      <msg name="payment_prop">Property</msg>
      <msg name="hint_payment_prop">Hint for property</msg>
      <msg name="placeholder_payment_prop">property</msg>
    </messages>
  </lang>
</mgrdata>

The <plugin> section contains module description. The name property matches the payment module's name. The section may contain the group element with the payment_method value indicating that this module is used for payment methods, and several msg elements. The lang property defines a language associated with the message, the name attribute may have the following values:

  • desc_short - brief description of the module, which is displayed in BILLmanager payment form.
  • desc_full - full description of the module, which is displayed in the list of installed modules in COREmanager.

The metadata section named paymethod.edit.XXX handles additional fields of the module that are displayed when you add or configure payment methods.

It is formed according to standard description of XML forms taking into account location of fields in the <page name="methodprops"></page> section to ensure correct location of fields on BILLmanager forms. The only difference from standard description is support for the private attribute, which forbids using this attribute in XML when printing the invoice based on that payment. It is used for security information , such as password or secret key.

The metadata section named payment.edit.xxx handles additional fields that a client can see when making a payment. It is described according to standard description of XML form.

The metadata section named paymethod.transfer.XXX handless additional fields that are displayed when making refund.It is described according to standard description of XML form.

The lang section contains translations of form fields according to the standard scheme of translation description. The <messages name="label_paymethod"> section is used to specify the module name in the list of payment methods.

Main script

The main script sends the information about functions supported by the module to BILLmanager, and handles some of those functions. BILLmanager executes the script file with the following parameters:

paymethods/pmxxx --command cmd [--payment id [--amount amnt]]

where

  • cmd - control command
  • id - payment id
  • amnt - amount converted into a payment method's currency (it used in case of refunds or transfer)

The following values can be sent to the --command parameter:

  • config - module configuration request. The module will send the following XML to the standard output:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <feature>
    <refund>on</refund>
    <transfer>on</transfer>
    <recurring>on</recurring>
    <redirect>on</redirect>
    <noselect>on</noselect>
    <notneedprofile>on</notneedprofile>
    <pmtune>on</pmtune>
    <pmvalidate>on</pmvalidate>
    <crtune>on</crtune>
    <crvalidate>on</crvalidate>
    <crset>on</crset>
    <crdelete>on</crdelete>
    <rftune>on</rftune>
    <rfvalidate>on</rfvalidate>
    <rfset>on</rfset>
    <rctune>on</rctune>
    <rcvalidate>on</rcvalidate>
    <rcset>on</rcset>
    <rcpay>on</rcpay>
    <tftune>on</tftune>
    <tfvalidate>on</tfvalidate>
    <tfset>on</tfset>
  </feature>
  <param>
    <payment_script>/mancgi/qiwipullpayment.php</payment_script>
    <recurring_script>/mancgi/qiwipullrecurringpayment.php</recurring_script>
    <recurring_type></recurring_script>
  </param>
</doc>

The feature branch contains features supported by the module. If a feature is not supported, it shouldn't be sent to a command's standard output.

Allowed values:

    • refund - indicates that payments can be cancelled, and clients can be refunded. If this feature is not supported, the rftune, rfvalidate, rfset commands may not be handled.
    • transfer - indicates that funds can be transferred from a payment system's account into a client's account. If this feature is not supported, the tftune, tfvalidate, tfset commands may not be handled.
    • recurring - support of recurring payments. If this feature is not supported, the recurring_script, and recurring_type parameters may not be specified
    • redirect - indicates that a client will be redirected to a payment gateway to complete the payment.
    • noselect - payment method won't be available to clients. This value is used if a client doesn't need to create invoice in BILLmanager.
    • notneedprofile - indicates that payment does not require a payer. However, if the payment method is associated with a company, the client will be asked to create or select a payer.
    • pmtune - indicates that the payment method's configuration form requires additional actions. See the pmtune command for more details.
    • pmvalidate - call the module to verify values when saving parameters of the payment method.
    • crtune - indicates that the payment form requires additional actions. See the crtune command for more details.
    • crvalidate - call the module to verify values when saving parameters that a client enters.
    • crset - indicates that the module is required to complete specific actions for payment or if a clients is not redirected to the payment system site to complete his payment. We recommend adding this feature, if the client is required to provide any data when making a payment.
    • crdelete - indicates that a client is required to perform additional actions on the payment system side to delete the payment correctly
    • rftune - similar to crtune, in case of refund.
    • rfvalidate - similar to crvalidate, in case of refund.
    • rfset - indicates that clients can be refunded. Calling this command will perform operations required for refund.
    • tftune - similar to crtune, it is used for transfer.
    • tfvalidate - similar to crvalidate, it is used for transfer.
    • tfset - mandatory feature for transfer. Calling this command will perform operations required for funds transfer.

The param branch contains parameters of the payment method. Supported parameters:

    • payment_script - the path to the payment redirect script relative to BILLmanager installation domain.
    • recurring_script - the path to the redirect script for recurring payments confirmation
    • recurring_type - the bit mask of supported options.
      • 1 - a separate payment is created for one service
      • 2 - a payment is created for several services
      • 7 - a payment is created for all services
      • 8 - the maximum amount is required for payment
      • 20 - redirect to a payment gateway is required for recurring payment confirmation
      • 21 - a client should perform additional operation for payment confirmation
  • pmtune - is called to change the payment method's form. The form XML is sent to standard input, and then the script returns the modified XML in its standard output.
  • pmvalidate - is called to check values in the payment method form. The XML with values from the form is sent to standard input, and the script returns the XML containing error description, or empty XML to its standard output.
  • crtune - is called to change the payment form. The payment form's XML is sent to standard input, and then the script returns the modified XML in its standard output.
  • crvalidate- is called to check values in the payment form. The XML with values from the form is sent to standard input, and then the script returns the XML containing error description, or empty XML to its standard output.
  • crset - is called when clicking OK on the payment form. The parameter sends id of the required payment. Data that the client enters are already kept in the database.
  • crdelete - is called when clicking Delete in the list of payments. The parameter sends id of the payment to be deleted.
  • rftune - is called to edit the refund form. The refund XML is sent to standard input, and and then the script returns the modified XML in its standard output.
  • rfvalidate -is called to check values in the refund method form. The XML with values from the form is sent to stdin, and then the script returns the XML containing error description, or empty XML to its standard output.
  • rfset - is called when clicking OK the refund form. The XML with information about new or existing payment for refund, amount to be refunded, cause, and payment method parameters is sent to standard input.
  • tftune - is called to change the transfer form. The transfer form's XML is sent to stdin, and then the script returns the modified XML to its standard output.
  • tfvalidate - is called to check values provided for funds transfer. The XM containing values from the form is sent to stdin, and then the XML containing error description, or empty XML is sent to standard output.
  • tfset - is called when clicking OK on the transfer form. The XML with information about payment, amount to be transferred, and payment method parameters are sent to standard input. Then the script returns the XML with information about transfer payment, amount to be transferred, and payment method are sent to its standard output.

An example of the script can be found below.

CGI scripts

CGI scripts are optional elements of the payment module. You don't need to specify them, if the logic is described in the main module.

The module may have several CGI scripts:

  • payments
  • notifications reporting payment status change
  • other scripts required by payment system

In general, CGI scripts can locate on a different server, IP address or domain, depending on the needs of the module's developer and/or payment system requirements.

Following are examples of two scripts: payment redirect and notification of change in payment status.

Payment redirects

BILLmanager gets the address of the payment redirect script along with the module data when first accessing the module. The most common way is to generate and automatically send a form with required parameters. The form should be as follows:


<html>
  <head>
    <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
    <link rel='shortcut icon' href='billmgr.ico' type='image/x-icon' />
    <script language='JavaScript'>
      function submit() {
        document.frm.submit();
      }
    </script>
  </head>
  <body onload='submit()'>
    <form name='frm' action='https://paysystem/url' method='post'>
      <input type='hidden' name='shop_id' value='1'>
      <input type='hidden' name='amount' value='1.00'>
    </form>
  </body>
</html>


The elid parameter with payment id is always sent to the script. With the payment.info parameter you can obtain all the data required to generate a payment form. The XML that the function returns (you can use JSON if needed) should be as follows:

<doc>
  <payment>                                                   <!-- payment information -->
    <id>1</id>                                                <!-- payment id -->
    <subaccount>1</subaccount>                                <!-- personal account id -->
    <paymethod>1</paymethod>                                  <!-- payment method id -->
    <recipient/>                                              <!-- payee id (company). Company data if any, will be also added into the function output -->
    <sender/>                                                 <!-- payer id who is making payment. Payer data if any, will be also added into the function output -->
    <subaccountamount>1.00</subaccountamount>                 <!-- payment amount converted into the invoice currency -->
    <status>2</status>                                        <!-- payment status -->
    <number>pfx/1</number>                                    <!-- payment number -->
    <paymethodamount>1.00</paymethodamount>                   <!-- payment amount converted into the payment method's currency -->
    <currency>126</currency>                                  <!-- payment currency id  -->
    <externalid/>                                             <!-- payment external id, can be saved by the payment.setpaid function -->
    <description>Advanced payment</description>               <!-- purpose of payment -->
    <remote_ip>127.0.0.1</remote_ip>                          <!-- payment IP address -->
    <manager_url>https://localhost:1500/billmgr</manager_url> <!-- BILLmanager payment URL -->
    <phone>7 000 0000000</phone>                              <!-- additional parameter of the payment specified in the module XML -->
    <useremail>email@example.com</useremail>                  <!-- payer email address -->
    <paymethod>                                               <!-- payment method -->
      <id>1</id>                                              <!-- payment method id -->
      <name>XXX</name>                                        <!-- payment method name -->
      <active>on</active>                                     <!-- status -->
      <minamount>0.00</minamount>                             <!-- minimum payment amount -->
      <maxamount/>                                            <!-- maximum payment amount -->
      <autoclearperiod/>                                      <!-- period to delete overdue invoices -->
      <currency>126</currency>                                <!-- payment method currency id -->
      <profiletype>1,2,3</profiletype>                        <!-- types of payers who can use this payment method -->
      <commissionamount>0.00</commissionamount>               <!-- commission amount -->
      <commissionpercent>0</commissionpercent>                <!-- payment commission in % -->
      <module>pmXXX</module>                                  <!-- module name -->
    </paymethod>
    <currency>                                                <!-- payment currency -->
      <id>126</id>                                            <!-- currency id from Directory -->
      <name>Russian Ruble</name>                              <!-- name -->
      <iso>RUB</iso>                                          <!-- ISO currency code -->
      <code>643</code>                                        <!-- ISO numerical code -->
      <active>on</active>                                     <!-- status -->
    </currency>
    <project>                                                 <!-- provider information -->
      <id>1</id>                                              <!-- id -->
      <name>ISPsystem</name>                                  <!-- name -->
      <notifyemail>email@example.com</notifyemail>            <!-- email for notifications -->
    </project>
    <items>                                                   <!-- invoice items; if associated with a service, it contains ordered services, otherwise - purpose payment -->
      <item>                                                  <!-- invoice item -->
        <name>Advanced payment</name>                         <!-- name -->
        <locale_name>Advanced payment</locale_name>           <!-- name in user localisation -->
        <amount>1.00</amount>                                 <!-- item subtotal-->
      </item>
    </items>
  </payment>
</doc>

Additional parameters that clients provide when making a payment are also added to the payment node. Payment method's parameters are added to the paymethod node. This method is more preferable than just receiving information directly from the BILLmanager database.

The example of the redirect script can be found at the end of this article.

Payment status change notifications

A script that handles the payment status change notifications must perform the following operations:

  • Select the payment id (from BILLmanager) from the data sent by the payment system.
  • Receive information related to that payment from the database, or execute the payment.info function to get information about the payment and payment method's parameters.
  • Compare the data from the payment system with those kept in BILLmanager.
  • Verify the control sign of the received data with the secret key (the most common way of data verification).
  • Change the payment status in BILLmanager based on the data received above.
  • Inform the payment system about successful or failed incoming request, if needed.

You can find the example of the script at the end of this article.

BILLmanager functions

  • payment.info - all the information about a certain payment, the elid parameter - payment id
  • payment.setfraud - set payment status to "Fraud", the elid parameter - payment id
  • payment.setinpay - set payment status to "Pending", the elid parameter - payment id
  • payment.setnopay - set payment status to "Not paid", the elid parameter - payment id
  • payment.setpaid - set payment status to "Paid", the elid parameter - payment id
  • payment.success - result page for a successful payment, the elid parameter - payment id
  • payment.fail - result page for a failed payment, the elid parameter - payment id

Return pages

To return your clients back to BILLmanager after the payment has been made, you can use custom CGI scripts, static html pages, or BILLmanager standard functions:

  • payment.success - result page for a successful payment, the elid parameters - payment id
  • payment.fail - result page for a failed payment, the elid - parameters - payment id

To add additional information into the forms that are displayed by these functions, add more description to the corresponding function:

<metadata name="payment.XXX.fail" type="form">
  <form>
    <field name="fail_description" noname="yes" formwidth="yes">
      <textdata name="fail_description"/>
    </field>
  </form>
</metadata>

 <metadata name="payment.XXX.success" type="form">
  <form> 
    <field name="success_description" noname="yes" formwidth="yes">
      <textdata name="success_description"/>
    </field>
  </form>
</metadata>

<lang name="en">
  <messages name="payment.XXX.fail">
    <msg name="fail_description">Fail</msg>
  </messages>
  <messages name="payment.XXX.success">
    <msg name="success_description">Success</msg>
  </messages>
</lang>
<lang name="ru">
  <messages name="payment.XXX.fail">
    <msg name="fail_description">Error</msg>
  </messages>
  <messages name="payment.XXX.success">
    <msg name="success_description">Success</msg>
  </messages>
</lang>

Example

The following is an example of the QIWI payment gateway (through the PULL(REST) protocol)

PHP

The module contains four main files:

  • etc/xml/billmgr_mod_pmqiwipull.php.xml - XML description
  • paymethods/pmqiwipull.php - main script
  • cgi/qiwipullpayment.php - CGI script redirects a client to the payment page
  • cgi/qiwipullresult.php - notifications from a payment gateway

And additional file with useful functions:

  • include/php/bill_util.php

You can download the file at https://github.com/ISPsystemLLC/billmanager/blob/master/tar/qiwipull.tar.gz, or view the list of files at https://github.com/ISPsystemLLC/billmanager/

The bill_util.php function

Note: Before adding the bill_util.php file into your script, be sure to define the __MODULE__ macro to form a log file name.

It looks like the following:

set_include_path(get_include_path() . PATH_SEPARATOR . "/usr/local/mgr5/include/php"); 
define('__MODULE__', "pmXXX"); 
require_once 'bill_util.php';

The bill_util.php file delivers the following functions:

  • Debug($str) - outputs $str into the log as additional information
  • Error($str) - outputs $str as an error message
  • LocalQuery($function, $param, $auth = NULL) - executes $function in BILLmanager and sends parameters from the $param array, and the session id from $auth to this function.
  • HttpQuery($url, $param, $requesttype = "POST", $username = "", $password = "", $header = array("Accept: application/xml")) - sends a request to $url with parameters from $param. The file uses $requesttype as a request type and authentication data from $username and $password. Additional headings can be also sent to $header
  • CgiInput($skip_auth = false) - receives an array of script parameters in the request or data POST. $skip_auth receives the auth parameter from cookie, if it is not present in the data received.
  • ClientIp() - get the IP address from which the script was called
  • class Error - error class imitating behavior similar to COREmanager errors.

C++ (with the use of BILLmanager libraries)

Starting from version 5.58.0 you can use BILLmanager header files to develop custom processing modules. Beside a simplified example, you can look into examples in the BILLmanager developer package - billmanager-[BILLmanager version]-devel, example:

 yum install billmanager-standard-devel

Then you can find examples in the directory:

/usr/local/mgr5/src/examples

С++

Description

You can find an example here. The module uses COREmanager and BILLmanager heading files. The module is based on custom components described in the articles Building custom components and Lower-level interaction, C++ plug-ins.

See also

Module structure

The module consists of mandatory files pminterkassa.cpp - a code of the main executable file of the payment method, and xml/billmgr_mod_pminterkassa.xml - XML description of the module.

The module also includes two CGI scripts for redirect to a processing center, and receipt of successful payments notifications.