Commit f2554d11a42f34eb1b58c823dbf92938f48162f3

Authored by Adhidarma Hadiwinoto
1 parent 4e7bd6d333
Exists in master

penanganan http 404

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