Commit 76889f7ac5e855ccd6ea051bc9f48050ea1c7ce4

Authored by Adhidarma Hadiwinoto
1 parent 866d1d2c16
Exists in master

bugfix refnum f

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