Commit 97991a1dc4df63ecb9c77272529389c899d1264c
1 parent
6998514971
Exists in
master
pakai whiskers
Showing 3 changed files with 96 additions and 1 deletions Inline Diff
message.xml
File was created | 1 | <?xml version="1.0" encoding="utf-8"?> | |
2 | |||
3 | <SOAP-ENV:Envelope | ||
4 | SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" | ||
5 | xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" | ||
6 | xmlns:xsd="http://www.w3.org/2001/XMLSchema" | ||
7 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
8 | xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" | ||
9 | xmlns:tns="urn:apih2h"> | ||
10 | |||
11 | <SOAP-ENV:Body> | ||
12 | <tns:billpayment xmlns:tns="urn:apih2h"> | ||
13 | <inputCheck xsi:type="tns:inputCheck"> | ||
14 | <userName xsi:type="xsd:string">{ params.userName }</userName> | ||
15 | <signature xsi:type="xsd:string">{ params.signature }</signature> | ||
16 | <productCode xsi:type="xsd:string">{ params.productCode }</productCode> | ||
17 | <terminal xsi:type="xsd:string">{ params.terminal }</terminal> | ||
18 | <transactionType xsi:type="xsd:string">{ params.transactionType }</transactionType> | ||
19 | <billNumber xsi:type="xsd:string">{ params.billNumber }</billNumber> | ||
20 | <amount xsi:type="xsd:string">{ params.amount }</amount> | ||
21 | <bit61 xsi:type="xsd:string">{ params.bit61 }</bit61> | ||
22 | <reff xsi:type="xsd:string">{ params.reff }</reff> | ||
23 | <timeStamp xsi:type="xsd:string">{ params.timeStamp }</timeStamp> | ||
24 | </inputCheck> | ||
25 | </tns:billpayment> | ||
26 | </SOAP-ENV:Body> | ||
27 | </SOAP-ENV:Envelope> | ||
28 |
package.json
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 | "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git", | 25 | "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git", |
26 | "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git", | 26 | "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git", |
27 | "soap": "^0.15.0", | 27 | "soap": "^0.15.0", |
28 | "whiskers": "^0.3.3", | ||
28 | "winston": "^2.2.0" | 29 | "winston": "^2.2.0" |
29 | }, | 30 | }, |
30 | "devDependencies": { | 31 | "devDependencies": { |
31 | "mocha": "^2.4.5", | 32 | "mocha": "^2.4.5", |
32 | "should": "^8.3.2" | 33 | "should": "^8.3.2" |
33 | } | 34 | } |
34 | } | 35 | } |
35 | 36 |
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"); | ||
6 | var whiskers = require("whiskers"); | ||
7 | var http = require("http"); | ||
8 | |||
9 | process.chdir(__dirname); | ||
10 | var soapTemplate = fs.readFileSync("message.xml"); | ||
5 | 11 | ||
6 | var max_retry = 10; | 12 | var max_retry = 10; |
7 | var sleep_before_retry = 5000; | 13 | var sleep_before_retry = 5000; |
8 | 14 | ||
9 | var config; | 15 | var config; |
10 | var callbackReport; | 16 | var callbackReport; |
11 | var aaa; | 17 | var aaa; |
12 | var logger; | 18 | var logger; |
13 | var options; | 19 | var options; |
14 | 20 | ||
15 | function start(_config, _callbackReport, options) { | 21 | function start(_config, _callbackReport, options) { |
16 | config = _config; | 22 | config = _config; |
17 | callbackReport = _callbackReport | 23 | callbackReport = _callbackReport |
18 | 24 | ||
19 | if (options && options.aaa) { | 25 | if (options && options.aaa) { |
20 | aaa = options.aaa; | 26 | aaa = options.aaa; |
21 | } | 27 | } |
22 | 28 | ||
23 | if (options && options.logger) { | 29 | if (options && options.logger) { |
24 | logger = options.logger; | 30 | logger = options.logger; |
25 | } else { | 31 | } else { |
26 | logger = new winston.Logger({ | 32 | logger = new winston.Logger({ |
27 | transports: [ | 33 | transports: [ |
28 | new (winston.transports.Console)() | 34 | new (winston.transports.Console)() |
29 | ] | 35 | ] |
30 | }); | 36 | }); |
31 | } | 37 | } |
32 | } | 38 | } |
33 | 39 | ||
34 | function topupRequest(task, retry) { | 40 | function topupRequest(task, retry) { |
35 | if (retry === undefined) { | 41 | if (retry === undefined) { |
36 | retry = max_retry; | 42 | retry = max_retry; |
37 | } | 43 | } |
38 | 44 | ||
39 | var remoteProduct = task.remoteProduct.split(','); | 45 | var remoteProduct = task.remoteProduct.split(','); |
40 | var params = { | 46 | var params = { |
41 | userName: config.h2h_out.userid, | 47 | userName: config.h2h_out.userid, |
42 | productCode: remoteProduct[0] , | 48 | productCode: remoteProduct[0] , |
43 | terminal: 'terminal0', | 49 | terminal: 'terminal0', |
44 | transactionType: '50', | 50 | transactionType: '50', |
45 | billNumber: createBillNumber(task.destination), | 51 | billNumber: createBillNumber(task.destination), |
46 | amount: remoteProduct[1], | 52 | amount: remoteProduct[1], |
47 | bit61: createBillNumber(task.destination), | 53 | bit61: createBillNumber(task.destination), |
48 | reff: task.requestId, | 54 | reff: task.requestId, |
49 | timeStamp: strftime('%d-%m-%Y %H:%M:%S', new Date()) | 55 | timeStamp: strftime('%d-%m-%Y %H:%M:%S', new Date()) |
50 | } | 56 | } |
51 | 57 | ||
52 | var signature = createSignature(params, config.h2h_out.password); | 58 | var signature = createSignature(params, config.h2h_out.password); |
53 | params.signature = signature; | 59 | params.signature = signature; |
54 | 60 | ||
55 | topupRequestSoap(task, params, retry); | 61 | topupRequestSoapDIY(task, params, retry); |
56 | } | 62 | } |
57 | 63 | ||
58 | function topupRequestSoap(task, params, retry) { | 64 | function topupRequestSoap(task, params, retry) { |
59 | 65 | ||
60 | soap.createClient(config.h2h_out.partner, function(err, soapClient) { | 66 | soap.createClient(config.h2h_out.partner, function(err, soapClient) { |
61 | 67 | ||
62 | var _params = { | 68 | var _params = { |
63 | userName: params.userName, | 69 | userName: params.userName, |
64 | signature: params.signature, | 70 | signature: params.signature, |
65 | productCode: params.productCode, | 71 | productCode: params.productCode, |
66 | terminal: params.terminal, | 72 | terminal: params.terminal, |
67 | transactionType: params.transactionType, | 73 | transactionType: params.transactionType, |
68 | billNumber: params.billNumber, | 74 | billNumber: params.billNumber, |
69 | amount: params.amount, | 75 | amount: params.amount, |
70 | bit61: params.bit61, | 76 | bit61: params.bit61, |
71 | reff: params.reff, | 77 | reff: params.reff, |
72 | timeStamp: params.timeStamp | 78 | timeStamp: params.timeStamp |
73 | } | 79 | } |
74 | 80 | ||
75 | logger.info('Requesting to service', {url: config.h2h_out.partner, params: _params}); | 81 | logger.info('Requesting to service', {url: config.h2h_out.partner, params: _params}); |
76 | 82 | ||
77 | soapClient.apih2h.apih2hPort.billpayment({ inputCheck: _params }, function(err, result) { | 83 | soapClient.apih2h.apih2hPort.billpayment({ inputCheck: _params }, function(err, result) { |
78 | 84 | ||
79 | logger.info('Got response', {lastRequest: soapClient.lastRequest}); | 85 | logger.info('Got response', {lastRequest: soapClient.lastRequest}); |
80 | 86 | ||
81 | if (err) { | 87 | if (err) { |
82 | logger.warn('Error requesting service', {err: err}); | 88 | logger.warn('Error requesting service', {err: err}); |
83 | callbackReport(task.requestId, '68', 'something wrong'); | 89 | callbackReport(task.requestId, '68', 'something wrong'); |
84 | return; | 90 | return; |
85 | } | 91 | } |
86 | 92 | ||
87 | var responseMessageToST24 = result.outputParameter.resultCode.$value + ' - ' + result.outputParameter.resultDesc.$value; | 93 | var responseMessageToST24 = result.outputParameter.resultCode.$value + ' - ' + result.outputParameter.resultDesc.$value; |
88 | 94 | ||
89 | logger.info('Got result: ' + responseMessageToST24, {result: result}); | 95 | logger.info('Got result: ' + responseMessageToST24, {result: result}); |
90 | 96 | ||
91 | callbackReport(task.requestId, '68', responseMessageToST24); | 97 | callbackReport(task.requestId, '68', responseMessageToST24); |
92 | }); | 98 | }); |
93 | }); | 99 | }); |
94 | } | 100 | } |
95 | 101 | ||
102 | function topupRequestSoapDIY(task, params, retry) { | ||
103 | var message = whiskers.render(soapTemplate, params); | ||
104 | logger.verbose("Generating SOAP message", {message: message}); | ||
105 | |||
106 | var partnerUrl = url.parse(config.h2h_out.partner); | ||
107 | var postRequest = { | ||
108 | host: partnerUrl.hostname, | ||
109 | path: partnerUrl.path, | ||
110 | port: partnerUrl.port, | ||
111 | method: "POST", | ||
112 | headers: { | ||
113 | 'Content-Type': 'application/soap', | ||
114 | 'Content-Length': Buffer.byteLength(message) | ||
115 | } | ||
116 | }; | ||
117 | |||
118 | logger.info('POST to partner', {postRequest: postRequest}); | ||
119 | var req = http.request(postRequest, function( res ) { | ||
120 | |||
121 | logger.verbose('Request status code: ' + res.statusCode ); | ||
122 | var buffer = ""; | ||
123 | |||
124 | res.on( "data", function( data ) { | ||
125 | buffer = buffer + data; | ||
126 | }); | ||
127 | |||
128 | res.on( "end", function( data ) { | ||
129 | topupResponseHandler(buffer, task); | ||
130 | }); | ||
131 | |||
132 | }); | ||
133 | |||
134 | req.on('error', function(e) { | ||
135 | logger.warn('problem with request: ' + e.message); | ||
136 | callbackReport(task.requestId, '68', e.message); | ||
137 | |||
138 | topupRequestRetry(task); | ||
139 | }); | ||
140 | |||
141 | req.write(message); | ||
142 | req.end(); | ||
143 | } | ||
144 | |||
145 | function topupResponseHandler(response, task) { | ||
146 | logger.verbose('Got response', {response: response, task: task}); | ||
147 | callbackReport(task.requestId, '68', 'Got response'); | ||
148 | } | ||
149 | |||
150 | function topupRequestRetry(task) { | ||
151 | task.retry--; | ||
152 | |||
153 | if (task.retry > 0) { | ||
154 | logger.info('Retrying in ' + sleepBeforeRetry + 's'); | ||
155 | setTimeout(topupRequest, sleepBeforeRetry * 1000, task, task.retry); | ||
156 | } | ||
157 | else { | ||
158 | logger.warn('Maximum retry for pending status exceeded', {task: task}); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | |||
96 | 163 | ||
97 | 164 | ||
98 | function createSignature(params, password) { | 165 | function createSignature(params, password) { |
99 | var passwordHash = crypto.createHash('sha256').update(password).digest().toString('hex'); | 166 | var passwordHash = crypto.createHash('sha256').update(password).digest().toString('hex'); |
100 | 167 | ||
101 | var plain = | 168 | var plain = |
102 | params.userName | 169 | params.userName |
103 | + passwordHash | 170 | + passwordHash |
104 | + params.productCode | 171 | + params.productCode |
105 | + params.terminal | 172 | + params.terminal |
106 | + params.transactionType | 173 | + params.transactionType |
107 | + params.billNumber | 174 | + params.billNumber |
108 | + params.amount | 175 | + params.amount |
109 | + params.reff | 176 | + params.reff |
110 | + params.timeStamp; | 177 | + params.timeStamp; |
111 | 178 | ||
112 | var result = crypto.createHash('sha1').update(plain).digest().toString('hex'); | 179 | var result = crypto.createHash('sha1').update(plain).digest().toString('hex'); |
113 | 180 | ||
114 | if (logger) { | 181 | if (logger) { |
115 | logger.verbose('Calculating signature', {plain: plain, result: result, params: params, password: password}); | 182 | logger.verbose('Calculating signature', {plain: plain, result: result, params: params, password: password}); |
116 | } | 183 | } |
117 | 184 | ||
118 | return result; | 185 | return result; |
119 | } | 186 | } |
120 | 187 | ||
121 | function createBillNumber(destination) { | 188 | function createBillNumber(destination) { |
122 | return ("0000000000000" + destination).slice(-13); | 189 | return ("0000000000000" + destination).slice(-13); |
123 | } | 190 | } |
124 | 191 | ||
125 | exports.start = start; | 192 | exports.start = start; |
126 | exports.topupRequest = topupRequest; | 193 | exports.topupRequest = topupRequest; |
127 | exports.createSignature = createSignature; | 194 | exports.createSignature = createSignature; |
128 | exports.createBillNumber = createBillNumber; | 195 | exports.createBillNumber = createBillNumber; |
129 | 196 |