Commit e57b649e56cb8c3e77794930ebf4c3709ae2ba3a

Authored by Adhidarma Hadiwinoto
1 parent d83e1d69fd
Exists in master

hapus beberapa field

Showing 1 changed file with 0 additions and 1 deletions Inline Diff

1 var winston = require('winston'); 1 var winston = require('winston');
2 var crypto = require('crypto'); 2 var crypto = require('crypto');
3 var xml = require('xml'); 3 var xml = require('xml');
4 var url = require('url'); 4 var url = require('url');
5 var http = require('http'); 5 var http = require('http');
6 var xml2js = require('xml2js').parseString; 6 var xml2js = require('xml2js').parseString;
7 var mongoClient = require('mongodb').MongoClient; 7 var mongoClient = require('mongodb').MongoClient;
8 var strftime = require('strftime'); 8 var strftime = require('strftime');
9 var moment = require('moment'); 9 var moment = require('moment');
10 10
11 var config; 11 var config;
12 var callbackReport; 12 var callbackReport;
13 var aaa; 13 var aaa;
14 var logger; 14 var logger;
15 var options; 15 var options;
16 var mongodb; 16 var mongodb;
17 17
18 function initMongoClient() { 18 function initMongoClient() {
19 if (!config.mongodb || !config.mongodb.url) { 19 if (!config.mongodb || !config.mongodb.url) {
20 return; 20 return;
21 } 21 }
22 22
23 try { 23 try {
24 var url = config.mongodb.url; 24 var url = config.mongodb.url;
25 25
26 mongoClient.connect(url, function(err, db) { 26 mongoClient.connect(url, function(err, db) {
27 if (err) { 27 if (err) {
28 logger.warn('Failed to connect to mongodb', {err: err}); 28 logger.warn('Failed to connect to mongodb', {err: err});
29 return; 29 return;
30 } 30 }
31 mongodb = db; 31 mongodb = db;
32 logger.info('MongoDB connected'); 32 logger.info('MongoDB connected');
33 }); 33 });
34 } 34 }
35 catch(err) { 35 catch(err) {
36 logger.warn('Exception when connecting to mongodb', {err: err, url: url}); 36 logger.warn('Exception when connecting to mongodb', {err: err, url: url});
37 } 37 }
38 } 38 }
39 39
40 var maxRetry = 10; 40 var maxRetry = 10;
41 var sleepBeforeRetry = 30; 41 var sleepBeforeRetry = 30;
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 initMongoClient(); 61 initMongoClient();
62 } 62 }
63 63
64 function calculateSignature(params) { 64 function calculateSignature(params) {
65 var passwordHash = crypto.createHash('sha1').update(params.password).digest().toString('hex'); 65 var passwordHash = crypto.createHash('sha1').update(params.password).digest().toString('hex');
66 var plain = params.trxtype + params.prdcode + params.value + params.msisdn + params.trxid + params.uid + passwordHash; 66 var plain = params.trxtype + params.prdcode + params.value + params.msisdn + params.trxid + params.uid + passwordHash;
67 var signature = crypto.createHash('sha256').update(plain).digest().toString('hex'); 67 var signature = crypto.createHash('sha256').update(plain).digest().toString('hex');
68 68
69 try { 69 try {
70 logger.verbose('Signature calculated', {plain: plain, signature: signature}); 70 logger.verbose('Signature calculated', {plain: plain, signature: signature});
71 } 71 }
72 catch(err) {} 72 catch(err) {}
73 73
74 return signature; 74 return signature;
75 } 75 }
76 76
77 function createXmlPayload(params) { 77 function createXmlPayload(params) {
78 var payload = "<?xml version=\"1.0\" ?>\n" + xml({ 78 var payload = "<?xml version=\"1.0\" ?>\n" + xml({
79 ciwaru: [ 79 ciwaru: [
80 {trxtype: params.trxtype}, 80 {trxtype: params.trxtype},
81 {prdcode: params.prdcode}, 81 {prdcode: params.prdcode},
82 {value: params.value}, 82 {value: params.value},
83 {msisdn: params.msisdn}, 83 {msisdn: params.msisdn},
84 {trxid: params.trxid}, 84 {trxid: params.trxid},
85 {uid: params.uid}, 85 {uid: params.uid},
86 {hash: calculateSignature(params)} 86 {hash: calculateSignature(params)}
87 ] 87 ]
88 }); 88 });
89 89
90 try { logger.verbose("Payload: " + payload); } 90 try { logger.verbose("Payload: " + payload); }
91 catch(errLog) {} 91 catch(errLog) {}
92 92
93 return payload; 93 return payload;
94 } 94 }
95 95
96 function insertTaskToMongoDb(task) { 96 function insertTaskToMongoDb(task) {
97 if (!isMongoReady()) { return; } 97 if (!isMongoReady()) { return; }
98 98
99 try { 99 try {
100 task.suppliers = [];
101 mongodb.collection(config.mongodb.collection).insertOne(task); 100 mongodb.collection(config.mongodb.collection).insertOne(task);
102 } 101 }
103 catch(err) { 102 catch(err) {
104 //logger.warn('Exception when inserting document to mongodb', {err: err, task: task}); 103 //logger.warn('Exception when inserting document to mongodb', {err: err, task: task});
105 } 104 }
106 } 105 }
107 106
108 function pushResponseToMongoDb(task, response) { 107 function pushResponseToMongoDb(task, response) {
109 if (!isMongoReady()) { return; } 108 if (!isMongoReady()) { return; }
110 109
111 try { 110 try {
112 mongodb.collection(config.mongodb.collection).updateOne( 111 mongodb.collection(config.mongodb.collection).updateOne(
113 {requestId: task.requestId}, 112 {requestId: task.requestId},
114 { 113 {
115 $set: { 114 $set: {
116 lastResponse: response 115 lastResponse: response
117 }, 116 },
118 $push: { 117 $push: {
119 responses: response 118 responses: response
120 } 119 }
121 }, 120 },
122 function(err, result) { 121 function(err, result) {
123 if (err) { 122 if (err) {
124 logger.warn('Error when pushing response to mongodb', {err: err, task: task, response: response}); 123 logger.warn('Error when pushing response to mongodb', {err: err, task: task, response: response});
125 return; 124 return;
126 } 125 }
127 } 126 }
128 ); 127 );
129 } 128 }
130 catch(err) { 129 catch(err) {
131 logger.warn('Exception when pushing response to mongodb', {err: err, task: task, response: response}); 130 logger.warn('Exception when pushing response to mongodb', {err: err, task: task, response: response});
132 } 131 }
133 } 132 }
134 133
135 function isMongoReady() { 134 function isMongoReady() {
136 if (!config.mongodb) { return; } 135 if (!config.mongodb) { return; }
137 if (!config.mongodb.collection) { return; } 136 if (!config.mongodb.collection) { return; }
138 if (!mongodb) { return; } 137 if (!mongodb) { return; }
139 138
140 return true; 139 return true;
141 } 140 }
142 141
143 function getSNFromMessage(message) { 142 function getSNFromMessage(message) {
144 try { 143 try {
145 var sn_match = message.match(/SN: (\w+)/); 144 var sn_match = message.match(/SN: (\w+)/);
146 return sn_match[1].trim(); 145 return sn_match[1].trim();
147 } 146 }
148 catch(err) { 147 catch(err) {
149 if (logger) { 148 if (logger) {
150 logger.verbose('Exception on getting sn from message', {err: err}); 149 logger.verbose('Exception on getting sn from message', {err: err});
151 } 150 }
152 return ''; 151 return '';
153 } 152 }
154 } 153 }
155 154
156 function hasSuccessKeywords(message) { 155 function hasSuccessKeywords(message) {
157 var keywords = ['SUKSES', 'Finish']; 156 var keywords = ['SUKSES', 'Finish'];
158 157
159 var count = keywords.length; 158 var count = keywords.length;
160 for (var i=0; i < count; i++) { 159 for (var i=0; i < count; i++) {
161 if (message.indexOf(keywords[i]) >= 0) { 160 if (message.indexOf(keywords[i]) >= 0) {
162 return true; 161 return true;
163 } 162 }
164 } 163 }
165 return false; 164 return false;
166 } 165 }
167 166
168 function supplierRcToST24Rc(rc) { 167 function supplierRcToST24Rc(rc) {
169 var rcs = { 168 var rcs = {
170 '0001': '40', 169 '0001': '40',
171 '0012': '40', // hash data tidak sesuai 170 '0012': '40', // hash data tidak sesuai
172 '0019': '13', // produk tidak tersedia 171 '0019': '13', // produk tidak tersedia
173 } 172 }
174 173
175 if (rcs[rc]) { 174 if (rcs[rc]) {
176 return rcs[rc]; 175 return rcs[rc];
177 } else { 176 } else {
178 return; 177 return;
179 } 178 }
180 } 179 }
181 180
182 function getSNFromResponseObject(respObj) { 181 function getSNFromResponseObject(respObj) {
183 try { 182 try {
184 return respObj.ciwaru.sn[0].trim(); 183 return respObj.ciwaru.sn[0].trim();
185 } 184 }
186 catch(err) { 185 catch(err) {
187 return; 186 return;
188 } 187 }
189 } 188 }
190 189
191 function topupResponseHandler(body, task) { 190 function topupResponseHandler(body, task) {
192 191
193 //logger.info('Got reply from partner', {body: body}); 192 //logger.info('Got reply from partner', {body: body});
194 193
195 xml2js(body, function(err, result) { 194 xml2js(body, function(err, result) {
196 var ts = strftime('%Y-%m-%d %H:%M:%S', new Date()); 195 var ts = strftime('%Y-%m-%d %H:%M:%S', new Date());
197 196
198 if (err) { 197 if (err) {
199 logger.warn('Got invalid XML from partner', {err: err, body: body, task: task}); 198 logger.warn('Got invalid XML from partner', {err: err, body: body, task: task});
200 callbackReport(task.requestId, '68', body); 199 callbackReport(task.requestId, '68', body);
201 200
202 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: body}); 201 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: body});
203 return; 202 return;
204 } 203 }
205 logger.info('XML message from partner', {result: result}); 204 logger.info('XML message from partner', {result: result});
206 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: body, parsed: result}); 205 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: body, parsed: result});
207 206
208 var rc = '68'; 207 var rc = '68';
209 var message = result.ciwaru.msg[0]; 208 var message = result.ciwaru.msg[0];
210 209
211 if (message.toUpperCase().indexOf('PENDING') >= 0) { 210 if (message.toUpperCase().indexOf('PENDING') >= 0) {
212 rc = '68'; 211 rc = '68';
213 } 212 }
214 else if (hasSuccessKeywords(message)) { 213 else if (hasSuccessKeywords(message)) {
215 214
216 var sn = getSNFromResponseObject(result); 215 var sn = getSNFromResponseObject(result);
217 216
218 if (!sn) { 217 if (!sn) {
219 sn = getSNFromMessage(message); 218 sn = getSNFromMessage(message);
220 } 219 }
221 220
222 message = 'SN=' + sn + '; ' + message; 221 message = 'SN=' + sn + '; ' + message;
223 rc = '00'; 222 rc = '00';
224 223
225 } 224 }
226 else if (message.indexOf('Nomor Pelanggan Salah') >= 0) { 225 else if (message.indexOf('Nomor Pelanggan Salah') >= 0) {
227 226
228 rc = '14'; 227 rc = '14';
229 228
230 } else { 229 } else {
231 rc = supplierRcToST24Rc(result.ciwaru.rc[0]); 230 rc = supplierRcToST24Rc(result.ciwaru.rc[0]);
232 if (!rc) { 231 if (!rc) {
233 rc = '68'; 232 rc = '68';
234 } 233 }
235 } 234 }
236 235
237 if ((task.retry == maxRetry) || (rc != '68')) { 236 if ((task.retry == maxRetry) || (rc != '68')) {
238 callbackReport(task.requestId, rc, message); 237 callbackReport(task.requestId, rc, message);
239 } else { 238 } else {
240 logger.info('Not reporting to AAA for duplicate 68', {task: task}); 239 logger.info('Not reporting to AAA for duplicate 68', {task: task});
241 } 240 }
242 241
243 if (rc == '68') { 242 if (rc == '68') {
244 topupRequestRetry(task); 243 topupRequestRetry(task);
245 } 244 }
246 }); 245 });
247 } 246 }
248 247
249 function topupRequestRetry(task) { 248 function topupRequestRetry(task) {
250 task.retry--; 249 task.retry--;
251 250
252 if (task.retry > 0) { 251 if (task.retry > 0) {
253 logger.info('Retrying in ' + sleepBeforeRetry + 's'); 252 logger.info('Retrying in ' + sleepBeforeRetry + 's');
254 setTimeout(topupRequest, sleepBeforeRetry * 1000, task, task.retry); 253 setTimeout(topupRequest, sleepBeforeRetry * 1000, task, task.retry);
255 } 254 }
256 else { 255 else {
257 logger.warn('Maximum retry for pending status exceeded', {task: task}); 256 logger.warn('Maximum retry for pending status exceeded', {task: task});
258 } 257 }
259 } 258 }
260 259
261 function topupRequest(task, retry) { 260 function topupRequest(task, retry) {
262 261
263 if (retry === undefined) { 262 if (retry === undefined) {
264 263
265 task.ts = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss'); 264 task.ts = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss');
266 task.ts_date = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYY-MM-DD'); 265 task.ts_date = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYY-MM-DD');
267 266
268 insertTaskToMongoDb(task); 267 insertTaskToMongoDb(task);
269 268
270 retry = maxRetry; 269 retry = maxRetry;
271 } 270 }
272 271
273 if (!task.retry) { 272 if (!task.retry) {
274 task.retry = retry; 273 task.retry = retry;
275 } 274 }
276 275
277 var remoteProduct = task.remoteProduct.split(','); 276 var remoteProduct = task.remoteProduct.split(',');
278 277
279 var params = { 278 var params = {
280 trxtype: '01', 279 trxtype: '01',
281 prdcode: remoteProduct[0], 280 prdcode: remoteProduct[0],
282 value: remoteProduct[1], 281 value: remoteProduct[1],
283 msisdn: task.destination, 282 msisdn: task.destination,
284 trxid: task.requestId, 283 trxid: task.requestId,
285 uid: config.h2h_out.userid, 284 uid: config.h2h_out.userid,
286 password: config.h2h_out.password, 285 password: config.h2h_out.password,
287 }; 286 };
288 287
289 var postBody = createXmlPayload(params); 288 var postBody = createXmlPayload(params);
290 289
291 var partnerUrl = url.parse(config.h2h_out.partner); 290 var partnerUrl = url.parse(config.h2h_out.partner);
292 var postRequest = { 291 var postRequest = {
293 host: partnerUrl.hostname, 292 host: partnerUrl.hostname,
294 path: partnerUrl.path, 293 path: partnerUrl.path,
295 port: partnerUrl.port, 294 port: partnerUrl.port,
296 method: "POST", 295 method: "POST",
297 headers: { 296 headers: {
298 'Content-Type': 'text/xml', 297 'Content-Type': 'text/xml',
299 'Content-Length': Buffer.byteLength(postBody) 298 'Content-Length': Buffer.byteLength(postBody)
300 } 299 }
301 }; 300 };
302 301
303 logger.info('POST to partner', {postRequest: postRequest}); 302 logger.info('POST to partner', {postRequest: postRequest});
304 var req = http.request(postRequest, function( res ) { 303 var req = http.request(postRequest, function( res ) {
305 304
306 logger.verbose('Status code: ' + res.statusCode ); 305 logger.verbose('Status code: ' + res.statusCode );
307 var buffer = ""; 306 var buffer = "";
308 307
309 res.on( "data", function( data ) { 308 res.on( "data", function( data ) {
310 buffer = buffer + data; 309 buffer = buffer + data;
311 }); 310 });
312 311
313 res.on( "end", function( data ) { 312 res.on( "end", function( data ) {
314 topupResponseHandler(buffer, task); 313 topupResponseHandler(buffer, task);
315 }); 314 });
316 315
317 }); 316 });
318 317
319 req.on('error', function(e) { 318 req.on('error', function(e) {
320 logger.warn('problem with request: ' + e.message); 319 logger.warn('problem with request: ' + e.message);
321 callbackReport(task['requestId'], '68', e.message); 320 callbackReport(task['requestId'], '68', e.message);
322 321
323 topupRequestRetry(task); 322 topupRequestRetry(task);
324 }); 323 });
325 324
326 req.write(postBody); 325 req.write(postBody);
327 req.end(); 326 req.end();
328 } 327 }
329 328
330 exports.start = start; 329 exports.start = start;
331 exports.topupRequest = topupRequest; 330 exports.topupRequest = topupRequest;
332 exports.calculateSignature = calculateSignature; 331 exports.calculateSignature = calculateSignature;
333 exports.createXmlPayload = createXmlPayload; 332 exports.createXmlPayload = createXmlPayload;
334 exports.getSNFromMessage = getSNFromMessage; 333 exports.getSNFromMessage = getSNFromMessage;
335 334