Commit 86e71ad257586dadc9b81a83a5885636975f33ee
1 parent
4f5d7f25ee
Exists in
master
splitRemoteProduct
Showing 2 changed files with 35 additions and 1 deletions Inline Diff
partner-bnisp.js
1 | "use strict"; | 1 | "use strict"; |
2 | 2 | ||
3 | const http = require('http'); | 3 | const http = require('http'); |
4 | http.globalAgent.maxSockets = Infinity; | 4 | http.globalAgent.maxSockets = Infinity; |
5 | 5 | ||
6 | const request = require('request'); | 6 | const request = require('request'); |
7 | 7 | ||
8 | var config; | 8 | var config; |
9 | var aaa; | 9 | var aaa; |
10 | var logger; | 10 | var logger; |
11 | 11 | ||
12 | function start(options) { | 12 | function start(options) { |
13 | if (!options) { | 13 | if (!options) { |
14 | console.log('Undefined options, terminating....'); | 14 | console.log('Undefined options, terminating....'); |
15 | process.exit(1); | 15 | process.exit(1); |
16 | } | 16 | } |
17 | 17 | ||
18 | if (options.config) { | 18 | if (options.config) { |
19 | config = options.config; | 19 | config = options.config; |
20 | } else { | 20 | } else { |
21 | console.log('Undefined options.config, terminating....') | 21 | console.log('Undefined options.config, terminating....') |
22 | process.exit(1); | 22 | process.exit(1); |
23 | } | 23 | } |
24 | 24 | ||
25 | if (options.aaa) { | 25 | if (options.aaa) { |
26 | aaa = options.aaa; | 26 | aaa = options.aaa; |
27 | } else { | 27 | } else { |
28 | console.log('Undefined options.aaa, terminating....') | 28 | console.log('Undefined options.aaa, terminating....') |
29 | process.exit(1); | 29 | process.exit(1); |
30 | } | 30 | } |
31 | 31 | ||
32 | if (options && options.logger) { | 32 | if (options && options.logger) { |
33 | logger = options.logger; | 33 | logger = options.logger; |
34 | } else { | 34 | } else { |
35 | console.log('Undefined options.logger, terminating....') | 35 | console.log('Undefined options.logger, terminating....') |
36 | process.exit(1); | 36 | process.exit(1); |
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | function callbackReport(requestId, rc, message, options) { | 40 | function callbackReport(requestId, rc, message, options) { |
41 | aaa.callbackReportWithPushToMongoDb(requestId, rc, message); | 41 | aaa.callbackReportWithPushToMongoDb(requestId, rc, message); |
42 | } | 42 | } |
43 | 43 | ||
44 | function topupRequest(task) { | 44 | function topupRequest(task) { |
45 | aaa.insertTaskToMongoDb(task); | 45 | aaa.insertTaskToMongoDb(task); |
46 | _hitTopup(task); | 46 | _hitTopup(task); |
47 | } | 47 | } |
48 | 48 | ||
49 | function splitRemoteProduct(remoteProduct) { | ||
50 | return remoteProduct.replace(/^\s+|\s+$/gm,'').split(/[\/\W]+/); | ||
51 | } | ||
52 | |||
49 | function _hitTopup(task, isCheckStatus) { | 53 | function _hitTopup(task, isCheckStatus) { |
50 | 54 | ||
51 | const remoteProduct = task.remoteProduct.split('/'); | 55 | const remoteProduct = splitRemoteProduct(task.remoteProduct); |
56 | |||
52 | if (remoteProduct.length < 4) { | 57 | if (remoteProduct.length < 4) { |
53 | callbackReport(task.requestId, '40', 'INTERNAL_MSG: Invalid remoteProduct', task) | 58 | callbackReport(task.requestId, '40', 'INTERNAL_MSG: Invalid remoteProduct', task) |
54 | return; | 59 | return; |
55 | } | 60 | } |
56 | 61 | ||
57 | let pathParams = { | 62 | let pathParams = { |
58 | request_type: "purchase", | 63 | request_type: "purchase", |
59 | noid: config.h2h_out.noid, | 64 | noid: config.h2h_out.noid, |
60 | token: config.h2h_out.token, | 65 | token: config.h2h_out.token, |
61 | product: remoteProduct[0], | 66 | product: remoteProduct[0], |
62 | product_type: remoteProduct[1], | 67 | product_type: remoteProduct[1], |
63 | id_pel: task.destination, | 68 | id_pel: task.destination, |
64 | nominal: remoteProduct[2], | 69 | nominal: remoteProduct[2], |
65 | admin: remoteProduct[3], | 70 | admin: remoteProduct[3], |
66 | trace_id: task.requestId | 71 | trace_id: task.requestId |
67 | } | 72 | } |
68 | 73 | ||
69 | const requestOptions = { | 74 | const requestOptions = { |
70 | url: config.h2h_out.partner.replace(/\/+$/, '') + '/' + createUrlPath(pathParams).replace(/^\/+/, '') | 75 | url: config.h2h_out.partner.replace(/\/+$/, '') + '/' + createUrlPath(pathParams).replace(/^\/+/, '') |
71 | } | 76 | } |
72 | 77 | ||
73 | logger.verbose('Requeting to partner', {requestOptions: requestOptions}); | 78 | logger.verbose('Requeting to partner', {requestOptions: requestOptions}); |
74 | request(requestOptions, function(error, response, body) { | 79 | request(requestOptions, function(error, response, body) { |
75 | if (error) { | 80 | if (error) { |
76 | let rc = '68'; | 81 | let rc = '68'; |
77 | 82 | ||
78 | if (!isCheckStatus && (error.syscall == 'connect')) { | 83 | if (!isCheckStatus && (error.syscall == 'connect')) { |
79 | rc = '91'; | 84 | rc = '91'; |
80 | } | 85 | } |
81 | 86 | ||
82 | logger.warn('Error requesting to partner', {task: task, rc: rc, error: error}); | 87 | logger.warn('Error requesting to partner', {task: task, rc: rc, error: error}); |
83 | callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error requesting to partner. ' + error, {task: task}); | 88 | callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error requesting to partner. ' + error, {task: task}); |
84 | return; | 89 | return; |
85 | } | 90 | } |
86 | 91 | ||
87 | if (response.statusCode != 200) { | 92 | if (response.statusCode != 200) { |
88 | let rc = '68'; | 93 | let rc = '68'; |
89 | 94 | ||
90 | logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode}); | 95 | logger.warn('HTTP status code is not 200', {task: task, http_status_code: response.statusCode}); |
91 | callbackReport(task.requestId, rc, 'INTERNAL_MSG: HTTP status code ' + response.statusCode, {task: task}); | 96 | callbackReport(task.requestId, rc, 'INTERNAL_MSG: HTTP status code ' + response.statusCode, {task: task}); |
92 | return; | 97 | return; |
93 | } | 98 | } |
94 | 99 | ||
95 | if (!body) { | 100 | if (!body) { |
96 | let rc = '68'; | 101 | let rc = '68'; |
97 | 102 | ||
98 | logger.warn('Error processing response body', {task: task, responseBody: body}); | 103 | logger.warn('Error processing response body', {task: task, responseBody: body}); |
99 | callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error processing response body', {task: task}); | 104 | callbackReport(task.requestId, rc, 'INTERNAL_MSG: Error processing response body', {task: task}); |
100 | return; | 105 | return; |
101 | } | 106 | } |
102 | 107 | ||
103 | if (body.trim() == 'invalid specs') { | 108 | if (body.trim() == 'invalid specs') { |
104 | let rc = '40'; | 109 | let rc = '40'; |
105 | 110 | ||
106 | logger.warn('Invalid specs', {task: task, responseBody: body}); | 111 | logger.warn('Invalid specs', {task: task, responseBody: body}); |
107 | callbackReport(task.requestId, rc, body); | 112 | callbackReport(task.requestId, rc, body); |
108 | return; | 113 | return; |
109 | } | 114 | } |
110 | 115 | ||
111 | logger.verbose('Got response from partner', {task: task, responseBody: body}); | 116 | logger.verbose('Got response from partner', {task: task, responseBody: body}); |
112 | 117 | ||
113 | const responseData = parseResponseBody(body); | 118 | const responseData = parseResponseBody(body); |
114 | logger.verbose('Response body parsed as json value', {responseData: responseData}); | 119 | logger.verbose('Response body parsed as json value', {responseData: responseData}); |
115 | const data = responseDataProcessor(responseData); | 120 | const data = responseDataProcessor(responseData); |
116 | 121 | ||
117 | if (data.balance && aaa.updateBalance) { | 122 | if (data.balance && aaa.updateBalance) { |
118 | aaa.updateBalance(data.balance); | 123 | aaa.updateBalance(data.balance); |
119 | } | 124 | } |
120 | 125 | ||
121 | callbackReport(task.requestId, data.rc, data.combinedMessage, {task: task}); | 126 | callbackReport(task.requestId, data.rc, data.combinedMessage, {task: task}); |
122 | }) | 127 | }) |
123 | 128 | ||
124 | } | 129 | } |
125 | 130 | ||
126 | function createUrlPath(options) { | 131 | function createUrlPath(options) { |
127 | let urlPath = [ | 132 | let urlPath = [ |
128 | "get", | 133 | "get", |
129 | options.request_type || "purchase", | 134 | options.request_type || "purchase", |
130 | "json", | 135 | "json", |
131 | options.noid, | 136 | options.noid, |
132 | options.token, | 137 | options.token, |
133 | options.product, | 138 | options.product, |
134 | options.product_type, | 139 | options.product_type, |
135 | options.id_pel, | 140 | options.id_pel, |
136 | options.nominal || 0, | 141 | options.nominal || 0, |
137 | options.admin || 0, | 142 | options.admin || 0, |
138 | options.trace_id | 143 | options.trace_id |
139 | ].join('/'); | 144 | ].join('/'); |
140 | 145 | ||
141 | return '/' + urlPath; | 146 | return '/' + urlPath; |
142 | } | 147 | } |
143 | 148 | ||
144 | function parseResponseBody(body) { | 149 | function parseResponseBody(body) { |
145 | let data; | 150 | let data; |
146 | 151 | ||
147 | try { | 152 | try { |
148 | data = JSON.parse(body); | 153 | data = JSON.parse(body); |
149 | } | 154 | } |
150 | catch(e) { | 155 | catch(e) { |
151 | if (logger) { | 156 | if (logger) { |
152 | logger.warn('Exception on parsing result body: ' + e); | 157 | logger.warn('Exception on parsing result body: ' + e); |
153 | return; | 158 | return; |
154 | } | 159 | } |
155 | } | 160 | } |
156 | 161 | ||
157 | return data; | 162 | return data; |
158 | } | 163 | } |
159 | 164 | ||
160 | function responseDataProcessor(responseData) { | 165 | function responseDataProcessor(responseData) { |
161 | let retval = { | 166 | let retval = { |
162 | rc: '68', | 167 | rc: '68', |
163 | sn: '', | 168 | sn: '', |
164 | responseMessage: '', | 169 | responseMessage: '', |
165 | combinedMessage: '', | 170 | combinedMessage: '', |
166 | amount: 0, | 171 | amount: 0, |
167 | balance: 0, | 172 | balance: 0, |
168 | saldo: 0, | 173 | saldo: 0, |
169 | ts: '', | 174 | ts: '', |
170 | loadTime: 0, | 175 | loadTime: 0, |
171 | product: '', | 176 | product: '', |
172 | productType: '' | 177 | productType: '' |
173 | } | 178 | } |
174 | 179 | ||
175 | let combinedMessage = []; | 180 | let combinedMessage = []; |
176 | 181 | ||
177 | if (responseData.response_code == '0000') { | 182 | if (responseData.response_code == '0000') { |
178 | retval.rc = '00'; | 183 | retval.rc = '00'; |
179 | } | 184 | } |
180 | else if (responseData.response_code == '0010') { | 185 | else if (responseData.response_code == '0010') { |
181 | retval.rc = '14'; | 186 | retval.rc = '14'; |
182 | } | 187 | } |
183 | else if (responseData.response_code == '0021') { | 188 | else if (responseData.response_code == '0021') { |
184 | retval.rc = '14'; | 189 | retval.rc = '14'; |
185 | } | 190 | } |
186 | else if (['9990','0099','0068','0063','0005','9997','9999','9998','9990','0600','1003'].indexOf(responseData.response_code) >= 0) { | 191 | else if (['9990','0099','0068','0063','0005','9997','9999','9998','9990','0600','1003'].indexOf(responseData.response_code) >= 0) { |
187 | retval.rc = '68'; | 192 | retval.rc = '68'; |
188 | } | 193 | } |
189 | else { | 194 | else { |
190 | retval.rc = '40'; | 195 | retval.rc = '40'; |
191 | } | 196 | } |
192 | 197 | ||
193 | if (responseData.response_code) { | 198 | if (responseData.response_code) { |
194 | combinedMessage.push(responseData.response_code); | 199 | combinedMessage.push(responseData.response_code); |
195 | } | 200 | } |
196 | 201 | ||
197 | if (responseData.product) { | 202 | if (responseData.product) { |
198 | combinedMessage.push(responseData.product) | 203 | combinedMessage.push(responseData.product) |
199 | } | 204 | } |
200 | 205 | ||
201 | if (responseData.produk_tipe) { | 206 | if (responseData.produk_tipe) { |
202 | combinedMessage.push(responseData.produk_tipe) | 207 | combinedMessage.push(responseData.produk_tipe) |
203 | } | 208 | } |
204 | 209 | ||
205 | if (responseData.idpel) { | 210 | if (responseData.idpel) { |
206 | combinedMessage.push(responseData.idpel) | 211 | combinedMessage.push(responseData.idpel) |
207 | } | 212 | } |
208 | 213 | ||
209 | retval.responseMessage = responseData.response_message || ''; | 214 | retval.responseMessage = responseData.response_message || ''; |
210 | if (retval.responseMessage) { | 215 | if (retval.responseMessage) { |
211 | combinedMessage.push(retval.responseMessage); | 216 | combinedMessage.push(retval.responseMessage); |
212 | } | 217 | } |
213 | 218 | ||
214 | if (responseData.detail) { | 219 | if (responseData.detail) { |
215 | retval.sn = responseData.detail.voucherSerialNumber || ''; | 220 | retval.sn = responseData.detail.voucherSerialNumber || ''; |
216 | } | 221 | } |
217 | 222 | ||
218 | retval.amount = responseData.amount || 0; | 223 | retval.amount = responseData.amount || 0; |
219 | combinedMessage.push('Amount: ' + retval.amount); | 224 | combinedMessage.push('Amount: ' + retval.amount); |
220 | 225 | ||
221 | retval.balance = responseData.saldo || 0; | 226 | retval.balance = responseData.saldo || 0; |
222 | retval.saldo = retval.balance; | 227 | retval.saldo = retval.balance; |
223 | combinedMessage.push('Balance: ' + retval.balance); | 228 | combinedMessage.push('Balance: ' + retval.balance); |
224 | 229 | ||
225 | retval.ts = responseData.waktu || ''; | 230 | retval.ts = responseData.waktu || ''; |
226 | combinedMessage.push(retval.ts); | 231 | combinedMessage.push(retval.ts); |
227 | 232 | ||
228 | retval.loadTime = responseData.loadTime || ''; | 233 | retval.loadTime = responseData.loadTime || ''; |
229 | combinedMessage.push('Load time: ' + retval.loadTime); | 234 | combinedMessage.push('Load time: ' + retval.loadTime); |
230 | 235 | ||
231 | retval.combinedMessage = combinedMessage.join(' | '); | 236 | retval.combinedMessage = combinedMessage.join(' | '); |
232 | 237 | ||
233 | if (retval.sn) { | 238 | if (retval.sn) { |
234 | retval.combinedMessage = 'SN=' + retval.sn + '; ' + retval.combinedMessage; | 239 | retval.combinedMessage = 'SN=' + retval.sn + '; ' + retval.combinedMessage; |
235 | } | 240 | } |
236 | 241 | ||
237 | return retval; | 242 | return retval; |
238 | } | 243 | } |
239 | 244 | ||
240 | exports.start = start; | 245 | exports.start = start; |
241 | exports.createUrlPath = createUrlPath; | 246 | exports.createUrlPath = createUrlPath; |
242 | exports.parseResponseBody = parseResponseBody; | 247 | exports.parseResponseBody = parseResponseBody; |
243 | exports.responseDataProcessor = responseDataProcessor; | 248 | exports.responseDataProcessor = responseDataProcessor; |
244 | exports.topupRequest = topupRequest; | 249 | exports.topupRequest = topupRequest; |
250 | exports.splitRemoteProduct = splitRemoteProduct; | ||
245 | 251 |
test.js
1 | "use strict"; | 1 | "use strict"; |
2 | 2 | ||
3 | const should = require("should"); | 3 | const should = require("should"); |
4 | const partner = require("./partner-bnisp"); | 4 | const partner = require("./partner-bnisp"); |
5 | 5 | ||
6 | describe("#partner", function() { | 6 | describe("#partner", function() { |
7 | describe("#createUrlPath", function() { | 7 | describe("#createUrlPath", function() { |
8 | 8 | ||
9 | it('should return correct url path based on example', function() { | 9 | it('should return correct url path based on example', function() { |
10 | let options = { | 10 | let options = { |
11 | noid: 1002003, | 11 | noid: 1002003, |
12 | token: 'CIPY6t6ruy5UuGG0PCqu', | 12 | token: 'CIPY6t6ruy5UuGG0PCqu', |
13 | product: 'PULSA', | 13 | product: 'PULSA', |
14 | product_type: 'THREE5000', | 14 | product_type: 'THREE5000', |
15 | id_pel: '0895385381299', | 15 | id_pel: '0895385381299', |
16 | trace_id: 16 | 16 | trace_id: 16 |
17 | } | 17 | } |
18 | 18 | ||
19 | partner.createUrlPath(options).should.equal('/get/purchase/json/1002003/CIPY6t6ruy5UuGG0PCqu/PULSA/THREE5000/0895385381299/0/0/16') | 19 | partner.createUrlPath(options).should.equal('/get/purchase/json/1002003/CIPY6t6ruy5UuGG0PCqu/PULSA/THREE5000/0895385381299/0/0/16') |
20 | }) | 20 | }) |
21 | 21 | ||
22 | }) | 22 | }) |
23 | 23 | ||
24 | const responseBody = '{"trxId":"064024","response_code":"0000","response_message":"SUKSES","detail":{"jmlTagihan":"1","kodeThree":"012001","nilaiPulsa":"000000005000","noHp":"0895385381299","transactionId":"0612143023138365102 ","voucherSerialNumber":"20170612143620980249"},"reff":"20170612143620980249","loadTime":"0.0107","tipe_request":"purchase","prv":"hpay","userID":"1002003","idpel":"0895385381299","product":"PULSA","produk":"PULSA","product_detail":"THREE5000","produk_tipe":"THREE5000","traceId":16,"tagihan":5050,"total_tagihan":5050,"amount":5050,"saldo":94950,"waktu":"2017-07-17 18:43:32"}'; | 24 | const responseBody = '{"trxId":"064024","response_code":"0000","response_message":"SUKSES","detail":{"jmlTagihan":"1","kodeThree":"012001","nilaiPulsa":"000000005000","noHp":"0895385381299","transactionId":"0612143023138365102 ","voucherSerialNumber":"20170612143620980249"},"reff":"20170612143620980249","loadTime":"0.0107","tipe_request":"purchase","prv":"hpay","userID":"1002003","idpel":"0895385381299","product":"PULSA","produk":"PULSA","product_detail":"THREE5000","produk_tipe":"THREE5000","traceId":16,"tagihan":5050,"total_tagihan":5050,"amount":5050,"saldo":94950,"waktu":"2017-07-17 18:43:32"}'; |
25 | const responseData = partner.parseResponseBody(responseBody); | 25 | const responseData = partner.parseResponseBody(responseBody); |
26 | 26 | ||
27 | describe('#parseResponseBody', function() { | 27 | describe('#parseResponseBody', function() { |
28 | 28 | ||
29 | it('should return correct response code', function() { | 29 | it('should return correct response code', function() { |
30 | responseData.response_code.should.equal('0000'); | 30 | responseData.response_code.should.equal('0000'); |
31 | }) | 31 | }) |
32 | 32 | ||
33 | it('should return correct voucher serial number', function() { | 33 | it('should return correct voucher serial number', function() { |
34 | responseData.detail.voucherSerialNumber.should.equal('20170612143620980249'); | 34 | responseData.detail.voucherSerialNumber.should.equal('20170612143620980249'); |
35 | }) | 35 | }) |
36 | }) | 36 | }) |
37 | 37 | ||
38 | describe('#responseDataProcessor', function() { | 38 | describe('#responseDataProcessor', function() { |
39 | const processed = partner.responseDataProcessor(responseData); | 39 | const processed = partner.responseDataProcessor(responseData); |
40 | 40 | ||
41 | it('should return correct rc', function() { | 41 | it('should return correct rc', function() { |
42 | processed.rc.should.equal('00'); | 42 | processed.rc.should.equal('00'); |
43 | }) | 43 | }) |
44 | 44 | ||
45 | it('should return correct sn', function() { | 45 | it('should return correct sn', function() { |
46 | processed.sn.should.equal('20170612143620980249'); | 46 | processed.sn.should.equal('20170612143620980249'); |
47 | }) | 47 | }) |
48 | 48 | ||
49 | it('should return correct amount', function() { | 49 | it('should return correct amount', function() { |
50 | processed.amount.should.equal(5050); | 50 | processed.amount.should.equal(5050); |
51 | }) | 51 | }) |
52 | 52 | ||
53 | it('should return correct balance', function() { | 53 | it('should return correct balance', function() { |
54 | processed.balance.should.equal(94950); | 54 | processed.balance.should.equal(94950); |
55 | }) | 55 | }) |
56 | }) | 56 | }) |
57 | |||
58 | describe('#splitRemoteProduct', function() { | ||
59 | it ('should return correctly using space as separator', function() { | ||
60 | const remoteProduct = 'PULSA THREE5000 0 0'; | ||
61 | partner.splitRemoteProduct(remoteProduct)[0].should.equal('PULSA'); | ||
62 | partner.splitRemoteProduct(remoteProduct)[1].should.equal('THREE5000'); | ||
63 | partner.splitRemoteProduct(remoteProduct)[2].should.equal('0'); | ||
64 | partner.splitRemoteProduct(remoteProduct)[3].should.equal('0'); | ||
65 | }) | ||
66 | |||
67 | it ('should return correctly using comma as separator', function() { | ||
68 | const remoteProduct = 'PULSA,THREE5000,0,0'; | ||
69 | partner.splitRemoteProduct(remoteProduct)[0].should.equal('PULSA'); | ||
70 | partner.splitRemoteProduct(remoteProduct)[1].should.equal('THREE5000'); | ||
71 | partner.splitRemoteProduct(remoteProduct)[2].should.equal('0'); | ||
72 | partner.splitRemoteProduct(remoteProduct)[3].should.equal('0'); | ||
73 | }) | ||
74 | |||
75 | it ('should return correctly using slash as separator', function() { | ||
76 | const remoteProduct = 'PULSA/THREE5000/0/0'; | ||
77 | partner.splitRemoteProduct(remoteProduct)[0].should.equal('PULSA'); | ||
78 | partner.splitRemoteProduct(remoteProduct)[1].should.equal('THREE5000'); | ||
79 | partner.splitRemoteProduct(remoteProduct)[2].should.equal('0'); | ||
80 | partner.splitRemoteProduct(remoteProduct)[3].should.equal('0'); | ||
81 | }) | ||
82 | |||
83 | |||
84 | }) | ||
57 | }) | 85 | }) |
58 | 86 |