Commit d11a8cb48ba454a2f9a4995cbaae7aa54830f85b

Authored by Adhidarma Hadiwinoto
0 parents
Exists in master

salin dari datacell

Showing 6 changed files with 421 additions and 0 deletions Side-by-side Diff

... ... @@ -0,0 +1 @@
  1 +node_modules/
... ... @@ -0,0 +1,13 @@
  1 +var iniparser = require('iniparser');
  2 +var config = iniparser.parseSync('./config.ini');
  3 +
  4 +var aaaHost = config.globals.aaa_host;
  5 +
  6 +HttpServer = require('sate24/httpserver.js');
  7 +var httpServer = HttpServer.start(config);
  8 +
  9 +var aaa = require('sate24/aaa.js');
  10 +var partner = require('./partner-datacell.js');
  11 +
  12 +partner.start(config, aaa.callbackReport);
  13 +aaa.start(config, partner);
... ... @@ -0,0 +1,30 @@
  1 +{
  2 + "name": "sate24-to-datacell",
  3 + "version": "0.0.1",
  4 + "description": "ST24 to Datacell",
  5 + "main": "index.js",
  6 + "scripts": {
  7 + "test": "mocha"
  8 + },
  9 + "repository": {
  10 + "type": "git",
  11 + "url": "git@gitlab.kodesumber.com:reload97/sate24-to-datacell.git"
  12 + },
  13 + "keywords": [
  14 + "datacell",
  15 + "ppob",
  16 + "st24"
  17 + ],
  18 + "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>",
  19 + "license": "BSD",
  20 + "dependencies": {
  21 + "sate24": "git+http://git@gitlab.kodesumber.com/reload97/node-sate24.git",
  22 + "iniparser": "~1.0.5",
  23 + "base64-xor": "~0.10.0",
  24 + "request": "~2.60.0",
  25 + "mathjs": "~1.7.1",
  26 + "xml": "~1.0.0",
  27 + "xml2js": "~0.4.9",
  28 + "strftime": "~0.9.2"
  29 + }
  30 +}
... ... @@ -0,0 +1,328 @@
  1 +var http = require('http');
  2 +var url = require('url');
  3 +var math = require('mathjs');
  4 +var xml = require('xml');
  5 +var xml2js = require('xml2js').parseString;
  6 +var strftime = require('strftime');
  7 +var xor = require('base64-xor');
  8 +var request = require('request');
  9 +
  10 +var config;
  11 +var callbackReport;
  12 +
  13 +var max_retry = 2;
  14 +var sleep_before_retry = 2000;
  15 +
  16 +var trx_balances = {};
  17 +var trx_prices = {};
  18 +
  19 +function calculateSignature(userid, password, msisdn, timestamp) {
  20 + var a = msisdn.substr(msisdn.length - 4) + timestamp;
  21 + var b = userid.substr(0, 4) + password;
  22 +
  23 + return xor.encode(a,b);
  24 +}
  25 +
  26 +function calculateBalanceSignature(userid, password, timestamp) {
  27 + var a = '0000' + timestamp;
  28 + var b = userid.substr(0, 4) + password;
  29 +
  30 + return xor.encode(a,b);
  31 +}
  32 +
  33 +
  34 +function createPayload(task) {
  35 + var timestamp = strftime('%H%M%S');
  36 +
  37 + var payload = {
  38 + datacell: [
  39 + { perintah: 'charge'},
  40 + {oprcode: task['remoteProduct']},
  41 + {userid: config.h2h_out.userid},
  42 + {time: timestamp},
  43 + {msisdn: task['destination']},
  44 + {ref_trxid: task['requestId']},
  45 + {sgn: calculateSignature(config.h2h_out.userid, config.h2h_out.password, task['destination'], timestamp)}
  46 + ]
  47 + };
  48 +
  49 + console.log(payload);
  50 + return "<?xml version=\"1.0\" ?>\n" + xml(payload);
  51 +}
  52 +
  53 +function topupRequest(task, retry) {
  54 + //balanceCheck();
  55 +
  56 + var payload_xml = createPayload(task);
  57 + //console.log(payload_xml);
  58 +
  59 + var postRequest = {
  60 + host: "202.152.62.2",
  61 + path: "/RELOAD97.php",
  62 + port: 7713,
  63 + method: "POST",
  64 + headers: {
  65 + 'Content-Type': 'text/xml',
  66 + 'Content-Length': Buffer.byteLength(payload_xml)
  67 + }
  68 + };
  69 +
  70 + var buffer = "";
  71 + var req = http.request( postRequest, function( res ) {
  72 +
  73 + console.log('Status code: ' + res.statusCode );
  74 + var buffer = "";
  75 + res.on( "data", function( data ) { buffer = buffer + data; } );
  76 + res.on( "end", function( data ) {
  77 + topupResponseHandler(buffer);
  78 + });
  79 +
  80 + });
  81 +
  82 + req.on('error', function(e) {
  83 + console.log('problem with request: ' + e.message);
  84 + callbackReport(task['requestId'], '40', e.message);
  85 + });
  86 +
  87 + req.write( payload_xml );
  88 + req.end();
  89 +}
  90 +
  91 +function topupResponseHandler(body, request_id) {
  92 + xml2js(body, function (err, result) {
  93 + if (err) {
  94 + console.log(body);
  95 + callbackReport(request_id, '40', buffer);
  96 + return;
  97 + }
  98 +
  99 + console.log(result);
  100 +
  101 + request_id = result.datacell.ref_trxid[0].trim();
  102 +
  103 + var response_code = '68';
  104 +
  105 + var message = '';
  106 + try {
  107 + if (result.datacell.message && result.datacell.message.length > 0) {
  108 + message = result.datacell.message[0].trim();
  109 + } else if (result.datacell.msg && result.datacell.msg.length > 0) {
  110 + message = result.datacell.msg[0].trim();
  111 + }
  112 + }
  113 + catch(err) {
  114 + message = 'exception saat parsing message';
  115 + }
  116 +
  117 + if (result.datacell.resultcode && result.datacell.resultcode[0] == '999') {
  118 + response_code = '40';
  119 + }
  120 +
  121 + if (message.indexOf('Nomor tujuan salah') >= 0) {
  122 + response_code = '14';
  123 + } else if (message.indexOf('*GAGAL, transaksi yang sama sudah ada dalam 10 menit') >= 0) {
  124 + response_code = '55';
  125 + } else if (message.indexOf('saldo sdh dikembalikan') >= 0) {
  126 + response_code = '40'
  127 + } else if (message.indexOf('Trx dpt diulang') >= 0) {
  128 + response_code = '40'
  129 + } else if (message.indexOf('SUKSES SN Operator:') >= 0) {
  130 + response_code = '00';
  131 +
  132 + var sn = parseSN(message);
  133 + console.log ('SN Operator: ' + sn);
  134 +
  135 + /*
  136 + if (!sn) {
  137 +
  138 + console.log('Missing real operator SN, using SN from suplier');
  139 + try {
  140 + sn = result.datacell.trxid[0].trim();
  141 + }
  142 + catch(err) {
  143 + sn = '';
  144 + }
  145 + }
  146 + */
  147 +
  148 + if (sn) {
  149 + message = 'SN=' + sn + '; ' + message;
  150 + } else {
  151 + message = 'SN belum didapat. ' + message;
  152 + response_code = '68';
  153 + }
  154 + }
  155 +
  156 +
  157 + var price = priceFromMessage(message);
  158 + if (price != null) {
  159 + console.log('Harga: ' + price);
  160 + trx_prices[request_id] = price;
  161 + setTimeout(deleteTrxPrice, 3 * 24 * 3600 * 1000, request_id);
  162 + } else if (response_code == '00' && trx_prices[request_id] !== undefined) {
  163 + price = trx_prices[request_id];
  164 + console.log('Harga: ' + price);
  165 + message = message + ' -- Harga: ' + price;
  166 + }
  167 +
  168 + var balance = balanceFromMessage(message);
  169 + if (balance != null) {
  170 + console.log('Saldo: ' + balance);
  171 + trx_balances[request_id] = balance;
  172 + setTimeout(deleteTrxBalance, 3 * 24 * 3600 * 1000, request_id);
  173 + } else if (response_code == '00' && trx_balances[request_id] !== undefined) {
  174 + balance = trx_balances[request_id];
  175 + console.log('Saldo: ' + balance);
  176 + message = message + ' -- Saldo: ' + balance;
  177 + }
  178 +
  179 + callbackReport(request_id, response_code, message);
  180 + });
  181 +}
  182 +
  183 +function deleteTrxPrice(request_id) {
  184 + delete trx_prices[request_id];
  185 +}
  186 +
  187 +function deleteTrxBalance(request_id) {
  188 + delete trx_balances[request_id];
  189 +}
  190 +
  191 +function parseSN(message) {
  192 + var results = message.match(/SN Operator: .+ SN Kami/);
  193 + if (!results || results.length <= 0) {
  194 + return '';
  195 + }
  196 +
  197 + var result = results[0];
  198 + result = result.replace('SN Operator:', '');
  199 + result = result.replace('SN Kami', '');
  200 + result = result.trim();
  201 +
  202 + if (result == '00') {
  203 + result = '';
  204 + }
  205 +
  206 + return result;
  207 +}
  208 +
  209 +function createServer() {
  210 +
  211 + var httpServer = http.createServer(function(req, res) {
  212 + var parsed_url = url.parse(req.url, true, true);
  213 +
  214 + console.log('Got request from partner ("' + req.url + '")');
  215 +
  216 + var body = "";
  217 + req.on('data', function (chunk) {
  218 + body += chunk;
  219 + });
  220 +
  221 + req.on('end', function () {
  222 + res.writeHead(200);
  223 + res.end('OK');
  224 +
  225 + //console.log(body);
  226 +
  227 + if (parsed_url.pathname == '/sn') {
  228 + console.log('Reverse report -- SN');
  229 + topupResponseHandler(body);
  230 +
  231 + } else if (parsed_url.pathname = '/refund') {
  232 + console.log('Reverse report -- REFUND');
  233 + callbackReport(parsed_url.query.ref_trxid, '40', parsed_url.query.message);
  234 +
  235 + } else {
  236 + console.log('Reverse report -- UNKNOWN');
  237 + console.log('Ignore unknown request on reverse url');
  238 + }
  239 + });
  240 + });
  241 +
  242 + httpServer.listen(config.h2h_out.listen_port, function() {
  243 + console.log('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
  244 + });
  245 +}
  246 +
  247 +function balanceCheck() {
  248 + var timestamp = strftime('%H%M%S');
  249 +
  250 + var payload = {
  251 + datacell: [
  252 + {perintah: 'saldo'},
  253 + {userid: config.h2h_out.userid},
  254 + {time: timestamp},
  255 + {sgn: calculateBalanceSignature(config.h2h_out.userid, config.h2h_out.password, timestamp)}
  256 + ]
  257 + };
  258 +
  259 + var postRequest = {
  260 + host: "202.152.62.2",
  261 + path: "/RELOAD97.php",
  262 + port: 7713,
  263 + method: "POST",
  264 + headers: {
  265 + 'Content-Type': 'text/xml',
  266 + 'Content-Length': Buffer.byteLength(payload_xml)
  267 + }
  268 + };
  269 +
  270 + var buffer = "";
  271 + var req = http.request( postRequest, function( res ) {
  272 +
  273 + console.log('Status code: ' + res.statusCode );
  274 + var buffer = "";
  275 + res.on( "data", function( data ) { buffer = buffer + data; } );
  276 + res.on( "end", function( data ) {
  277 + console.log('CHECK BALANCE RESULT:');
  278 + console.log(buffer);
  279 + });
  280 +
  281 + });
  282 +
  283 + req.on('error', function(e) {
  284 + console.log('problem with request: ' + e.message);
  285 + });
  286 +
  287 + req.write( payload_xml );
  288 + req.end();
  289 +
  290 +}
  291 +
  292 +function balanceFromMessage(message) {
  293 + var matches = message.match(/Saldo: Rp (\d+)/);
  294 +
  295 + if (!matches) {
  296 + return null;
  297 + }
  298 + if (matches.length < 2) {
  299 + return null;
  300 + }
  301 +
  302 + return matches[1];
  303 +}
  304 +
  305 +function priceFromMessage(message) {
  306 + var matches = message.match(/Harga: (\d+)/);
  307 +
  308 + if (!matches) {
  309 + return null;
  310 + }
  311 + if (matches.length < 2) {
  312 + return null;
  313 + }
  314 +
  315 + return matches[1];
  316 +}
  317 +
  318 +function start(_config, _callbackReport) {
  319 + config = _config;
  320 + callbackReport = _callbackReport
  321 +
  322 + createServer();
  323 +}
  324 +
  325 +exports.start = start;
  326 +exports.topupRequest = topupRequest;
  327 +exports.balanceFromMessage = balanceFromMessage;
  328 +exports.priceFromMessage = priceFromMessage;
... ... @@ -0,0 +1,49 @@
  1 +var assert = require("assert");
  2 +
  3 +describe('partner-datacell', function() {
  4 + var partner = require('./partner-datacell');
  5 +
  6 + describe('#balanceFromMessage', function() {
  7 + var message;
  8 +
  9 + it('should return 8306874', function() {
  10 + assert.equal(8306874, partner.balanceFromMessage('IR25 No: 085697273881 sudah diterima dan sdg diproses. SN Kami :243588112. Harga: 24750. Saldo: Rp 8306874.'));
  11 + });
  12 +
  13 + it('should return 8351574', function() {
  14 + assert.equal(8351574, partner.balanceFromMessage('TEL20 No: 085372113774 sudah diterima dan sdg diproses. SN Kami :243586975. Harga: 19950. Saldo: Rp 8351574.'));
  15 + });
  16 +
  17 + it('should return 0', function() {
  18 + assert.equal(0, partner.balanceFromMessage('TEL20 No: 085372113774 sudah diterima dan sdg diproses. SN Kami :243586975. Harga: 19950. Saldo: Rp 0.'));
  19 + });
  20 +
  21 + it('should return null', function() {
  22 + assert.equal(null, partner.balanceFromMessage('XL25 No: 08174945541 SUKSES SN Operator: 970729963933 SN Kami: 243591297.'));
  23 + });
  24 + });
  25 +
  26 + describe('#priceFromMessage', function() {
  27 + var message;
  28 +
  29 + it('should return 24750', function() {
  30 + assert.equal(24750, partner.priceFromMessage('IR25 No: 085697273881 sudah diterima dan sdg diproses. SN Kami :243588112. Harga: 24750. Saldo: Rp 8306874.'));
  31 + });
  32 +
  33 + it('should return 19950', function() {
  34 + assert.equal(19950, partner.priceFromMessage('TEL20 No: 085372113774 sudah diterima dan sdg diproses. SN Kami :243586975. Harga: 19950. Saldo: Rp 8351574.'));
  35 + });
  36 +
  37 + it('should return 0', function() {
  38 + assert.equal(0, partner.priceFromMessage('TEL20 No: 085372113774 sudah diterima dan sdg diproses. SN Kami :243586975. Harga: 0. Saldo: Rp 8351574.'));
  39 + });
  40 +
  41 + it('should return null', function() {
  42 + assert.equal(null, partner.priceFromMessage('XL25 No: 08174945541 SUKSES SN Operator: 970729963933 SN Kami: 243591297.'));
  43 + });
  44 + });
  45 +
  46 +
  47 +
  48 +
  49 +});