Commit aa14700d874b6c0e7d4d32b01978ec53d1873572

Authored by Adhidarma Hadiwinoto
1 parent 810851055a
Exists in master

insertTaskToMongoDb dan callbackReportWithPushToMongoDb

Showing 2 changed files with 21 additions and 6 deletions Inline Diff

1 var fs = require('fs'); 1 var fs = require('fs');
2 var ini = require('ini'); 2 var ini = require('ini');
3 var expresso = require('sate24-expresso'); 3 var expresso = require('sate24-expresso');
4 var config = ini.parse(fs.readFileSync(__dirname + '/config.ini', 'utf-8')); 4 var config = ini.parse(fs.readFileSync(__dirname + '/config.ini', 'utf-8'));
5 5
6 process.chdir(__dirname); 6 process.chdir(__dirname);
7 7
8 var logger = require('sate24/logger.js').start(); 8 var logger = require('sate24/logger.js').start();
9 var HttpServer = require('sate24/httpserver.js'); 9 var HttpServer = require('sate24/httpserver.js');
10 var aaa = require('sate24/aaa.js'); 10 var aaa = require('sate24/aaa.js');
11 var partner = require('./partner-masterpulsa-voucher.js'); 11 var partner = require('./partner-masterpulsa-voucher.js');
12 12
13 var matrix = aaa.prepareMatrix(); 13 var matrix = aaa.prepareMatrix();
14 14
15 var options = { 15 var options = {
16 'aaa': aaa, 16 'aaa': aaa,
17 'logger': logger, 17 'logger': logger,
18 'config': config, 18 'config': config,
19 'matrix': matrix, 19 'matrix': matrix,
20 } 20 }
21 21
22 var httpServer = HttpServer.start(config, options); 22 var httpServer = HttpServer.start(config, options);
23 23
24 partner.start(config, aaa.callbackReport, options); 24 partner.start(options);
25 aaa.start(config, partner, options); 25 aaa.start(config, partner, options);
26 expresso.start(options); 26 expresso.start(options);
27 27
partner-masterpulsa-voucher.js
1 var winston = require('winston'); 1 var winston = require('winston');
2 var request = require('request'); 2 var request = require('request');
3 var strftime = require('strftime'); 3 var strftime = require('strftime');
4 var crypto = require('crypto'); 4 var crypto = require('crypto');
5 var redis = require('redis'); 5 var redis = require('redis');
6 6
7 var config; 7 var config;
8 var callbackReport; 8 var callbackReport;
9 var aaa; 9 var aaa;
10 var logger; 10 var logger;
11 var options; 11 var options;
12 var redisClient; 12 var redisClient;
13 13
14 var adviceDelay = 30000; 14 var adviceDelay = 30000;
15 15
16 function callbackReportWrapper(requestId, rc, message) { 16 function callbackReportWrapper(requestId, rc, message) {
17 try { 17 try {
18 message = message.replace(/:/g, ' ').replace(/#/g, ' '); 18 message = message.replace(/:/g, ' ').replace(/#/g, ' ');
19 message = message.replace(/\s+/g, ' '); 19 message = message.replace(/\s+/g, ' ');
20 } 20 }
21 catch(err) { 21 catch(err) {
22 if (logger) { 22 if (logger) {
23 logger.warn('Exception on callbackReportWrapper: ' + err); 23 logger.warn('Exception on callbackReportWrapper: ' + err);
24 } 24 }
25 } 25 }
26 26
27 if (rc != '00' && rc != '68') { 27 if (rc != '00' && rc != '68') {
28 try { 28 try {
29 var key = dupcheckKey(config.globals.gateway_name, task); 29 var key = dupcheckKey(config.globals.gateway_name, task);
30 redisClient.del(key); 30 redisClient.del(key);
31 } 31 }
32 catch(delErr) { 32 catch(delErr) {
33 } 33 }
34 } 34 }
35 35
36 callbackReport(requestId, rc, message); 36 callbackReport(requestId, rc, message);
37 } 37 }
38 38
39 function createRedisClient() { 39 function createRedisClient() {
40 redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host); 40 redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host);
41 } 41 }
42 42
43 function start(_config, _callbackReport, options) { 43 function start(options) {
44 config = _config; 44 if (!options) {
45 callbackReport = _callbackReport 45 console.log('Undefined options, terminating....');
46 process.exit(1);
47 }
48
49 if (options.config) {
50 config = options.config;
51 } else {
52 console.log('Undefined options.config, terminating....')
53 process.exit(1);
54 }
46 55
47 if (options && options.aaa) { 56 if (options.aaa) {
48 aaa = options.aaa; 57 aaa = options.aaa;
58 callbackReport = options.aaa.callbackReportWithPushToMongoDb;
59 } else {
60 console.log('Undefined options.aaa, terminating....')
61 process.exit(1);
49 } 62 }
50 63
51 if (options && options.logger) { 64 if (options && options.logger) {
52 logger = options.logger; 65 logger = options.logger;
53 } else { 66 } else {
54 logger = new winston.Logger({ 67 logger = new winston.Logger({
55 transports: [ 68 transports: [
56 new (winston.transports.Console)() 69 new (winston.transports.Console)()
57 ] 70 ]
58 }); 71 });
59 } 72 }
60 73
61 createRedisClient(); 74 createRedisClient();
62 } 75 }
63 76
64 function getRedisKey(task) { 77 function getRedisKey(task) {
65 return config.globals.gateway_name + '.tid:' + task.requestId; 78 return config.globals.gateway_name + '.tid:' + task.requestId;
66 } 79 }
67 80
68 function dupcheckKey(gatewayName, task) { 81 function dupcheckKey(gatewayName, task) {
69 return 'DUPCHECK.gw:' + gatewayName + '.prod:' + task.remoteProduct + '.dest:' + task.destination + '.date:' + strftime('%Y%m%d', new Date); 82 return 'DUPCHECK.gw:' + gatewayName + '.prod:' + task.remoteProduct + '.dest:' + task.destination + '.date:' + strftime('%Y%m%d', new Date);
70 } 83 }
71 84
72 function topupRequest(task, retry) { 85 function topupRequest(task, retry) {
86 aaa.insertTaskToMongoDb(task);
87
73 var key = dupcheckKey(config.globals.gateway_name, task); 88 var key = dupcheckKey(config.globals.gateway_name, task);
74 89
75 redisClient.get(key, function(err, data) { 90 redisClient.get(key, function(err, data) {
76 if (err) { 91 if (err) {
77 callbackReportWrapper(task.requestId, '40', 'Gagal cek anti transaksi duplikat (redis error)'); 92 callbackReportWrapper(task.requestId, '40', 'Gagal cek anti transaksi duplikat (redis error)');
78 return; 93 return;
79 } 94 }
80 95
81 if (!data) { 96 if (!data) {
82 logger.verbose('Belum ada trx dengan tujuan dan denom yang sama pada hari ini. Lanjutkan.'); 97 logger.verbose('Belum ada trx dengan tujuan dan denom yang sama pada hari ini. Lanjutkan.');
83 98
84 redisClient.set(key, JSON.stringify(task)); 99 redisClient.set(key, JSON.stringify(task));
85 redisClient.expire(key, 3600 * 24 * 2); 100 redisClient.expire(key, 3600 * 24 * 2);
86 101
87 voucherPay(task, retry); 102 voucherPay(task, retry);
88 103
89 } else { 104 } else {
90 105
91 try { 106 try {
92 var taskOnRedis = JSON.parse(data); 107 var taskOnRedis = JSON.parse(data);
93 if (task.requestId == taskOnRedis.requestId) { 108 if (task.requestId == taskOnRedis.requestId) {
94 logger.verbose('Sudah ada trx dengan tujuan dan denom yg sama, requestId jg sama. Lanjutkan dengan advice.') 109 logger.verbose('Sudah ada trx dengan tujuan dan denom yg sama, requestId jg sama. Lanjutkan dengan advice.')
95 advice(task, retry); 110 advice(task, retry);
96 } else { 111 } else {
97 logger.verbose('Sudah ada trx dengan tujuan dan denom yg sama, requestId tidak sama. Batalkan.') 112 logger.verbose('Sudah ada trx dengan tujuan dan denom yg sama, requestId tidak sama. Batalkan.')
98 callbackReportWrapper(task.requestId, '55', 'Transaksi duplikat') 113 callbackReportWrapper(task.requestId, '55', 'Transaksi duplikat')
99 } 114 }
100 } 115 }
101 catch(errJSONParse) { 116 catch(errJSONParse) {
102 callbackReportWrapper(task.requestId, '68', "error parsing json"); 117 callbackReportWrapper(task.requestId, '68', "error parsing json");
103 } 118 }
104 } 119 }
105 }); 120 });
106 } 121 }
107 122
108 function calculateSignature(cid, secret, dt) { 123 function calculateSignature(cid, secret, dt) {
109 return crypto.createHash('sha256').update(cid + dt + secret).digest().toString('hex'); 124 return crypto.createHash('sha256').update(cid + dt + secret).digest().toString('hex');
110 } 125 }
111 126
112 function parsePaymentResponse(message) { 127 function parsePaymentResponse(message) {
113 var data = message.split('#'); 128 var data = message.split('#');
114 var retval = {}; 129 var retval = {};
115 130
116 if (data[0] == 'ERROR') { 131 if (data[0] == 'ERROR') {
117 retval = { 132 retval = {
118 status: data[0], 133 status: data[0],
119 rc: data[1], 134 rc: data[1],
120 rcmessage: data[2], 135 rcmessage: data[2],
121 } 136 }
122 137
123 } else { 138 } else {
124 139
125 var i = 0; 140 var i = 0;
126 retval = { 141 retval = {
127 status: data[i++], 142 status: data[i++],
128 rc: data[i++], 143 rc: data[i++],
129 rcmessage: data[i++], 144 rcmessage: data[i++],
130 resptext: data[i++], 145 resptext: data[i++],
131 dt: data[i++], 146 dt: data[i++],
132 refnum: data[i++], 147 refnum: data[i++],
133 voucherid: data[i++], 148 voucherid: data[i++],
134 nominal: data[i++] 149 nominal: data[i++]
135 } 150 }
136 151
137 try { 152 try {
138 retval.sn = data[9]; 153 retval.sn = data[9];
139 } 154 }
140 catch(err) { 155 catch(err) {
141 retval.sn = null; 156 retval.sn = null;
142 } 157 }
143 158
144 if (!retval.sn) { 159 if (!retval.sn) {
145 retval.sn = rehashRefnum(retval.refnum); 160 retval.sn = rehashRefnum(retval.refnum);
146 } 161 }
147 } 162 }
148 163
149 retval.raw = message; 164 retval.raw = message;
150 165
151 return retval; 166 return retval;
152 } 167 }
153 168
154 function rehashRefnum(refnum) { 169 function rehashRefnum(refnum) {
155 var hashed = refnum.replace(/^0+/, ''); 170 var hashed = refnum.replace(/^0+/, '');
156 171
157 try { 172 try {
158 hashed = hashed.replace(/A/g, '1').replace(/B/g, '2').replace(/C/g, '3').replace(/D/g, '4').replace(/E/g, '5').replace(/F/g, '6'); 173 hashed = hashed.replace(/A/g, '1').replace(/B/g, '2').replace(/C/g, '3').replace(/D/g, '4').replace(/E/g, '5').replace(/F/g, '6');
159 hashed = hashed.substring(0, 20); 174 hashed = hashed.substring(0, 20);
160 } 175 }
161 catch(err) { 176 catch(err) {
162 logger.warn('Gagal rehashRefnum: ' + err); 177 logger.warn('Gagal rehashRefnum: ' + err);
163 hashed = refnum; 178 hashed = refnum;
164 } 179 }
165 return hashed; 180 return hashed;
166 } 181 }
167 182
168 function reportPaymentSuccess(task, response) { 183 function reportPaymentSuccess(task, response) {
169 var message = 'SN=' + response.sn + '; ' + response.raw; 184 var message = 'SN=' + response.sn + '; ' + response.raw;
170 185
171 logger.info('Report payment success to ST24', {task: task, response: response}); 186 logger.info('Report payment success to ST24', {task: task, response: response});
172 187
173 callbackReportWrapper(task.requestId, '00', message); 188 callbackReportWrapper(task.requestId, '00', message);
174 } 189 }
175 190
176 function reportPaymentError(task, response) { 191 function reportPaymentError(task, response) {
177 var errorCode = getErrorCode(response.rcmessage); 192 var errorCode = getErrorCode(response.rcmessage);
178 var st24rc = getST24ResponseCode(errorCode); 193 var st24rc = getST24ResponseCode(errorCode);
179 194
180 if (st24rc == '68') { 195 if (st24rc == '68') {
181 logger.info('Got pending response, requesting advice in ' + adviceDelay + 'ms', {task: task, response: response}); 196 logger.info('Got pending response, requesting advice in ' + adviceDelay + 'ms', {task: task, response: response});
182 setTimeout(advice, adviceDelay, task); 197 setTimeout(advice, adviceDelay, task);
183 } 198 }
184 199
185 logger.info('Report payment error/pending to ST24', {supplier_rc: errorCode, st24_rc: st24rc, task: task, response: response}); 200 logger.info('Report payment error/pending to ST24', {supplier_rc: errorCode, st24_rc: st24rc, task: task, response: response});
186 201
187 callbackReportWrapper( 202 callbackReportWrapper(
188 task.requestId, 203 task.requestId,
189 getST24ResponseCode(errorCode), 204 getST24ResponseCode(errorCode),
190 response.raw 205 response.raw
191 ); 206 );
192 } 207 }
193 208
194 function getST24ResponseCode(supplierResponseCode) { 209 function getST24ResponseCode(supplierResponseCode) {
195 var st24rc = '40'; 210 var st24rc = '40';
196 211
197 if (supplierResponseCode.length == 1) { 212 if (supplierResponseCode.length == 1) {
198 supplierResponseCode = '0' + supplierResponseCode; 213 supplierResponseCode = '0' + supplierResponseCode;
199 } 214 }
200 215
201 if (supplierResponseCode == '05') { 216 if (supplierResponseCode == '05') {
202 st24rc = '40'; 217 st24rc = '40';
203 } 218 }
204 else if (['00', '13', '14', '47', '68'].indexOf(supplierResponseCode) >= 0) { 219 else if (['00', '13', '14', '47', '68'].indexOf(supplierResponseCode) >= 0) {
205 st24rc = supplierResponseCode; 220 st24rc = supplierResponseCode;
206 } 221 }
207 else if (['15', '56'].indexOf(supplierResponseCode) >= 0) { 222 else if (['15', '56'].indexOf(supplierResponseCode) >= 0) {
208 // nomor tidak valid 223 // nomor tidak valid
209 st24rc = '14'; 224 st24rc = '14';
210 } 225 }
211 else if (['18', '63', '68'].indexOf(supplierResponseCode) >= 0) { 226 else if (['18', '63', '68'].indexOf(supplierResponseCode) >= 0) {
212 st24rc = '68'; 227 st24rc = '68';
213 } 228 }
214 else if (supplierResponseCode == '67') { 229 else if (supplierResponseCode == '67') {
215 st24rc = '91' 230 st24rc = '91'
216 } 231 }
217 else if (supplierResponseCode == '46') { 232 else if (supplierResponseCode == '46') {
218 st24rc = '40' 233 st24rc = '40'
219 234
220 if (aaa && config && config.globals && config.globals.pause_on_not_enough_balance 235 if (aaa && config && config.globals && config.globals.pause_on_not_enough_balance
221 && (config.globals.pause_on_not_enough_balance == '1')) { 236 && (config.globals.pause_on_not_enough_balance == '1')) {
222 237
223 logger.warn('Not enough balance detected. Going to pause the system.'); 238 logger.warn('Not enough balance detected. Going to pause the system.');
224 aaa.pause(); 239 aaa.pause();
225 } 240 }
226 } 241 }
227 242
228 return st24rc; 243 return st24rc;
229 } 244 }
230 245
231 function getErrorCode(rcmessage) { 246 function getErrorCode(rcmessage) {
232 try { 247 try {
233 var errorCode = rcmessage.match(/\[(\d+)\]/); 248 var errorCode = rcmessage.match(/\[(\d+)\]/);
234 return errorCode[1]; 249 return errorCode[1];
235 } 250 }
236 catch(err) { 251 catch(err) {
237 logger.warn('Empty RCMESSAGE, returning 68 as RC for safety'); 252 logger.warn('Empty RCMESSAGE, returning 68 as RC for safety');
238 return '68'; 253 return '68';
239 } 254 }
240 } 255 }
241 256
242 function generateDt(taskTimestamp) { 257 function generateDt(taskTimestamp) {
243 if (!taskTimestamp) { 258 if (!taskTimestamp) {
244 return strftime('%Y%m%d', new Date()); 259 return strftime('%Y%m%d', new Date());
245 } 260 }
246 261
247 return taskTimestamp.slice(0, 8); 262 return taskTimestamp.slice(0, 8);
248 } 263 }
249 264
250 function generateRequestOptions(userid, password, partnerUrl, task) { 265 function generateRequestOptions(userid, password, partnerUrl, task) {
251 var dt = generateDt(task.timestamp); 266 var dt = generateDt(task.timestamp);
252 var sign = calculateSignature(userid, password, dt); 267 var sign = calculateSignature(userid, password, dt);
253 268
254 var requestOptions = { 269 var requestOptions = {
255 method: 'GET', 270 method: 'GET',
256 url: partnerUrl, 271 url: partnerUrl,
257 qs: { 272 qs: {
258 modul: '', 273 modul: '',
259 command: '', 274 command: '',
260 tujuan: task['destination'], 275 tujuan: task['destination'],
261 voucherid: task['remoteProduct'], 276 voucherid: task['remoteProduct'],
262 cid: userid, 277 cid: userid,
263 dt: dt, 278 dt: dt,
264 hc: sign, 279 hc: sign,
265 trxid: task['requestId'], 280 trxid: task['requestId'],
266 } 281 }
267 } 282 }
268 283
269 return requestOptions; 284 return requestOptions;
270 } 285 }
271 286
272 function advice(task, retry) { 287 function advice(task, retry) {
273 288
274 if (retry === null || retry === undefined) { 289 if (retry === null || retry === undefined) {
275 retry = 10; 290 retry = 10;
276 } 291 }
277 292
278 var requestOptions = generateRequestOptions(config.h2h_out.userid, config.h2h_out.password, config.h2h_out.partner, task); 293 var requestOptions = generateRequestOptions(config.h2h_out.userid, config.h2h_out.password, config.h2h_out.partner, task);
279 294
280 requestOptions.qs.modul = 'ISI'; 295 requestOptions.qs.modul = 'ISI';
281 requestOptions.qs.command = 'ADV'; 296 requestOptions.qs.command = 'ADV';
282 297
283 logger.info('Requesting advice to supplier', {requestOptions: requestOptions}); 298 logger.info('Requesting advice to supplier', {requestOptions: requestOptions});
284 request(requestOptions, function(requestError, requestResponse, requestResponseBody) { 299 request(requestOptions, function(requestError, requestResponse, requestResponseBody) {
285 if (requestError || requestResponse.statusCode != 200) { 300 if (requestError || requestResponse.statusCode != 200) {
286 logger.warn('Advice error', {error: requestError, http_response: requestResponse.statusCode}); 301 logger.warn('Advice error', {error: requestError, http_response: requestResponse.statusCode});
287 302
288 if (retry > 0) { 303 if (retry > 0) {
289 logger.warn('Going to retry advice in ' + adviceDelay + 'ms', {task: task, retry: retry}); 304 logger.warn('Going to retry advice in ' + adviceDelay + 'ms', {task: task, retry: retry});
290 setTimeout(advice, adviceDelay, task, --retry); 305 setTimeout(advice, adviceDelay, task, --retry);
291 } 306 }
292 307
293 return; 308 return;
294 } 309 }
295 310
296 var paymentResponse = parsePaymentResponse(requestResponseBody); 311 var paymentResponse = parsePaymentResponse(requestResponseBody);
297 logger.info('Got advice payment response', {paymentResponse: paymentResponse}); 312 logger.info('Got advice payment response', {paymentResponse: paymentResponse});
298 313
299 if (paymentResponse.status == 'SUCCESS') { 314 if (paymentResponse.status == 'SUCCESS') {
300 reportPaymentSuccess(task, paymentResponse); 315 reportPaymentSuccess(task, paymentResponse);
301 } 316 }
302 else { 317 else {
303 reportPaymentError(task, paymentResponse); 318 reportPaymentError(task, paymentResponse);
304 } 319 }
305 }); 320 });
306 321
307 } 322 }
308 323
309 function voucherPay(task) { 324 function voucherPay(task) {
310 var requestOptions = generateRequestOptions(config.h2h_out.userid, config.h2h_out.password, config.h2h_out.partner, task); 325 var requestOptions = generateRequestOptions(config.h2h_out.userid, config.h2h_out.password, config.h2h_out.partner, task);
311 326
312 requestOptions.qs.modul = 'ISI'; 327 requestOptions.qs.modul = 'ISI';
313 requestOptions.qs.command = 'PAY'; 328 requestOptions.qs.command = 'PAY';
314 329
315 logger.info('Requesting auto payment to supplier', {requestOptions: requestOptions}); 330 logger.info('Requesting auto payment to supplier', {requestOptions: requestOptions});
316 request(requestOptions, function(requestError, requestResponse, requestResponseBody) { 331 request(requestOptions, function(requestError, requestResponse, requestResponseBody) {
317 if (requestError) { 332 if (requestError) {
318 logger.warn('Request error', {error: requestError}); 333 logger.warn('Request error', {error: requestError});
319 334
320 setTimeout(advice, adviceDelay, task); 335 setTimeout(advice, adviceDelay, task);
321 return; 336 return;
322 } 337 }
323 338
324 if (requestResponse.statusCode != 200) { 339 if (requestResponse.statusCode != 200) {
325 logger.warn('HTTP response status code is not 200', {http_response: requestResponse.statusCode}); 340 logger.warn('HTTP response status code is not 200', {http_response: requestResponse.statusCode});
326 341
327 setTimeout(advice, adviceDelay, task); 342 setTimeout(advice, adviceDelay, task);
328 return; 343 return;
329 } 344 }
330 345
331 logger.info('Supplier response: ' + requestResponseBody); 346 logger.info('Supplier response: ' + requestResponseBody);
332 347
333 var paymentResponse = parsePaymentResponse(requestResponseBody); 348 var paymentResponse = parsePaymentResponse(requestResponseBody);
334 logger.info('Got payment response', {paymentResponse: paymentResponse}); 349 logger.info('Got payment response', {paymentResponse: paymentResponse});
335 350
336 if (paymentResponse.status == 'SUCCESS') { 351 if (paymentResponse.status == 'SUCCESS') {
337 reportPaymentSuccess(task, paymentResponse); 352 reportPaymentSuccess(task, paymentResponse);
338 } 353 }
339 else { 354 else {
340 reportPaymentError(task, paymentResponse); 355 reportPaymentError(task, paymentResponse);
341 } 356 }
342 }); 357 });
343 } 358 }
344 359
345 exports.start = start; 360 exports.start = start;
346 exports.topupRequest = topupRequest; 361 exports.topupRequest = topupRequest;
347 exports.calculateSignature = calculateSignature; 362 exports.calculateSignature = calculateSignature;
348 exports.parsePaymentResponse = parsePaymentResponse; 363 exports.parsePaymentResponse = parsePaymentResponse;
349 exports.getErrorCode = getErrorCode; 364 exports.getErrorCode = getErrorCode;
350 exports.getST24ResponseCode = getST24ResponseCode; 365 exports.getST24ResponseCode = getST24ResponseCode;
351 exports.generateDt = generateDt; 366 exports.generateDt = generateDt;
352 367