Commit 002f8976e2aa6628d65b45ebfcf997c93b2b972e
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 |