Commit cb49ed9c41d0ecc34f154478a26d355668b9ee3a

Authored by Adhidarma Hadiwinoto
1 parent fc6f0278c7
Exists in master

typo again

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

partner-simplepay.js
1 "use strict"; 1 "use strict";
2 2
3 process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; 3 process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
4 4
5 const request = require('request'); 5 const request = require('request');
6 const crypto = require('crypto'); 6 const crypto = require('crypto');
7 const moment = require('moment'); 7 const moment = require('moment');
8 8
9 const http = require('http'); 9 const http = require('http');
10 http.globalAgent.maxSockets = Infinity; 10 http.globalAgent.maxSockets = Infinity;
11 11
12 const seconds_to_wait_before_resend_on_pending = 30; 12 const seconds_to_wait_before_resend_on_pending = 30;
13 13
14 var config; 14 var config;
15 var aaa; 15 var aaa;
16 var logger; 16 var logger;
17 17
18 function start(options) { 18 function start(options) {
19 if (!options) { 19 if (!options) {
20 console.log('Undefined options, terminating....'); 20 console.log('Undefined options, terminating....');
21 process.exit(1); 21 process.exit(1);
22 } 22 }
23 23
24 if (options.config) { 24 if (options.config) {
25 config = options.config; 25 config = options.config;
26 } else { 26 } else {
27 console.log('Undefined options.config, terminating....') 27 console.log('Undefined options.config, terminating....')
28 process.exit(1); 28 process.exit(1);
29 } 29 }
30 30
31 if (options.aaa) { 31 if (options.aaa) {
32 aaa = options.aaa; 32 aaa = options.aaa;
33 } else { 33 } else {
34 console.log('Undefined options.aaa, terminating....') 34 console.log('Undefined options.aaa, terminating....')
35 process.exit(1); 35 process.exit(1);
36 } 36 }
37 37
38 if (options && options.logger) { 38 if (options && options.logger) {
39 logger = options.logger; 39 logger = options.logger;
40 } else { 40 } else {
41 console.log('Undefined options.logger, terminating....') 41 console.log('Undefined options.logger, terminating....')
42 process.exit(1); 42 process.exit(1);
43 } 43 }
44 44
45 createReverseHttpServer(); 45 createReverseHttpServer();
46 } 46 }
47 47
48 function callbackReport(requestId, rc, message, options) { 48 function callbackReport(requestId, rc, message, options) {
49 aaa.callbackReportWithPushToMongoDb(requestId, rc, message); 49 aaa.callbackReportWithPushToMongoDb(requestId, rc, message);
50 50
51 // resend trx as status check if rc 68 and task is defined 51 // resend trx as status check if rc 68 and task is defined
52 if (options && options.task && (rc == '68')) { 52 if (options && options.task && (rc == '68')) {
53 logger.verbose('Got pending trx, requesting in ' + seconds_to_wait_before_resend_on_pending + ' secs'); 53 logger.verbose('Got pending trx, requesting in ' + seconds_to_wait_before_resend_on_pending + ' secs');
54 setTimeout(function() { 54 setTimeout(function() {
55 checkStatus(options.task); 55 checkStatus(options.task);
56 }, seconds_to_wait_before_resend_on_pending * 1000) 56 }, seconds_to_wait_before_resend_on_pending * 1000)
57 } 57 }
58 } 58 }
59 59
60 function calculateSign(dt, trx_ref_id, cust_num, username, password) { 60 function calculateSign(dt, trx_ref_id, cust_num, username, password) {
61 const cryptoHashPassword = crypto.createHash('sha1'); 61 const cryptoHashPassword = crypto.createHash('sha1');
62 const cryptoHashUsernamePassword = crypto.createHash('sha1'); 62 const cryptoHashUsernamePassword = crypto.createHash('sha1');
63 const cryptoHashOutest = crypto.createHash('sha1'); 63 const cryptoHashOutest = crypto.createHash('sha1');
64 64
65 cryptoHashPassword.update(password); 65 cryptoHashPassword.update(password);
66 const hashPassword = cryptoHashPassword.digest('hex'); 66 const hashPassword = cryptoHashPassword.digest('hex');
67 67
68 cryptoHashUsernamePassword.update(username + hashPassword); 68 cryptoHashUsernamePassword.update(username + hashPassword);
69 const hashUsernamePassword = cryptoHashUsernamePassword.digest('hex'); 69 const hashUsernamePassword = cryptoHashUsernamePassword.digest('hex');
70 70
71 cryptoHashOutest.update(dt + trx_ref_id + cust_num + hashUsernamePassword); 71 cryptoHashOutest.update(dt + trx_ref_id + cust_num + hashUsernamePassword);
72 return cryptoHashOutest.digest('hex'); 72 return cryptoHashOutest.digest('hex');
73 } 73 }
74 74
75 function _decodeResponseBody(responseBody) { 75 function _decodeResponseBody(responseBody) {
76 let response; 76 let response;
77 77
78 try { 78 try {
79 response = JSON.parse(responseBody) 79 response = JSON.parse(responseBody)
80 } 80 }
81 catch(e) { 81 catch(e) {
82 logger.warn('Error parsing response body'); 82 logger.warn('Error parsing response body');
83 } 83 }
84 84
85 return response; 85 return response;
86 } 86 }
87 87
88 function _composeMessageFromResponseData(responseDataObj) { 88 function _composeMessageFromResponseData(responseDataObj) {
89 const diag = _getPropertyFromObjectSafe(responseDataObj, 'diag'); 89 const diag = _getPropertyFromObjectSafe(responseDataObj, 'diag');
90 const msg = _getPropertyFromObjectSafe(responseDataObj, 'message'); 90 const msg = _getPropertyFromObjectSafe(responseDataObj, 'message');
91 const balance = _getPropertyFromObjectSafe(responseDataObj, 'balance'); 91 const balance = _getPropertyFromObjectSafe(responseDataObj, 'balance');
92 const timestamp = _getPropertyFromObjectSafe(responseDataObj, 'timestamp'); 92 const timestamp = _getPropertyFromObjectSafe(responseDataObj, 'timestamp');
93 93
94 let messages = []; 94 let messages = [];
95 95
96 if (timestamp) { 96 if (timestamp) {
97 messages.push(timestamp); 97 messages.push(timestamp);
98 } 98 }
99 99
100 if (diag) { 100 if (diag) {
101 messages.push(diag); 101 messages.push(diag);
102 } 102 }
103 103
104 if (msg) { 104 if (msg) {
105 messages.push(msg); 105 messages.push(msg);
106 } 106 }
107 107
108 if (balance) { 108 if (balance) {
109 messages.push('Balance: ' + balance); 109 messages.push('Balance: ' + balance);
110 } 110 }
111 111
112 return messages.join('. ') + '.'; 112 return messages.join('. ') + '.';
113 } 113 }
114 114
115 function _composeCompleteSn(responseDataObj) { 115 function _composeCompleteSn(responseDataObj) {
116 const serial = _getPropertyFromObjectSafe(responseDataObj, 'serial'); 116 const serial = _getPropertyFromObjectSafe(responseDataObj, 'serial');
117 const info = _getPropertyFromObjectSafe(responseDataObj, 'info'); 117 const info = _getPropertyFromObjectSafe(responseDataObj, 'info');
118 118
119 if (!info) { 119 if (!info) {
120 //logger.warn('Undefined data.info on _composeCompleteSn'); 120 //logger.warn('Undefined data.info on _composeCompleteSn');
121 return serial; 121 return serial;
122 } 122 }
123 123
124 const cleanedData = { 124 const cleanedData = {
125 token: serial, 125 token: serial,
126 cust_name: _getPropertyFromObjectSafe(info, 'cust_name'), 126 cust_name: _getPropertyFromObjectSafe(info, 'cust_name'),
127 tariff: _getPropertyFromObjectSafe(info, 'kelas') + 'VA', 127 tariff: _getPropertyFromObjectSafe(info, 'kelas') + 'VA',
128 total_kwh: _getPropertyFromObjectSafe(info, 'size') 128 total_kwh: _getPropertyFromObjectSafe(info, 'size')
129 } 129 }
130 130
131 if (cleanedData.cust_name) { 131 if (cleanedData.cust_name) {
132 cleanedData.cust_name = cleanedData.cust_name.replace(/\W+/g, ' ').trim().replace(/\W+/g, '-').toUpperCase(); 132 cleanedData.cust_name = cleanedData.cust_name.replace(/\W+/g, ' ').trim().replace(/\W+/g, '-').toUpperCase();
133 } 133 }
134 logger.verbose('Detail token info extracted', {originalResponseInfo: info, cleanedData: cleanedData}); 134 logger.verbose('Detail token info extracted', {originalResponseInfo: info, cleanedData: cleanedData});
135 135
136 return [ 136 return [
137 cleanedData.token, cleanedData.cust_name, cleanedData.tariff, cleanedData.total_kwh 137 cleanedData.token, cleanedData.cust_name, cleanedData.tariff, cleanedData.total_kwh
138 ].join('/'); 138 ].join('/');
139 } 139 }
140 140
141 function _responseBodyHandler(responseBody, task) { 141 function _responseBodyHandler(responseBody, task) {
142 let rc = '68'; 142 let rc = '68';
143 let response = _decodeResponseBody(responseBody); 143 let response = _decodeResponseBody(responseBody);
144 144
145 logger.verbose('RESPONSE', {response: response}); 145 logger.verbose('RESPONSE', {response: response});
146 146
147 const responseStatus = _getPropertyFromObjectSafe(response, 'status'); 147 const responseStatus = _getPropertyFromObjectSafe(response, 'status');
148 const responseInfo = _getPropertyFromObjectSafe(response, 'info'); 148 const responseInfo = _getPropertyFromObjectSafe(response, 'info');
149 149
150 if (responseStatus == 'Error') { 150 if (responseStatus == 'Error') {
151 if (responseInfo == 'insufficient balance') { 151 if (responseInfo == 'insufficient balance') {
152 rc = '91'; 152 rc = '91';
153 } 153 }
154 callbackReport(task.requestId, '91', [responeStatus, responseInfo].join(': '), {task: task}); 154 callbackReport(task.requestId, '91', [responseStatus, responseInfo].join(': '), {task: task});
155 return; 155 return;
156 } 156 }
157 157
158 const requestId = _getPropertyFromObjectSafe(response.data, 'request_id'); 158 const requestId = _getPropertyFromObjectSafe(response.data, 'request_id');
159 const trxStatus = _getPropertyFromObjectSafe(response.data, 'trx_status'); 159 const trxStatus = _getPropertyFromObjectSafe(response.data, 'trx_status');
160 const diag = _getPropertyFromObjectSafe(response.data, 'diag'); 160 const diag = _getPropertyFromObjectSafe(response.data, 'diag');
161 let balance = _getPropertyFromObjectSafe(response.data, 'balance'); 161 let balance = _getPropertyFromObjectSafe(response.data, 'balance');
162 162
163 if (balance && aaa.updateBalance) { 163 if (balance && aaa.updateBalance) {
164 balance = balance.replace(/\D/g, ''); 164 balance = balance.replace(/\D/g, '');
165 if (balance) { 165 if (balance) {
166 aaa.updateBalance(balance); 166 aaa.updateBalance(balance);
167 } 167 }
168 } 168 }
169 169
170 let aaaMessage = _composeMessageFromResponseData(response.data); 170 let aaaMessage = _composeMessageFromResponseData(response.data);
171 if (!aaaMessage) { 171 if (!aaaMessage) {
172 aaaMessage = 'Transaksi sedang diproses'; 172 aaaMessage = 'Transaksi sedang diproses';
173 } 173 }
174 174
175 if (trxStatus == 'P') { 175 if (trxStatus == 'P') {
176 logger.verbose('Got pending trx response', {response: response.data}); 176 logger.verbose('Got pending trx response', {response: response.data});
177 rc = '68'; 177 rc = '68';
178 } 178 }
179 else if (trxStatus == 'S') { 179 else if (trxStatus == 'S') {
180 logger.verbose('Got succcess trx response', {response: response.data}); 180 logger.verbose('Got succcess trx response', {response: response.data});
181 181
182 rc = '00'; 182 rc = '00';
183 aaaMessage = 'SN=' + _composeCompleteSn(response.data) + '; ' + aaaMessage; 183 aaaMessage = 'SN=' + _composeCompleteSn(response.data) + '; ' + aaaMessage;
184 } 184 }
185 else if (trxStatus == 'R') { 185 else if (trxStatus == 'R') {
186 logger.verbose('Got rejected trx response', {response: response.data}); 186 logger.verbose('Got rejected trx response', {response: response.data});
187 187
188 const partnerRC = getPartnerRCFromDiagMessage(diag); 188 const partnerRC = getPartnerRCFromDiagMessage(diag);
189 if (partnerRC == '15') { 189 if (partnerRC == '15') {
190 rc = '14'; 190 rc = '14';
191 } 191 }
192 else { 192 else {
193 rc = '40'; 193 rc = '40';
194 } 194 }
195 } 195 }
196 196
197 callbackReport(requestId, rc, aaaMessage, {task: task}); 197 callbackReport(requestId, rc, aaaMessage, {task: task});
198 } 198 }
199 199
200 function getPartnerRCFromDiagMessage(diag) { 200 function getPartnerRCFromDiagMessage(diag) {
201 let matches = diag.match(/^\s*\[(.*)\]/); 201 let matches = diag.match(/^\s*\[(.*)\]/);
202 if (matches.length < 2) { 202 if (matches.length < 2) {
203 return; 203 return;
204 } 204 }
205 205
206 return matches[1]; 206 return matches[1];
207 } 207 }
208 208
209 function _hitTopup(task, pendingOnErrorConnect) { 209 function _hitTopup(task, pendingOnErrorConnect) {
210 210
211 const dt = moment().format('YYYY-MM-DD HH:mm:ss'); 211 const dt = moment().format('YYYY-MM-DD HH:mm:ss');
212 const username = config.h2h_out.username || config.h2h_out.userid; 212 const username = config.h2h_out.username || config.h2h_out.userid;
213 const password = config.h2h_out.password || config.h2h_out.pin; 213 const password = config.h2h_out.password || config.h2h_out.pin;
214 const sign = calculateSign(dt, task.requestId, task.destination, username, password); 214 const sign = calculateSign(dt, task.requestId, task.destination, username, password);
215 215
216 logger.verbose('Sign for ' + dt + ', ' + task.requestId + ', ' + task.destination + ', ' + username + ', ' + password + ' is ' + sign); 216 logger.verbose('Sign for ' + dt + ', ' + task.requestId + ', ' + task.destination + ', ' + username + ', ' + password + ' is ' + sign);
217 const requestOptions = { 217 const requestOptions = {
218 url: config.h2h_out.partner, 218 url: config.h2h_out.partner,
219 form: { 219 form: {
220 username: username, 220 username: username,
221 datetime: dt, 221 datetime: dt,
222 code: task.remoteProduct, 222 code: task.remoteProduct,
223 trx_ref_id: task.requestId, 223 trx_ref_id: task.requestId,
224 cust_num: task.destination, 224 cust_num: task.destination,
225 sign: sign 225 sign: sign
226 } 226 }
227 } 227 }
228 228
229 logger.verbose('Requeting to partner', {requestOptions: requestOptions}); 229 logger.verbose('Requeting to partner', {requestOptions: requestOptions});
230 230
231 request.post(requestOptions, function(error, response, body) { 231 request.post(requestOptions, function(error, response, body) {
232 if (error) { 232 if (error) {
233 let rc = '68'; 233 let rc = '68';
234 234
235 if (!pendingOnErrorConnect && (error.syscall == 'connect')) { 235 if (!pendingOnErrorConnect && (error.syscall == 'connect')) {
236 rc = '91'; 236 rc = '91';
237 } 237 }
238 238
239 logger.warn('Error requesting to partner', {task: task, rc: rc, error: error}); 239 logger.warn('Error requesting to partner', {task: task, rc: rc, error: error});
240 callbackReport(task.requestId, rc, 'Error requesting to partner. ' + error, {task: task}); 240 callbackReport(task.requestId, rc, 'Error requesting to partner. ' + error, {task: task});
241 return; 241 return;
242 } 242 }
243 243
244 if (response.statusCode != 200) { 244 if (response.statusCode != 200) {
245 let rc = '68'; 245 let rc = '68';
246 246
247 logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode}); 247 logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode});
248 callbackReport(task.requestId, rc, 'HTTP status code ' + response.statusCode, {task: task}); 248 callbackReport(task.requestId, rc, 'HTTP status code ' + response.statusCode, {task: task});
249 return; 249 return;
250 } 250 }
251 251
252 logger.info('Transaksi sedang diproses', {task: task, response_body: body}); 252 logger.info('Transaksi sedang diproses', {task: task, response_body: body});
253 253
254 _responseBodyHandler(body, task); 254 _responseBodyHandler(body, task);
255 255
256 }) 256 })
257 } 257 }
258 258
259 function _getPropertyFromObjectSafe(obj, property) { 259 function _getPropertyFromObjectSafe(obj, property) {
260 let retval; 260 let retval;
261 261
262 if (!obj) { 262 if (!obj) {
263 logger.warn('Invalid object') 263 logger.warn('Invalid object')
264 return; 264 return;
265 } 265 }
266 266
267 try { 267 try {
268 retval = obj[property]; 268 retval = obj[property];
269 } 269 }
270 catch(e) { 270 catch(e) {
271 logger.warn('Error getting ' + property + ' from object'); 271 logger.warn('Error getting ' + property + ' from object');
272 } 272 }
273 273
274 return retval; 274 return retval;
275 } 275 }
276 276
277 function topupRequest(task) { 277 function topupRequest(task) {
278 aaa.insertTaskToMongoDb(task); 278 aaa.insertTaskToMongoDb(task);
279 _hitTopup(task); 279 _hitTopup(task);
280 } 280 }
281 281
282 function checkStatus(task) { 282 function checkStatus(task) {
283 _hitTopup(task, true); 283 _hitTopup(task, true);
284 } 284 }
285 285
286 286
287 function reverseReportHandler(body) { 287 function reverseReportHandler(body) {
288 logger.info('Got reverse report', {body: body}); 288 logger.info('Got reverse report', {body: body});
289 } 289 }
290 290
291 function createReverseHttpServer() { 291 function createReverseHttpServer() {
292 var httpServer = http.createServer(function(request, response) { 292 var httpServer = http.createServer(function(request, response) {
293 293
294 logger.info('Got request from partner'); 294 logger.info('Got request from partner');
295 295
296 var body = ""; 296 var body = "";
297 request.on('data', function (chunk) { 297 request.on('data', function (chunk) {
298 body += chunk; 298 body += chunk;
299 }); 299 });
300 300
301 request.on('end', function () { 301 request.on('end', function () {
302 response.writeHead(200); 302 response.writeHead(200);
303 response.end('OK'); 303 response.end('OK');
304 304
305 reverseReportHandler(body); 305 reverseReportHandler(body);
306 }); 306 });
307 307
308 }); 308 });
309 309
310 httpServer.listen(config.h2h_out.listen_port, function() { 310 httpServer.listen(config.h2h_out.listen_port, function() {
311 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); 311 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
312 }); 312 });
313 } 313 }
314 314
315 315
316 exports.calculateSign = calculateSign; 316 exports.calculateSign = calculateSign;
317 exports.start = start; 317 exports.start = start;
318 exports.topupRequest = topupRequest; 318 exports.topupRequest = topupRequest;
319 exports.checkStatus = checkStatus; 319 exports.checkStatus = checkStatus;
320 320