Additional modules of payment systems
From ISPWiki
Payment systems are described in the following BILLmanager modules:
1. Log in as Administrator (Provider) and go to the Company management module ->Payment methods;
2. Log in as Customer and go to the Credits/Payments module;
To add a custom payment interface you need to create a program or script that will fill out and handle form fields, and start the payment process, if necessary; create an xml document containing description of the interface elements and text messages in different languages; create CGI scripts and programs that will exchange data with payment gateways, if necessary.
Contents |
XML-document
Locate the XML document in /usr/local/ispmgr/etc and name it as billmgr_mod_xxx.xml, where xxx is a random name, for example, test (billmgr_mod_test.xml). The document should be encoded in the UTF-8 character set. Example:
<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<metadata name="company.paymethod.edit_XXX" type="form">
<form>
<field name="name">
<input type="text" name="name" empty="no"/>
</field>
<field name="minamount">
<input type="text" name="minamount"/>
</field>
----the filds you need----
</form>
<jscript>
document.frm.func.value = 'company.paymethod.edit';
</jscript>
</metadata>
<metadata name="credit.pay.XXX" type="form">
<form>
<field name="amount">
<input type="text" name="amount" readonly="yes"/>
</field>
----the filds you need----
<field name="merchantfield"> If you use a link to the payment system web-site
<link name="merchant"/>
</field>
</form>
<jscript> If you use a link to the payment system web-site
function GoMerchant(id, lnk) {
window.open('/mancgi/testcgi?elid='+id);
if (lnk) {
lnk.className = 'disabled';
lnk.onclick = function () { return false; }
}
}
</jscript>
</metadata>
<lang name="en">
<messages name="credit.pay.XXX">
<msg name="amount">Amount</msg>
<msg name="merchant">Pay now</msg>
<msg name="title">XXX pay method</msg>
<msg name="hint_default">Fill form</msg>
<msg name="hint_amount">Amount</msg>
---other messages----
</messages>
</lang>
</mgrdata>
XXX is a payment system internal name. It is strongly recommended that messages are described in English, otherwise other languages may not be created. The merchant field is required if you want to use a link to the web-site.
Handler program
The program or script should locate in the /usr/local/ispmgr/sbin/ directory. The file's name should start with pm symbols. The symbols following pm is an payment system internal name that will be used by the interface elements. When started with the feature parameter, the program must return a list of supported features space separated.
Features list
pmtune The program will modify the payment method edit form. It is used provide required values. BILLmanager passes the XML-document that describe the form to STDIN and waits for the modified XML-document to STDOUT.
pmvalidate The program will verify the data the user will provide. BILLmanager transfers the XML-document that contains form fields with values to STDIN. If the field name is param1, param2 b param3, the XML will be as follows:
<?xml version="1.0" encoding="UTF-8"?> <doc> <param1>value</param1> <param2>value</param2> <param3>value</param3> </doc>
If all of the parameters have correct values, the program will output pmok to STDOUT, otherwise it will return Error: parameter_name. If a success, BILLmanager will record parameters in the same XML-form into the params field of the companycrtype table. You can use these data when creating payments.
crtune The program will edit the form for adding new payments. It is used to provide required values and operates the same way as pmtune.
crvalidate The program will check the data provided by the use when making payment. It is working in the same ways as pmvalidate.
crget The program will fill out the form for creating new payment. It is used to enter data from the database into the payment edit form. Operates the same way as pmtune.
crset It is used if a user does not need to pass to the payment system's web-site and the payment is based on the input data. BILLmanager uses this method when making payments via WebMoney and Ogone. It is based on the LongTask system. The following warning message will show if an error occurs:
crid payment_code error_description
The yellow banner will be displayed:
An error occurred while making payment. Id: 'payment_id' Error: 'error message'. Edit the incorrect data or contact the Support center.
You can add funds to your personal account by starting
/usr/local/ispmgr/sbin/mgrctl -m billmgr credit.setpaid elid=payment_id info="data to be saved"
Cgi program
If you need to exchange data with a payment system, you should create CGI programs. You can locate them in /usr/local/ispmgr/cgi Https address is https://your_domain/mancgi/XXX, where XXX is a file name. We do not provide CGI program examples as you can find them on the Internet.
Database structure
You may need the following tables when creating a module:
1. companycrtype - table contains information about a payment method. Its rows:
1.1 id - payment method id;
1.2 currency - currency. Link to the currency table;
1.3 minamount - minimum payment amount;
1.4 params - XML-document with parameters provided in the form;
2. credit - table contains payments. Its rows:
2.1 id - payment id;
2.2 nativeamount - currency amount;
2.3 state - current payment status;
2.4 userinfo - XML-document with data provided in the form;
2.5 info - is used to save payment information; for example data that a payment gateway sent.
The tables may have more rows, but they are not for public use and are not required for the payment gateway.
Example on Perl
The following example contains test functions that you may need when creating a payment interface. You will need XML::LibXML and Mysql modules. The file name is pmtest. This example does not implement any protocol, but shows which features can be realized if our system is used.
Brief description:
The main part is used to specify how the process was started, either as the LongTask or not. Depending on this factor the functions may start in different ways.
pmtune - defines how you can fill out the select with values.
pmvalidate - verifies that testinput has "test", or an error will return.
crtune - the same operation as pmtune.
crget - selects values from the database and puts them to the form.
Provide a script interpreter:
#!/usr/bin/perl no warnings;
enable required libraries:
use XML::LibXML; use Mysql; use Env;
open the log file to add new records:
open(DEBUG, ">>/tmp/debug.log");
Select the error check box (change into 1 if an error occurs):
$errflg = 0;
Process the command that was passed to the module:
foreach $x(@ARGV) {
if ($x eq "pmtune"){
pmtune();
}
if ($x eq "feature"){
print "pmtune pmvalidate crtune crget crset";
}
if ($x eq "pmvalidate"){
pmvalidate();
}
if ($x eq "crtune"){
crtune();
}
if ($x eq "crget"){
crget();
}
if ($x eq "crset"){
crset();
}
}
Process module results:
if ($env{"MGR_LT_PID"}) {
if ($errflg) {
system "/usr/local/ispmgr/sbin/mgrctl -m billmgr longtask.finish elid=".$env{"MGR_LT_PID"}." status=ok";
} else {
system "/usr/local/ispmgr/sbin/mgrctl -m billmgr longtask.finish elid=".$env{"MGR_LT_PID"}." status=err errmsg='Error message'";
}
}
close the log file:
close(DEBUG);
Return the XML file that was sent to STDIN:
sub GetInputXml(){
my $input;
my $buf = <STDIN>;
while($buf) {
$input = "$input$buf";
$buf = <STDIN>;
}
return $input;
}
Check parameters that were passed:
sub pmvalidate{
my $parser = XML::LibXML->new();
my $xml = $parser->parse_string(GetInputXml());
@testinput = $xml->getElementsByTagName('testinput');
print DEBUG $testinput[0]->textContent;
if($testinput[0]->textContent eq "test"){
print "pmok";
} else {
print "Error: testinput";
}
}
Get the XML of the payment method edit form from STDIN, add values and return the form XML file:
sub pmtune{
my $input = GetInputXml;
my $parser = XML::LibXML->new();
my $xml = $parser->parse_string($input);
my $root = $xml->getDocumentElement();
my $elem2 = $xml->createElement("slist");
$elem2->setAttributeNode($xml->createAttribute("name","testselect"));
my $slist1=$xml->createElement("msg");
$slist1->appendText( "select_1");
$elem2->appendChild($slist1);
my $slist2=$xml->createElement("msg");
$slist2->appendText( "select_2");
$elem2->appendChild($slist2);
my $slist3=$xml->createElement("msg");
$slist3->appendText( "select_3");
$elem2->appendChild($slist3);
$root->appendChild($elem2);
#print DEBUG $root->toString;
print $root->toString;
}
Get the XML of the payment creation form from STDIN, edit and return the form XML file:
sub crtune{
my $input = GetInputXml;
my $parser = XML::LibXML->new();
my $xml = $parser->parse_string($input);
my $root = $xml->getDocumentElement();
my $elem2 = $xml->createElement("slist");
$elem2->setAttributeNode($xml->createAttribute("name","testselect"));
my $slist1=$xml->createElement("msg");
$slist1->appendText( "select_1");
$elem2->appendChild($slist1);
my $slist2=$xml->createElement("msg");
$slist2->appendText( "select_2");
$elem2->appendChild($slist2);
my $slist3=$xml->createElement("msg");
$slist3->appendText( "select_3");
$elem2->appendChild($slist3);
$root->appendChild($elem2);
#print DEBUG $root->toString;
print $root->toString;
}
Get the XML of the payment creation form from STDIN, add the values from the database and return the form XML file:
sub crget{
my $input = GetInputXml;
my $parser = XML::LibXML->new();
my $xml = $parser->parse_string($input);
my $root = $xml->getDocumentElement();
my @xelid = $xml->getElementsByTagName('elid');
#print DEBUG $xelid[0]->textContent;
my $elid = $xelid[0]->textContent;
$user = "root";
$password = "1";
$database = "billmgr";
$host = "localhost";
my $query="select cr.nativeamount, cr.state, cu.iso, type.params from credit cr \
join companycrtype type on type.id=cr.type join currency cu on cu.id=type.currency where cr.id=$elid";
$dbh = Mysql->Connect($host,$database,$user,$password);
$sth = $dbh->Query($query);
@arr = $sth->FetchRow;
my $elem = $xml->createElement("amount");
$elem->appendText("$arr[0] $arr[2]");
$root->appendChild($elem);
if($arr[1] eq "4"){
$elem = $xml->createElement("merchant");
$elem->appendText("GoMerchant($elid, this); return false;");
$root->appendChild($elem);
} else {
#$root->removeChild($xml->findnodes("//field/merchantfield"));
}
print $root->toString;
}
Payment handler (if a module is used for handling):
sub crset(){
print DEBUG "\nin crset\n";
print DEBUG "credit id: $ltparams[2]";
return "crid $ltparams[2] Test error";
}
Example of the XML-document
<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
<metadata name="company.paymethod.edit_test" type="form">
<form>
<field name="name">
<input type="text" name="name" empty="no"/>
</field>
<field name="minamount">
<input type="text" name="minamount"/>
</field>
<field name="testselect">
<select name="testselect"/>
</field>
<field name="testinput">
<input type="text" name="testinput"/>
</field>
</form>
<jscript>
document.frm.func.value = 'company.paymethod.edit';
</jscript>
</metadata>
<metadata name="credit.pay.test" type="form">
<form>
<field name="amount">
<input type="text" name="amount" readonly="yes"/>
</field>
<field name="testselect">
<select name="testselect"/>
</field>
<field name="merchantfield">
<link name="merchant"/>
</field>
</form>
<jscript>
function GoMerchant(id, lnk) {
window.open('/mancgi/testcgi?elid='+id);
if (lnk) {
lnk.className = 'disabled';
lnk.onclick = function () { return false; }
}
}
</jscript>
</metadata>
<lang name="en">
<messages name="credit.pay.test">
<msg name="amount">Amount</msg>
<msg name="merchant">pay now</msg>
<msg name="testselect">Testselect</msg>
<msg name="title">Test pay method</msg>
<msg name="hint_default">Fill form</msg>
<msg name="hint_amount">Amount</msg>
</messages>
</lang>
</mgrdata>
