Commit 4acfa7529325b3040e4247cdef9f01df4d3ed850
1 parent
7e92010a8b
Exists in
master
ready to test
Showing 4 changed files with 281 additions and 1 deletions Side-by-side Diff
index.js
... | ... | @@ -4,7 +4,7 @@ var aaa = require('sate24/aaa.js'); |
4 | 4 | var expresso = require('sate24-expresso'); |
5 | 5 | var logger = require('sate24/logger.js').start(); |
6 | 6 | var HttpServer = require('sate24/httpserver.js'); |
7 | -var partner = require('./partner-simplepay.js'); | |
7 | +var partner = require('./partner-bnisp.js'); | |
8 | 8 | |
9 | 9 | var fs = require('fs'); |
10 | 10 | var ini = require('ini'); |
package.json
... | ... | @@ -20,7 +20,12 @@ |
20 | 20 | "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", |
21 | 21 | "license": "ISC", |
22 | 22 | "dependencies": { |
23 | + "request": "^2.81.0", | |
23 | 24 | "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git", |
24 | 25 | "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git" |
26 | + }, | |
27 | + "devDependencies": { | |
28 | + "mocha": "^3.4.2", | |
29 | + "should": "^11.2.1" | |
25 | 30 | } |
26 | 31 | } |
partner-bnisp.js
... | ... | @@ -0,0 +1,218 @@ |
1 | +"use strict"; | |
2 | + | |
3 | +const http = require('http'); | |
4 | +http.globalAgent.maxSockets = Infinity; | |
5 | + | |
6 | +const request = require('request'); | |
7 | + | |
8 | +var config; | |
9 | +var aaa; | |
10 | +var logger; | |
11 | + | |
12 | +function start(options) { | |
13 | + if (!options) { | |
14 | + console.log('Undefined options, terminating....'); | |
15 | + process.exit(1); | |
16 | + } | |
17 | + | |
18 | + if (options.config) { | |
19 | + config = options.config; | |
20 | + } else { | |
21 | + console.log('Undefined options.config, terminating....') | |
22 | + process.exit(1); | |
23 | + } | |
24 | + | |
25 | + if (options.aaa) { | |
26 | + aaa = options.aaa; | |
27 | + } else { | |
28 | + console.log('Undefined options.aaa, terminating....') | |
29 | + process.exit(1); | |
30 | + } | |
31 | + | |
32 | + if (options && options.logger) { | |
33 | + logger = options.logger; | |
34 | + } else { | |
35 | + console.log('Undefined options.logger, terminating....') | |
36 | + process.exit(1); | |
37 | + } | |
38 | +} | |
39 | + | |
40 | +function callbackReport(requestId, rc, message, options) { | |
41 | + aaa.callbackReportWithPushToMongoDb(requestId, rc, message); | |
42 | +} | |
43 | + | |
44 | +function topupRequest(task) { | |
45 | + aaa.insertTaskToMongoDb(task); | |
46 | + _hitTopup(task); | |
47 | +} | |
48 | + | |
49 | +function _hitTopup(task, isCheckStatus) { | |
50 | + | |
51 | + const remoteProduct = task.remoteProduct.split('/'); | |
52 | + if (remoteProduct.length < 4) { | |
53 | + callbackReport(task.requestId, '40', 'INTERNAL_MSG: Invalid remoteProduct', task) | |
54 | + return; | |
55 | + } | |
56 | + | |
57 | + let pathParams = { | |
58 | + request_type: "purchase", | |
59 | + noid: config.h2h_out.noid, | |
60 | + token: config.h2h_out.token, | |
61 | + product: task.remoteProduct[0], | |
62 | + product_type: task.remoteProduct[1], | |
63 | + id_pel: task.destination, | |
64 | + nominal: task.remoteProduct[2], | |
65 | + admin: task.remoteProduct[3], | |
66 | + trace_id: task.requestId | |
67 | + } | |
68 | + | |
69 | + const requestOptions = { | |
70 | + url: config.h2h_out.partner + createUrlPath(pathParams) | |
71 | + } | |
72 | + | |
73 | + logger.verbose('Requeting to partner', {requestOptions: requestOptions}); | |
74 | + request(requestOptions, function(error, response, body) { | |
75 | + if (error) { | |
76 | + let rc = '68'; | |
77 | + | |
78 | + if (!isCheckStatus && (error.syscall == 'connect')) { | |
79 | + rc = '91'; | |
80 | + } | |
81 | + | |
82 | + logger.warn('Error requesting to partner', {task: task, rc: rc, error: error}); | |
83 | + callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error requesting to partner. ' + error, {task: task}); | |
84 | + return; | |
85 | + } | |
86 | + | |
87 | + if (response.statusCode != 200) { | |
88 | + let rc = '68'; | |
89 | + | |
90 | + logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode}); | |
91 | + callbackReport(task.requestId, rc, 'INTERNAL_MSG: HTTP status code ' + response.statusCode, {task: task}); | |
92 | + return; | |
93 | + } | |
94 | + | |
95 | + if (!body) { | |
96 | + let rc = '68'; | |
97 | + | |
98 | + logger.warn('Error processing response body', {task: task, responseBody: body}); | |
99 | + callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error processing response body', {task: task}); | |
100 | + return; | |
101 | + } | |
102 | + | |
103 | + const responseData = parseResponseBody(body); | |
104 | + const data = responseDataProcessor(responseData); | |
105 | + | |
106 | + callbackReport(task.requestId, data.rc, data.combinedMessage, {task: task}); | |
107 | + }) | |
108 | + | |
109 | +} | |
110 | + | |
111 | +function createUrlPath(options) { | |
112 | + let urlPath = [ | |
113 | + "get", | |
114 | + options.request_type || "purchase", | |
115 | + "json", | |
116 | + options.noid, | |
117 | + options.token, | |
118 | + options.product, | |
119 | + options.product_type, | |
120 | + options.id_pel, | |
121 | + options.nominal || 0, | |
122 | + options.admin || 0, | |
123 | + options.trace_id | |
124 | + ].join('/'); | |
125 | + | |
126 | + return '/' + urlPath; | |
127 | +} | |
128 | + | |
129 | +function parseResponseBody(body) { | |
130 | + let data; | |
131 | + | |
132 | + try { | |
133 | + data = JSON.parse(body); | |
134 | + } | |
135 | + catch(e) { | |
136 | + if (logger) { | |
137 | + logger.warn('Exception on parsing result body: ' + e); | |
138 | + return; | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + return data; | |
143 | +} | |
144 | + | |
145 | +function responseDataProcessor(responseData) { | |
146 | + let retval = { | |
147 | + rc: '68', | |
148 | + sn: '', | |
149 | + responseMessage: '', | |
150 | + amount: 0, | |
151 | + balance: 0, | |
152 | + ts: '', | |
153 | + product: '', | |
154 | + productType: '' | |
155 | + } | |
156 | + | |
157 | + let combinedMessage = []; | |
158 | + | |
159 | + if (responseData.response_code == '0000') { | |
160 | + retval.rc = '00'; | |
161 | + } | |
162 | + else if (['9990','0099','0068','0063','0005','9997','9999','9998','9990','0600','1003'].indexOf(responseData.response_code) >= 0) { | |
163 | + retval.rc = '68'; | |
164 | + } | |
165 | + else { | |
166 | + retval.rc = '40'; | |
167 | + } | |
168 | + | |
169 | + if (responseData.response_code) { | |
170 | + combinedMessage.push(responseData.response_code); | |
171 | + } | |
172 | + | |
173 | + if (responseData.product) { | |
174 | + combinedMessage.push(responseData.product) | |
175 | + } | |
176 | + | |
177 | + if (responseData.produk_tipe) { | |
178 | + combinedMessage.push(responseData.produk_tipe) | |
179 | + } | |
180 | + | |
181 | + if (responseData.idpel) { | |
182 | + combinedMessage.push(responseData.idpel) | |
183 | + } | |
184 | + | |
185 | + retval.responseMessage = responseData.response_message || ''; | |
186 | + if (retval.responseMessage) { | |
187 | + combinedMessage.push(retval.responseMessage); | |
188 | + } | |
189 | + | |
190 | + if (responseData.detail) { | |
191 | + retval.sn = responseData.detail.voucherSerialNumber || ''; | |
192 | + } | |
193 | + | |
194 | + retval.amount = responseData.amount || 0; | |
195 | + combinedMessage.push('amount: ' + retval.amount); | |
196 | + | |
197 | + retval.balance = responseData.saldo || 0; | |
198 | + combinedMessage.push('balance: ' + retval.balance); | |
199 | + | |
200 | + retval.ts = responseData.waktu || ''; | |
201 | + combinedMessage.push(retval.ts); | |
202 | + | |
203 | + retval.loadTime = responseData.loadTime || ''; | |
204 | + combinedMessage.push('load time: ' + retval.loadTime); | |
205 | + | |
206 | + retval.combinedMessage = combinedMessage.join(' '); | |
207 | + | |
208 | + if (retval.sn) { | |
209 | + retval.combinedMessage = 'SN=' + retval.sn + '; ' + retval.combinedMessage; | |
210 | + } | |
211 | + | |
212 | + return retval; | |
213 | +} | |
214 | + | |
215 | +exports.createUrlPath = createUrlPath; | |
216 | +exports.parseResponseBody = parseResponseBody; | |
217 | +exports.responseDataProcessor = responseDataProcessor; | |
218 | +exports.topupRequest = topupRequest; |
test.js
... | ... | @@ -0,0 +1,57 @@ |
1 | +"use strict"; | |
2 | + | |
3 | +const should = require("should"); | |
4 | +const partner = require("./partner-bnisp"); | |
5 | + | |
6 | +describe("#partner", function() { | |
7 | + describe("#createUrlPath", function() { | |
8 | + | |
9 | + it('should return correct url path based on example', function() { | |
10 | + let options = { | |
11 | + noid: 1002003, | |
12 | + token: 'CIPY6t6ruy5UuGG0PCqu', | |
13 | + product: 'PULSA', | |
14 | + product_type: 'THREE5000', | |
15 | + id_pel: '0895385381299', | |
16 | + trace_id: 16 | |
17 | + } | |
18 | + | |
19 | + partner.createUrlPath(options).should.equal('/get/purchase/json/1002003/CIPY6t6ruy5UuGG0PCqu/PULSA/THREE5000/0895385381299/0/0/16') | |
20 | + }) | |
21 | + | |
22 | + }) | |
23 | + | |
24 | + 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"}'; | |
25 | + const responseData = partner.parseResponseBody(responseBody); | |
26 | + | |
27 | + describe('#parseResponseBody', function() { | |
28 | + | |
29 | + it('should return correct response code', function() { | |
30 | + responseData.response_code.should.equal('0000'); | |
31 | + }) | |
32 | + | |
33 | + it('should return correct voucher serial number', function() { | |
34 | + responseData.detail.voucherSerialNumber.should.equal('20170612143620980249'); | |
35 | + }) | |
36 | + }) | |
37 | + | |
38 | + describe('#responseDataProcessor', function() { | |
39 | + const processed = partner.responseDataProcessor(responseData); | |
40 | + | |
41 | + it('should return correct rc', function() { | |
42 | + processed.rc.should.equal('00'); | |
43 | + }) | |
44 | + | |
45 | + it('should return correct sn', function() { | |
46 | + processed.sn.should.equal('20170612143620980249'); | |
47 | + }) | |
48 | + | |
49 | + it('should return correct amount', function() { | |
50 | + processed.amount.should.equal(5050); | |
51 | + }) | |
52 | + | |
53 | + it('should return correct balance', function() { | |
54 | + processed.balance.should.equal(94950); | |
55 | + }) | |
56 | + }) | |
57 | +}) |