Commit f4ad423194adb8351cc3c3fccbb4c1629406eb84

Authored by Adhidarma Hadiwinoto
1 parent 88dddf1ef8
Exists in master

hit pakai ref_id

Showing 1 changed file with 2 additions and 1 deletions Inline Diff

1 var fs = require('fs'); 1 var fs = require('fs');
2 var https = require('https'); 2 var https = require('https');
3 var http = require('http'); 3 var http = require('http');
4 var url = require('url'); 4 var url = require('url');
5 var request = require('request'); 5 var request = require('request');
6 var xml2js = require('xml2js').parseString; 6 var xml2js = require('xml2js').parseString;
7 var strftime = require('strftime'); 7 var strftime = require('strftime');
8 var redis = require('redis'); 8 var redis = require('redis');
9 9
10 var Router = require('node-simple-router'); 10 var Router = require('node-simple-router');
11 11
12 var winston = require('winston'); 12 var winston = require('winston');
13 13
14 var logger; 14 var logger;
15 var config; 15 var config;
16 var httpServer; 16 var httpServer;
17 var redisClient; 17 var redisClient;
18 18
19 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 19 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
20 20
21 var aaa; 21 var aaa;
22 22
23 var logTag = __filename.split('/').reverse()[0]; 23 var logTag = __filename.split('/').reverse()[0];
24 24
25 function getRedisKey(timestamp) { 25 function getRedisKey(timestamp) {
26 var prefix = config.globals.gateway_name; 26 var prefix = config.globals.gateway_name;
27 if (config.globals.redis_prefix) { 27 if (config.globals.redis_prefix) {
28 prefix = config.globals.redis_prefix; 28 prefix = config.globals.redis_prefix;
29 } 29 }
30 return prefix + '.ts:' + timestamp + '.rid'; 30 return prefix + '.ts:' + timestamp + '.rid';
31 } 31 }
32 32
33 function generateTimestamp(request_id) { 33 function generateTimestamp(request_id) {
34 var ts = strftime('%F %T', new Date()); 34 var ts = strftime('%F %T', new Date());
35 35
36 var key = getRedisKey(ts); 36 var key = getRedisKey(ts);
37 redisClient.set(key, request_id); 37 redisClient.set(key, request_id);
38 redisClient.expire(key, 3600*48); 38 redisClient.expire(key, 3600*48);
39 39
40 return ts; 40 return ts;
41 } 41 }
42 42
43 function topupRequest(task) { 43 function topupRequest(task) {
44 aaa.insertTaskToMongoDb(task); 44 aaa.insertTaskToMongoDb(task);
45 45
46 var ts = strftime('%F %T', new Date()); 46 var ts = strftime('%F %T', new Date());
47 ts = generateTimestamp(task['requestId']); 47 ts = generateTimestamp(task['requestId']);
48 48
49 var options = { 49 var options = {
50 url: config.h2h_out.partner, 50 url: config.h2h_out.partner,
51 qs: { 51 qs: {
52 code: task['remoteProduct'], 52 code: task['remoteProduct'],
53 msisdn: task['destination'], 53 msisdn: task['destination'],
54 user_id: config.h2h_out.userid, 54 user_id: config.h2h_out.userid,
55 password: config.h2h_out.password, 55 password: config.h2h_out.password,
56 ts: ts 56 ts: ts,
57 ref_id: task.requestId
57 } 58 }
58 }; 59 };
59 60
60 logger.info('Creating http request to gateway', {options: options}); 61 logger.info('Creating http request to gateway', {options: options});
61 62
62 if (aaa) { 63 if (aaa) {
63 aaa.incrementTrxCount(); 64 aaa.incrementTrxCount();
64 aaa.incrementActiveTrxCount(); 65 aaa.incrementActiveTrxCount();
65 } 66 }
66 67
67 request(options, function (error, response, body) { 68 request(options, function (error, response, body) {
68 aaa.decrementActiveTrxCount(); 69 aaa.decrementActiveTrxCount();
69 70
70 if (error) { 71 if (error) {
71 72
72 var error_message = 'Error on http connection to gateway: ' + error; 73 var error_message = 'Error on http connection to gateway: ' + error;
73 logger.warn(error_message); 74 logger.warn(error_message);
74 callbackReport(task['requestId'], '91', error_message); 75 callbackReport(task['requestId'], '91', error_message);
75 return; 76 return;
76 77
77 } 78 }
78 79
79 if (response.statusCode != 200) { 80 if (response.statusCode != 200) {
80 81
81 var error_message = 'Gateway error, http response code: ' + response.statusCode; 82 var error_message = 'Gateway error, http response code: ' + response.statusCode;
82 logger.warn(error_message); 83 logger.warn(error_message);
83 callbackReport(task['requestId'], '91', error_message); 84 callbackReport(task['requestId'], '91', error_message);
84 return; 85 return;
85 } 86 }
86 87
87 var responseCode = 40; 88 var responseCode = 40;
88 var responseMessage; 89 var responseMessage;
89 90
90 xml2js(body, function (err, result) { 91 xml2js(body, function (err, result) {
91 if (err) { 92 if (err) {
92 logger.warn('Error parsing XML', {response_error: err, response_body: body}); 93 logger.warn('Error parsing XML', {response_error: err, response_body: body});
93 callbackReport(task['requestId'], '40', body); 94 callbackReport(task['requestId'], '40', body);
94 return; 95 return;
95 } 96 }
96 97
97 logger.info('Got direct response from request', {result: result}); 98 logger.info('Got direct response from request', {result: result});
98 99
99 try { 100 try {
100 responseMessage = result.direct_ack.info[0]; 101 responseMessage = result.direct_ack.info[0];
101 102
102 if (result.direct_ack.request_status[0] == 'OK') { 103 if (result.direct_ack.request_status[0] == 'OK') {
103 responseCode = '68'; 104 responseCode = '68';
104 } else { 105 } else {
105 responseCode = '40'; 106 responseCode = '40';
106 107
107 var new_response_code = responseCodeFromMessage(responseMessage); 108 var new_response_code = responseCodeFromMessage(responseMessage);
108 if (new_response_code) { 109 if (new_response_code) {
109 responseCode = new_response_code; 110 responseCode = new_response_code;
110 } 111 }
111 112
112 } 113 }
113 114
114 } 115 }
115 catch(err) { 116 catch(err) {
116 logger.warn('Exception on parsing xml response'); 117 logger.warn('Exception on parsing xml response');
117 responseCode = 40; 118 responseCode = 40;
118 responseMessage = 'Invalid xml response from gateway'; 119 responseMessage = 'Invalid xml response from gateway';
119 } 120 }
120 121
121 callbackReport(task['requestId'], responseCode, responseMessage); 122 callbackReport(task['requestId'], responseCode, responseMessage);
122 123
123 }); 124 });
124 125
125 }); 126 });
126 } 127 }
127 128
128 function createRedisClient() { 129 function createRedisClient() {
129 redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host); 130 redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host);
130 } 131 }
131 132
132 function paddingSN(sn, _config) { 133 function paddingSN(sn, _config) {
133 134
134 if (!_config) { 135 if (!_config) {
135 _config = config; 136 _config = config;
136 } 137 }
137 138
138 if (_config.h2h_out.sn_min_length && (sn.length < Number(_config.h2h_out.sn_min_length))) { 139 if (_config.h2h_out.sn_min_length && (sn.length < Number(_config.h2h_out.sn_min_length))) {
139 sn = '0000000000000000' + sn; 140 sn = '0000000000000000' + sn;
140 sn = sn.slice(Number(_config.h2h_out.sn_min_length) * -1); 141 sn = sn.slice(Number(_config.h2h_out.sn_min_length) * -1);
141 } 142 }
142 return sn; 143 return sn;
143 } 144 }
144 145
145 function parseSN(message, _config) { 146 function parseSN(message, _config) {
146 147
147 if (!_config) { 148 if (!_config) {
148 _config = config; 149 _config = config;
149 } 150 }
150 151
151 var sn_regex = new RegExp(_config.h2h_out.sn_pattern); 152 var sn_regex = new RegExp(_config.h2h_out.sn_pattern);
152 var sn_match = message.match(sn_regex); 153 var sn_match = message.match(sn_regex);
153 154
154 if (sn_match <= 0) { 155 if (sn_match <= 0) {
155 logger.info('SN Not found: ' + message); 156 logger.info('SN Not found: ' + message);
156 return ''; 157 return '';
157 } 158 }
158 159
159 var match_index = 0; 160 var match_index = 0;
160 if (_config.h2h_out.sn_match_index) { 161 if (_config.h2h_out.sn_match_index) {
161 match_index = Number(_config.h2h_out.sn_match_index) 162 match_index = Number(_config.h2h_out.sn_match_index)
162 } 163 }
163 164
164 var sn = sn_match[match_index]; 165 var sn = sn_match[match_index];
165 166
166 if (_config.h2h_out.sn_remove_whitespace) { 167 if (_config.h2h_out.sn_remove_whitespace) {
167 sn = sn.replace(/\s/g, ''); 168 sn = sn.replace(/\s/g, '');
168 } 169 }
169 170
170 var sn_remove_patterns = _config.h2h_out.sn_remove_patterns.split(_config.h2h_out.sn_remove_patterns_separator); 171 var sn_remove_patterns = _config.h2h_out.sn_remove_patterns.split(_config.h2h_out.sn_remove_patterns_separator);
171 172
172 var count = sn_remove_patterns.length; 173 var count = sn_remove_patterns.length;
173 174
174 for(var i = 0; i < count; i++) { 175 for(var i = 0; i < count; i++) {
175 176
176 //sn = sn.replace(sn_remove_patterns[i], ''); 177 //sn = sn.replace(sn_remove_patterns[i], '');
177 178
178 var re = new RegExp(sn_remove_patterns[i], 'g'); 179 var re = new RegExp(sn_remove_patterns[i], 'g');
179 sn = sn.replace(re, ''); 180 sn = sn.replace(re, '');
180 } 181 }
181 182
182 sn = paddingSN(sn, _config); 183 sn = paddingSN(sn, _config);
183 184
184 return sn.trim(); 185 return sn.trim();
185 } 186 }
186 187
187 function createServer() { 188 function createServer() {
188 var httpServer = http.createServer(function(request, response) { 189 var httpServer = http.createServer(function(request, response) {
189 190
190 var response_code = '68'; 191 var response_code = '68';
191 var sn = ''; 192 var sn = '';
192 193
193 var qs = url.parse(request.url, true).query; 194 var qs = url.parse(request.url, true).query;
194 195
195 logger.info('Got reverse report from gateway', {qs: qs}); 196 logger.info('Got reverse report from gateway', {qs: qs});
196 197
197 if (qs.topup_status == 'S') { 198 if (qs.topup_status == 'S') {
198 response_code = '00'; 199 response_code = '00';
199 if (qs.sn && !config.h2h_out.force_parse_sn && !Number(config.h2h_out.force_parse_sn)) { 200 if (qs.sn && !config.h2h_out.force_parse_sn && !Number(config.h2h_out.force_parse_sn)) {
200 sn = qs.sn; 201 sn = qs.sn;
201 } else { 202 } else {
202 logger.warn('Missing SN from query string. Trying to get SN from message'); 203 logger.warn('Missing SN from query string. Trying to get SN from message');
203 sn = parseSN(qs.info); 204 sn = parseSN(qs.info);
204 } 205 }
205 206
206 if (config.h2h_out.sn_split_index) { 207 if (config.h2h_out.sn_split_index) {
207 sn = splitSN(sn, config); 208 sn = splitSN(sn, config);
208 } 209 }
209 210
210 if (sn) { 211 if (sn) {
211 sn = paddingSN(sn, config); 212 sn = paddingSN(sn, config);
212 } 213 }
213 214
214 sn = sn.trim(); 215 sn = sn.trim();
215 216
216 } else if (qs.topup_status == 'R') { 217 } else if (qs.topup_status == 'R') {
217 218
218 response_code = '40'; 219 response_code = '40';
219 220
220 } 221 }
221 222
222 try { 223 try {
223 224
224 var new_response_code = responseCodeFromMessage(qs.info); 225 var new_response_code = responseCodeFromMessage(qs.info);
225 if (new_response_code) { 226 if (new_response_code) {
226 response_code = new_response_code; 227 response_code = new_response_code;
227 } 228 }
228 229
229 } 230 }
230 catch(err) { 231 catch(err) {
231 logger.warn('Exception on parsing reverse report', {exception: err} ); 232 logger.warn('Exception on parsing reverse report', {exception: err} );
232 response_code = '40'; 233 response_code = '40';
233 } 234 }
234 235
235 message = qs.info; 236 message = qs.info;
236 //updateBalance(message); 237 //updateBalance(message);
237 if (sn) { 238 if (sn) {
238 message = 'SN=' + sn + '; ' + message; 239 message = 'SN=' + sn + '; ' + message;
239 } 240 }
240 241
241 response.end('OK'); 242 response.end('OK');
242 243
243 var key = getRedisKey(qs.ts); 244 var key = getRedisKey(qs.ts);
244 redisClient.get(key, function(err, request_id) { 245 redisClient.get(key, function(err, request_id) {
245 if (err) { 246 if (err) {
246 logger.warn('Error when requesting request id for ts:' + qs.ts + ' (' + key + ')', {redis_error: err}); 247 logger.warn('Error when requesting request id for ts:' + qs.ts + ' (' + key + ')', {redis_error: err});
247 return; 248 return;
248 } 249 }
249 250
250 callbackReport(request_id, response_code, message); 251 callbackReport(request_id, response_code, message);
251 }); 252 });
252 }); 253 });
253 254
254 httpServer.listen(config.h2h_out.listen_port, function() { 255 httpServer.listen(config.h2h_out.listen_port, function() {
255 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); 256 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
256 }); 257 });
257 } 258 }
258 259
259 function splitSN(sn, _config) { 260 function splitSN(sn, _config) {
260 var sn_pieces = sn.split(' '); 261 var sn_pieces = sn.split(' ');
261 262
262 if (sn_pieces.length <= 0) { 263 if (sn_pieces.length <= 0) {
263 logger.info('Returning original SN because SN only has one element'); 264 logger.info('Returning original SN because SN only has one element');
264 return sn; 265 return sn;
265 } 266 }
266 267
267 if (!_config.h2h_out.sn_split_index) { 268 if (!_config.h2h_out.sn_split_index) {
268 logger.info('Returning original SN because config.h2h_out.sn_split_index undefined'); 269 logger.info('Returning original SN because config.h2h_out.sn_split_index undefined');
269 return sn; 270 return sn;
270 } 271 }
271 var sn_indexes = _config.h2h_out.sn_split_index.split(','); 272 var sn_indexes = _config.h2h_out.sn_split_index.split(',');
272 273
273 logger.info('Split SN', {sn_pieces: sn_pieces, sn_indexes: sn_indexes}); 274 logger.info('Split SN', {sn_pieces: sn_pieces, sn_indexes: sn_indexes});
274 275
275 var _sn = ''; 276 var _sn = '';
276 277
277 var id_count = sn_indexes.length; 278 var id_count = sn_indexes.length;
278 for(var i = 0; i < id_count; i++) { 279 for(var i = 0; i < id_count; i++) {
279 280
280 var sn_index = sn_indexes[i]; 281 var sn_index = sn_indexes[i];
281 var sn_piece = sn_pieces[sn_index]; 282 var sn_piece = sn_pieces[sn_index];
282 283
283 if (sn_pieces[i]) { 284 if (sn_pieces[i]) {
284 _sn = _sn + sn_piece; 285 _sn = _sn + sn_piece;
285 } else { 286 } else {
286 logger.warn('Undefined value on sn piece ' + sn_index); 287 logger.warn('Undefined value on sn piece ' + sn_index);
287 } 288 }
288 } 289 }
289 290
290 _sn = _sn.trim(); 291 _sn = _sn.trim();
291 292
292 if (_sn) { 293 if (_sn) {
293 sn = _sn; 294 sn = _sn;
294 logger.info('Got new SN: ' + sn); 295 logger.info('Got new SN: ' + sn);
295 } else { 296 } else {
296 logger.warn('Got empty SN when using split SN. Use original SN'); 297 logger.warn('Got empty SN when using split SN. Use original SN');
297 } 298 }
298 299
299 return sn; 300 return sn;
300 } 301 }
301 302
302 function responseCodeFromMessage(message) { 303 function responseCodeFromMessage(message) {
303 if (message.toLowerCase().indexOf('nomor salah/tidak terdaftar') >= 0) { 304 if (message.toLowerCase().indexOf('nomor salah/tidak terdaftar') >= 0) {
304 return '14'; 305 return '14';
305 } 306 }
306 else if (message.toLowerCase().indexOf('nomor tidak di temukan/tidak aktif') >= 0) { 307 else if (message.toLowerCase().indexOf('nomor tidak di temukan/tidak aktif') >= 0) {
307 return '14'; 308 return '14';
308 } 309 }
309 else if (message.toLowerCase().indexOf('kode produk tidak sesuai nomor tujuan') >= 0) { 310 else if (message.toLowerCase().indexOf('kode produk tidak sesuai nomor tujuan') >= 0) {
310 return '14'; 311 return '14';
311 } 312 }
312 else if (message.toLowerCase().indexOf('nomor yang anda masukan salah') >= 0) { 313 else if (message.toLowerCase().indexOf('nomor yang anda masukan salah') >= 0) {
313 return '14'; 314 return '14';
314 } 315 }
315 else if (message.toLowerCase().indexOf('nomor yang anda masukkan salah') >= 0) { 316 else if (message.toLowerCase().indexOf('nomor yang anda masukkan salah') >= 0) {
316 return '14'; 317 return '14';
317 } 318 }
318 else if (message.toLowerCase().indexOf('nomor telepon seluler salah') >= 0) { 319 else if (message.toLowerCase().indexOf('nomor telepon seluler salah') >= 0) {
319 return '14'; 320 return '14';
320 } 321 }
321 else if (message.indexOf('UNKNOWN_NUMBER') >= 0) { 322 else if (message.indexOf('UNKNOWN_NUMBER') >= 0) {
322 return '14'; 323 return '14';
323 } 324 }
324 else if (message.toLowerCase().indexOf('bulk or forbidden request') >= 0) { 325 else if (message.toLowerCase().indexOf('bulk or forbidden request') >= 0) {
325 return '55'; 326 return '55';
326 } 327 }
327 else if (message.toLowerCase().indexOf('sudah pernah dilakukan') >= 0) { 328 else if (message.toLowerCase().indexOf('sudah pernah dilakukan') >= 0) {
328 return '55'; 329 return '55';
329 } 330 }
330 else if (message.toLowerCase().indexOf('transaksi yg sama sudah pernah dilakukan tunggu dlm') >= 0) { 331 else if (message.toLowerCase().indexOf('transaksi yg sama sudah pernah dilakukan tunggu dlm') >= 0) {
331 return '55'; 332 return '55';
332 } 333 }
333 else if (message.toLowerCase().indexOf('transaksi tsb sudah pernah dilakukan') >= 0) { 334 else if (message.toLowerCase().indexOf('transaksi tsb sudah pernah dilakukan') >= 0) {
334 return '55'; 335 return '55';
335 } 336 }
336 else if (message.toLowerCase().indexOf('mohon maaf saat ini stock belum tersedia') >= 0) { 337 else if (message.toLowerCase().indexOf('mohon maaf saat ini stock belum tersedia') >= 0) {
337 return '13'; 338 return '13';
338 } 339 }
339 else if (message.toLowerCase().indexOf('stock tidak tersedia') >= 0) { 340 else if (message.toLowerCase().indexOf('stock tidak tersedia') >= 0) {
340 return '13'; 341 return '13';
341 } 342 }
342 else if (message.toLowerCase().indexOf('tidak tersedia atau nonaktif') >= 0) { 343 else if (message.toLowerCase().indexOf('tidak tersedia atau nonaktif') >= 0) {
343 return '13'; 344 return '13';
344 } 345 }
345 else if (message.toLowerCase().indexOf('saldo di account anda saat ini tidak mencukupi') >= 0) { 346 else if (message.toLowerCase().indexOf('saldo di account anda saat ini tidak mencukupi') >= 0) {
346 return '40'; 347 return '40';
347 } 348 }
348 else if (message.toLowerCase().indexOf('tidak mencukupi untuk melakukan transaksi') >= 0) { 349 else if (message.toLowerCase().indexOf('tidak mencukupi untuk melakukan transaksi') >= 0) {
349 return '40'; 350 return '40';
350 } 351 }
351 else if (message.toLowerCase().indexOf('saldo anda tidak mencukupi') >= 0) { 352 else if (message.toLowerCase().indexOf('saldo anda tidak mencukupi') >= 0) {
352 return '40'; 353 return '40';
353 } 354 }
354 else if (message.search(/stok product .* tidak tersedia ke nomor .* dari pilihan2 yg tersedia/i) >= 0) { 355 else if (message.search(/stok product .* tidak tersedia ke nomor .* dari pilihan2 yg tersedia/i) >= 0) {
355 return '13'; 356 return '13';
356 } 357 }
357 else if (message.search(/stok produk .* gangguan ke no tujuan/i) >= 0) { 358 else if (message.search(/stok produk .* gangguan ke no tujuan/i) >= 0) {
358 return '13'; 359 return '13';
359 } 360 }
360 else if (message.toLowerCase().indexOf('stok tidak tersedia dari pilihan2 yg tersedia') >= 0) { 361 else if (message.toLowerCase().indexOf('stok tidak tersedia dari pilihan2 yg tersedia') >= 0) {
361 return '13'; 362 return '13';
362 } 363 }
363 364
364 return; 365 return;
365 } 366 }
366 367
367 function start(options) { 368 function start(options) {
368 if (!options) { 369 if (!options) {
369 console.log('Undefined options, terminating....'); 370 console.log('Undefined options, terminating....');
370 process.exit(1); 371 process.exit(1);
371 } 372 }
372 373
373 if (options.config) { 374 if (options.config) {
374 config = options.config; 375 config = options.config;
375 } else { 376 } else {
376 console.log('Undefined options.config, terminating....') 377 console.log('Undefined options.config, terminating....')
377 process.exit(1); 378 process.exit(1);
378 } 379 }
379 380
380 if (options.aaa) { 381 if (options.aaa) {
381 aaa = options.aaa; 382 aaa = options.aaa;
382 callbackReport = options.aaa.callbackReportWithPushToMongoDb; 383 callbackReport = options.aaa.callbackReportWithPushToMongoDb;
383 } else { 384 } else {
384 console.log('Undefined options.aaa, terminating....') 385 console.log('Undefined options.aaa, terminating....')
385 process.exit(1); 386 process.exit(1);
386 } 387 }
387 388
388 if (options.logger) { 389 if (options.logger) {
389 logger = options.logger; 390 logger = options.logger;
390 } else { 391 } else {
391 logger = new winston.Logger({ 392 logger = new winston.Logger({
392 transports: [ 393 transports: [
393 new (winston.transports.Console)() 394 new (winston.transports.Console)()
394 ] 395 ]
395 }); 396 });
396 } 397 }
397 398
398 createRedisClient(); 399 createRedisClient();
399 createServer(); 400 createServer();
400 } 401 }
401 402
402 exports.start = start; 403 exports.start = start;
403 exports.topupRequest = topupRequest; 404 exports.topupRequest = topupRequest;
404 exports.parseSN = parseSN; 405 exports.parseSN = parseSN;
405 406