Developing payment plugins

Contents...

Payment plugins are used to manage payments for customers placing orders on a website. An opportunity to provide a payment is offered, when an order has been completed, in the form of a page where a customer can perform certain actions to provide payment; e.g., complete a payment form or proceed to the payment service website.

In the Webasyst framework the basis for development of payment plugins is provided by the system kernel. The framework offers a set of methods and a special data exchange format for retrieving order details and processing callbacks from payment gateways. Payment plugins are supported at the framework's system level rather than at the application level. This allows various applications (e.g., Shop-Script 5) to rely on the same payment plugins installed in the system.

Take a look at the source code of PayPal payment plugin as an example (GitHub repository).

The source code of payment plugins resides inside wa-plugins/payment/ directory. Each plugin is stored in a separate subdirectory containing implementation of a plugin class extending base class waPayment and implementing interfaces waIPayment, waIPaymentCapture, waIPaymentRefund, waIPaymentCancel, which provide templates for public methods payment(), capture(), cancel(), and refund() ­for processing the corresponding types of payment transactions (if supported by the corresponding gateway; otherwise they must return an error code).

The name of the subdirectory with plugin files is the plugin's unique identifier, which is used to form the correct name for the main class and the file it is contained in. Below is provided an example of the correct class and file names for some plugin with yourpayment identifier:

wa-plugins/payment/yourpayment/lib/yourpaymentPayment.class.php

<?php

class yourpaymentPayment extends waPayment
{

...

}

In addition to the main plugin class extending base class waPayment, each plugin also requires configuration files for correct functioning, which, like for apps and plugins, must be placed inside the lib/config/ subdirectory (see descriptions of plugin conifiguration files below in this article).

The development of a payment plugin is very similar to that of an application plugin with the exception that, unlike the development of an app plugin, creation of a payment plugin often requires only implementation of one or several main methods of one base class, which are listed below.

Methods

In methods of the main plugin class you can access values of plugin settings specified in its configuration file lib/config/settings.php by using private class fields of the form $this->field_name. Instead of field_name specify the id of the settings field whose value you need to obtain.

payment()

This method generates the main content of the page which offers a customer to initiate the payment process; e.g., enter payment credentials or proceed to a secure payment page. In the latter case a form with hidden element is often used, which is sent to the payment gateway when a customer clicks on a button or a link.

The following methods are required if your payment plugin implements integration with a payment gateway which supports callbacks to the online store; e.g., to valdate the received order details or to transmit additional data to the online store such as the payment transaction status.

callbackInit()

This method allows extracting the id of the app which should process the callback and the payment plugin settings values specified for that app. Below is the general example of how such a method should look in your plugin class:

protected function callbackInit($request)
{
    $this->order_id = null; //extract the order id from callback params
    $this->app_id = null; //do the same for app id
    $this->merchant_id = null;//do the same for payment plugin settings specified for that app
    
    return parent::callbackInit($request); //mandatory call of parent class method at the end
}

callbackHandler()

This method must describe the algorithm processing callbacks from the payment gateway. Such callbacks must be sent to URLs of the form http://yourdomain.com/payments.php/[plugin_id]/. Additional parameters can be passed to a payment plugin by means of URL parameters, which are usually accessible as $_GET array items. It is an established practice to use the transaction_result variable with the following values:

Here is an example of a URL to which a payment system should send its callbacks: http://yourdomain.com/payments.php/[plugin_id]/?transaction_result=result

The main purpose of this method is to call the transaction handler provided by the app utilizing your payment plugin:

$this->execAppCallback($state, $transaction_data)

Instead of $state specify the desired transaction status using one of the following constants of system class waPayment: CALLBACK_PAYMENT, CALLBACK_REFUND, CALLBACK_CONFIRMATION, CALLBACK_CAPTURE, CALLBACK_DECLINE, CALLBACK_CANCEL, CALLBACK_CHARGEBACK; e.g.:

$result = $this->execAppCallback(self::CALLBACK_PAYMENT, $transaction_data);

Call app's transaction handler only after you have verified that received data are correct and valid using checksum, signature, etc. Use of non-verified data may cause saving of incosistent payment information to the database!

After processing a callback from a payment system, method callbackHandler may redirect the customer to the specified URL or display a web page generated by the specified template file. For that, the method must return an array of values corresponding to each of these two options as shown below:

formalizeData()

Method formalizeData() is good for transforming requests received as callbacks from the payment gateway to the format suitable for saving transaction information in the Webasyst database.

Configuration files

plugin.php

File plugin.php is plugin's main configuration file used to store basic information: plugin name, description, version, etc. as shown below:

<?php
    
return array(
    'name'        => ...,
    'description' => ...,
    'icon'        => ...,
    'logo'        => ...,
    'vendor'      => ...,
    'version'     => ...,
    'type'        => ...,
);

Field descriptions

requirements.php

File requirements.php is used to specify additional system requirements applicable to the functioning of your payment plugin (e.g., availability of extra PHP extensions or configuration parameters, or installed Webasyst apps). See a detailed description of the system requirements configuration file.

settings.php

File settings.php is used for automatica generation of settings interface for a payment plugin displayed in the backend of the app utilizing the plugin. Read a detailed description of the plugin settings file.

guide.php

This file is used to display various non-editable parameters to users to enable them to copy and paste those data to their merchant account settings fields on the payment gateway website; e.g.: callback URL for updating order statuses, plugin setup instance id, name of required character set or data transfer method.

File guide.php must be a valid PHP file containing an array of parameters for each such field as shown below:

<?php
    
return array(
    array(
        'title'       => '',
        'description' => '',
        'value'       => '',
    ),
    array(
        'title'       => '',
        'description' => '',
        'value'       => '',
    ),
    ...
);

Each sub-array corresponds to one field. Sub-array keys have the following meanings:

Example of file guide.php:

<?php
    
return array(
    array(
        'title'       => 'Successful payment notification URL',
        'description' => '',
        'value'       => '%HTTPS_RELAY_URL%',
    ),
    array(
        'title'       => 'Failed transaction notification URL',
        'description' => '',
        'value'       => '%HTTPS_RELAY_URL%?transaction_result=failure',
    ),
    array(
        'title'       => 'Data transfer encoding',
        'description' => 'Specify this value when setting up connection using new integration protocol',
        'value'       => 'UTF-8',
    ),
);

Custom controls for frontend

A payment plugin can display additional controls including custom ones. To do so, you need to implement public method customFields() in the plugin class. This method must return an array of sub-arrays, each representing an additional control. Using argument $order you can access various properties of the current order to generate additional frontend fields and their values. Here is an example:

public function customFields(waOrder $order)
{
    return array(
        'field1' => array(
            'value'        => $default_field_value, //if necessary
            'title'        => _wp('First field name'),
            'control_type' => waHtmlControl::INPUT,
        ),
        'field2' => array(
            'value'        => $default_field_value, //if necessary
            'title'        => _wp('Second field name'),
            'control_type' => 'MyPaymentPluginControl', //custom control key
        ),
        //...
    );
}

For 'control_type' parameters you may specify a custom control key, which can be any string of HTML or JavaScript code.

To implement a custom control, the following is required:

  1. Add a public method to your plugin class to return the desired control HTML code.
  2. At the beginning of customFields() method, add the following call:

    $this->registerControl('MyPaymentPluginControl', array($this, 'myPaymentPluginControl'));

    In this example, 'MyPaymentPluginControl' as the first parameter of the registerControl() method is your custom control key, and 'myPaymentPluginControl' is its implementation method name.

Custom control keys and their implementation methods can be named freely.

Tips

Various useful URLs for setting up integration between your website and the payment system can be obtained in plugin's PHP code using the following methods:

Values of variables acceptable in file guide.php:

URLs for returning customers from payment gateway's website:

$this->getAdapter()->getBackUrl($type, $data);

Instead of $type, specify the desired action type in the form of one of the following constants of system class waAppPayment: URL_SUCCESS (successful payment), URL_DECLINE (declined payment), URL_FAIL (payment failure), URL_CHECKOUT (return to chekout page), URL_PRINTFORM (display a printable form). Instead of $data you must specify an array of transaction data. Example:

$return_url = $this->getAdapter()->getBackUrl(waAppPayment::URL_SUCCESS, $transaction_data);
The app utilizing your payment plugin must have support for the return URL type which you specify when calling method getBackUrl().