From afd80f70b85a745cfadc8957973af1911fa50970 Mon Sep 17 00:00:00 2001
From: Adhidarma Hadiwinoto <me@adhisimon.org>
Date: Tue, 21 May 2019 16:02:52 +0700
Subject: [PATCH] support irs reverse report

---
 index.js                  |  13 +++++-
 lib/irs/irs.js            | 103 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/irs/rc.js             |  65 +++++++++++++++++++++++++++++
 lib/irs/reverse-report.js |  62 ++++++++++++++++++++++++++++
 4 files changed, 242 insertions(+), 1 deletion(-)
 create mode 100644 lib/irs/irs.js
 create mode 100644 lib/irs/rc.js
 create mode 100644 lib/irs/reverse-report.js

diff --git a/index.js b/index.js
index bc14214..fefaeb7 100644
--- a/index.js
+++ b/index.js
@@ -3,11 +3,22 @@ process.chdir(__dirname);
 const fs = require('fs');
 fs.writeFileSync('pid.txt', process.pid);
 
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+
 require('komodo-sdk/api-server');
 const pullgw = require('komodo-sdk/gateway/pull');
 const partner = require('./lib/partner');
-require('./lib/reverse-report');
 const adviceServer = require('komodo-sdk/gateway/advice-push-server');
 
+if (config.partner && config.partner.reverse_report_irs) {
+    logger.info('Reverse report using IRS mode');
+    require('./lib/irs/reverse-report');
+}
+else {
+    require('./lib/reverse-report');
+}
+
+
 pullgw.setPartner(partner);
 adviceServer.setPartner(partner);
diff --git a/lib/irs/irs.js b/lib/irs/irs.js
new file mode 100644
index 0000000..7a743d0
--- /dev/null
+++ b/lib/irs/irs.js
@@ -0,0 +1,103 @@
+"use strict";
+
+const rcFromMsg = require('komodo-sdk/rc-from-msg');
+const organicRc = require('./rc');
+
+function getRcFromMessage(msg, customRc) {
+    let rc;
+    if (customRc) {
+        rc = rcFromMsg(msg, customRc);
+    }
+
+    if (!rc) {
+        rc = rcFromMsg(msg, organicRc);
+    }
+
+    return rc;
+}
+
+function getPriceFromMessage(msg, rule) {
+    if (typeof msg !== 'string') {
+        return;
+    }
+
+    if (process.env.DEBUG_IRS && !rule) {
+        console.log('** IRS.getPriceFromMessage no rule'); // eslint-disable-line no-console
+    }
+
+    if (process.env.DEBUG_IRS && rule) {
+        console.log('** IRS.getPriceFromMessage rule: ' + JSON.stringify(rule, null, 2)); // eslint-disable-line no-console
+    }
+
+    const pattern = (rule && typeof rule.pattern === 'string') ? rule.pattern : "Harga: ([\\d\\.]+?) ";
+    const match_idx = (rule && typeof rule.match_idx === 'number') ? rule.match_idx : 1;
+
+    const re = new RegExp(pattern);
+    const matches = msg.match(re);
+    if (process.env.DEBUG_IRS) {
+        console.log('** IRS.getPriceFromMessage msg: "' + msg + '" active_pattern: "' + pattern + '" active_match_idx: ' + match_idx); // eslint-disable-line no-console
+        console.log('** IRS.getPriceFromMessage matches:\n' + JSON.stringify(matches)); // eslint-disable-line no-console
+    }
+    if (matches && matches[match_idx]) {
+        const result =  Number(matches[match_idx].replace(/\./g, ''));
+        if (process.env.DEBUG_IRS) {
+            console.log('** IRS.getPriceFromMessage SUPPLIER-PRICE: ' + result); // eslint-disable-line no-console
+        }
+        return result;
+    }
+}
+
+function extractFromMessage(msg, rule) {
+    if (typeof msg !== 'string') { return; }
+
+    if (!rule) { return; }
+
+    if (typeof rule !== 'object') {
+        return;
+    }
+
+    rule.match_idx = Number(rule.match_idx);
+
+    if (!rule.match_idx) {
+        rule.match_idx = 1;
+    }
+
+    const re = new RegExp(rule.pattern);
+    const matches = msg.match(re);
+    if (matches && matches[rule.match_idx] && typeof matches[rule.match_idx] === 'string') {
+        return matches[rule.match_idx];
+    }
+}
+
+function getSnFromMessage(msg, rule) {
+    if (!rule) {
+        rule = {
+            pattern: "SN: (\\d+)",
+            match_idx: 1
+        }
+    }
+
+    let sn = extractFromMessage(msg, rule);
+    if (!sn || typeof sn !== 'string') { return; }
+
+    return sn.toUpperCase().replace(/[^a-zA-Z0-9/]/g, '-').replace(/-+/g, '-').replace(/-*\/-*/g, '/').replace(/^-+/, '').replace(/-+$/, '');
+}
+
+function getBalanceFromMessage(msg, rule) {
+    if (!rule) {
+        rule = {
+            pattern: "Sisa Saldo: .+? = ([\\d\\.]+) ",
+            match_idx: 1
+        }
+    }
+
+    let result = extractFromMessage(msg, rule);
+    if (!result || typeof result !== 'string') { return; }
+
+    return Number(result.replace(/\./g, ''));
+}
+
+exports.getRcFromMessage = getRcFromMessage;
+exports.getPriceFromMessage = getPriceFromMessage;
+exports.getSnFromMessage = getSnFromMessage;
+exports.getBalanceFromMessage = getBalanceFromMessage;
diff --git a/lib/irs/rc.js b/lib/irs/rc.js
new file mode 100644
index 0000000..a179a95
--- /dev/null
+++ b/lib/irs/rc.js
@@ -0,0 +1,65 @@
+module.exports = [
+    {
+        pattern: " BERHASIL",
+        rc: '00'
+    },
+    {
+        pattern: "SUKSES",
+        rc: '00'
+    },
+    {
+        pattern: " under process",
+        rc: '68'
+    },
+    {
+        pattern: " under proses",
+        rc: '68'
+    },
+    {
+        pattern: " sedang dalam antrian",
+        rc: '68'
+    },
+    {
+        pattern: " sdg dalam antrian",
+        rc: '68'
+    },
+    {
+        pattern: " sedang diproses",
+        rc: '68'
+    },
+    {
+        pattern: " sdg diproses",
+        rc: '68'
+    },
+    {
+        pattern: " nomor tujuan dan produk tidak sesuai",
+        rc: '14',
+        flags: 'i'
+    },
+    {
+        pattern: " tujuan salah",
+        rc: '14'
+    },
+    {
+        pattern: "Nomor tidak valid",
+        rc: '14'
+    },
+    {
+        pattern: "Maaf Produk sedang gangguan",
+        rc: '90',
+        flags: 'i'
+    },
+    {
+        pattern: "Maaf.*Sedang gangguan. Coba ulangi beberapa saat lagi",
+        rc: '90',
+        flags: 'i'
+    },
+    {
+        pattern: " RC:61 ",
+        rc: '90'
+    },
+    {
+        pattern: "GAGAL",
+        rc: '40'
+    }
+]
diff --git a/lib/irs/reverse-report.js b/lib/irs/reverse-report.js
new file mode 100644
index 0000000..638fa85
--- /dev/null
+++ b/lib/irs/reverse-report.js
@@ -0,0 +1,62 @@
+"use strict";
+
+const http = require('http');
+const url = require('url');
+
+const stringify = require("json-stringify-pretty-compact");
+
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+
+const partner = require('../partner');
+const irs = require('./irs');
+
+function processPartnerReport(qs) {
+    let rc = '68';
+    if (qs.statuscode === '1') {
+        rc = '00';
+    }
+    else if (qs.statuscode === '2') {
+        rc = '40';
+    }
+
+    if (rc === '40') {
+        rc = irs.getRcFromMessage(qs.msg) || '40';
+    }
+
+    let amount = null;
+    if (rc === '00') {
+        amount = Number(qs.hrg);
+        if (!amount) {
+            amount = irs.getPriceFromMessage(qs.msg, config.partner.price_pattern);
+        }
+    }
+
+    partner.report({
+        trx_id: qs.clientid,
+        rc: rc,
+        message: 'REVERSE-REPORT: ' + stringify(qs),
+        raw: stringify(qs),
+        sn: (qs.sn ? qs.sn : null) || irs.getSnFromMessage(qs.msg, config.partner.sn_pattern) || null,
+        amount: amount,
+        balance: (rc === '00') ? irs.getBalanceFromMessage(qs.msg, config.partner.balance_pattern) : null,
+        misc: {}
+    })
+}
+
+function create() {
+    http.createServer(function (req, res) {
+        res.writeHead(200, {'Content-Type': 'text/html'});
+        const qs = url.parse(req.url, true).query;
+        res.end('OK');
+
+        const remote_ip = req.connection ? req.connection.remoteAddress : null;
+        logger.verbose('REVERSE-REPORT: got report from partner', {url: req.url, remote_ip: remote_ip});
+
+        processPartnerReport(qs);
+    }).listen(config.reverse_report_port);
+
+    logger.info('REVERSE-REPORT: listen on port ' + config.reverse_report_port);
+}
+
+config.reverse_report_port && create();
-- 
1.9.0