Commit f987dc6b6baa9479d9dbd32d2b4cc09351b3645a

Authored by Adhidarma Hadiwinoto
1 parent 4334f5ca88
Exists in master

perbaikan sn

Showing 1 changed file with 2 additions and 9 deletions Inline Diff

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