Commit 9ced2cfdf03e19f6c35901c59076ab1322236d6b
1 parent
635fc54bfa
Exists in
master
and in
1 other branch
PAY finished
Showing 3 changed files with 111 additions and 1 deletions Inline Diff
lib/core-callback/sender.js
1 | const MODULE_NAME = 'CORE-CALLBACK-SENDER'; | 1 | const MODULE_NAME = 'CORE-CALLBACK-SENDER'; |
2 | const MAX_RETRY = 10; | 2 | const MAX_RETRY = 10; |
3 | const SLEEP_BEFORE_RETRY_MS = 60 * 1000; | 3 | const SLEEP_BEFORE_RETRY_MS = 60 * 1000; |
4 | 4 | ||
5 | const axios = require('axios').default; | 5 | const axios = require('axios').default; |
6 | const logger = require('komodo-sdk/logger'); | 6 | const logger = require('komodo-sdk/logger'); |
7 | 7 | ||
8 | const sleep = require('../sleep'); | 8 | const sleep = require('../sleep'); |
9 | const urlConcatQs = require('../url-concat-qs'); | 9 | const urlConcatQs = require('../url-concat-qs'); |
10 | 10 | ||
11 | const sender = async (data, xid, retry) => { | 11 | const sender = async (data, xid, retry) => { |
12 | if (!data.reverse_url) return; | 12 | if (!data.reverse_url) return; |
13 | 13 | ||
14 | const params = { | 14 | const params = { |
15 | httpgetx_xid: xid, | 15 | httpgetx_xid: xid, |
16 | command: data.command, | 16 | command: data.command, |
17 | request_id: data.request_id && data.request_id.toString(), | 17 | request_id: data.request_id && data.request_id.toString(), |
18 | transaction_id: data.transaction_id && data.transaction_id.toString(), | 18 | transaction_id: data.transaction_id && data.transaction_id.toString(), |
19 | transaction_date: data.transaction_date, | 19 | transaction_date: data.transaction_date, |
20 | store_name: data.store_name, | 20 | store_name: data.store_name, |
21 | terminal_name: data.terminal_name, | 21 | terminal_name: data.terminal_name, |
22 | product_name: data.product_name, | 22 | product_name: data.product_name, |
23 | destination: data.destination, | 23 | destination: data.destination, |
24 | rc: data.rc, | 24 | rc: data.rc, |
25 | sn: data.sn, | 25 | sn: data.sn, |
26 | message: data.message, | 26 | message: data.message, |
27 | amount: data.amount, | 27 | amount: data.amount, |
28 | ending_balance: data.ending_balance, | 28 | ending_balance: data.ending_balance, |
29 | amount_to_charge: data.amount_to_charge, | ||
30 | }; | 29 | }; |
31 | 30 | ||
31 | if (data.command === 'INQUIRY' && data.amount_to_charge) { | ||
32 | params.amount_to_charge = data.amount_to_charge; | ||
33 | } | ||
34 | |||
32 | const fullUrl = urlConcatQs(data.reverse_url, params); | 35 | const fullUrl = urlConcatQs(data.reverse_url, params); |
33 | logger.info(`${MODULE_NAME} 8B6A4CEC: Sending CORE-CALLBACK to PARTNER`, { | 36 | logger.info(`${MODULE_NAME} 8B6A4CEC: Sending CORE-CALLBACK to PARTNER`, { |
34 | xid, retry, params, fullUrl, | 37 | xid, retry, params, fullUrl, |
35 | }); | 38 | }); |
36 | 39 | ||
37 | try { | 40 | try { |
38 | const result = await axios.get(data.reverse_url, { | 41 | const result = await axios.get(data.reverse_url, { |
39 | params, | 42 | params, |
40 | timeout: 60 * 1000, | 43 | timeout: 60 * 1000, |
41 | }); | 44 | }); |
42 | 45 | ||
43 | logger.info(`${MODULE_NAME} 3641FBD7: CORE-CALLBACK has been sent to PARTNER successfully`, { | 46 | logger.info(`${MODULE_NAME} 3641FBD7: CORE-CALLBACK has been sent to PARTNER successfully`, { |
44 | xid, retry, fullUrl, body: result && result.data, | 47 | xid, retry, fullUrl, body: result && result.data, |
45 | }); | 48 | }); |
46 | } catch (e) { | 49 | } catch (e) { |
47 | logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending CORE-CALLBACK to PARTNER`, { | 50 | logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending CORE-CALLBACK to PARTNER`, { |
48 | xid, | 51 | xid, |
49 | retry, | 52 | retry, |
50 | maxRetry: MAX_RETRY, | 53 | maxRetry: MAX_RETRY, |
51 | errCode: e.code, | 54 | errCode: e.code, |
52 | errMessage: e.message, | 55 | errMessage: e.message, |
53 | reverseUrl: data.reverse_url, | 56 | reverseUrl: data.reverse_url, |
54 | fullUrl, | 57 | fullUrl, |
55 | httpStatus: e.response && e.response.status, | 58 | httpStatus: e.response && e.response.status, |
56 | body: e.response && e.response.data, | 59 | body: e.response && e.response.data, |
57 | }); | 60 | }); |
58 | 61 | ||
59 | if ((retry || 0) < MAX_RETRY) { | 62 | if ((retry || 0) < MAX_RETRY) { |
60 | await sleep(SLEEP_BEFORE_RETRY_MS); | 63 | await sleep(SLEEP_BEFORE_RETRY_MS); |
61 | logger.verbose(`${MODULE_NAME} D8958695: Going to retry sending CORE-CALLBACK TO PARTNER`, { | 64 | logger.verbose(`${MODULE_NAME} D8958695: Going to retry sending CORE-CALLBACK TO PARTNER`, { |
62 | xid, sleepTime: SLEEP_BEFORE_RETRY_MS, | 65 | xid, sleepTime: SLEEP_BEFORE_RETRY_MS, |
63 | }); | 66 | }); |
64 | sender(data, xid, (retry || 0) + 1); | 67 | sender(data, xid, (retry || 0) + 1); |
65 | } | 68 | } |
66 | } | 69 | } |
67 | }; | 70 | }; |
68 | 71 | ||
69 | module.exports = sender; | 72 | module.exports = sender; |
lib/listener-partner/index.js
1 | 'use strict'; | 1 | 'use strict'; |
2 | 2 | ||
3 | const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614; | 3 | const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614; |
4 | 4 | ||
5 | const express = require('express'); | 5 | const express = require('express'); |
6 | 6 | ||
7 | const config = require('komodo-sdk/config'); | 7 | const config = require('komodo-sdk/config'); |
8 | const logger = require('komodo-sdk/logger'); | 8 | const logger = require('komodo-sdk/logger'); |
9 | 9 | ||
10 | const middlewareCommon = require('../middlewares/common'); | 10 | const middlewareCommon = require('../middlewares/common'); |
11 | 11 | ||
12 | const routerInquiry = require('./routers/inquiry'); | 12 | const routerInquiry = require('./routers/inquiry'); |
13 | const routerPay = require('./routers/pay'); | ||
13 | const routerTopup = require('./routers/topup'); | 14 | const routerTopup = require('./routers/topup'); |
14 | const routerTrxStatus = require('./routers/trx-status'); | 15 | const routerTrxStatus = require('./routers/trx-status'); |
15 | 16 | ||
16 | const app = express(); | 17 | const app = express(); |
17 | 18 | ||
18 | app.use(express.json({ extended: true })); | 19 | app.use(express.json({ extended: true })); |
19 | app.use(express.urlencoded({ extended: true })); | 20 | app.use(express.urlencoded({ extended: true })); |
20 | app.use(middlewareCommon); | 21 | app.use(middlewareCommon); |
21 | 22 | ||
22 | app.use('/inquiry', routerInquiry); | 23 | app.use('/inquiry', routerInquiry); |
24 | app.use('/pay', routerPay); | ||
23 | app.use('/topup', routerTopup); | 25 | app.use('/topup', routerTopup); |
24 | app.use('/trx-status', routerTrxStatus); | 26 | app.use('/trx-status', routerTrxStatus); |
25 | 27 | ||
26 | app.use((req, res) => { | 28 | app.use((req, res) => { |
27 | const { xid } = res.locals; | 29 | const { xid } = res.locals; |
28 | res.status(404).end(`KOMODO-HTTP-GET-X CENTER.\n404: Method not found.\n\nXID: ${xid}.\n`); | 30 | res.status(404).end(`KOMODO-HTTP-GET-X CENTER.\n404: Method not found.\n\nXID: ${xid}.\n`); |
29 | }); | 31 | }); |
30 | 32 | ||
31 | app.listen(config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT, () => { | 33 | app.listen(config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT, () => { |
32 | logger.info(`Listen from partner request on port ${config.listener.partner.port}`); | 34 | logger.info(`Listen from partner request on port ${config.listener.partner.port}`); |
33 | }).on('error', (e) => { | 35 | }).on('error', (e) => { |
34 | logger.error(`Can not listen request from partner on port ${config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT}. ${e.toString()}`); | 36 | logger.error(`Can not listen request from partner on port ${config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT}. ${e.toString()}`); |
35 | process.exit(1); | 37 | process.exit(1); |
36 | }); | 38 | }); |
37 | 39 |
lib/listener-partner/routers/pay.js
File was created | 1 | const axios = require('axios').default; | |
2 | const express = require('express'); | ||
3 | const coreUrl = require('komodo-sdk/core-url'); | ||
4 | |||
5 | const config = require('komodo-sdk/config'); | ||
6 | const logger = require('komodo-sdk/logger'); | ||
7 | |||
8 | const getFromBodyQsParams = require('../../get-from-body-qs-params'); | ||
9 | const ipv6ToIpv4 = require('../../ipv6-to-ipv4'); | ||
10 | |||
11 | const router = express.Router(); | ||
12 | module.exports = router; | ||
13 | |||
14 | const CORE_ENDPOINT = `${coreUrl}/postpaid2/pay`; | ||
15 | |||
16 | const mainHandler = async (req, res) => { | ||
17 | const { xid } = res.locals; | ||
18 | |||
19 | const requestId = (getFromBodyQsParams(req, 'request_id') || '').toString().trim(); | ||
20 | const terminalNameWithoutIp = (getFromBodyQsParams(req, 'terminal_name') || '').toString().trim(); | ||
21 | const terminalName = `${terminalNameWithoutIp}@${ipv6ToIpv4(req.ip)}`; | ||
22 | const productName = (getFromBodyQsParams(req, 'product_name') || '').trim().toUpperCase(); | ||
23 | const destination = (getFromBodyQsParams(req, 'destination') || '').toString().trim(); | ||
24 | const password = getFromBodyQsParams(req, 'password'); | ||
25 | const reverseUrl = getFromBodyQsParams(req, 'reverse_url'); | ||
26 | |||
27 | if (!requestId || !terminalNameWithoutIp || !productName || !destination) { | ||
28 | res.end('INVALID REQUEST. Missing request_id or terminal_name or product_name or destination.'); | ||
29 | return; | ||
30 | } | ||
31 | |||
32 | const params = { | ||
33 | origin: config.name, | ||
34 | report_ip: config.listener.core.from_ip, | ||
35 | report_port: config.listener.core.port || 25614, | ||
36 | request_id: requestId, | ||
37 | terminal_name: terminalName, | ||
38 | product_name: productName, | ||
39 | destination, | ||
40 | terminal_password: password, | ||
41 | reverse_url: reverseUrl, | ||
42 | }; | ||
43 | |||
44 | logger.info('Forwarding PAY request to CORE', { xid, params }); | ||
45 | try { | ||
46 | const result = await axios.get(CORE_ENDPOINT, { | ||
47 | params, | ||
48 | timeout: 10000, | ||
49 | }); | ||
50 | |||
51 | if (!result || !result.data) { | ||
52 | const newError = new Error('0D428E4C: Empty CORE PAY direct-response'); | ||
53 | logger.warn(newError.message, { xid }); | ||
54 | throw newError; | ||
55 | } | ||
56 | |||
57 | logger.verbose('Got PAY direct-response from CORE', { | ||
58 | xid, | ||
59 | coreResponse: result.data, | ||
60 | }); | ||
61 | |||
62 | const resultForPartner = { | ||
63 | httpgetx_xid: xid, | ||
64 | command: result.data.command, | ||
65 | request_id: result.data.request_id && result.data.request_id.toString(), | ||
66 | transaction_id: result.data.transaction_id && result.data.transaction_id.toString(), | ||
67 | transaction_date: result.data.transaction_date, | ||
68 | store_name: result.data.store_name, | ||
69 | terminal_name: result.data.terminal_name, | ||
70 | product_name: result.data.product_name, | ||
71 | destination: result.data.destination, | ||
72 | rc: result.data.rc, | ||
73 | sn: result.data.sn, | ||
74 | message: result.data.message, | ||
75 | amount: result.data.amount, | ||
76 | ending_balance: result.data.ending_balance, | ||
77 | }; | ||
78 | |||
79 | logger.verbose('Forwarding CORE PAY direct-response to partner', { | ||
80 | xid, | ||
81 | resultForPartner, | ||
82 | }); | ||
83 | |||
84 | res.json(resultForPartner); | ||
85 | } catch (e) { | ||
86 | logger.warn('EXCEPTION on forwarding PAY request to CORE', { | ||
87 | xid, | ||
88 | errCode: e.code, | ||
89 | errMessage: e.message, | ||
90 | }); | ||
91 | |||
92 | res.json({ | ||
93 | httpgetx_xid: xid, | ||
94 | command: 'PAY', | ||
95 | request_id: requestId, | ||
96 | terminal_name: terminalName, | ||
97 | product_name: productName, | ||
98 | destination, | ||
99 | rc: '68', | ||
100 | message: 'CORE tidak merespon dengan benar, tidak dapat mengetahui status request anda', | ||
101 | }); | ||
102 | } | ||
103 | }; | ||
104 | |||
105 | router.all('/', mainHandler); | ||
106 |