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