Commit 1cdb39dd784df47208e45fcc3c22ac2ecf8d20d3

Authored by Adhidarma Hadiwinoto
1 parent cd70b1f414
Exists in master

topupCheck on duplicate

Showing 2 changed files with 66 additions and 1 deletions Inline Diff

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