From 4acfa7529325b3040e4247cdef9f01df4d3ed850 Mon Sep 17 00:00:00 2001
From: Adhidarma Hadiwinoto <gua@adhisimon.org>
Date: Tue, 25 Jul 2017 15:14:46 +0700
Subject: [PATCH] ready to test

---
 index.js         |   2 +-
 package.json     |   5 ++
 partner-bnisp.js | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test.js          |  57 +++++++++++++++
 4 files changed, 281 insertions(+), 1 deletion(-)
 create mode 100644 partner-bnisp.js
 create mode 100644 test.js

diff --git a/index.js b/index.js
index 437e940..07fabc6 100644
--- a/index.js
+++ b/index.js
@@ -4,7 +4,7 @@ var aaa = require('sate24/aaa.js');
 var expresso = require('sate24-expresso');
 var logger = require('sate24/logger.js').start();
 var HttpServer = require('sate24/httpserver.js');
-var partner = require('./partner-simplepay.js');
+var partner = require('./partner-bnisp.js');
 
 var fs = require('fs');
 var ini = require('ini');
diff --git a/package.json b/package.json
index 5ab09cd..c887b84 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,12 @@
   "author": "Adhidarma Hadiwinoto <me@adhisimon.org>",
   "license": "ISC",
   "dependencies": {
+    "request": "^2.81.0",
     "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git",
     "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git"
+  },
+  "devDependencies": {
+    "mocha": "^3.4.2",
+    "should": "^11.2.1"
   }
 }
diff --git a/partner-bnisp.js b/partner-bnisp.js
new file mode 100644
index 0000000..c8dbb9f
--- /dev/null
+++ b/partner-bnisp.js
@@ -0,0 +1,218 @@
+"use strict";
+
+const http = require('http');
+http.globalAgent.maxSockets = Infinity;
+
+const request = require('request');
+
+var config;
+var aaa;
+var logger;
+
+function start(options) {
+    if (!options) {
+        console.log('Undefined options, terminating....');
+        process.exit(1);
+    }
+
+    if (options.config) {
+        config = options.config;
+    } else {
+        console.log('Undefined options.config, terminating....')
+        process.exit(1);
+    }
+
+    if (options.aaa) {
+        aaa = options.aaa;
+    } else {
+        console.log('Undefined options.aaa, terminating....')
+        process.exit(1);
+    }
+
+    if (options && options.logger) {
+        logger = options.logger;
+    } else {
+        console.log('Undefined options.logger, terminating....')
+        process.exit(1);
+    }
+}
+
+function callbackReport(requestId, rc, message, options) {
+    aaa.callbackReportWithPushToMongoDb(requestId, rc, message);
+}
+
+function topupRequest(task) {
+    aaa.insertTaskToMongoDb(task);
+    _hitTopup(task);
+}
+
+function _hitTopup(task, isCheckStatus) {
+
+    const remoteProduct = task.remoteProduct.split('/');
+    if (remoteProduct.length < 4) {
+        callbackReport(task.requestId, '40', 'INTERNAL_MSG: Invalid remoteProduct', task)
+        return;
+    }
+
+    let pathParams = {
+        request_type: "purchase",
+        noid: config.h2h_out.noid,
+        token: config.h2h_out.token,
+        product: task.remoteProduct[0],
+        product_type: task.remoteProduct[1],
+        id_pel: task.destination,
+        nominal: task.remoteProduct[2],
+        admin: task.remoteProduct[3],
+        trace_id: task.requestId
+    }
+
+    const requestOptions = {
+        url: config.h2h_out.partner + createUrlPath(pathParams)
+    }
+
+    logger.verbose('Requeting to partner', {requestOptions: requestOptions});
+    request(requestOptions, function(error, response, body) {
+        if (error) {
+            let rc = '68';
+
+            if (!isCheckStatus && (error.syscall == 'connect')) {
+                rc = '91';
+            }
+
+            logger.warn('Error requesting to partner', {task: task, rc: rc, error: error});
+            callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error requesting to partner. ' + error, {task: task});
+            return;
+        }
+
+        if (response.statusCode != 200) {
+            let rc = '68';
+
+            logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode});
+            callbackReport(task.requestId, rc, 'INTERNAL_MSG: HTTP status code ' + response.statusCode, {task: task});
+            return;
+        }
+
+        if (!body) {
+            let rc = '68';
+
+            logger.warn('Error processing response body', {task: task, responseBody: body});
+            callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error processing response body', {task: task});
+            return;
+        }
+
+        const responseData = parseResponseBody(body);
+        const data = responseDataProcessor(responseData);
+
+        callbackReport(task.requestId, data.rc, data.combinedMessage, {task: task});
+    })
+
+}
+
+function createUrlPath(options) {
+    let urlPath = [
+        "get",
+        options.request_type || "purchase",
+        "json",
+        options.noid,
+        options.token,
+        options.product,
+        options.product_type,
+        options.id_pel,
+        options.nominal || 0,
+        options.admin || 0,
+        options.trace_id
+    ].join('/');
+
+    return '/' + urlPath;
+}
+
+function parseResponseBody(body) {
+    let data;
+
+    try {
+        data = JSON.parse(body);
+    }
+    catch(e) {
+        if (logger) {
+            logger.warn('Exception on parsing result body: ' + e);
+            return;
+        }
+    }
+
+    return data;
+}
+
+function responseDataProcessor(responseData) {
+    let retval = {
+        rc: '68',
+        sn: '',
+        responseMessage: '',
+        amount: 0,
+        balance: 0,
+        ts: '',
+        product: '',
+        productType: ''
+    }
+
+    let combinedMessage = [];
+
+    if (responseData.response_code == '0000') {
+        retval.rc = '00';
+    }
+    else if (['9990','0099','0068','0063','0005','9997','9999','9998','9990','0600','1003'].indexOf(responseData.response_code) >= 0) {
+        retval.rc = '68';
+    }
+    else {
+        retval.rc = '40';
+    }
+
+    if (responseData.response_code) {
+        combinedMessage.push(responseData.response_code);
+    }
+
+    if (responseData.product) {
+        combinedMessage.push(responseData.product)
+    }
+
+    if (responseData.produk_tipe) {
+        combinedMessage.push(responseData.produk_tipe)
+    }
+
+    if (responseData.idpel) {
+        combinedMessage.push(responseData.idpel)
+    }
+
+    retval.responseMessage = responseData.response_message || '';
+    if (retval.responseMessage) {
+        combinedMessage.push(retval.responseMessage);
+    }
+
+    if (responseData.detail) {
+        retval.sn = responseData.detail.voucherSerialNumber || '';
+    }
+
+    retval.amount = responseData.amount || 0;
+    combinedMessage.push('amount: ' + retval.amount);
+
+    retval.balance = responseData.saldo || 0;
+    combinedMessage.push('balance: ' + retval.balance);
+
+    retval.ts = responseData.waktu || '';
+    combinedMessage.push(retval.ts);
+
+    retval.loadTime = responseData.loadTime || '';
+    combinedMessage.push('load time: ' + retval.loadTime);
+
+    retval.combinedMessage = combinedMessage.join(' ');
+
+    if (retval.sn) {
+        retval.combinedMessage = 'SN=' + retval.sn + '; ' + retval.combinedMessage;
+    }
+
+    return retval;
+}
+
+exports.createUrlPath = createUrlPath;
+exports.parseResponseBody = parseResponseBody;
+exports.responseDataProcessor = responseDataProcessor;
+exports.topupRequest = topupRequest;
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..3826639
--- /dev/null
+++ b/test.js
@@ -0,0 +1,57 @@
+"use strict";
+
+const should = require("should");
+const partner = require("./partner-bnisp");
+
+describe("#partner", function() {
+    describe("#createUrlPath", function() {
+
+        it('should return correct url path based on example', function() {
+            let options = {
+                noid: 1002003,
+                token: 'CIPY6t6ruy5UuGG0PCqu',
+                product: 'PULSA',
+                product_type: 'THREE5000',
+                id_pel: '0895385381299',
+                trace_id: 16
+            }
+
+            partner.createUrlPath(options).should.equal('/get/purchase/json/1002003/CIPY6t6ruy5UuGG0PCqu/PULSA/THREE5000/0895385381299/0/0/16')
+        })
+
+    })
+
+    const responseBody = '{"trxId":"064024","response_code":"0000","response_message":"SUKSES","detail":{"jmlTagihan":"1","kodeThree":"012001","nilaiPulsa":"000000005000","noHp":"0895385381299","transactionId":"0612143023138365102 ","voucherSerialNumber":"20170612143620980249"},"reff":"20170612143620980249","loadTime":"0.0107","tipe_request":"purchase","prv":"hpay","userID":"1002003","idpel":"0895385381299","product":"PULSA","produk":"PULSA","product_detail":"THREE5000","produk_tipe":"THREE5000","traceId":16,"tagihan":5050,"total_tagihan":5050,"amount":5050,"saldo":94950,"waktu":"2017-07-17 18:43:32"}';
+    const responseData = partner.parseResponseBody(responseBody);
+
+    describe('#parseResponseBody', function() {
+
+        it('should return correct response code', function() {
+            responseData.response_code.should.equal('0000');
+        })
+
+        it('should return correct voucher serial number', function() {
+            responseData.detail.voucherSerialNumber.should.equal('20170612143620980249');
+        })
+    })
+
+    describe('#responseDataProcessor', function() {
+        const processed = partner.responseDataProcessor(responseData);
+
+        it('should return correct rc', function() {
+            processed.rc.should.equal('00');
+        })
+
+        it('should return correct sn', function() {
+            processed.sn.should.equal('20170612143620980249');
+        })
+
+        it('should return correct amount', function() {
+            processed.amount.should.equal(5050);
+        })
+
+        it('should return correct balance', function() {
+            processed.balance.should.equal(94950);
+        })
+    })
+})
-- 
1.9.0