1. Home
  2. Libraries for webmasters
  3. How to hook plate payments?

How to hook plate payments?

Five prices are defined in plate payments. There is a button in a different color provided for each price. After click on the button, the buyer is asked about the acceptance of prices in the browser and then in the application. After accepting a series of payments is started and the buyer can execute payments within this series just by clicking buttons without accepting payments in the dialog boxes on the page and in the application. The plate payments are designed for use as payments of small amounts for the articles published on the website. The plate payments work exclusively with app Billon for Android system.

Server-side plate payment processing

To begin support plate payments, install the framework Sails.js (guide), create a Sails.js application and install the Node.js module ‘billon’:

sudo npm install billon --save

After installing the module that supports payments a file (service) named eg. ‘plates.js’ must be created in file structure generated by ‘Sails.js’ in catalog ‘/api/services/’:

var billon = require("billon");
var myShop = new billon.Shop();
var vat = 0.23; // VAT
var vat_percent = vat * 100;
var alpha = 0.01; // a price of the cheapest article
var alpha_net = alpha / 1.23;
var alpha_vat = alpha - alpha_net;
var beta = 0.1; // a price of the second article
var beta_net = beta / 1.23;
var beta_vat = beta - beta_net;
var gamma = 0.2; // a price of the third article
var gamma_net = gamma / 1.23;
var gamma_vat = gamma - gamma_net;
var delta = 0.5; // a price of the fourth article
var delta_net = delta / 1.23;
var delta_vat = delta - delta_net;
var epsilon = 1; // a price of the most expensive article
var epsilon_net = epsilon / 1.23;
var epsilon_vat = epsilon - epsilon_net;
myShop.user(function (requestData, cb)
{
   cb(requestData.user);
}).products(function (requestData, cb)
{
   cb(requestData.itemsId);
}).product(function (requestData, itemId, cb)
{
   switch (itemId)
   { // a list of articles - products, article setting according to the type of the plate is not recommended in case of tariffs consisting of a smaller number of plates
      case 1:
          cb({
             "item_id": itemId,
             "item_name": "Article 1", // not required
             "quantity": 1, // not required if configuration method 'productBillon' is being called
             "unit_type": "pcs", // not required
             "unit_price_net": alpha_net,
             "amount_net": alpha_net,
             "amount_discount_net": 0,
             "vat": {
                "percent": 20,
                "amount": alpha_vat
             },
             "amount_gross": alpha
          });
       break;
       case 2:
          cb({
             "item_id": itemId,
             "item_name": "Article 2",
             "quantity": 1,
             "unit_type": "pcs",
             "unit_price_net": beta_net,
             "amount_net": beta_net,
             "amount_discount_net": 0,
             "vat": {
                "percent": 20,
                "amount": beta_vat
             },
             "amount_gross": beta
          });
       break;
       case 3:
          cb({
             "item_id": itemId,
             "item_name": "Article 3",
             "quantity": 1,
             "unit_type": "pcs",
             "unit_price_net": gamma_net,
             "amount_net": gamma_net,
             "amount_discount_net": 0,
             "vat": {
                "percent": 20,
                "amount": gamma_vat
             },
             "amount_gross": gamma
          });
       break;
       case 4:
          cb({
             "item_id": itemId,
             "item_name": "Article 4",
             "quantity": 1,
             "unit_type": "pcs",
             "unit_price_net": delta_net,
             "amount_net": delta_net,
             "amount_discount_net": 0,
             "vat": {
                "percent": 20,
                "amount": delta_vat
             },
             "amount_gross": delta
          });
       break;
       case 5:
          cb({
             "item_id": itemId,
             "item_name": "Article 5",
             "quantity": 1,
             "unit_type": "pcs",
             "unit_price_net": epsilon_net,
             "amount_net": epsilon_net,
             "amount_discount_net": 0,
             "vat": {
                "percent": 20,
                "amount": epsilon_vat
             },
             "amount_gross": epsilon
          });
       break;
   }
}).productBillon(function (requestData, item, cb) 
{ // call of the method not required if parameter 'quantity' is defined for all products
   cb(item);
}).paymentTitle(function (requestData, items, delivery, cb) 
{
   return cb("Payment title");
}).plates(function(requestData, cb)
{ // price setting, the lack of an argument or number 0 removes a plate from the tariff
   cb(alpha * 1000, beta * 1000, gamma * 1000, delta * 1000, epsilon * 1000); // multiplying to number of thousandths of a basic monetary unit
}).app24(function (requestData, param1, param2, cb)
{
    cb("eyJhkGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c3VyIjp7ImlkIjoyNSwic2FsdCI6IjEyZWVkMzQwLTM2NGUtMThNjgyN1hNDM5zA1MiOjEh0OTCJpYXQiDk0NjF9Q1M.zeWXG7Nyr3PFVhb4HRgLi5rh8fLZx41VHySHWUStIzc"); // API key użytkownika serwisu "billon.me"
    /*cb({
       Name: "billonpayments4", // 24/7 app username
       Address: "http://213.189.38.34:20891" // address and port of 24/7 app
    });*/ // direct communication with 24/7 app
}).currency(function(requestData, cb)
{ // ISO 4217 currency code, not required method, 'PLN' by default
   cb('GBP');
}).maxTotalAmount(function(requestData, cb)
{ // the maximum sum payment in the series expressed in thousandths of a basic monetary unit, not required method
   cb(10000);
}).duration(function(requestData, cb)
{ // the duration of a series of payments in seconds, not required method
   cb(3600);
}).maxPaymentsInSeries(function(requestData, cb)
{ // the maximum number of payments in the series, not required method
   cb(10);
}).platePayment(function(requestData, cb)
{ // setting of series identifier and kind of plate 
   cb(requestData.seriesId, requestData.type);
}).merchantBrandName(function(requestData, cb)
{ // setting of brand, not required method, domain of the page on which payment is executed by default
   cb('Nazwa brandu');
}).onReceivedPlatePaymentSeriesStatus(function (response)
{ // event of 24/7 app response during the proces of the acceptance of the series, not reqiured method
   console.log(response);
   if (response.status == 'SERIES_ACCEPTED' || response.status == 'TRANSFERRING' || response.status == 'TRANSFERING')
   {
      console.log('The series of payment accepted');
   }
}).onAcceptedPlatePaymentSeries(function (paymentData)
{ // event of acceptance of the series, not required method
   console.log(paymentData);
}).onFinishedPayment(function (items, delivery_option, document, requestData)
{ // event of finished payment, not required method
   console.log(document);
   console.log(requestData);
   if (requestData.itemsId.constructor === Array)
   {
      for (var i = 0; i < requestData.itemsId; ++i)
      { // a operation can be performed here after successfully finished purchase of article - product
         console.log(requestData.itemsId[i]);
      }
   }
}).onRequestSend(function (requestName, parameters, requestResponse, error)
{ // the event of sending SOAP request, not required method
   console.log('SOAP request: ', requestName);
   console.log('Parameters of request: ', parameters);
   console.log('Response of the app: ', requestResponse);
   console.log('Error while sending: ', error);
});
module.exports = myShop;

Once you have configured the server and Sails.js service, you need to create a controller to be able to communicate with the user on a webpage

sails generate controller Plates

A file ‘PlatesController.js’, in which the communication to given address must be handled and associated with previously created service ‘plates.js’, will be created in catalog ‘api/controllers’.

Example of file ‘PlatesController.js’:

module.exports = {
  list: function(req, res)
  { // method that outputs the list of prices, the currency, the limit of the duration of the series,
    // the maximum amount of the payments in the series and merchant brand name
    plates.tariff(res);
  },
  initiate: function(req, res)
  { // method that initiate start of series of payment
    plates.platePaymentSeriesStart(req, res);
  },
  pay: function(req, res)
  { // method that initiates payment
    plates.paymentInitiation(req, res);
  },
  status: function(req, res)
  { // listening method
    plates.paymentStatus(req.body.taskId || req.query.taskId, function(response)
    {
      res.json(response);
    });
  }
};

Taking plate payments on webpages

Use JavaScript Billon scripts for taking the plate payments on a webpage:

<div id="button-container-1"></div>
<script src="//billon.info/lib/js/billon.js"></script>
<script src="//billon.info/lib/js/billon-agent.js"></script>
<script src="//billon.info/lib/js/billon-object.js"></script>
<script src="//billon.info/lib/js/billon-user.js"></script>
<script src="//billon.info/lib/js/billon-plates.js"></script>
<script>
   billon.plates({
      connection: new billon.agent("http://billon.info:1401/plates"), // address pointing to Sails.js controller that supports payment (in this case PlatesController)
      lang: 'en', // language 'en' or 'pl', 'en' by default
      plateButtonAddress: "https://billon.info/lib/screen/plate-button/index.html", // in the case of not showing buttons, skip in the case of the lack of problems
      plateDialogAddress: "https://billon.info/lib/screen/plate-dialog/index.html", // in the case of not showing dialog, skip in the case of the lack of problems
      SkipAnotherUser: false, // optional - omission of the step of of choosing another user than detected, the step is not skipped by default
      DisableButtonsTitle: false, // optional - default not adding title (tooltip) with the price to the buttons, the titles are being set by default
      tariff: {
         Address: 'list', // name of controller parameter where method 'tariff' is being called
         DisplayedCurrency: ' £', // displayed currency, ISO 4217 currency code set in module 'billon' by default
         CentSign: 'p' // sign of currency for the hundredth part of the basic monetary unit displayed for the price lower than this unit, 
                       // sign set in parameter 'DisplayedCurrency'
                       // or ISO 4217 currency code set in module 'billon'
                       // in case of lack of this parameter is used by default
      },
      series: {
         request: {
            Address: 'initiate', // name of controller parameter where method 'platePaymentSeriesStart' is being called
            Data: function (user) 
            {
              return {
                user: user
              };
            }
         },
         ListenResponse: function (response, user)
         {
            if (response.status == "SERIES_ACCEPTED" || response.status == "TRANSFERRING" || response.status == "TRANSFERING")
            { // save of identifier of series and Billon username, in this case in Local Storage
               localStorage.setItem("seriesId", response.taskId);
	       localStorage.setItem("user", JSON.stringify(user));
            }
         }
      },
      paymentRequest: {
         Address: 'pay', // name of controller parameter where method 'paymentInitiation' is being called
         Data: function()
         { // reading previously saved identifier of series and Billon username, in this case from Local Storage
            try
            {
               return {
                  seriesId: localStorage.getItem("seriesId"),
                  user: JSON.parse(localStorage.getItem("user"))
               };
            }
            catch (e)
            {
               return {};
            }
         }
      },
      listen: {
         Address: "status", // name of controller parameter where method 'paymentStatus' is being called
         Data: function (requestResponse) 
         {
           return {
             taskId: requestResponse.taskId
           };
         }
      },
      buttons: [ // array of buttons
      {
         place: document.getElementById('button-container-1'), // HTML element in which the button is to be placed
         type: 'alpha', // type of the button
         DisableTitle: false, // optional - not setting the title of the button with the price,
                              // the global option 'DisableButtonsTitle' is acted on by default
         RequestData: function(type)
         {
            return {
               type: type,
               itemsId: [1] // array of identifiers of products
            }
         },
         ListenResponse: function(response)
         { // optional method
            switch (response.status)
            {
               case "FINISHED_OK":
                  // event of successfully purchase with the button
                  break;
               case "FINISHED_ERR_USER_REJECTED": // a lack of possibility to pay within the stored series
                  localStorage.setItem("seriesId", null);
		  localStorage.setItem("user", JSON.stringify(null));
            }
         }
      },
      {
         place: document.getElementById('button-container-2'),
         type: 'beta',
         RequestData: function(type)
         {
            return {
               type: type,
               itemsId: [2]
            }
         },
         ListenResponse: function(response)
         {
            switch (response.status)
            {
               case "FINISHED_OK":
                  // event of successfully purchase with the button
                  break;
               case "FINISHED_ERR_USER_REJECTED": // a lack of possibility to pay within the stored series
                  localStorage.setItem("seriesId", null);
		  localStorage.setItem("user", JSON.stringify(null));
            }
         }
      },
      {
         place: document.getElementById('button-container-3'),
         type: 'gamma',
         RequestData: function(type)
         {
            return {
               type: type,
               itemsId: [3]
            }
         },
         ListenResponse: function(response)
         {
            switch (response.status)
            {
               case "FINISHED_OK":
                  // event of successfully purchase with the button
                  break;
               case "FINISHED_ERR_USER_REJECTED": // a lack of possibility to pay within the stored series
                  localStorage.setItem("seriesId", null);
		  localStorage.setItem("user", JSON.stringify(null));
            }
         }
      },
      {
         place: document.getElementById('button-container-4'),
         type: 'delta',
         RequestData: function(type)
         {
            return {
               type: type,
               itemsId: [4]
            }
         },
         ListenResponse: function(response)
         {
            switch (response.status)
            {
               case "FINISHED_OK":
                  // event of successfully purchase with the button
                  break;
               case "FINISHED_ERR_USER_REJECTED": // a lack of possibility to pay within the stored series
                  localStorage.setItem("seriesId", null);
		  localStorage.setItem("user", JSON.stringify(null));
            }
         }
      },
      {
         place: document.getElementById('button-container-5'),
         type: 'epsilon',
         RequestData: function(type)
         {
            return {
               type: type,
               itemsId: [5]
            }
         },
         ListenResponse: function(response)
         {
            switch (response.status)
            {
               case "FINISHED_OK":
                  // event of successfully purchase with the button
                  break;
               case "FINISHED_ERR_USER_REJECTED": // a lack of possibility to pay within the stored series
                  localStorage.setItem("seriesId", null);
		  localStorage.setItem("user", JSON.stringify(null));
            }
         }
      }]
   });
</script>
Was this article helpful to you? Yes No

How can we help?