Commit 452e294b540a0779b6fdb4b419f99d18244cd5b9

Authored by Adhidarma Hadiwinoto
1 parent 1c840a7088
Exists in master

url

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

1 { 1 {
2 "name": "sate24-to-trugee", 2 "name": "sate24-to-trugee",
3 "version": "0.0.1", 3 "version": "0.0.1",
4 "description": "ST24 to Trugee", 4 "description": "ST24 to Trugee",
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-trugee.git" 11 "url": "git@gitlab.kodesumber.com:reload97/sate24-to-trugee.git"
12 }, 12 },
13 "keywords": [ 13 "keywords": [
14 "datacell", 14 "datacell",
15 "ppob", 15 "ppob",
16 "st24" 16 "st24"
17 ], 17 ],
18 "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>", 18 "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>",
19 "license": "BSD", 19 "license": "BSD",
20 "dependencies": { 20 "dependencies": {
21 "sate24": "git+http://git@gitlab.kodesumber.com/reload97/node-sate24.git", 21 "sate24": "git+http://git@gitlab.kodesumber.com/reload97/node-sate24.git",
22 "iniparser": "~1.0.5", 22 "iniparser": "~1.0.5",
23 "base64-xor": "~0.10.0", 23 "base64-xor": "~0.10.0",
24 "request": "~2.60.0", 24 "request": "~2.60.0",
25 "mathjs": "~1.7.1", 25 "mathjs": "~1.7.1",
26 "xml": "~1.0.0", 26 "xml": "~1.0.0",
27 "xml2js": "~0.4.9", 27 "xml2js": "~0.4.9",
28 "strftime": "~0.9.2" 28 "strftime": "~0.9.2",
29 "url": "~0.10.3"
29 } 30 }
30 } 31 }
31 32
1 var http = require('http'); 1 var http = require('http');
2 var url = require('url'); 2 var url = require('url');
3 var math = require('mathjs'); 3 var math = require('mathjs');
4 var xml = require('xml'); 4 var xml = require('xml');
5 var xml2js = require('xml2js').parseString; 5 var xml2js = require('xml2js').parseString;
6 var strftime = require('strftime'); 6 var strftime = require('strftime');
7 var xor = require('base64-xor'); 7 var xor = require('base64-xor');
8 var request = require('request'); 8 var request = require('request');
9 9
10 var config; 10 var config;
11 var callbackReport; 11 var callbackReport;
12 12
13 var max_retry = 2; 13 var max_retry = 2;
14 var sleep_before_retry = 2000; 14 var sleep_before_retry = 2000;
15 15
16 var trx_balances = {}; 16 var trx_balances = {};
17 var trx_prices = {}; 17 var trx_prices = {};
18 18
19 function calculateSignature(password, msisdn, timestamp) { 19 function calculateSignature(password, msisdn, timestamp) {
20 var a = timestamp + msisdn.substr(msisdn.length - 4); 20 var a = timestamp + msisdn.substr(msisdn.length - 4);
21 var b = msisdn.substr(msisdn.length - 4).split('').reverse().join('') + password; 21 var b = msisdn.substr(msisdn.length - 4).split('').reverse().join('') + password;
22 22
23 return xor.encode(a,b); 23 return xor.encode(a,b);
24 } 24 }
25 25
26 /** 26 /**
27 * Kalkulasi signature untuk cek balance 27 * Kalkulasi signature untuk cek balance
28 * 28 *
29 * @deprecated 29 * @deprecated
30 */ 30 */
31 function calculateBalanceSignature(userid, password, timestamp) { 31 function calculateBalanceSignature(userid, password, timestamp) {
32 var a = '0000' + timestamp; 32 var a = '0000' + timestamp;
33 var b = userid.substr(0, 4) + password; 33 var b = userid.substr(0, 4) + password;
34 34
35 return xor.encode(a,b); 35 return xor.encode(a,b);
36 } 36 }
37 37
38 38
39 function createPayload(task) { 39 function createPayload(task) {
40 var timestamp = strftime('%H%M%S'); 40 var timestamp = strftime('%H%M%S');
41 41
42 var payload = { 42 var payload = {
43 datacell: [ 43 datacell: [
44 {command: 'TOPUP'}, 44 {command: 'TOPUP'},
45 {vtype: task['remoteProduct']}, 45 {vtype: task['remoteProduct']},
46 {userid: config.h2h_out.userid}, 46 {userid: config.h2h_out.userid},
47 {time: timestamp}, 47 {time: timestamp},
48 {msisdn: task['destination']}, 48 {msisdn: task['destination']},
49 {trxid: task['requestId']}, 49 {trxid: task['requestId']},
50 {sign: calculateSignature(config.h2h_out.password, task['destination'], timestamp)} 50 {sign: calculateSignature(config.h2h_out.password, task['destination'], timestamp)}
51 ] 51 ]
52 }; 52 };
53 53
54 console.log(payload); 54 console.log(payload);
55 return "<?xml version=\"1.0\" ?>\n" + xml(payload); 55 return "<?xml version=\"1.0\" ?>\n" + xml(payload);
56 } 56 }
57 57
58 function topupRequest(task, retry) { 58 function topupRequest(task, retry) {
59 //balanceCheck(); 59 //balanceCheck();
60 60
61 var payload_xml = createPayload(task); 61 var payload_xml = createPayload(task);
62 //console.log(payload_xml); 62 //console.log(payload_xml);
63 63
64 var partner = url.parse(config.h2h_out.partner);
65 console.log(partner);
66 return;
67
64 var request_options = { 68 var request_options = {
65 url: config.h2h_out.partner, 69 url: config.h2h_out.partner,
66 method: "POST", 70 method: "POST",
67 headers: { 71 headers: {
68 'Content-Type': 'text/xml', 72 'Content-Type': 'text/xml',
69 'Content-Length': Buffer.byteLength(payload_xml) 73 'Content-Length': Buffer.byteLength(payload_xml)
70 } 74 }
71 }; 75 };
72 76
73 var buffer = ""; 77 var buffer = "";
74 var req = http.request(request_options, function( res ) { 78 var req = http.request(request_options, function( res ) {
75 79
76 console.log('Status code: ' + res.statusCode ); 80 console.log('Status code: ' + res.statusCode );
77 var buffer = ""; 81 var buffer = "";
78 res.on( "data", function( data ) { buffer = buffer + data; } ); 82 res.on( "data", function( data ) { buffer = buffer + data; } );
79 res.on( "end", function( data ) { 83 res.on( "end", function( data ) {
80 topupResponseHandler(buffer); 84 topupResponseHandler(buffer);
81 }); 85 });
82 86
83 }); 87 });
84 88
85 req.on('error', function(e) { 89 req.on('error', function(e) {
86 console.log('problem with request: ' + e.message); 90 console.log('problem with request: ' + e.message);
87 callbackReport(task['requestId'], '40', e.message); 91 callbackReport(task['requestId'], '40', e.message);
88 }); 92 });
89 93
90 req.write( payload_xml ); 94 req.write( payload_xml );
91 req.end(); 95 req.end();
92 } 96 }
93 97
94 function topupResponseHandler(body, request_id) { 98 function topupResponseHandler(body, request_id) {
95 console.log(body); 99 console.log(body);
96 return; 100 return;
97 xml2js(body, function (err, result) { 101 xml2js(body, function (err, result) {
98 if (err) { 102 if (err) {
99 console.log(body); 103 console.log(body);
100 callbackReport(request_id, '40', buffer); 104 callbackReport(request_id, '40', buffer);
101 return; 105 return;
102 } 106 }
103 107
104 console.log(result); 108 console.log(result);
105 109
106 request_id = result.datacell.ref_trxid[0].trim(); 110 request_id = result.datacell.ref_trxid[0].trim();
107 111
108 var response_code = '68'; 112 var response_code = '68';
109 113
110 var message = ''; 114 var message = '';
111 try { 115 try {
112 if (result.datacell.message && result.datacell.message.length > 0) { 116 if (result.datacell.message && result.datacell.message.length > 0) {
113 message = result.datacell.message[0].trim(); 117 message = result.datacell.message[0].trim();
114 } else if (result.datacell.msg && result.datacell.msg.length > 0) { 118 } else if (result.datacell.msg && result.datacell.msg.length > 0) {
115 message = result.datacell.msg[0].trim(); 119 message = result.datacell.msg[0].trim();
116 } 120 }
117 } 121 }
118 catch(err) { 122 catch(err) {
119 message = 'exception saat parsing message'; 123 message = 'exception saat parsing message';
120 } 124 }
121 125
122 if (result.datacell.resultcode && result.datacell.resultcode[0] == '999') { 126 if (result.datacell.resultcode && result.datacell.resultcode[0] == '999') {
123 response_code = '40'; 127 response_code = '40';
124 } 128 }
125 129
126 if (message.indexOf('Nomor tujuan salah') >= 0) { 130 if (message.indexOf('Nomor tujuan salah') >= 0) {
127 response_code = '14'; 131 response_code = '14';
128 } else if (message.indexOf('*GAGAL, transaksi yang sama sudah ada dalam 10 menit') >= 0) { 132 } else if (message.indexOf('*GAGAL, transaksi yang sama sudah ada dalam 10 menit') >= 0) {
129 response_code = '55'; 133 response_code = '55';
130 } else if (message.indexOf('saldo sdh dikembalikan') >= 0) { 134 } else if (message.indexOf('saldo sdh dikembalikan') >= 0) {
131 response_code = '40' 135 response_code = '40'
132 } else if (message.indexOf('Trx dpt diulang') >= 0) { 136 } else if (message.indexOf('Trx dpt diulang') >= 0) {
133 response_code = '40' 137 response_code = '40'
134 } else if (message.indexOf('SUKSES SN Operator:') >= 0) { 138 } else if (message.indexOf('SUKSES SN Operator:') >= 0) {
135 response_code = '00'; 139 response_code = '00';
136 140
137 var sn = parseSN(message); 141 var sn = parseSN(message);
138 console.log ('SN Operator: ' + sn); 142 console.log ('SN Operator: ' + sn);
139 143
140 if (sn) { 144 if (sn) {
141 message = 'SN=' + sn + '; ' + message; 145 message = 'SN=' + sn + '; ' + message;
142 } else { 146 } else {
143 message = 'SN belum didapat. ' + message; 147 message = 'SN belum didapat. ' + message;
144 response_code = '68'; 148 response_code = '68';
145 } 149 }
146 } 150 }
147 151
148 152
149 var price = priceFromMessage(message); 153 var price = priceFromMessage(message);
150 if (price != null) { 154 if (price != null) {
151 console.log('Harga: ' + price); 155 console.log('Harga: ' + price);
152 trx_prices[request_id] = price; 156 trx_prices[request_id] = price;
153 setTimeout(deleteTrxPrice, 3 * 24 * 3600 * 1000, request_id); 157 setTimeout(deleteTrxPrice, 3 * 24 * 3600 * 1000, request_id);
154 } else if (response_code == '00' && trx_prices[request_id] !== undefined) { 158 } else if (response_code == '00' && trx_prices[request_id] !== undefined) {
155 price = trx_prices[request_id]; 159 price = trx_prices[request_id];
156 console.log('Harga: ' + price); 160 console.log('Harga: ' + price);
157 message = message + ' -- Harga: ' + price; 161 message = message + ' -- Harga: ' + price;
158 } 162 }
159 163
160 var balance = balanceFromMessage(message); 164 var balance = balanceFromMessage(message);
161 if (balance != null) { 165 if (balance != null) {
162 console.log('Saldo: ' + balance); 166 console.log('Saldo: ' + balance);
163 trx_balances[request_id] = balance; 167 trx_balances[request_id] = balance;
164 setTimeout(deleteTrxBalance, 3 * 24 * 3600 * 1000, request_id); 168 setTimeout(deleteTrxBalance, 3 * 24 * 3600 * 1000, request_id);
165 } else if (response_code == '00' && trx_balances[request_id] !== undefined) { 169 } else if (response_code == '00' && trx_balances[request_id] !== undefined) {
166 balance = trx_balances[request_id]; 170 balance = trx_balances[request_id];
167 console.log('Saldo: ' + balance); 171 console.log('Saldo: ' + balance);
168 message = message + ' -- Saldo: ' + balance; 172 message = message + ' -- Saldo: ' + balance;
169 } 173 }
170 174
171 callbackReport(request_id, response_code, message); 175 callbackReport(request_id, response_code, message);
172 }); 176 });
173 } 177 }
174 178
175 function deleteTrxPrice(request_id) { 179 function deleteTrxPrice(request_id) {
176 delete trx_prices[request_id]; 180 delete trx_prices[request_id];
177 } 181 }
178 182
179 function deleteTrxBalance(request_id) { 183 function deleteTrxBalance(request_id) {
180 delete trx_balances[request_id]; 184 delete trx_balances[request_id];
181 } 185 }
182 186
183 function parseSN(message) { 187 function parseSN(message) {
184 var results = message.match(/SN Operator: .+ SN Kami/); 188 var results = message.match(/SN Operator: .+ SN Kami/);
185 if (!results || results.length <= 0) { 189 if (!results || results.length <= 0) {
186 return ''; 190 return '';
187 } 191 }
188 192
189 var result = results[0]; 193 var result = results[0];
190 result = result.replace('SN Operator:', ''); 194 result = result.replace('SN Operator:', '');
191 result = result.replace('SN Kami', ''); 195 result = result.replace('SN Kami', '');
192 result = result.trim(); 196 result = result.trim();
193 197
194 if (result == '00') { 198 if (result == '00') {
195 result = ''; 199 result = '';
196 } 200 }
197 201
198 return result; 202 return result;
199 } 203 }
200 204
201 function createServer() { 205 function createServer() {
202 206
203 var httpServer = http.createServer(function(req, res) { 207 var httpServer = http.createServer(function(req, res) {
204 var parsed_url = url.parse(req.url, true, true); 208 var parsed_url = url.parse(req.url, true, true);
205 209
206 console.log('Got request from partner ("' + req.url + '")'); 210 console.log('Got request from partner ("' + req.url + '")');
207 211
208 var body = ""; 212 var body = "";
209 req.on('data', function (chunk) { 213 req.on('data', function (chunk) {
210 body += chunk; 214 body += chunk;
211 }); 215 });
212 216
213 req.on('end', function () { 217 req.on('end', function () {
214 res.writeHead(200); 218 res.writeHead(200);
215 res.end('OK'); 219 res.end('OK');
216 220
217 //console.log(body); 221 //console.log(body);
218 222
219 if (parsed_url.pathname == '/sn') { 223 if (parsed_url.pathname == '/sn') {
220 console.log('Reverse report -- SN'); 224 console.log('Reverse report -- SN');
221 topupResponseHandler(body); 225 topupResponseHandler(body);
222 226
223 } else if (parsed_url.pathname = '/refund') { 227 } else if (parsed_url.pathname = '/refund') {
224 console.log('Reverse report -- REFUND'); 228 console.log('Reverse report -- REFUND');
225 callbackReport(parsed_url.query.ref_trxid, '40', parsed_url.query.message); 229 callbackReport(parsed_url.query.ref_trxid, '40', parsed_url.query.message);
226 230
227 } else { 231 } else {
228 console.log('Reverse report -- UNKNOWN'); 232 console.log('Reverse report -- UNKNOWN');
229 console.log('Ignore unknown request on reverse url'); 233 console.log('Ignore unknown request on reverse url');
230 } 234 }
231 }); 235 });
232 }); 236 });
233 237
234 httpServer.listen(config.h2h_out.listen_port, function() { 238 httpServer.listen(config.h2h_out.listen_port, function() {
235 console.log('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); 239 console.log('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
236 }); 240 });
237 } 241 }
238 242
239 function balanceCheck() { 243 function balanceCheck() {
240 var timestamp = strftime('%H%M%S'); 244 var timestamp = strftime('%H%M%S');
241 245
242 var payload = { 246 var payload = {
243 datacell: [ 247 datacell: [
244 {perintah: 'saldo'}, 248 {perintah: 'saldo'},
245 {userid: config.h2h_out.userid}, 249 {userid: config.h2h_out.userid},
246 {time: timestamp}, 250 {time: timestamp},
247 {sgn: calculateBalanceSignature(config.h2h_out.userid, config.h2h_out.password, timestamp)} 251 {sgn: calculateBalanceSignature(config.h2h_out.userid, config.h2h_out.password, timestamp)}
248 ] 252 ]
249 }; 253 };
250 254
251 var postRequest = { 255 var postRequest = {
252 host: "202.152.62.2", 256 host: "202.152.62.2",
253 path: "/RELOAD97.php", 257 path: "/RELOAD97.php",
254 port: 7713, 258 port: 7713,
255 method: "POST", 259 method: "POST",
256 headers: { 260 headers: {
257 'Content-Type': 'text/xml', 261 'Content-Type': 'text/xml',
258 'Content-Length': Buffer.byteLength(payload_xml) 262 'Content-Length': Buffer.byteLength(payload_xml)
259 } 263 }
260 }; 264 };
261 265
262 var buffer = ""; 266 var buffer = "";
263 var req = http.request( postRequest, function( res ) { 267 var req = http.request( postRequest, function( res ) {
264 268
265 console.log('Status code: ' + res.statusCode ); 269 console.log('Status code: ' + res.statusCode );
266 var buffer = ""; 270 var buffer = "";
267 res.on( "data", function( data ) { buffer = buffer + data; } ); 271 res.on( "data", function( data ) { buffer = buffer + data; } );
268 res.on( "end", function( data ) { 272 res.on( "end", function( data ) {
269 console.log('CHECK BALANCE RESULT:'); 273 console.log('CHECK BALANCE RESULT:');
270 console.log(buffer); 274 console.log(buffer);
271 }); 275 });
272 276
273 }); 277 });
274 278
275 req.on('error', function(e) { 279 req.on('error', function(e) {
276 console.log('problem with request: ' + e.message); 280 console.log('problem with request: ' + e.message);
277 }); 281 });
278 282
279 req.write( payload_xml ); 283 req.write( payload_xml );
280 req.end(); 284 req.end();
281 285
282 } 286 }
283 287
284 function balanceFromMessage(message) { 288 function balanceFromMessage(message) {
285 var matches = message.match(/Saldo: Rp (\d+)/); 289 var matches = message.match(/Saldo: Rp (\d+)/);
286 290
287 if (!matches) { 291 if (!matches) {
288 return null; 292 return null;
289 } 293 }
290 if (matches.length < 2) { 294 if (matches.length < 2) {
291 return null; 295 return null;
292 } 296 }
293 297
294 return matches[1]; 298 return matches[1];
295 } 299 }
296 300
297 function priceFromMessage(message) { 301 function priceFromMessage(message) {
298 var matches = message.match(/Harga: (\d+)/); 302 var matches = message.match(/Harga: (\d+)/);
299 303
300 if (!matches) { 304 if (!matches) {
301 return null; 305 return null;
302 } 306 }
303 if (matches.length < 2) { 307 if (matches.length < 2) {
304 return null; 308 return null;
305 } 309 }
306 310
307 return matches[1]; 311 return matches[1];
308 } 312 }
309 313
310 function start(_config, _callbackReport) { 314 function start(_config, _callbackReport) {
311 config = _config; 315 config = _config;
312 callbackReport = _callbackReport 316 callbackReport = _callbackReport
313 317
314 createServer(); 318 createServer();
315 } 319 }
316 320
317 exports.start = start; 321 exports.start = start;
318 exports.topupRequest = topupRequest; 322 exports.topupRequest = topupRequest;
319 exports.balanceFromMessage = balanceFromMessage; 323 exports.balanceFromMessage = balanceFromMessage;
320 exports.priceFromMessage = priceFromMessage; 324 exports.priceFromMessage = priceFromMessage;
321 exports.calculateSignature = calculateSignature; 325 exports.calculateSignature = calculateSignature;
322 326