Commit 3dcba2b1a96e5f2d0aa69b6cee3b9dd27b07ad5c

Authored by Adhidarma Hadiwinoto
1 parent a53a823c5e
Exists in master

55 - Transaksi tsb sudah pernah dilakukan

Showing 1 changed file with 3 additions and 0 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 var ts = strftime('%F %T', new Date()); 44 var ts = strftime('%F %T', new Date());
45 ts = generateTimestamp(task['requestId']); 45 ts = generateTimestamp(task['requestId']);
46 46
47 var options = { 47 var options = {
48 url: config.h2h_out.partner, 48 url: config.h2h_out.partner,
49 qs: { 49 qs: {
50 code: task['remoteProduct'], 50 code: task['remoteProduct'],
51 msisdn: task['destination'], 51 msisdn: task['destination'],
52 user_id: config.h2h_out.userid, 52 user_id: config.h2h_out.userid,
53 password: config.h2h_out.password, 53 password: config.h2h_out.password,
54 ts: ts 54 ts: ts
55 } 55 }
56 }; 56 };
57 57
58 logger.info('Creating http request to gateway', {options: options}); 58 logger.info('Creating http request to gateway', {options: options});
59 59
60 if (aaa) { 60 if (aaa) {
61 aaa.incrementTrxCount(); 61 aaa.incrementTrxCount();
62 aaa.incrementActiveTrxCount(); 62 aaa.incrementActiveTrxCount();
63 } 63 }
64 64
65 request(options, function (error, response, body) { 65 request(options, function (error, response, body) {
66 aaa.decrementActiveTrxCount(); 66 aaa.decrementActiveTrxCount();
67 67
68 if (error) { 68 if (error) {
69 69
70 var error_message = 'Error on http connection to gateway: ' + error; 70 var error_message = 'Error on http connection to gateway: ' + error;
71 logger.warn(error_message); 71 logger.warn(error_message);
72 callbackReport(task['requestId'], '91', error_message); 72 callbackReport(task['requestId'], '91', error_message);
73 return; 73 return;
74 74
75 } 75 }
76 76
77 if (response.statusCode != 200) { 77 if (response.statusCode != 200) {
78 78
79 var error_message = 'Gateway error, http response code: ' + response.statusCode; 79 var error_message = 'Gateway error, http response code: ' + response.statusCode;
80 logger.warn(error_message); 80 logger.warn(error_message);
81 callbackReport(task['requestId'], '91', error_message); 81 callbackReport(task['requestId'], '91', error_message);
82 return; 82 return;
83 } 83 }
84 84
85 var responseCode = 40; 85 var responseCode = 40;
86 var responseMessage; 86 var responseMessage;
87 87
88 xml2js(body, function (err, result) { 88 xml2js(body, function (err, result) {
89 if (err) { 89 if (err) {
90 logger.warn('Error parsing XML', {response_error: err, response_body: body}); 90 logger.warn('Error parsing XML', {response_error: err, response_body: body});
91 callbackReport(task['requestId'], '40', body); 91 callbackReport(task['requestId'], '40', body);
92 return; 92 return;
93 } 93 }
94 94
95 logger.info('Got direct response from request', {result: result}); 95 logger.info('Got direct response from request', {result: result});
96 96
97 try { 97 try {
98 responseMessage = result.direct_ack.info[0]; 98 responseMessage = result.direct_ack.info[0];
99 99
100 if (result.direct_ack.request_status[0] == 'OK') { 100 if (result.direct_ack.request_status[0] == 'OK') {
101 responseCode = 68; 101 responseCode = 68;
102 } else { 102 } else {
103 responseCode = 40; 103 responseCode = 40;
104 104
105 var new_response_code = responseCodeFromMessage(responseMessage); 105 var new_response_code = responseCodeFromMessage(responseMessage);
106 if (new_response_code) { 106 if (new_response_code) {
107 responseCode = new_response_code; 107 responseCode = new_response_code;
108 } 108 }
109 109
110 } 110 }
111 111
112 } 112 }
113 catch(err) { 113 catch(err) {
114 logger.warn('Exception on parsing xml response'); 114 logger.warn('Exception on parsing xml response');
115 responseCode = 40; 115 responseCode = 40;
116 responseMessage = 'Invalid xml response from gateway'; 116 responseMessage = 'Invalid xml response from gateway';
117 } 117 }
118 118
119 callbackReport(task['requestId'], responseCode, responseMessage); 119 callbackReport(task['requestId'], responseCode, responseMessage);
120 120
121 }); 121 });
122 122
123 }); 123 });
124 } 124 }
125 125
126 function createRedisClient() { 126 function createRedisClient() {
127 redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host); 127 redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host);
128 } 128 }
129 129
130 function paddingSN(sn, _config) { 130 function paddingSN(sn, _config) {
131 131
132 if (!_config) { 132 if (!_config) {
133 _config = config; 133 _config = config;
134 } 134 }
135 135
136 if (_config.h2h_out.sn_min_length && (sn.length < Number(_config.h2h_out.sn_min_length))) { 136 if (_config.h2h_out.sn_min_length && (sn.length < Number(_config.h2h_out.sn_min_length))) {
137 sn = '0000000000000000' + sn; 137 sn = '0000000000000000' + sn;
138 sn = sn.slice(Number(_config.h2h_out.sn_min_length) * -1); 138 sn = sn.slice(Number(_config.h2h_out.sn_min_length) * -1);
139 } 139 }
140 return sn; 140 return sn;
141 } 141 }
142 142
143 function parseSN(message, _config) { 143 function parseSN(message, _config) {
144 144
145 if (!_config) { 145 if (!_config) {
146 _config = config; 146 _config = config;
147 } 147 }
148 148
149 var sn_regex = new RegExp(_config.h2h_out.sn_pattern); 149 var sn_regex = new RegExp(_config.h2h_out.sn_pattern);
150 var sn_match = message.match(sn_regex); 150 var sn_match = message.match(sn_regex);
151 151
152 if (sn_match <= 0) { 152 if (sn_match <= 0) {
153 logger.info('SN Not found: ' + message); 153 logger.info('SN Not found: ' + message);
154 return ''; 154 return '';
155 } 155 }
156 156
157 var match_index = 0; 157 var match_index = 0;
158 if (_config.h2h_out.sn_match_index) { 158 if (_config.h2h_out.sn_match_index) {
159 match_index = Number(_config.h2h_out.sn_match_index) 159 match_index = Number(_config.h2h_out.sn_match_index)
160 } 160 }
161 161
162 var sn = sn_match[match_index]; 162 var sn = sn_match[match_index];
163 163
164 if (_config.h2h_out.sn_remove_whitespace) { 164 if (_config.h2h_out.sn_remove_whitespace) {
165 sn = sn.replace(/\s/g, ''); 165 sn = sn.replace(/\s/g, '');
166 } 166 }
167 167
168 var sn_remove_patterns = _config.h2h_out.sn_remove_patterns.split(_config.h2h_out.sn_remove_patterns_separator); 168 var sn_remove_patterns = _config.h2h_out.sn_remove_patterns.split(_config.h2h_out.sn_remove_patterns_separator);
169 169
170 var count = sn_remove_patterns.length; 170 var count = sn_remove_patterns.length;
171 171
172 for(var i = 0; i < count; i++) { 172 for(var i = 0; i < count; i++) {
173 173
174 //sn = sn.replace(sn_remove_patterns[i], ''); 174 //sn = sn.replace(sn_remove_patterns[i], '');
175 175
176 var re = new RegExp(sn_remove_patterns[i], 'g'); 176 var re = new RegExp(sn_remove_patterns[i], 'g');
177 sn = sn.replace(re, ''); 177 sn = sn.replace(re, '');
178 } 178 }
179 179
180 sn = paddingSN(sn, _config); 180 sn = paddingSN(sn, _config);
181 181
182 return sn.trim(); 182 return sn.trim();
183 } 183 }
184 184
185 function createServer() { 185 function createServer() {
186 var httpServer = http.createServer(function(request, response) { 186 var httpServer = http.createServer(function(request, response) {
187 187
188 var response_code = '68'; 188 var response_code = '68';
189 var sn = ''; 189 var sn = '';
190 190
191 var qs = url.parse(request.url, true).query; 191 var qs = url.parse(request.url, true).query;
192 192
193 logger.info('Got reverse report from gateway', {qs: qs}); 193 logger.info('Got reverse report from gateway', {qs: qs});
194 194
195 if (qs.topup_status == 'S') { 195 if (qs.topup_status == 'S') {
196 response_code = '00'; 196 response_code = '00';
197 if (qs.sn && !config.h2h_out.force_parse_sn && !Number(config.h2h_out.force_parse_sn)) { 197 if (qs.sn && !config.h2h_out.force_parse_sn && !Number(config.h2h_out.force_parse_sn)) {
198 sn = qs.sn; 198 sn = qs.sn;
199 } else { 199 } else {
200 logger.warn('Missing SN from query string. Trying to get SN from message'); 200 logger.warn('Missing SN from query string. Trying to get SN from message');
201 sn = parseSN(qs.info); 201 sn = parseSN(qs.info);
202 } 202 }
203 203
204 if (config.h2h_out.sn_split_index) { 204 if (config.h2h_out.sn_split_index) {
205 sn = splitSN(sn, config); 205 sn = splitSN(sn, config);
206 } 206 }
207 207
208 if (sn) { 208 if (sn) {
209 sn = paddingSN(sn, config); 209 sn = paddingSN(sn, config);
210 } 210 }
211 211
212 } else if (qs.topup_status == 'R') { 212 } else if (qs.topup_status == 'R') {
213 213
214 response_code = '40'; 214 response_code = '40';
215 215
216 } 216 }
217 217
218 try { 218 try {
219 219
220 var new_response_code = responseCodeFromMessage(qs.info); 220 var new_response_code = responseCodeFromMessage(qs.info);
221 if (new_response_code) { 221 if (new_response_code) {
222 response_code = new_response_code; 222 response_code = new_response_code;
223 } 223 }
224 224
225 } 225 }
226 catch(err) { 226 catch(err) {
227 logger.warn('Exception on parsing reverse report', {exception: err} ); 227 logger.warn('Exception on parsing reverse report', {exception: err} );
228 response_code = '40'; 228 response_code = '40';
229 } 229 }
230 230
231 message = qs.info; 231 message = qs.info;
232 //updateBalance(message); 232 //updateBalance(message);
233 if (sn) { 233 if (sn) {
234 message = 'SN=' + sn + '; ' + message; 234 message = 'SN=' + sn + '; ' + message;
235 } 235 }
236 236
237 response.end('OK'); 237 response.end('OK');
238 238
239 var key = getRedisKey(qs.ts); 239 var key = getRedisKey(qs.ts);
240 redisClient.get(key, function(err, request_id) { 240 redisClient.get(key, function(err, request_id) {
241 if (err) { 241 if (err) {
242 logger.warn('Error when requesting request id for ts:' + qs.ts + ' (' + key + ')', {redis_error: err}); 242 logger.warn('Error when requesting request id for ts:' + qs.ts + ' (' + key + ')', {redis_error: err});
243 return; 243 return;
244 } 244 }
245 245
246 callbackReport(request_id, response_code, message); 246 callbackReport(request_id, response_code, message);
247 }); 247 });
248 }); 248 });
249 249
250 httpServer.listen(config.h2h_out.listen_port, function() { 250 httpServer.listen(config.h2h_out.listen_port, function() {
251 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); 251 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
252 }); 252 });
253 } 253 }
254 254
255 function splitSN(sn, _config) { 255 function splitSN(sn, _config) {
256 var sn_pieces = sn.split(' '); 256 var sn_pieces = sn.split(' ');
257 257
258 if (sn_pieces.length <= 0) { 258 if (sn_pieces.length <= 0) {
259 logger.info('Returning original SN because SN only has one element'); 259 logger.info('Returning original SN because SN only has one element');
260 return sn; 260 return sn;
261 } 261 }
262 262
263 if (!_config.h2h_out.sn_split_index) { 263 if (!_config.h2h_out.sn_split_index) {
264 logger.info('Returning original SN because config.h2h_out.sn_split_index undefined'); 264 logger.info('Returning original SN because config.h2h_out.sn_split_index undefined');
265 return sn; 265 return sn;
266 } 266 }
267 var sn_indexes = _config.h2h_out.sn_split_index.split(','); 267 var sn_indexes = _config.h2h_out.sn_split_index.split(',');
268 268
269 logger.info('Split SN', {sn_pieces: sn_pieces, sn_indexes: sn_indexes}); 269 logger.info('Split SN', {sn_pieces: sn_pieces, sn_indexes: sn_indexes});
270 270
271 var _sn = ''; 271 var _sn = '';
272 272
273 var id_count = sn_indexes.length; 273 var id_count = sn_indexes.length;
274 for(var i = 0; i < id_count; i++) { 274 for(var i = 0; i < id_count; i++) {
275 275
276 var sn_index = sn_indexes[i]; 276 var sn_index = sn_indexes[i];
277 var sn_piece = sn_pieces[sn_index]; 277 var sn_piece = sn_pieces[sn_index];
278 278
279 if (sn_pieces[i]) { 279 if (sn_pieces[i]) {
280 _sn = _sn + sn_piece; 280 _sn = _sn + sn_piece;
281 } else { 281 } else {
282 logger.warn('Undefined value on sn piece ' + sn_index); 282 logger.warn('Undefined value on sn piece ' + sn_index);
283 } 283 }
284 } 284 }
285 285
286 _sn = _sn.trim(); 286 _sn = _sn.trim();
287 287
288 if (_sn) { 288 if (_sn) {
289 sn = _sn; 289 sn = _sn;
290 logger.info('Got new SN: ' + sn); 290 logger.info('Got new SN: ' + sn);
291 } else { 291 } else {
292 logger.warn('Got empty SN when using split SN. Use original SN'); 292 logger.warn('Got empty SN when using split SN. Use original SN');
293 } 293 }
294 294
295 return sn; 295 return sn;
296 } 296 }
297 297
298 function responseCodeFromMessage(message) { 298 function responseCodeFromMessage(message) {
299 if (message.indexOf('Nomor salah/tidak terdaftar') >= 0) { 299 if (message.indexOf('Nomor salah/tidak terdaftar') >= 0) {
300 return '14'; 300 return '14';
301 } 301 }
302 else if (message.indexOf('Nomor tidak di temukan/tidak aktif') >= 0) { 302 else if (message.indexOf('Nomor tidak di temukan/tidak aktif') >= 0) {
303 return '14'; 303 return '14';
304 } 304 }
305 else if (message.indexOf('Kode produk tidak sesuai nomor tujuan') >= 0) { 305 else if (message.indexOf('Kode produk tidak sesuai nomor tujuan') >= 0) {
306 return '14'; 306 return '14';
307 } 307 }
308 else if (message.indexOf('nomor yang anda masukan salah') >= 0) { 308 else if (message.indexOf('nomor yang anda masukan salah') >= 0) {
309 return '14'; 309 return '14';
310 } 310 }
311 else if (message.indexOf('Nomor Telepon seluler salah') >= 0) { 311 else if (message.indexOf('Nomor Telepon seluler salah') >= 0) {
312 return '14'; 312 return '14';
313 } 313 }
314 else if (message.indexOf('bulk or forbidden request') >= 0) { 314 else if (message.indexOf('bulk or forbidden request') >= 0) {
315 return '55'; 315 return '55';
316 } 316 }
317 else if (message.indexOf('Sudah pernah dilakukan') >= 0) { 317 else if (message.indexOf('Sudah pernah dilakukan') >= 0) {
318 return '55'; 318 return '55';
319 } 319 }
320 else if (message.indexOf('transaksi yg sama sudah pernah dilakukan tunggu dlm') >= 0) { 320 else if (message.indexOf('transaksi yg sama sudah pernah dilakukan tunggu dlm') >= 0) {
321 return '55'; 321 return '55';
322 } 322 }
323 else if (message.indexOf('Transaksi tsb sudah pernah dilakukan') >= 0) {
324 return '55';
325 }
323 else if (message.indexOf('Mohon maaf saat ini stock belum tersedia') >= 0) { 326 else if (message.indexOf('Mohon maaf saat ini stock belum tersedia') >= 0) {
324 return '13'; 327 return '13';
325 } 328 }
326 else if (message.indexOf('Stock tidak tersedia') >= 0) { 329 else if (message.indexOf('Stock tidak tersedia') >= 0) {
327 return '13'; 330 return '13';
328 } 331 }
329 else if (message.indexOf('Stok tidak tersedia') >= 0) { 332 else if (message.indexOf('Stok tidak tersedia') >= 0) {
330 return '13'; 333 return '13';
331 } 334 }
332 else if (message.indexOf('Saldo di account anda saat ini tidak mencukupi') >= 0) { 335 else if (message.indexOf('Saldo di account anda saat ini tidak mencukupi') >= 0) {
333 return '40'; 336 return '40';
334 } 337 }
335 338
336 return; 339 return;
337 } 340 }
338 341
339 function start(_config, _callbackReport, options) { 342 function start(_config, _callbackReport, options) {
340 config = _config; 343 config = _config;
341 callbackReport = _callbackReport 344 callbackReport = _callbackReport
342 345
343 if (options && options.aaa) { 346 if (options && options.aaa) {
344 aaa = options.aaa; 347 aaa = options.aaa;
345 } 348 }
346 349
347 if (options && options.logger) { 350 if (options && options.logger) {
348 logger = options.logger; 351 logger = options.logger;
349 } else { 352 } else {
350 logger = new winston.Logger({ 353 logger = new winston.Logger({
351 transports: [ 354 transports: [
352 new (winston.transports.Console)() 355 new (winston.transports.Console)()
353 ] 356 ]
354 }); 357 });
355 } 358 }
356 359
357 createRedisClient(); 360 createRedisClient();
358 createServer(); 361 createServer();
359 } 362 }
360 363
361 exports.start = start; 364 exports.start = start;
362 exports.topupRequest = topupRequest; 365 exports.topupRequest = topupRequest;
363 exports.parseSN = parseSN; 366 exports.parseSN = parseSN;
364 367