Commit 002f8976e2aa6628d65b45ebfcf997c93b2b972e

Authored by Adhidarma Hadiwinoto
1 parent 3b800bacd7
Exists in master

201 pending

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

partner-bayarkilat.js
1 var request = require('request'); 1 var request = require('request');
2 var url = require('url'); 2 var url = require('url');
3 var winston = require('winston'); 3 var winston = require('winston');
4 var xml2jsParser = require('xml2js').parseString; 4 var xml2jsParser = require('xml2js').parseString;
5 var redis = require('redis'); 5 var redis = require('redis');
6 6
7 var config; 7 var config;
8 var aaa; 8 var aaa;
9 var callbackReport; 9 var callbackReport;
10 var logger; 10 var logger;
11 var redisClient; 11 var redisClient;
12 12
13 var maxCheckRetry = 20; 13 var maxCheckRetry = 20;
14 var delayBeforeCheckRetry = 30 * 1000; 14 var delayBeforeCheckRetry = 30 * 1000;
15 15
16 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 16 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
17 17
18 function createRedisClient(host, port) { 18 function createRedisClient(host, port) {
19 try { 19 try {
20 redisClient = redis.createClient(port, host); 20 redisClient = redis.createClient(port, host);
21 } catch(err) { 21 } catch(err) {
22 logger.warn("Error creating redis client to " + host + ':' + port); 22 logger.warn("Error creating redis client to " + host + ':' + port);
23 } 23 }
24 } 24 }
25 25
26 function start(_config, _callbackReport, options) { 26 function start(_config, _callbackReport, options) {
27 config = _config; 27 config = _config;
28 callbackReport = _callbackReport; 28 callbackReport = _callbackReport;
29 29
30 if (options && options.aaa) { 30 if (options && options.aaa) {
31 aaa = options.aaa; 31 aaa = options.aaa;
32 } 32 }
33 33
34 if (options && options.logger) { 34 if (options && options.logger) {
35 logger = options.logger; 35 logger = options.logger;
36 } else { 36 } else {
37 logger = new winston.Logger({ 37 logger = new winston.Logger({
38 transports: [ 38 transports: [
39 new (winston.transports.Console)() 39 new (winston.transports.Console)()
40 ] 40 ]
41 }); 41 });
42 } 42 }
43 43
44 createRedisClient(config.globals.redis_host, config.globals.redis_port); 44 createRedisClient(config.globals.redis_host, config.globals.redis_port);
45 } 45 }
46 46
47 function createRequestOptions(methodName, task) { 47 function createRequestOptions(methodName, task) {
48 var partnerUrl = url.parse(config.h2h_out.partner); 48 var partnerUrl = url.parse(config.h2h_out.partner);
49 var product = prepareRemoteProductCode(task.remoteProduct); 49 var product = prepareRemoteProductCode(task.remoteProduct);
50 50
51 var destination = task.destination; 51 var destination = task.destination;
52 if (methodName == 'CHECKING') { 52 if (methodName == 'CHECKING') {
53 destination = paddingDestination(destination); 53 destination = paddingDestination(destination);
54 } 54 }
55 55
56 var options = { 56 var options = {
57 url: config.h2h_out.partner, 57 url: config.h2h_out.partner,
58 qs: { 58 qs: {
59 request: methodName + '*' 59 request: methodName + '*'
60 + task.requestId + '*' 60 + task.requestId + '*'
61 + product.product + '*' 61 + product.product + '*'
62 + product.productDetail + '*' 62 + product.productDetail + '*'
63 + destination + '*' 63 + destination + '*'
64 + product.nominal + '*' 64 + product.nominal + '*'
65 + '0*' 65 + '0*'
66 + config.h2h_out.noid + '*' 66 + config.h2h_out.noid + '*'
67 + config.h2h_out.userid + '*' 67 + config.h2h_out.userid + '*'
68 + config.h2h_out.password 68 + config.h2h_out.password
69 } 69 }
70 }; 70 };
71 71
72 return options; 72 return options;
73 } 73 }
74 74
75 function topupCheck(task, _retry) { 75 function topupCheck(task, _retry) {
76 var retry = _retry; 76 var retry = _retry;
77 77
78 if (retry === null || retry === undefined) { 78 if (retry === null || retry === undefined) {
79 retry = maxCheckRetry + 1; 79 retry = maxCheckRetry + 1;
80 } 80 }
81 81
82 retry = retry - 1; 82 retry = retry - 1;
83 83
84 if (retry < 0) { 84 if (retry < 0) {
85 var message = 'Max retry check transaction retry exceeded'; 85 var message = 'Max retry check transaction retry exceeded';
86 var response = { 86 var response = {
87 raw: message, 87 raw: message,
88 parsed: { 88 parsed: {
89 MESSAGE: message 89 MESSAGE: message
90 } 90 }
91 } 91 }
92 aaa.pushResponseToMongoDb(task, response, '68'); 92 aaa.pushResponseToMongoDb(task, response, '68');
93 callbackReport(task.requestId, '68', message); 93 callbackReport(task.requestId, '68', message);
94 return; 94 return;
95 } 95 }
96 96
97 requestToPartner('CHECKING', task, retry); 97 requestToPartner('CHECKING', task, retry);
98 } 98 }
99 99
100 function topupRequest(task) { 100 function topupRequest(task) {
101 if (!aaa.isTodayTrx(task)) { 101 if (!aaa.isTodayTrx(task)) {
102 logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan'); 102 logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan');
103 callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan'); 103 callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan');
104 return; 104 return;
105 } 105 }
106 106
107 getTaskForDupeCheck(task, function(err, dupeTask) { 107 getTaskForDupeCheck(task, function(err, dupeTask) {
108 if (dupeTask) { 108 if (dupeTask) {
109 logger.info('Duplicate task detected, requesting topupCheck', {task: task}); 109 logger.info('Duplicate task detected, requesting topupCheck', {task: task});
110 topupCheck(task); 110 topupCheck(task);
111 } else { 111 } else {
112 saveTaskForDupeCheck(task); 112 saveTaskForDupeCheck(task);
113 requestToPartner('PURCHASE', task); 113 requestToPartner('PURCHASE', task);
114 } 114 }
115 }); 115 });
116 116
117 } 117 }
118 118
119 function requestToPartner(methodName, task, retry) { 119 function requestToPartner(methodName, task, retry) {
120 aaa.insertTaskToMongoDb(task); 120 aaa.insertTaskToMongoDb(task);
121 121
122 var options = createRequestOptions(methodName, task); 122 var options = createRequestOptions(methodName, task);
123 123
124 logger.info('Requesting to partner', {requestOption: options}); 124 logger.info('Requesting to partner', {requestOption: options});
125 request(options, function(error, response, body) { 125 request(options, function(error, response, body) {
126 if (error) { 126 if (error) {
127 var msg = 'Error requesting to partner. ' + error; 127 var msg = 'Error requesting to partner. ' + error;
128 var rc = '68'; 128 var rc = '68';
129 129
130 try { 130 try {
131 if (methodName == 'PURCHASE') { 131 if (methodName == 'PURCHASE') {
132 if ((error.connect === true || error.syscall == "connect") && (error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED')) { 132 if ((error.connect === true || error.syscall == "connect") && (error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED')) {
133 rc = '40'; 133 rc = '40';
134 } 134 }
135 } 135 }
136 } 136 }
137 catch(e) { 137 catch(e) {
138 logger.warn('Parsing error exception on requestToPartner()'); 138 logger.warn('Parsing error exception on requestToPartner()');
139 } 139 }
140 140
141 logger.warn(msg, {error: error}); 141 logger.warn(msg, {error: error});
142 callbackReport(task.requestId, rc, msg); 142 callbackReport(task.requestId, rc, msg);
143 143
144 var _response = { 144 var _response = {
145 raw: JSON.stringify({msg: msg, error: error}), 145 raw: JSON.stringify({msg: msg, error: error}),
146 parsed: { 146 parsed: {
147 MESSAGE: msg, 147 MESSAGE: msg,
148 error: error 148 error: error
149 } 149 }
150 } 150 }
151 aaa.pushResponseToMongoDb(task, _response, rc); 151 aaa.pushResponseToMongoDb(task, _response, rc);
152 152
153 if (rc == '68') { 153 if (rc == '68') {
154 setTimeout( 154 setTimeout(
155 topupCheck, 155 topupCheck,
156 delayBeforeCheckRetry, 156 delayBeforeCheckRetry,
157 task, 157 task,
158 retry 158 retry
159 ); 159 );
160 } 160 }
161 161
162 return; 162 return;
163 } 163 }
164 164
165 if (response.statusCode != 200) { 165 if (response.statusCode != 200) {
166 var message = 'Partner response with http status code other that 200 (' + response.statusCode + ')'; 166 var message = 'Partner response with http status code other that 200 (' + response.statusCode + ')';
167 var rc = '68'; 167 var rc = '68';
168 168
169 if (!retry && response.statusCode == 404) { 169 if (!retry && response.statusCode == 404) {
170 rc = '91'; 170 rc = '91';
171 } 171 }
172 172
173 logger.warn(message); 173 logger.warn(message);
174 callbackReport(task.requestId, rc, message); 174 callbackReport(task.requestId, rc, message);
175 175
176 var _response = { 176 var _response = {
177 raw: message, 177 raw: message,
178 parsed: { 178 parsed: {
179 MESSAGE: message, 179 MESSAGE: message,
180 responseHttpStatus: response.statusCode, 180 responseHttpStatus: response.statusCode,
181 responseBody: body, 181 responseBody: body,
182 } 182 }
183 } 183 }
184 aaa.pushResponseToMongoDb(task, _response, rc); 184 aaa.pushResponseToMongoDb(task, _response, rc);
185 185
186 if (rc == '68') { 186 if (rc == '68') {
187 setTimeout( 187 setTimeout(
188 topupCheck, 188 topupCheck,
189 delayBeforeCheckRetry, 189 delayBeforeCheckRetry,
190 task, 190 task,
191 retry 191 retry
192 ); 192 );
193 } 193 }
194 194
195 return; 195 return;
196 } 196 }
197 197
198 logger.verbose('Got respose', {rawBody: body}); 198 logger.verbose('Got respose', {rawBody: body});
199 parseResponse(body, task); 199 parseResponse(body, task);
200 }); 200 });
201 } 201 }
202 202
203 function getSn(response) { 203 function getSn(response) {
204 try { 204 try {
205 var sn = response.xml.ket1[0]; 205 var sn = response.xml.ket1[0];
206 return sn; 206 return sn;
207 } 207 }
208 catch (err) { 208 catch (err) {
209 return; 209 return;
210 } 210 }
211 } 211 }
212 212
213 function getHarga(response) { 213 function getHarga(response) {
214 try { 214 try {
215 var harga = response.xml.amount[0]; 215 var harga = response.xml.amount[0];
216 return harga; 216 return harga;
217 } 217 }
218 catch (err) { 218 catch (err) {
219 return; 219 return;
220 } 220 }
221 } 221 }
222 222
223 function getSaldo(response) { 223 function getSaldo(response) {
224 try { 224 try {
225 var saldo = response.xml.saldo[0]; 225 var saldo = response.xml.saldo[0];
226 return saldo; 226 return saldo;
227 } 227 }
228 catch (err) { 228 catch (err) {
229 return; 229 return;
230 } 230 }
231 } 231 }
232 232
233 function parseResponse(body, task) { 233 function parseResponse(body, task) {
234 xml2jsParser(body, function(err, response) { 234 xml2jsParser(body, function(err, response) {
235 if (err) { 235 if (err) {
236 logger.warn('Error parsing XML', {error: err, task: task, responseBody: body}); 236 logger.warn('Error parsing XML', {error: err, task: task, responseBody: body});
237 237
238 var message = 'Error parsing XML. ' + err + '. ' + body; 238 var message = 'Error parsing XML. ' + err + '. ' + body;
239 239
240 var _response = { 240 var _response = {
241 raw: body, 241 raw: body,
242 parsed: { 242 parsed: {
243 MESSAGE: message 243 MESSAGE: message
244 } 244 }
245 } 245 }
246 aaa.pushResponseToMongoDb(task, _response, '68'); 246 aaa.pushResponseToMongoDb(task, _response, '68');
247 247
248 callbackReport(task.requestId, '68', message); 248 callbackReport(task.requestId, '68', message);
249 return; 249 return;
250 } 250 }
251 251
252 logger.info('Got response', {response: response}); 252 logger.info('Got response', {response: response});
253 253
254 var responseCode; 254 var responseCode;
255 var message; 255 var message;
256 256
257 try { 257 try {
258 responseCode = response.xml.response_code[0]; 258 responseCode = response.xml.response_code[0];
259 message = response.xml.response_message[0]; 259 message = response.xml.response_message[0];
260 } 260 }
261 catch(errGetParam) { 261 catch(errGetParam) {
262 logger.warn('Exception saat parsing hasil', {error: errGetParam, task: task, responseBody: body}); 262 logger.warn('Exception saat parsing hasil', {error: errGetParam, task: task, responseBody: body});
263 263
264 var _response = { 264 var _response = {
265 raw: body, 265 raw: body,
266 parsed: { 266 parsed: {
267 MESSAGE: 'Exception saat parsing hasil. ' + errGetParam, 267 MESSAGE: 'Exception saat parsing hasil. ' + errGetParam,
268 xml: response.xml 268 xml: response.xml
269 } 269 }
270 } 270 }
271 aaa.pushResponseToMongoDb(task, _response, '68'); 271 aaa.pushResponseToMongoDb(task, _response, '68');
272 272
273 callbackReport(task.requestId, '68', 'Exception saat parsing hasil. ' + errGetParam); 273 callbackReport(task.requestId, '68', 'Exception saat parsing hasil. ' + errGetParam);
274 return; 274 return;
275 } 275 }
276 276
277 var st24rc; 277 var st24rc;
278 if (parseInt(responseCode) == 0) { 278 if (parseInt(responseCode) == 0) {
279 st24rc = '00'; 279 st24rc = '00';
280 } 280 }
281 else if (parseInt(responseCode) == '99') { 281 else if (parseInt(responseCode) == '99') {
282 st24rc = '68' 282 st24rc = '68'
283 } 283 }
284 else if (parseInt(responseCode) == '201') {
285 st24rc = '68'
286 }
287 else if (message.indexOf('Transaksi sedang dalam proses') >= 0) {
288 st24rc = '68';
289 }
284 else { 290 else {
285 st24rc = '40'; 291 st24rc = '40';
286 } 292 }
287 293
288 var st24message = message; 294 var st24message = message;
289 if (responseCode) { 295 if (responseCode) {
290 st24message = responseCode + ' ' + st24message; 296 st24message = responseCode + ' ' + st24message;
291 } 297 }
292 298
293 if (st24rc == '00') { 299 if (st24rc == '00') {
294 var sn = getSn(response); 300 var sn = getSn(response);
295 301
296 if (sn) { 302 if (sn) {
297 st24message = 'SN=' + sn + ';' + st24message + '. SN=' + sn; 303 st24message = 'SN=' + sn + ';' + st24message + '. SN=' + sn;
298 } 304 }
299 } 305 }
300 306
301 var harga = getHarga(response); 307 var harga = getHarga(response);
302 if (harga) { 308 if (harga) {
303 st24message = st24message + '. Harga ' + harga; 309 st24message = st24message + '. Harga ' + harga;
304 } 310 }
305 311
306 var saldo = getSaldo(response); 312 var saldo = getSaldo(response);
307 if (saldo) { 313 if (saldo) {
308 st24message = st24message + '. Saldo ' + saldo; 314 st24message = st24message + '. Saldo ' + saldo;
309 aaa.updateBalance(saldo); 315 aaa.updateBalance(saldo);
310 } 316 }
311 317
312 var _response = { 318 var _response = {
313 raw: body, 319 raw: body,
314 parsed: { 320 parsed: {
315 MESSAGE: st24message, 321 MESSAGE: st24message,
316 xml: response.xml 322 xml: response.xml
317 } 323 }
318 } 324 }
319 325
320 aaa.pushResponseToMongoDb(task, _response, st24rc); 326 aaa.pushResponseToMongoDb(task, _response, st24rc);
321 327
322 callbackReport(task.requestId, st24rc, st24message); 328 callbackReport(task.requestId, st24rc, st24message);
323 }); 329 });
324 } 330 }
325 331
326 function prepareRemoteProductCode(remoteProduct) { 332 function prepareRemoteProductCode(remoteProduct) {
327 var product = remoteProduct.split(','); 333 var product = remoteProduct.split(',');
328 334
329 if (product.length != 3) { 335 if (product.length != 3) {
330 return; 336 return;
331 } 337 }
332 338
333 return { 339 return {
334 product: product[0], 340 product: product[0],
335 productDetail: product[1], 341 productDetail: product[1],
336 nominal: product[2] 342 nominal: product[2]
337 } 343 }
338 } 344 }
339 345
340 function paddingDestination(destination, _width) { 346 function paddingDestination(destination, _width) {
341 var width = _width; 347 var width = _width;
342 if (!width) { 348 if (!width) {
343 width = 13; 349 width = 13;
344 } 350 }
345 351
346 if (destination.length > width) { 352 if (destination.length > width) {
347 return destination; 353 return destination;
348 } 354 }
349 355
350 var padder = "000000000000000000000000000"; 356 var padder = "000000000000000000000000000";
351 357
352 return (padder + destination).slice(-1 * width); 358 return (padder + destination).slice(-1 * width);
353 } 359 }
354 360
355 function getTaskKeyForDupeCheck(task) { 361 function getTaskKeyForDupeCheck(task) {
356 return config.globals.gateway_name + '.dupecheck.reqId:' + task.requestId; 362 return config.globals.gateway_name + '.dupecheck.reqId:' + task.requestId;
357 } 363 }
358 364
359 function saveTaskForDupeCheck(task, cb) { 365 function saveTaskForDupeCheck(task, cb) {
360 var key = getTaskKeyForDupeCheck(task); 366 var key = getTaskKeyForDupeCheck(task);
361 367
362 logger.verbose('Saving ' + key + ' to redis for dupecheck protection'); 368 logger.verbose('Saving ' + key + ' to redis for dupecheck protection');
363 369
364 redisClient.set(key, JSON.stringify(task), function() { 370 redisClient.set(key, JSON.stringify(task), function() {
365 redisClient.expire(key, 3600*24*7); 371 redisClient.expire(key, 3600*24*7);
366 if (cb) { 372 if (cb) {
367 cb(null, task); 373 cb(null, task);
368 } 374 }
369 }); 375 });
370 } 376 }
371 377
372 function getTaskForDupeCheck(task, cb) { 378 function getTaskForDupeCheck(task, cb) {
373 var key = getTaskKeyForDupeCheck(task); 379 var key = getTaskKeyForDupeCheck(task);
374 380
375 redisClient.get(key, function(err, result) { 381 redisClient.get(key, function(err, result) {
376 if (err) { 382 if (err) {
377 cb(err, null); 383 cb(err, null);
378 return; 384 return;
379 } 385 }
380 386
381 var taskOnRedis = null; 387 var taskOnRedis = null;
382 try { 388 try {
383 taskOnRedis = JSON.parse(result); 389 taskOnRedis = JSON.parse(result);
384 } 390 }
385 catch(err1) { 391 catch(err1) {
386 cb(err1, null); 392 cb(err1, null);
387 return; 393 return;
388 } 394 }
389 395
390 cb(null, taskOnRedis); 396 cb(null, taskOnRedis);
391 }); 397 });
392 } 398 }
393 399
394 exports.start = start; 400 exports.start = start;
395 exports.topupRequest = topupRequest; 401 exports.topupRequest = topupRequest;
396 exports.prepareRemoteProductCode = prepareRemoteProductCode; 402 exports.prepareRemoteProductCode = prepareRemoteProductCode;
397 exports.paddingDestination = paddingDestination; 403 exports.paddingDestination = paddingDestination;
398 404