Commit 1caba187c264b39c9c96890ec1f84f44636c5dd8

Authored by Adhidarma Hadiwinoto
1 parent 6fc0cd5de0
Exists in master

mongodb

Showing 2 changed files with 105 additions and 8 deletions Inline Diff

1 { 1 {
2 "name": "sate24-to-kospinjasa", 2 "name": "sate24-to-kospinjasa",
3 "version": "1.0.0", 3 "version": "1.0.0",
4 "description": "ST24 to Kospin JASA", 4 "description": "ST24 to Kospin JASA",
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-kospinjasa.git" 11 "url": "git@gitlab.kodesumber.com:reload97/sate24-to-kospinjasa.git"
12 }, 12 },
13 "keywords": [ 13 "keywords": [
14 "st24", 14 "st24",
15 "reload97", 15 "reload97",
16 "r97", 16 "r97",
17 "ppob", 17 "ppob",
18 "kospinjasa" 18 "kospinjasa"
19 ], 19 ],
20 "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", 20 "author": "Adhidarma Hadiwinoto <me@adhisimon.org>",
21 "license": "ISC", 21 "license": "ISC",
22 "dependencies": { 22 "dependencies": {
23 "easysoap": "^1.0.5", 23 "easysoap": "^1.0.5",
24 "ini": "^1.3.4", 24 "ini": "^1.3.4",
25 "moment": "^2.13.0",
25 "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git", 26 "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git",
26 "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git", 27 "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git",
27 "soap": "^0.15.0", 28 "soap": "^0.15.0",
28 "whiskers": "^0.3.3", 29 "whiskers": "^0.3.3",
29 "winston": "^2.2.0" 30 "winston": "^2.2.0"
30 }, 31 },
31 "devDependencies": { 32 "devDependencies": {
32 "mocha": "^2.4.5", 33 "mocha": "^2.4.5",
33 "should": "^8.3.2" 34 "should": "^8.3.2"
34 } 35 }
35 } 36 }
36 37
partner-kospinjasa.js
1 var winston = require('winston'); 1 var winston = require('winston');
2 var soap = require('soap'); 2 var soap = require('soap');
3 var crypto = require('crypto'); 3 var crypto = require('crypto');
4 var strftime = require('strftime'); 4 var strftime = require('strftime');
5 var fs = require("fs"); 5 var fs = require("fs");
6 var whiskers = require("whiskers"); 6 var whiskers = require("whiskers");
7 var http = require("http"); 7 var http = require("http");
8 var url = require("url"); 8 var url = require("url");
9 var mongoClient = require('mongodb').MongoClient;
10 var moment = require('moment');
9 11
10 process.chdir(__dirname); 12 process.chdir(__dirname);
11 var soapTemplate = fs.readFileSync("message.xml"); 13 var soapTemplate = fs.readFileSync("message.xml");
12 14
13 var max_retry = 10; 15 var max_retry = 10;
14 var sleep_before_retry = 5000; 16 var sleep_before_retry = 5000;
15 17
16 var config; 18 var config;
17 var callbackReport; 19 var callbackReport;
18 var aaa; 20 var aaa;
19 var logger; 21 var logger;
20 var options; 22 var options;
23 var mongodb;
21 24
22 function start(_config, _callbackReport, options) { 25 function start(_config, _callbackReport, options) {
23 config = _config; 26 config = _config;
24 callbackReport = _callbackReport 27 callbackReport = _callbackReport
25 28
26 if (options && options.aaa) { 29 if (options && options.aaa) {
27 aaa = options.aaa; 30 aaa = options.aaa;
28 } 31 }
29 32
30 if (options && options.logger) { 33 if (options && options.logger) {
31 logger = options.logger; 34 logger = options.logger;
32 } else { 35 } else {
33 logger = new winston.Logger({ 36 logger = new winston.Logger({
34 transports: [ 37 transports: [
35 new (winston.transports.Console)() 38 new (winston.transports.Console)()
36 ] 39 ]
37 }); 40 });
38 } 41 }
42
43 initMongoClient();
44 }
45
46 function initMongoClient() {
47 if (!config || !config.mongodb || !config.mongodb.url) {
48 return;
49 }
50
51 try {
52 var url = config.mongodb.url;
53
54 mongoClient.connect(url, function(err, db) {
55 if (err) {
56 logger.warn('Failed to connect to mongodb', {err: err});
57 return;
58 }
59 mongodb = db;
60 logger.info('MongoDB connected');
61 });
62 }
63 catch(err) {
64 logger.warn('Exception when connecting to mongodb', {err: err, url: url});
65 }
66 }
67
68 function insertTaskToMongoDb(task) {
69 if (!isMongoReady()) { return; }
70
71 task.supplier = config.globals.gateway_name;
72 task.rc = '68';
73
74 try {
75 mongodb.collection(config.mongodb.collection).insertOne(task);
76 }
77 catch(err) {
78 //logger.warn('Exception when inserting document to mongodb', {err: err, task: task});
79 }
80 }
81
82 function pushResponseToMongoDb(task, response, rc) {
83 if (!isMongoReady()) { return; }
84
85 try {
86 mongodb.collection(config.mongodb.collection).updateOne(
87 {requestId: task.requestId},
88 {
89 $set: {
90 lastResponse: response,
91 supplier: config.globals.gateway_name,
92 rc: rc
93 },
94 $push: {
95 responses: response
96 }
97 },
98 function(err, result) {
99 if (err) {
100 logger.warn('Error when pushing response to mongodb', {err: err, task: task, response: response});
101 return;
102 }
103 }
104 );
105 }
106 catch(err) {
107 logger.warn('Exception when pushing response to mongodb', {err: err, task: task, response: response});
108 }
109 }
110
111 function isMongoReady() {
112 if (!config.mongodb) { return; }
113 if (!config.mongodb.collection) { return; }
114 if (!mongodb) { return; }
115
116 return true;
39 } 117 }
40 118
41 function topupRequest(task, retry) { 119 function topupRequest(task, retry) {
120 task.ts = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss');
121 task.ts_date = moment(task.timestamp, 'YYYYMMDDHHmmss').format('YYYY-MM-DD');
122
123 insertTaskToMongoDb(task);
124
42 saldoCheck(billpayment, task); 125 saldoCheck(billpayment, task);
43 } 126 }
44 127
45 function saldoCheck(callback, task) { 128 function saldoCheck(callback, task) {
46 129
47 var params = { 130 var params = {
48 userName: config.h2h_out.userid, 131 userName: config.h2h_out.userid,
49 productCode: '00000' , 132 productCode: '00000' ,
50 terminal: 'H2HIPN10', 133 terminal: 'H2HIPN10',
51 transactionType: '61', 134 transactionType: '61',
52 reff: Math.ceil( Math.random() * 99999999 ), 135 reff: Math.ceil( Math.random() * 99999999 ),
53 timeStamp: strftime('%Y-%m-%d %H:%M:%S', new Date()) 136 timeStamp: strftime('%Y-%m-%d %H:%M:%S', new Date())
54 } 137 }
55 138
56 params.signature = createSignatureForSaldoCheck(params, config.h2h_out.password); 139 params.signature = createSignatureForSaldoCheck(params, config.h2h_out.password);
57 140
58 soap.createClient(config.h2h_out.partner, function(err, soapClient) { 141 soap.createClient(config.h2h_out.partner, function(err, soapClient) {
59 142
60 if (err) { 143 if (err) {
61 logger.warn('Error creating soap client for saldoCheck', {err: err}); 144
62 callbackReport(task.requestId, '40', 'Error creating soap client for saldoCheck: ' + err); 145 var errorMessage = 'Error creating soap client for saldoCheck: ' + err;
146
147 logger.warn(errorMessage, {err: err});
148 callbackReport(task.requestId, '40', errorMessage);
149 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: errorMessage}, '40');
150
63 return; 151 return;
64 } 152 }
65 153
66 logger.info('Requesting to service', {url: config.h2h_out.partner, params: params}); 154 logger.info('Requesting to service', {url: config.h2h_out.partner, params: params});
67 soapClient.apih2h.apih2hPort.saldoCheck({ inputSaldo: params }, function(err, result) { 155 soapClient.apih2h.apih2hPort.saldoCheck({ inputSaldo: params }, function(err, result) {
68 156
69 logger.verbose( 157 logger.verbose(
70 'Got saldoCheck response', 158 'Got saldoCheck response',
71 { 159 {
72 lastEndpoint: soapClient.lastEndpoint, 160 lastEndpoint: soapClient.lastEndpoint,
73 lastRequest: soapClient.lastRequest, 161 lastRequest: soapClient.lastRequest,
74 lastMessage: soapClient.lastMessage, 162 lastMessage: soapClient.lastMessage,
75 lastResponse: soapClient.lastResponse, 163 lastResponse: soapClient.lastResponse,
76 } 164 }
77 ); 165 );
78 166
79 if (err) { 167 if (err) {
80 logger.warn('Error requesting saldoCheck', {err: err}); 168 var errorMessage = 'Error requesting saldoCheck: ' + err;
81 callbackReport(task.requestId, '40', 'Gagal check saldo'); 169
170 logger.warn(errorMessage, {err: err});
171 callbackReport(task.requestId, '40', errorMessage);
172 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: errorMessage}, '40');
82 } 173 }
83 174
84 var balance; 175 var balance;
85 logger.verbose('saldoCheck result', {result: result}); 176 logger.verbose('saldoCheck result', {result: result});
86 177
87 try { 178 try {
88 balance = result.outputParameter.bit61.$value; 179 balance = result.outputParameter.bit61.$value;
89 } 180 }
90 catch(e) { 181 catch(e) {
91 balance = 'UNKNOWN'; 182 balance = 'UNKNOWN';
92 } 183 }
93 184
94 185
95 if (task) { 186 if (task) {
96 callback(task, balance); 187 callback(task, balance);
97 } 188 }
98 }); 189 });
99 }); 190 });
100 191
101 } 192 }
102 193
103 function billpayment(task, balance) { 194 function billpayment(task, balance) {
104 195
105 var remoteProduct = task.remoteProduct.split(','); 196 var remoteProduct = task.remoteProduct.split(',');
106 var params = { 197 var params = {
107 userName: config.h2h_out.userid, 198 userName: config.h2h_out.userid,
108 productCode: remoteProduct[0] , 199 productCode: remoteProduct[0] ,
109 terminal: 'H2HIPN10', 200 terminal: 'H2HIPN10',
110 transactionType: '50', 201 transactionType: '50',
111 billNumber: createBillNumber(task.destination), 202 billNumber: createBillNumber(task.destination),
112 amount: remoteProduct[1], 203 amount: remoteProduct[1],
113 bit61: createBillNumber(task.destination), 204 bit61: createBillNumber(task.destination),
114 reff: task.requestId, 205 reff: task.requestId,
115 timeStamp: strftime('%Y-%m-%d %H:%M:%S', new Date()) 206 timeStamp: strftime('%Y-%m-%d %H:%M:%S', new Date())
116 } 207 }
117 208
118 var signature = createSignature(params, config.h2h_out.password); 209 var signature = createSignature(params, config.h2h_out.password);
119 params.signature = signature; 210 params.signature = signature;
120 211
121 soap.createClient(config.h2h_out.partner, function(err, soapClient) { 212 soap.createClient(config.h2h_out.partner, function(err, soapClient) {
122 213
123 var _params = { 214 var _params = {
124 userName: params.userName, 215 userName: params.userName,
125 signature: params.signature, 216 signature: params.signature,
126 productCode: params.productCode, 217 productCode: params.productCode,
127 terminal: params.terminal, 218 terminal: params.terminal,
128 transactionType: params.transactionType, 219 transactionType: params.transactionType,
129 billNumber: params.billNumber, 220 billNumber: params.billNumber,
130 amount: params.amount, 221 amount: params.amount,
131 bit61: params.bit61, 222 bit61: params.bit61,
132 reff: params.reff, 223 reff: params.reff,
133 timeStamp: params.timeStamp 224 timeStamp: params.timeStamp
134 } 225 }
135 226
136 logger.info('Requesting to service', {url: config.h2h_out.partner, params: _params}); 227 logger.info('Requesting to service', {url: config.h2h_out.partner, params: _params});
137 228
138 soapClient.apih2h.apih2hPort.billpayment({ inputCheck: _params }, function(err, result) { 229 soapClient.apih2h.apih2hPort.billpayment({ inputCheck: _params }, function(err, result) {
139 logger.verbose( 230 logger.verbose(
140 'Got response', 231 'Got response',
141 { 232 {
142 lastEndpoint: soapClient.lastEndpoint, 233 lastEndpoint: soapClient.lastEndpoint,
143 lastRequest: soapClient.lastRequest, 234 lastRequest: soapClient.lastRequest,
144 lastMessage: soapClient.lastMessage, 235 lastMessage: soapClient.lastMessage,
145 lastResponse: soapClient.lastResponse, 236 lastResponse: soapClient.lastResponse,
146 } 237 }
147 ); 238 );
148 239
149 if (err) { 240 if (err) {
150 logger.warn('Error requesting service', {err: err}); 241 var errorMessage = 'Error requesting service: ' + err;
151 callbackReport(task.requestId, '68', 'something wrong'); 242
243 logger.warn(errorMessage, {err: err});
244 callbackReport(task.requestId, '68', errorMessage);
245 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: soapClient.lastResponse, parsed: result}, '68');
246
152 return; 247 return;
153 } 248 }
154 249
155 topupResponseHandler(task, result, balance); 250 topupResponseHandler(task, result, balance, soapClient.lastResponse);
156 }); 251 });
157 }); 252 });
158 } 253 }
159 254
160 function topupResponseHandler(task, response, balance) { 255 function topupResponseHandler(task, response, balance, rawResponse) {
161 var st24rc = '68'; 256 var st24rc = '68';
162 var st24message = response.outputParameter.resultDesc.$value; 257 var st24message = response.outputParameter.resultDesc.$value;
163 258
164 var resultCode = parseInt(response.outputParameter.resultCode.$value); 259 var resultCode = parseInt(response.outputParameter.resultCode.$value);
165 var bit39 = parseInt(response.outputParameter.bit39.$value); 260 var bit39 = parseInt(response.outputParameter.bit39.$value);
166 261
167 if ( resultCode == 1 ) { 262 if ( resultCode == 1 ) {
168 // product disabled 263 // product disabled
169 st24rc = '13'; 264 st24rc = '13';
170 } 265 }
171 else if ( resultCode == 2 ) { 266 else if ( resultCode == 2 ) {
172 // prodcode disable 267 // prodcode disable
173 st24rc = '13'; 268 st24rc = '13';
174 } 269 }
175 else if ( resultCode == 3 ) { 270 else if ( resultCode == 3 ) {
176 // duplicate reff 271 // duplicate reff
177 st24rc = '55'; 272 st24rc = '55';
178 } 273 }
179 else if ( resultCode == 4 ) { 274 else if ( resultCode == 4 ) {
180 // not enough balance 275 // not enough balance
181 st24rc = '40'; 276 st24rc = '40';
182 } 277 }
183 else if ( resultCode == 5 ) { 278 else if ( resultCode == 5 ) {
184 // username blocked 279 // username blocked
185 st24rc = '40'; 280 st24rc = '40';
186 } 281 }
187 else if ( resultCode == 6 ) { 282 else if ( resultCode == 6 ) {
188 // not exists username 283 // not exists username
189 st24rc = '40'; 284 st24rc = '40';
190 } 285 }
191 else if ( resultCode == 11 ) { 286 else if ( resultCode == 11 ) {
192 // invalid request 287 // invalid request
193 st24rc = '40' 288 st24rc = '40'
194 } 289 }
195 else if ( resultCode == 12 ) { 290 else if ( resultCode == 12 ) {
196 // no route to host 291 // no route to host
197 st24rc = '40' 292 st24rc = '40'
198 } 293 }
199 else if ( resultCode == 13 ) { 294 else if ( resultCode == 13 ) {
200 // invalid signature 295 // invalid signature
201 st24rc = '40' 296 st24rc = '40'
202 } 297 }
203 else if ( bit39 == 6 ) { 298 else if ( bit39 == 6 ) {
204 st24rc = '40'; 299 st24rc = '40';
205 st24message = 'Error Transaksi ditolak karena terjadi error di H2H dengan response code diluar daftar ini. Silahkan hubungi H2H'; 300 st24message = 'Error Transaksi ditolak karena terjadi error di H2H dengan response code diluar daftar ini. Silahkan hubungi H2H';
206 } 301 }
207 else if ( bit39 == 12 ) { 302 else if ( bit39 == 12 ) {
208 st24rc = '40'; 303 st24rc = '40';
209 st24message = 'Invalid Transaction Transaksi ditolak karena flow transaksi tidak valid'; 304 st24message = 'Invalid Transaction Transaksi ditolak karena flow transaksi tidak valid';
210 } 305 }
211 else if ( bit39 == 13 ) { 306 else if ( bit39 == 13 ) {
212 st24rc = '13'; 307 st24rc = '13';
213 st24message = 'Invalid voucher nominal'; 308 st24message = 'Invalid voucher nominal';
214 } 309 }
215 else if ( bit39 == 14 ) { 310 else if ( bit39 == 14 ) {
216 st24rc = '14'; 311 st24rc = '14';
217 st24message = 'MSISDN tidak ditemukan'; 312 st24message = 'MSISDN tidak ditemukan';
218 } 313 }
219 else if ( bit39 == 30 ) { 314 else if ( bit39 == 30 ) {
220 st24rc = '40'; 315 st24rc = '40';
221 st24message = 'Format Error'; 316 st24message = 'Format Error';
222 } 317 }
223 else if ( bit39 == 31 ) { 318 else if ( bit39 == 31 ) {
224 st24rc = '40'; 319 st24rc = '40';
225 st24message = 'Kode bank tidak terdaftar'; 320 st24message = 'Kode bank tidak terdaftar';
226 } 321 }
227 else if ( bit39 == 63 ) { 322 else if ( bit39 == 63 ) {
228 st24rc = '40'; 323 st24rc = '40';
229 st24message = 'Reversal denied'; 324 st24message = 'Reversal denied';
230 } 325 }
231 else if ( bit39 == 68 ) { 326 else if ( bit39 == 68 ) {
232 st24rc = '68'; 327 st24rc = '68';
233 st24message = 'Transaksi sedang dalam proses'; 328 st24message = 'Transaksi sedang dalam proses';
234 } 329 }
235 else if ( bit39 == 69 ) { 330 else if ( bit39 == 69 ) {
236 st24rc = '68'; 331 st24rc = '68';
237 st24message = 'Respon Ok lebih dari 24 detik'; 332 st24message = 'Respon Ok lebih dari 24 detik';
238 } 333 }
239 else if ( bit39 == 70 ) { 334 else if ( bit39 == 70 ) {
240 st24rc = '13'; 335 st24rc = '13';
241 st24message = 'Voucher out of stock'; 336 st24message = 'Voucher out of stock';
242 } 337 }
243 else if ( bit39 == 79 ) { 338 else if ( bit39 == 79 ) {
244 st24rc = '14'; 339 st24rc = '14';
245 st24message = 'Phone number is blocked by Telkomsel'; 340 st24message = 'Phone number is blocked by Telkomsel';
246 } 341 }
247 else if ( bit39 == 81 ) { 342 else if ( bit39 == 81 ) {
248 st24rc = '14'; 343 st24rc = '14';
249 st24message = 'Phone number is expired'; 344 st24message = 'Phone number is expired';
250 } 345 }
251 else if ( bit39 == 89 ) { 346 else if ( bit39 == 89 ) {
252 st24rc = '40'; 347 st24rc = '40';
253 st24message = 'Link to billing provider is down'; 348 st24message = 'Link to billing provider is down';
254 } 349 }
255 else if ( bit39 == 91 ) { 350 else if ( bit39 == 91 ) {
256 st24rc = '40'; 351 st24rc = '40';
257 st24message = 'Database problem'; 352 st24message = 'Database problem';
258 } 353 }
259 else if ( bit39 == 92 ) { 354 else if ( bit39 == 92 ) {
260 st24rc = '40'; 355 st24rc = '40';
261 st24message = 'Unable to route transaction'; 356 st24message = 'Unable to route transaction';
262 } 357 }
263 else if ( bit39 == 94 ) { 358 else if ( bit39 == 94 ) {
264 st24rc = '40'; 359 st24rc = '40';
265 st24message = 'Duplicate reversal request'; 360 st24message = 'Duplicate reversal request';
266 } 361 }
267 else if ( resultCode == 0 && bit39 == 0) { 362 else if ( resultCode == 0 && bit39 == 0) {
268 363
269 var sn = ''; 364 var sn = '';
270 365
271 try { 366 try {
272 sn = response.outputParameter.bit61.$value.substring(43); 367 sn = response.outputParameter.bit61.$value.substring(43);
273 } 368 }
274 catch(e) { 369 catch(e) {
275 sn = ''; 370 sn = '';
276 } 371 }
277 372
278 st24message = 'SN=' + sn + '; ' + st24message; 373 st24message = 'SN=' + sn + '; ' + st24message;
279 st24rc = '00'; 374 st24rc = '00';
280 } 375 }
281 376
282 var message = 377 var message =
283 response.outputParameter.resultCode.$value 378 response.outputParameter.resultCode.$value
284 + " " + response.outputParameter.resultDesc.$value 379 + " " + response.outputParameter.resultDesc.$value
285 + "; BIT39: " + response.outputParameter.bit39.$value 380 + "; BIT39: " + response.outputParameter.bit39.$value
286 ; 381 ;
287 382
288 if (response.outputParameter.resultDesc.$value != st24message) { 383 if (response.outputParameter.resultDesc.$value != st24message) {
289 var message = message + " " + st24message; 384 var message = message + " " + st24message;
290 } 385 }
291 386
292 message = message + ' -- Prev Balance: ' + balance; 387 message = message + ' -- Prev Balance: ' + balance;
293 388
294 logger.info('Got result: ' + message, {response: response}); 389 logger.info('Got result: ' + message, {response: response});
295 callbackReport(task.requestId, st24rc, st24message + ' -- Prev Balance: ' + balance); 390 callbackReport(task.requestId, st24rc, st24message + ' -- Prev Balance: ' + balance);
391 pushResponseToMongoDb(task, {ts: ts, supplier: config.globals.gateway_name, raw: rawResponse, parsed: response}, st24rc);
296 } 392 }
297 393
298 function createSignature(params, password) { 394 function createSignature(params, password) {
299 var passwordHash = crypto.createHash('sha256').update(password).digest().toString('hex'); 395 var passwordHash = crypto.createHash('sha256').update(password).digest().toString('hex');
300 var plain = 396 var plain =
301 params.userName 397 params.userName
302 + passwordHash 398 + passwordHash
303 + params.productCode 399 + params.productCode
304 + params.terminal 400 + params.terminal
305 + params.transactionType 401 + params.transactionType
306 + params.billNumber 402 + params.billNumber
307 + params.amount 403 + params.amount
308 + params.reff 404 + params.reff
309 + params.timeStamp; 405 + params.timeStamp;
310 406
311 return crypto.createHash('sha1').update(plain).digest().toString('hex'); 407 return crypto.createHash('sha1').update(plain).digest().toString('hex');
312 } 408 }
313 409
314 function createSignatureForSaldoCheck(params, password) { 410 function createSignatureForSaldoCheck(params, password) {
315 var passwordHash = crypto.createHash('sha256').update(password).digest().toString('hex'); 411 var passwordHash = crypto.createHash('sha256').update(password).digest().toString('hex');
316 var plain = 412 var plain =
317 params.userName 413 params.userName
318 + passwordHash 414 + passwordHash
319 + params.productCode 415 + params.productCode
320 + params.terminal 416 + params.terminal
321 + params.transactionType 417 + params.transactionType
322 + params.reff 418 + params.reff
323 + params.timeStamp; 419 + params.timeStamp;
324 420
325 return crypto.createHash('sha1').update(plain).digest().toString('hex'); 421 return crypto.createHash('sha1').update(plain).digest().toString('hex');
326 } 422 }
327 423
328 function createBillNumber(destination) { 424 function createBillNumber(destination) {
329 return ("0000000000000" + destination).slice(-13); 425 return ("0000000000000" + destination).slice(-13);
330 } 426 }
331 427
332 exports.start = start; 428 exports.start = start;
333 exports.topupRequest = topupRequest; 429 exports.topupRequest = topupRequest;
334 exports.createSignature = createSignature; 430 exports.createSignature = createSignature;
335 exports.createBillNumber = createBillNumber; 431 exports.createBillNumber = createBillNumber;
336 432