Commit 998960429203fdd1732c322f6057d77773cfeffb

Authored by Adhidarma Hadiwinoto
1 parent efdf72c3e9
Exists in master

info harga supplier

Showing 1 changed file with 5 additions and 0 deletions Inline Diff

partner-simplepay.js
1 "use strict"; 1 "use strict";
2 2
3 process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; 3 process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
4 4
5 const request = require('request'); 5 const request = require('request');
6 const crypto = require('crypto'); 6 const crypto = require('crypto');
7 const moment = require('moment'); 7 const moment = require('moment');
8 8
9 const http = require('http'); 9 const http = require('http');
10 http.globalAgent.maxSockets = Infinity; 10 http.globalAgent.maxSockets = Infinity;
11 11
12 const seconds_to_wait_before_resend_on_pending = 30; 12 const seconds_to_wait_before_resend_on_pending = 30;
13 13
14 var config; 14 var config;
15 var aaa; 15 var aaa;
16 var logger; 16 var logger;
17 17
18 function start(options) { 18 function start(options) {
19 if (!options) { 19 if (!options) {
20 console.log('Undefined options, terminating....'); 20 console.log('Undefined options, terminating....');
21 process.exit(1); 21 process.exit(1);
22 } 22 }
23 23
24 if (options.config) { 24 if (options.config) {
25 config = options.config; 25 config = options.config;
26 } else { 26 } else {
27 console.log('Undefined options.config, terminating....') 27 console.log('Undefined options.config, terminating....')
28 process.exit(1); 28 process.exit(1);
29 } 29 }
30 30
31 if (options.aaa) { 31 if (options.aaa) {
32 aaa = options.aaa; 32 aaa = options.aaa;
33 } else { 33 } else {
34 console.log('Undefined options.aaa, terminating....') 34 console.log('Undefined options.aaa, terminating....')
35 process.exit(1); 35 process.exit(1);
36 } 36 }
37 37
38 if (options && options.logger) { 38 if (options && options.logger) {
39 logger = options.logger; 39 logger = options.logger;
40 } else { 40 } else {
41 console.log('Undefined options.logger, terminating....') 41 console.log('Undefined options.logger, terminating....')
42 process.exit(1); 42 process.exit(1);
43 } 43 }
44 44
45 createReverseHttpServer(); 45 createReverseHttpServer();
46 } 46 }
47 47
48 function callbackReport(requestId, rc, message, options) { 48 function callbackReport(requestId, rc, message, options) {
49 aaa.callbackReportWithPushToMongoDb(requestId, rc, message); 49 aaa.callbackReportWithPushToMongoDb(requestId, rc, message);
50 50
51 // resend trx as status check if rc 68 and task is defined 51 // resend trx as status check if rc 68 and task is defined
52 if (options && options.task && (rc == '68')) { 52 if (options && options.task && (rc == '68')) {
53 logger.verbose('Got pending trx, requesting in ' + seconds_to_wait_before_resend_on_pending + ' secs'); 53 logger.verbose('Got pending trx, requesting in ' + seconds_to_wait_before_resend_on_pending + ' secs');
54 setTimeout(function() { 54 setTimeout(function() {
55 checkStatus(options.task); 55 checkStatus(options.task);
56 }, seconds_to_wait_before_resend_on_pending * 1000) 56 }, seconds_to_wait_before_resend_on_pending * 1000)
57 } 57 }
58 } 58 }
59 59
60 function calculateSign(dt, trx_ref_id, cust_num, username, password) { 60 function calculateSign(dt, trx_ref_id, cust_num, username, password) {
61 const cryptoHashPassword = crypto.createHash('sha1'); 61 const cryptoHashPassword = crypto.createHash('sha1');
62 const cryptoHashUsernamePassword = crypto.createHash('sha1'); 62 const cryptoHashUsernamePassword = crypto.createHash('sha1');
63 const cryptoHashOutest = crypto.createHash('sha1'); 63 const cryptoHashOutest = crypto.createHash('sha1');
64 64
65 cryptoHashPassword.update(password); 65 cryptoHashPassword.update(password);
66 const hashPassword = cryptoHashPassword.digest('hex'); 66 const hashPassword = cryptoHashPassword.digest('hex');
67 67
68 cryptoHashUsernamePassword.update(username + hashPassword); 68 cryptoHashUsernamePassword.update(username + hashPassword);
69 const hashUsernamePassword = cryptoHashUsernamePassword.digest('hex'); 69 const hashUsernamePassword = cryptoHashUsernamePassword.digest('hex');
70 70
71 cryptoHashOutest.update(dt + trx_ref_id + cust_num + hashUsernamePassword); 71 cryptoHashOutest.update(dt + trx_ref_id + cust_num + hashUsernamePassword);
72 return cryptoHashOutest.digest('hex'); 72 return cryptoHashOutest.digest('hex');
73 } 73 }
74 74
75 function _decodeResponseBody(responseBody) { 75 function _decodeResponseBody(responseBody) {
76 let response; 76 let response;
77 77
78 try { 78 try {
79 response = JSON.parse(responseBody); 79 response = JSON.parse(responseBody);
80 } 80 }
81 catch(e) { 81 catch(e) {
82 logger.warn('Error parsing response body'); 82 logger.warn('Error parsing response body');
83 } 83 }
84 84
85 return response; 85 return response;
86 } 86 }
87 87
88 function _composeMessageFromResponseData(responseDataObj) { 88 function _composeMessageFromResponseData(responseDataObj) {
89 const diag = _getPropertyFromObjectSafe(responseDataObj, 'diag'); 89 const diag = _getPropertyFromObjectSafe(responseDataObj, 'diag');
90 const msg = _getPropertyFromObjectSafe(responseDataObj, 'message'); 90 const msg = _getPropertyFromObjectSafe(responseDataObj, 'message');
91 const balance = _getPropertyFromObjectSafe(responseDataObj, 'balance'); 91 const balance = _getPropertyFromObjectSafe(responseDataObj, 'balance');
92 const timestamp = _getPropertyFromObjectSafe(responseDataObj, 'timestamp'); 92 const timestamp = _getPropertyFromObjectSafe(responseDataObj, 'timestamp');
93 const price = _getPropertyFromObjectSafe(response.data, 'harga');
93 94
94 let messages = []; 95 let messages = [];
95 96
96 if (timestamp) { 97 if (timestamp) {
97 messages.push(timestamp); 98 messages.push(timestamp);
98 } 99 }
99 100
100 if (diag) { 101 if (diag) {
101 messages.push(diag); 102 messages.push(diag);
102 } 103 }
103 104
104 if (msg) { 105 if (msg) {
105 messages.push(msg); 106 messages.push(msg);
106 } 107 }
107 108
108 if (balance) { 109 if (balance) {
109 messages.push('Balance: ' + balance); 110 messages.push('Balance: ' + balance);
110 } 111 }
111 112
113 if (price) {
114 messages.push('Price: ' + price);
115 }
116
112 return messages.join('. ') + '.'; 117 return messages.join('. ') + '.';
113 } 118 }
114 119
115 function _composeCompleteSn(responseDataObj) { 120 function _composeCompleteSn(responseDataObj) {
116 const serial = _getPropertyFromObjectSafe(responseDataObj, 'serial'); 121 const serial = _getPropertyFromObjectSafe(responseDataObj, 'serial');
117 const info = _getPropertyFromObjectSafe(responseDataObj, 'info'); 122 const info = _getPropertyFromObjectSafe(responseDataObj, 'info');
118 123
119 if (!info) { 124 if (!info) {
120 //logger.warn('Undefined data.info on _composeCompleteSn'); 125 //logger.warn('Undefined data.info on _composeCompleteSn');
121 return serial; 126 return serial;
122 } 127 }
123 128
124 const cleanedData = { 129 const cleanedData = {
125 token: serial, 130 token: serial,
126 cust_name: _getPropertyFromObjectSafe(info, 'cust_name'), 131 cust_name: _getPropertyFromObjectSafe(info, 'cust_name'),
127 tariff: _getPropertyFromObjectSafe(info, 'kelas') + 'VA', 132 tariff: _getPropertyFromObjectSafe(info, 'kelas') + 'VA',
128 total_kwh: _getPropertyFromObjectSafe(info, 'size') 133 total_kwh: _getPropertyFromObjectSafe(info, 'size')
129 } 134 }
130 135
131 if (cleanedData.token) { 136 if (cleanedData.token) {
132 cleanedData.token = cleanedData.token.replace(/ /g, '-'); 137 cleanedData.token = cleanedData.token.replace(/ /g, '-');
133 } 138 }
134 139
135 if (cleanedData.cust_name) { 140 if (cleanedData.cust_name) {
136 cleanedData.cust_name = cleanedData.cust_name.replace(/\W+/g, ' ').trim().replace(/\W+/g, '-').toUpperCase(); 141 cleanedData.cust_name = cleanedData.cust_name.replace(/\W+/g, ' ').trim().replace(/\W+/g, '-').toUpperCase();
137 } 142 }
138 143
139 if (cleanedData.total_kwh) { 144 if (cleanedData.total_kwh) {
140 cleanedData.total_kwh = cleanedData.total_kwh.replace(/kWh /g, ''); 145 cleanedData.total_kwh = cleanedData.total_kwh.replace(/kWh /g, '');
141 } 146 }
142 147
143 148
144 logger.verbose('Detail token info extracted', {originalResponseInfo: info, cleanedData: cleanedData}); 149 logger.verbose('Detail token info extracted', {originalResponseInfo: info, cleanedData: cleanedData});
145 150
146 return [ 151 return [
147 cleanedData.token, cleanedData.cust_name, cleanedData.tariff, cleanedData.total_kwh 152 cleanedData.token, cleanedData.cust_name, cleanedData.tariff, cleanedData.total_kwh
148 ].join('/'); 153 ].join('/');
149 } 154 }
150 155
151 function _responseBodyHandler(responseBody, task) { 156 function _responseBodyHandler(responseBody, task) {
152 let rc = '68'; 157 let rc = '68';
153 let response = _decodeResponseBody(responseBody); 158 let response = _decodeResponseBody(responseBody);
154 159
155 logger.verbose('RESPONSE', {response: response}); 160 logger.verbose('RESPONSE', {response: response});
156 161
157 const responseStatus = _getPropertyFromObjectSafe(response, 'status'); 162 const responseStatus = _getPropertyFromObjectSafe(response, 'status');
158 const responseInfo = _getPropertyFromObjectSafe(response, 'info'); 163 const responseInfo = _getPropertyFromObjectSafe(response, 'info');
159 164
160 if (responseStatus == 'Error') { 165 if (responseStatus == 'Error') {
161 if (['insufficient balance', 'System Cut-Off'].indexOf(responseInfo) >= 0) { 166 if (['insufficient balance', 'System Cut-Off'].indexOf(responseInfo) >= 0) {
162 rc = '91'; 167 rc = '91';
163 } 168 }
164 callbackReport(task.requestId, '91', [responseStatus, responseInfo].join(': '), {task: task}); 169 callbackReport(task.requestId, '91', [responseStatus, responseInfo].join(': '), {task: task});
165 return; 170 return;
166 } 171 }
167 172
168 const requestId = _getPropertyFromObjectSafe(response.data, 'request_id'); 173 const requestId = _getPropertyFromObjectSafe(response.data, 'request_id');
169 const trxStatus = _getPropertyFromObjectSafe(response.data, 'trx_status'); 174 const trxStatus = _getPropertyFromObjectSafe(response.data, 'trx_status');
170 const diag = _getPropertyFromObjectSafe(response.data, 'diag'); 175 const diag = _getPropertyFromObjectSafe(response.data, 'diag');
171 let balance = _getPropertyFromObjectSafe(response.data, 'balance'); 176 let balance = _getPropertyFromObjectSafe(response.data, 'balance');
172 177
173 if (balance && aaa.updateBalance) { 178 if (balance && aaa.updateBalance) {
174 balance = balance.replace(/\D/g, ''); 179 balance = balance.replace(/\D/g, '');
175 if (balance) { 180 if (balance) {
176 aaa.updateBalance(balance); 181 aaa.updateBalance(balance);
177 } 182 }
178 } 183 }
179 184
180 let aaaMessage = _composeMessageFromResponseData(response.data); 185 let aaaMessage = _composeMessageFromResponseData(response.data);
181 if (!aaaMessage) { 186 if (!aaaMessage) {
182 aaaMessage = 'Transaksi sedang diproses'; 187 aaaMessage = 'Transaksi sedang diproses';
183 } 188 }
184 189
185 if (trxStatus == 'P') { 190 if (trxStatus == 'P') {
186 logger.verbose('Got pending trx response', {response: response.data}); 191 logger.verbose('Got pending trx response', {response: response.data});
187 rc = '68'; 192 rc = '68';
188 } 193 }
189 else if (trxStatus == 'S') { 194 else if (trxStatus == 'S') {
190 logger.verbose('Got succcess trx response', {response: response.data}); 195 logger.verbose('Got succcess trx response', {response: response.data});
191 196
192 rc = '00'; 197 rc = '00';
193 aaaMessage = 'SN=' + _composeCompleteSn(response.data) + '; ' + aaaMessage; 198 aaaMessage = 'SN=' + _composeCompleteSn(response.data) + '; ' + aaaMessage;
194 } 199 }
195 else if (trxStatus == 'R') { 200 else if (trxStatus == 'R') {
196 logger.verbose('Got rejected trx response', {response: response.data}); 201 logger.verbose('Got rejected trx response', {response: response.data});
197 202
198 const partnerRC = getPartnerRCFromDiagMessage(diag); 203 const partnerRC = getPartnerRCFromDiagMessage(diag);
199 if (partnerRC == '15') { 204 if (partnerRC == '15') {
200 rc = '14'; 205 rc = '14';
201 } 206 }
202 else { 207 else {
203 rc = '40'; 208 rc = '40';
204 } 209 }
205 } 210 }
206 211
207 callbackReport(requestId, rc, aaaMessage, {task: task}); 212 callbackReport(requestId, rc, aaaMessage, {task: task});
208 } 213 }
209 214
210 function getPartnerRCFromDiagMessage(diag) { 215 function getPartnerRCFromDiagMessage(diag) {
211 let matches = diag.match(/^\s*\[(.*)\]/); 216 let matches = diag.match(/^\s*\[(.*)\]/);
212 if (!matches || matches.length < 2) { 217 if (!matches || matches.length < 2) {
213 return; 218 return;
214 } 219 }
215 220
216 return matches[1]; 221 return matches[1];
217 } 222 }
218 223
219 function _hitTopup(task, isCheckStatus) { 224 function _hitTopup(task, isCheckStatus) {
220 225
221 const dt = moment().format('YYYY-MM-DD HH:mm:ss'); 226 const dt = moment().format('YYYY-MM-DD HH:mm:ss');
222 const username = config.h2h_out.username || config.h2h_out.userid; 227 const username = config.h2h_out.username || config.h2h_out.userid;
223 const password = config.h2h_out.password || config.h2h_out.pin; 228 const password = config.h2h_out.password || config.h2h_out.pin;
224 const sign = calculateSign(dt, task.requestId, task.destination, username, password); 229 const sign = calculateSign(dt, task.requestId, task.destination, username, password);
225 230
226 logger.verbose('Sign for ' + dt + ', ' + task.requestId + ', ' + task.destination + ', ' + username + ', ' + password + ' is ' + sign); 231 logger.verbose('Sign for ' + dt + ', ' + task.requestId + ', ' + task.destination + ', ' + username + ', ' + password + ' is ' + sign);
227 const requestOptions = { 232 const requestOptions = {
228 url: config.h2h_out.partner, 233 url: config.h2h_out.partner,
229 form: { 234 form: {
230 username: username, 235 username: username,
231 datetime: dt, 236 datetime: dt,
232 code: task.remoteProduct, 237 code: task.remoteProduct,
233 trx_ref_id: task.requestId, 238 trx_ref_id: task.requestId,
234 cust_num: task.destination, 239 cust_num: task.destination,
235 sign: sign 240 sign: sign
236 } 241 }
237 } 242 }
238 243
239 logger.verbose('Requesting to partner', {requestOptions: requestOptions}); 244 logger.verbose('Requesting to partner', {requestOptions: requestOptions});
240 245
241 request.post(requestOptions, function(error, response, body) { 246 request.post(requestOptions, function(error, response, body) {
242 if (error) { 247 if (error) {
243 let rc = '68'; 248 let rc = '68';
244 249
245 if (!isCheckStatus && (error.syscall == 'connect')) { 250 if (!isCheckStatus && (error.syscall == 'connect')) {
246 rc = '91'; 251 rc = '91';
247 } 252 }
248 253
249 logger.warn('Error requesting to partner', {task: task, rc: rc, error: error, isCheckStatus: isCheckStatus}); 254 logger.warn('Error requesting to partner', {task: task, rc: rc, error: error, isCheckStatus: isCheckStatus});
250 callbackReport(task.requestId, rc, 'Error requesting to partner. ' + error, {task: task}); 255 callbackReport(task.requestId, rc, 'Error requesting to partner. ' + error, {task: task});
251 return; 256 return;
252 } 257 }
253 258
254 if (response.statusCode != 200) { 259 if (response.statusCode != 200) {
255 let rc = '68'; 260 let rc = '68';
256 261
257 logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode, isCheckStatus: isCheckStatus}); 262 logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode, isCheckStatus: isCheckStatus});
258 callbackReport(task.requestId, rc, 'HTTP status code ' + response.statusCode, {task: task}); 263 callbackReport(task.requestId, rc, 'HTTP status code ' + response.statusCode, {task: task});
259 return; 264 return;
260 } 265 }
261 266
262 logger.info('Transaksi sedang diproses', {task: task, response_body: body}); 267 logger.info('Transaksi sedang diproses', {task: task, response_body: body});
263 268
264 _responseBodyHandler(body, task); 269 _responseBodyHandler(body, task);
265 270
266 }) 271 })
267 } 272 }
268 273
269 function _getPropertyFromObjectSafe(obj, property) { 274 function _getPropertyFromObjectSafe(obj, property) {
270 let retval; 275 let retval;
271 276
272 if (!obj) { 277 if (!obj) {
273 logger.warn('Invalid object') 278 logger.warn('Invalid object')
274 return; 279 return;
275 } 280 }
276 281
277 try { 282 try {
278 retval = obj[property]; 283 retval = obj[property];
279 } 284 }
280 catch(e) { 285 catch(e) {
281 logger.warn('Error getting ' + property + ' from object'); 286 logger.warn('Error getting ' + property + ' from object');
282 } 287 }
283 288
284 return retval; 289 return retval;
285 } 290 }
286 291
287 function topupRequest(task) { 292 function topupRequest(task) {
288 aaa.insertTaskToMongoDb(task); 293 aaa.insertTaskToMongoDb(task);
289 _hitTopup(task); 294 _hitTopup(task);
290 } 295 }
291 296
292 function checkStatus(task) { 297 function checkStatus(task) {
293 _hitTopup(task, true); 298 _hitTopup(task, true);
294 } 299 }
295 300
296 301
297 function reverseReportHandler(body) { 302 function reverseReportHandler(body) {
298 logger.info('Got reverse report', {body: body}); 303 logger.info('Got reverse report', {body: body});
299 } 304 }
300 305
301 function createReverseHttpServer() { 306 function createReverseHttpServer() {
302 var httpServer = http.createServer(function(request, response) { 307 var httpServer = http.createServer(function(request, response) {
303 308
304 logger.info('Got request from partner'); 309 logger.info('Got request from partner');
305 310
306 var body = ""; 311 var body = "";
307 request.on('data', function (chunk) { 312 request.on('data', function (chunk) {
308 body += chunk; 313 body += chunk;
309 }); 314 });
310 315
311 request.on('end', function () { 316 request.on('end', function () {
312 response.writeHead(200); 317 response.writeHead(200);
313 response.end('OK'); 318 response.end('OK');
314 319
315 reverseReportHandler(body); 320 reverseReportHandler(body);
316 }); 321 });
317 322
318 }); 323 });
319 324
320 httpServer.listen(config.h2h_out.listen_port, function() { 325 httpServer.listen(config.h2h_out.listen_port, function() {
321 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); 326 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
322 }); 327 });
323 } 328 }
324 329
325 330
326 exports.calculateSign = calculateSign; 331 exports.calculateSign = calculateSign;
327 exports.start = start; 332 exports.start = start;
328 exports.topupRequest = topupRequest; 333 exports.topupRequest = topupRequest;
329 exports.checkStatus = checkStatus; 334 exports.checkStatus = checkStatus;
330 335