Commit fea1167446661308b44b795e0f28b60dd3be5aae

Authored by Adhidarma Hadiwinoto
1 parent 8124d89a46
Exists in master

headless xml payload

Showing 2 changed files with 3 additions and 4 deletions Inline Diff

anti-same-day-dupe.js
1 var redis = require('redis'); 1 var redis = require('redis');
2 var LRU = require('lru-cache'); 2 var LRU = require('lru-cache');
3 var moment = require('moment'); 3 var moment = require('moment');
4 4
5 var config; 5 var config;
6 var logger; 6 var logger;
7 var redisClient; 7 var redisClient;
8 8
9 var taskCache = LRU({max: 100, maxAge: 1000 * 3600 * 2}); 9 var taskCache = LRU({max: 100, maxAge: 1000 * 3600 * 2});
10 10
11 function createRedisClient(host, port) { 11 function createRedisClient(host, port) {
12 try { 12 try {
13 redisClient = redis.createClient(port, host); 13 redisClient = redis.createClient(port, host);
14 logger.verbose(__filename + ': Redis client for task history created'); 14 logger.verbose(__filename + ': Redis client for task history created');
15 } catch(err) { 15 } catch(err) {
16 logger.warn(__filename + ": Error creating redis client to " + host + ':' + port); 16 logger.warn(__filename + ": Error creating redis client to " + host + ':' + port);
17 process.exit(1); 17 process.exit(1);
18 } 18 }
19 } 19 }
20 20
21 function init(options) { 21 function init(options) {
22 if (!options) { 22 if (!options) {
23 console.log('Undefined options, terminating....'); 23 console.log('Undefined options, terminating....');
24 process.exit(1); 24 process.exit(1);
25 } 25 }
26 26
27 if (options.config) { 27 if (options.config) {
28 config = options.config; 28 config = options.config;
29 } else { 29 } else {
30 console.log('Undefined options.config, terminating....') 30 console.log('Undefined options.config, terminating....')
31 process.exit(1); 31 process.exit(1);
32 } 32 }
33 33
34 if (options && options.logger) { 34 if (options && options.logger) {
35 logger = options.logger; 35 logger = options.logger;
36 } else { 36 } else {
37 console.log('Undefined options.logger, terminating....') 37 console.log('Undefined options.logger, terminating....')
38 process.exit(1); 38 process.exit(1);
39 } 39 }
40 40
41 createRedisClient(config.globals.redis_host, config.globals.redis_port); 41 createRedisClient(config.globals.redis_host, config.globals.redis_port);
42 } 42 }
43 43
44 function getKey(task, chipInfo) { 44 function getKey(task, chipInfo) {
45 var today = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYYMMDD'); 45 var today = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYYMMDD');
46 return chipInfo + '.antiSameDayDupe.trx.date:' + today + '.rProd:' + task.remoteProduct.toUpperCase() + '.dest:' + task.destination ; 46 return chipInfo + '.antiSameDayDupe.trx.date:' + today + '.rProd:' + task.remoteProduct.toUpperCase() + '.dest:' + task.destination ;
47 } 47 }
48 48
49 function register(task, cb) { 49 function register(task, cb) {
50 var key = getKey(task, config.globals.gateway_name); 50 var key = getKey(task, config.globals.gateway_name);
51 51
52 taskCache.set(key, task); 52 taskCache.set(key, task);
53 saveToRedis(task,cb); 53 saveToRedis(task,cb);
54 } 54 }
55 55
56 function saveToRedis(task, cb) { 56 function saveToRedis(task, cb) {
57 var key = getKey(task, config.globals.gateway_name); 57 var key = getKey(task, config.globals.gateway_name);
58 logger.verbose('Saving task', {key: key, task: task}); 58 logger.verbose('Saving task', {key: key, task: task});
59 59
60 redisClient.set(key, JSON.stringify(task), function() { 60 redisClient.set(key, JSON.stringify(task), function() {
61 redisClient.expire(key, 3600*24); 61 redisClient.expire(key, 3600*24);
62 if (cb) { 62 if (cb) {
63 cb(); 63 cb();
64 } 64 }
65 }); 65 });
66 } 66 }
67 67
68 function createDummyTask(remoteProduct, destination) { 68 function createDummyTask(remoteProduct, destination) {
69 return { 69 return {
70 remoteProduct: remoteProduct, 70 remoteProduct: remoteProduct,
71 destination: destination, 71 destination: destination,
72 timestamp: moment().format('YYYYMMDD'), 72 timestamp: moment().format('YYYYMMDD'),
73 } 73 }
74 } 74 }
75 75
76 function get(remoteProduct, destination, cb) { 76 function get(remoteProduct, destination, cb) {
77 var dummyTask = createDummyTask(remoteProduct, destination); 77 var dummyTask = createDummyTask(remoteProduct, destination);
78 78
79 var key = getKey(dummyTask, config.globals.gateway_name); 79 var key = getKey(dummyTask, config.globals.gateway_name);
80 var task = taskCache.get(key); 80 var task = taskCache.get(key);
81 81
82 if (task) { 82 if (task) {
83 cb(null, task); 83 cb(null, task);
84 } 84 }
85 else { 85 else {
86 getFromRedis(remoteProduct, destination, cb); 86 getFromRedis(remoteProduct, destination, cb);
87 } 87 }
88 } 88 }
89 89
90 function getFromRedis(remoteProduct, destination, cb) { 90 function getFromRedis(remoteProduct, destination, cb) {
91 var dummyTask = createDummyTask(remoteProduct, destination); 91 var dummyTask = createDummyTask(remoteProduct, destination);
92 92
93 var key = getKey(dummyTask, config.globals.gateway_name, moment().format('YYYYMMDD')); 93 var key = getKey(dummyTask, config.globals.gateway_name, moment().format('YYYYMMDD'));
94 redisClient.get(key, function(err, result) { 94 redisClient.get(key, function(err, result) {
95 if (err) { 95 if (err) {
96 logger.warn('antiDupe.get: error getting task from redis', {key: key, params: dummyTask}); 96 logger.warn('antiDupe.get: error getting task from redis', {key: key, params: dummyTask});
97 97
98 cb(err, null); 98 cb(err, null);
99 return; 99 return;
100 } 100 }
101 101
102 var task = {}; 102 var task = {};
103 103
104 try { 104 try {
105 task = JSON.parse(result); 105 task = JSON.parse(result);
106 } 106 }
107 catch(e) { 107 catch(e) {
108 logger.warn('antiDupe.get: Can not parse result', {key: key, params: dummyTask, data: result}); 108 logger.warn('antiDupe.get: Can not parse result', {key: key, params: dummyTask, data: result});
109 err = "Can not parse task"; 109 err = "Can not parse task";
110 cb(err, null); 110 cb(err, null);
111 return; 111 return;
112 } 112 }
113 113
114 cb(err, task); 114 cb(err, task);
115 }); 115 });
116 } 116 }
117 117
118 function check(task, cbNoDupe, cbDupe, cbDupeWithSameReqId) { 118 function check(task, cbNoDupe, cbDupe, cbDupeWithSameReqId) {
119 if (Number(config.globals.no_same_day_dupe_check)) { 119 if (Number(config.globals.no_same_day_dupe_check)) {
120 logger.verbose('Skipping same day dupe check because of config.globals.no_same_day_dupe_check'); 120 logger.verbose('Skipping same day dupe check because of config.globals.no_same_day_dupe_check');
121 cbNoDupe(task); 121 cbNoDupe(task);
122 return;
122 } 123 }
123 124
124 get(task.remoteProduct, task.destination, function(err, archivedTask) { 125 get(task.remoteProduct, task.destination, function(err, archivedTask) {
125 if (err) { 126 if (err) {
126 logger.warn('Error on checking same day duplicate', {task: task}); 127 logger.warn('Error on checking same day duplicate', {task: task});
127 cbNoDupe(task); 128 cbNoDupe(task);
128 return; 129 return;
129 } 130 }
130 131
131 if (archivedTask && archivedTask.requestId) { 132 if (archivedTask && archivedTask.requestId) {
132 if (task.requestId == archivedTask.requestId) { 133 if (task.requestId == archivedTask.requestId) {
133 logger.verbose('Duplicate trx on same day with same requestId', {task: task}); 134 logger.verbose('Duplicate trx on same day with same requestId', {task: task});
134 cbDupeWithSameReqId(task); 135 cbDupeWithSameReqId(task);
135 return; 136 return;
136 } 137 }
137 138
138 logger.verbose('Duplicate trx on same day', {task: task, archivedTask: archivedTask}); 139 logger.verbose('Duplicate trx on same day', {task: task, archivedTask: archivedTask});
139 cbDupe(task); 140 cbDupe(task);
140 return; 141 return;
141 } 142 }
142 143
143 register(task, function() { 144 register(task, function() {
144 cbNoDupe(task); 145 cbNoDupe(task);
145 }); 146 });
146 }); 147 });
147 } 148 }
148 149
149 exports.init = init; 150 exports.init = init;
150 exports.check = check; 151 exports.check = check;
151 152
1 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 1 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
2 2
3 var request = require('request'); 3 var request = require('request');
4 var xml2js = require('xml2js'); 4 var xml2js = require('xml2js');
5 5
6 var resendDelay = require('sate24/resend-delay.js'); 6 var resendDelay = require('sate24/resend-delay.js');
7 var taskHistory = require('./task-history.js'); 7 var taskHistory = require('./task-history.js');
8 var antiSameDayDupe = require('./anti-same-day-dupe.js'); 8 var antiSameDayDupe = require('./anti-same-day-dupe.js');
9 9
10 var config; 10 var config;
11 var aaa; 11 var aaa;
12 var _callbackReport; 12 var _callbackReport;
13 var logger; 13 var logger;
14 14
15 var xmlBuilder = new xml2js.Builder({rootName: 'xml'}); 15 var xmlBuilder = new xml2js.Builder({rootName: 'xml', headless: true});
16 16
17 function start(options) { 17 function start(options) {
18 if (!options) { 18 if (!options) {
19 console.log('Undefined options, terminating....'); 19 console.log('Undefined options, terminating....');
20 process.exit(1); 20 process.exit(1);
21 } 21 }
22 22
23 if (options.config) { 23 if (options.config) {
24 config = options.config; 24 config = options.config;
25 } else { 25 } else {
26 console.log('Undefined options.config, terminating....') 26 console.log('Undefined options.config, terminating....')
27 process.exit(1); 27 process.exit(1);
28 } 28 }
29 29
30 if (options.aaa) { 30 if (options.aaa) {
31 aaa = options.aaa; 31 aaa = options.aaa;
32 _callbackReport = options.aaa.callbackReportWithPushToMongoDb; 32 _callbackReport = options.aaa.callbackReportWithPushToMongoDb;
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 resendDelay.init({ 45 resendDelay.init({
46 config: config, 46 config: config,
47 topupRequest: _topupStatus, 47 topupRequest: _topupStatus,
48 logger: logger 48 logger: logger
49 }); 49 });
50 50
51 taskHistory.init(options); 51 taskHistory.init(options);
52 antiSameDayDupe.init(options); 52 antiSameDayDupe.init(options);
53 } 53 }
54 54
55 function callbackReport(requestId, responseCode, msg) { 55 function callbackReport(requestId, responseCode, msg) {
56 if (responseCode != '68') { 56 if (responseCode != '68') {
57 resendDelay.cancel(requestId); 57 resendDelay.cancel(requestId);
58 58
59 } else { 59 } else {
60 taskHistory.get(requestId, function(err, task) { 60 taskHistory.get(requestId, function(err, task) {
61 if (task) { 61 if (task) {
62 resendDelay.register(task); 62 resendDelay.register(task);
63 } 63 }
64 }); 64 });
65 } 65 }
66 66
67 _callbackReport(requestId, responseCode, msg); 67 _callbackReport(requestId, responseCode, msg);
68 } 68 }
69 69
70 function parseResponse(task, response) { 70 function parseResponse(task, response) {
71 var xmlParser = xml2js.parseString; 71 var xmlParser = xml2js.parseString;
72 72
73 xmlParser(response, function(err, result) { 73 xmlParser(response, function(err, result) {
74 if (err) { 74 if (err) {
75 var msg = 'Error parsing response. ' + err; 75 var msg = 'Error parsing response. ' + err;
76 logger.warn(msg, {task: task, response: response, err: err}); 76 logger.warn(msg, {task: task, response: response, err: err});
77 callbackReport(task.requestId, '68', msg); 77 callbackReport(task.requestId, '68', msg);
78 return; 78 return;
79 } 79 }
80 80
81 logger.verbose('Response parsed', {result: result, task: task}); 81 logger.verbose('Response parsed', {result: result, task: task});
82 82
83 var rc = '68'; 83 var rc = '68';
84 84
85 var partnerResponseCode; 85 var partnerResponseCode;
86 try { 86 try {
87 partnerResponseCode = result.hpay.responseCode[0]; 87 partnerResponseCode = result.hpay.responseCode[0];
88 } catch(e) {} 88 } catch(e) {}
89 89
90 var partnerMessage = ''; 90 var partnerMessage = '';
91 try { 91 try {
92 partnerMessage = result.hpay.responseMessage[0]; 92 partnerMessage = result.hpay.responseMessage[0];
93 } catch(e) {} 93 } catch(e) {}
94 94
95 if (partnerResponseCode == '00') { 95 if (partnerResponseCode == '00') {
96 rc = '00'; 96 rc = '00';
97 } 97 }
98 else if ((partnerResponseCode == '99') && (partnerMessage == 'Member Not Found')) { 98 else if ((partnerResponseCode == '99') && (partnerMessage == 'Member Not Found')) {
99 rc = '40'; 99 rc = '40';
100 } 100 }
101 else if (partnerResponseCode == '99') { 101 else if (partnerResponseCode == '99') {
102 rc = '68'; 102 rc = '68';
103 } 103 }
104 else { 104 else {
105 rc = '40'; 105 rc = '40';
106 } 106 }
107 107
108 var msg = ''; 108 var msg = '';
109 if (partnerResponseCode) { 109 if (partnerResponseCode) {
110 msg = partnerResponseCode; 110 msg = partnerResponseCode;
111 } 111 }
112 112
113 if (partnerMessage) { 113 if (partnerMessage) {
114 msg = msg + ' ' + partnerMessage; 114 msg = msg + ' ' + partnerMessage;
115 } 115 }
116 msg = msg.trim(); 116 msg = msg.trim();
117 117
118 callbackReport(task.requestId, rc, msg); 118 callbackReport(task.requestId, rc, msg);
119 }); 119 });
120 } 120 }
121 121
122 function requestToPartner(methodName, task) { 122 function requestToPartner(methodName, task) {
123 var payload = createPayload(methodName, task, config.h2h_out.userid, config.h2h_out.noid, config.h2h_out.password); 123 var payload = createPayload(methodName, task, config.h2h_out.userid, config.h2h_out.noid, config.h2h_out.password);
124 if (!payload) { 124 if (!payload) {
125 callbackReport(task.requestId, '40', 'ERROR: Undefined payload'); 125 callbackReport(task.requestId, '40', 'ERROR: Undefined payload');
126 return; 126 return;
127 } 127 }
128 128
129 var requestOpts = { 129 var requestOpts = {
130 url: config.h2h_out.partner, 130 url: config.h2h_out.partner,
131 method: "POST", 131 method: "POST",
132 body: payload, 132 body: payload,
133 headers: { 133
134 'Content-Type': 'text/xml',
135 }
136 } 134 }
137 135
138 logger.verbose('Requesting to partner', {methodName: methodName, task: task, requestOpts: requestOpts}); 136 logger.verbose('Requesting to partner', {methodName: methodName, task: task, requestOpts: requestOpts});
139 request(requestOpts, function (err, response, responseBody) { 137 request(requestOpts, function (err, response, responseBody) {
140 if (err) { 138 if (err) {
141 var rc = '68'; 139 var rc = '68';
142 if (methodName === 'pay') { 140 if (methodName === 'pay') {
143 rc = '40'; 141 rc = '40';
144 } 142 }
145 143
146 var msg = 'Error requesting pay method. ' + err; 144 var msg = 'Error requesting pay method. ' + err;
147 callbackReport(task.requestId, rc, msg); 145 callbackReport(task.requestId, rc, msg);
148 return; 146 return;
149 } 147 }
150 148
151 logger.info('Got direct response from partner', {task: task, responseBody: responseBody}); 149 logger.info('Got direct response from partner', {task: task, responseBody: responseBody});
152 parseResponse(task, responseBody); 150 parseResponse(task, responseBody);
153 }); 151 });
154 } 152 }
155 153
156 154
157 function topupRequest(task) { 155 function topupRequest(task) {
158 if (!aaa.isTodayTrx(task)) { 156 if (!aaa.isTodayTrx(task)) {
159 logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan'); 157 logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan');
160 callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan'); 158 callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan');
161 resendDelay.cancel(task); 159 resendDelay.cancel(task);
162 return; 160 return;
163 } 161 }
164 162
165 antiSameDayDupe.check(task, _topupRequest, onSameDayDupe, _topupStatus); 163 antiSameDayDupe.check(task, _topupRequest, onSameDayDupe, _topupStatus);
166 } 164 }
167 165
168 function _topupRequest(task) { 166 function _topupRequest(task) {
169 taskHistory.put(task, function() { 167 taskHistory.put(task, function() {
170 requestToPartner('pay', task);; 168 requestToPartner('pay', task);;
171 }); 169 });
172 } 170 }
173 171
174 function _topupStatus(task) { 172 function _topupStatus(task) {
175 requestToPartner('checking', task); 173 requestToPartner('checking', task);
176 } 174 }
177 175
178 function onSameDayDupe(task) { 176 function onSameDayDupe(task) {
179 callbackReport(task.requestId, '55', 'Transaksi duplikat dalam satu hari yang sama'); 177 callbackReport(task.requestId, '55', 'Transaksi duplikat dalam satu hari yang sama');
180 } 178 }
181 179
182 function extractProductDetail(remoteProduct) { 180 function extractProductDetail(remoteProduct) {
183 var product; 181 var product;
184 182
185 try { 183 try {
186 product = remoteProduct.split(','); 184 product = remoteProduct.split(',');
187 } 185 }
188 catch(e) { 186 catch(e) {
189 logger.warn('extractProductDetail: exception on split'); 187 logger.warn('extractProductDetail: exception on split');
190 return null; 188 return null;
191 } 189 }
192 190
193 if (product.length !== 3) { 191 if (product.length !== 3) {
194 logger.warn('extractProductDetail: product.length <> 3'); 192 logger.warn('extractProductDetail: product.length <> 3');
195 return null; 193 return null;
196 } 194 }
197 195
198 return {product: product[0], productType: product[1], nominal: product[2]}; 196 return {product: product[0], productType: product[1], nominal: product[2]};
199 } 197 }
200 198
201 function createPayload(transactionType, task, user, noid, pin) { 199 function createPayload(transactionType, task, user, noid, pin) {
202 var product = extractProductDetail(task.remoteProduct); 200 var product = extractProductDetail(task.remoteProduct);
203 if (!product) { 201 if (!product) {
204 logger.warn('createPayload: undefined product'); 202 logger.warn('createPayload: undefined product');
205 return; 203 return;
206 } 204 }
207 205
208 var payload = { 206 var payload = {
209 transactionType: transactionType, 207 transactionType: transactionType,
210 product: product.product, 208 product: product.product,
211 productType: product.productType, 209 productType: product.productType,
212 idpel: task.destination, 210 idpel: task.destination,
213 pin: pin, 211 pin: pin,
214 noid: noid, 212 noid: noid,
215 user: user, 213 user: user,
216 nominal: product.nominal 214 nominal: product.nominal
217 }; 215 };
218 216
219 return xmlBuilder.buildObject(payload); 217 return xmlBuilder.buildObject(payload);
220 } 218 }
221 219
222 exports.start = start; 220 exports.start = start;
223 exports.topupRequest = topupRequest; 221 exports.topupRequest = topupRequest;
224 222