Commit 8c258ccd9821fd7f7081bf1b3b49665dbd6e4e1f

Authored by Adhidarma Hadiwinoto
1 parent f02e2a18b2
Exists in master

advice prepaid

Showing 6 changed files with 299 additions and 142 deletions Side-by-side Diff

lib/hit/axios-error-is-safe.js
... ... @@ -0,0 +1,13 @@
  1 +const safeErrorCodes = [
  2 + 'EHOSTUNREACH',
  3 + 'ENOTFOUND',
  4 + 'ECONNREFUSED',
  5 + 'ETIMEDOUT', // timeout on connecting
  6 +
  7 + // Berikut adalah error code yang tidak aman untuk dianggap gagal
  8 +
  9 + // terjadi karena timeout setelah konek (akibat pengaturan timeout pada request axios)
  10 + // 'ECONNABORTED',
  11 +];
  12 +
  13 +module.exports = (e) => safeErrorCodes.indexOf(e.code) >= 0;
lib/hit/dump-req-res.js
... ... @@ -22,7 +22,7 @@ if (!fs.existsSync(requestDumpDir)) {
22 22 }
23 23  
24 24 module.exports = async (
25   - xid, task, httpMethod, endpointUrl, params, responseBody, responseStatus,
  25 + xid, task, httpMethod, endpointUrl, params, responseBody, responseStatus, isAdvice,
26 26 ) => {
27 27 if (
28 28 !config
... ... @@ -40,6 +40,7 @@ DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')}
40 40 TASK:
41 41 ${JSON.stringify(task, null, 2)}
42 42  
  43 +IS-ADVICE: !!${isAdvice}
43 44  
44 45 HTTP-METHOD: ${httpMethod}
45 46 URL: ${endpointUrl}
... ... @@ -59,6 +60,7 @@ ${
59 60 || JSON.stringify(responseBody, null, 2)
60 61 )
61 62 }
  63 +
62 64 `;
63 65  
64 66 const dumpDir = path.join(
... ... @@ -72,7 +74,7 @@ ${
72 74 await fsPromise.mkdir(dumpDir, { recursive: true });
73 75 }
74 76  
75   - await fsPromise.writeFile(
  77 + await fsPromise.appendFile(
76 78 path.join(
77 79 dumpDir,
78 80 `trx_${task.trx_id}`,
lib/hit/prepaid-advice.js
... ... @@ -0,0 +1,140 @@
  1 +const MODULE_NAME = 'HIT.PREPAID-ADVICE';
  2 +
  3 +const axios = require('axios').default;
  4 +const urljoin = require('url-join');
  5 +const uniqid = require('uniqid');
  6 +
  7 +const config = require('komodo-sdk/config');
  8 +const logger = require('komodo-sdk/logger');
  9 +
  10 +const report = require('../report/prepaid');
  11 +const translateRc = require('../translate-rc');
  12 +const dumpReqRes = require('./dump-req-res');
  13 +
  14 +module.exports = async (task) => {
  15 + const xid = uniqid();
  16 +
  17 + logger.verbose(`${MODULE_NAME} 90350EF7: Processing task`, {
  18 + xid,
  19 + task,
  20 + });
  21 +
  22 + const params = {
  23 + request_id: task.trx_id,
  24 + terminal_name: config.partner.terminal_name,
  25 + password: config.partner.password,
  26 + };
  27 +
  28 + const endpointUrl = urljoin(config.partner.url, '/trx-status');
  29 + let lastResponse = null;
  30 +
  31 + try {
  32 + logger.verbose(`${MODULE_NAME} 453A48DC: Going to HIT ADVICE endpoint`, {
  33 + xid,
  34 + endpointUrl,
  35 + params,
  36 + });
  37 +
  38 + const response = await axios.get(endpointUrl, {
  39 + headers: {
  40 + 'User-Agent': 'KOMODO-GW-HTTPGETX',
  41 + },
  42 + timeout: config.partner.hit_timeout_ms || 10 * 1000,
  43 + params,
  44 + });
  45 +
  46 + if (!response) {
  47 + const e = new Error(`${MODULE_NAME} FD20A1AF: Empty response`);
  48 + e.rc = '68';
  49 + e.response = response;
  50 + throw e;
  51 + }
  52 +
  53 + if (!response.data) {
  54 + const e = new Error(`${MODULE_NAME} 17FF8971: Empty response data`);
  55 + e.rc = '68';
  56 + e.response = response;
  57 + throw e;
  58 + }
  59 +
  60 + if (typeof response.data !== 'object') {
  61 + const e = new Error(`${MODULE_NAME} A6761E9F: Response data is not a JSON`);
  62 + e.rc = '68';
  63 + e.response = response;
  64 + throw e;
  65 + }
  66 +
  67 + lastResponse = response;
  68 +
  69 + logger.verbose(`${MODULE_NAME} 3B5C70C4: Got a direct response`, {
  70 + xid,
  71 + responseBody: response.data,
  72 + });
  73 +
  74 + if (!response.data.trx_found || !response.data.trx) {
  75 + report(xid, {
  76 + trx_id: task.trx_id,
  77 + rc: '40',
  78 + message: {
  79 + xid,
  80 + 'ADVICE-DIRECT-RESPONSE': response.data,
  81 + },
  82 + });
  83 +
  84 + return;
  85 + }
  86 +
  87 + report(xid, {
  88 + trx_id: task.trx_id,
  89 + rc: response.data.trx.rc ? translateRc[response.data.trx.rc] || response.data.trx.rc
  90 + : '68',
  91 + sn: response.data.trx.sn || null,
  92 + amount: Number(response.data.trx.amount) || undefined,
  93 + balance: Number(response.data.trx.ending_balance) || undefined,
  94 + message: {
  95 + xid,
  96 + 'ADVICE-DIRECT-RESPONSE': response.data,
  97 + },
  98 + });
  99 + } catch (e) {
  100 + const rc = e.rc || '68';
  101 +
  102 + logger.warn(`${MODULE_NAME} 1427175A: Exception`, {
  103 + xid,
  104 + eCode: e.code,
  105 + eMessage: e.message,
  106 + eRc: e.rc,
  107 + rc,
  108 + responseHttpStatus: e.response && e.response.status,
  109 + responseBody: e.response && e.response.data,
  110 + });
  111 +
  112 + lastResponse = e.response;
  113 +
  114 + report(xid, {
  115 + trx_id: task.trx_id,
  116 + rc,
  117 + message: {
  118 + xid,
  119 + 'KOMODO-GW-ADVICE-ERROR': {
  120 + eCode: e.code,
  121 + eMessage: e.message,
  122 + responseHttpStatus: e.response && e.response.status,
  123 + responseBody: e.response && e.response.data,
  124 + },
  125 + },
  126 + });
  127 + } finally {
  128 + dumpReqRes(
  129 + xid,
  130 + task,
  131 + 'GET',
  132 + endpointUrl,
  133 + params,
  134 + lastResponse && lastResponse.data,
  135 + lastResponse && lastResponse.status,
  136 + lastResponse,
  137 + true,
  138 + );
  139 + }
  140 +};
lib/hit/prepaid-topup.js
... ... @@ -0,0 +1,138 @@
  1 +const MODULE_NAME = 'HIT.PREPAID-TOPUP';
  2 +
  3 +const axios = require('axios').default;
  4 +const urljoin = require('url-join');
  5 +const uniqid = require('uniqid');
  6 +
  7 +const config = require('komodo-sdk/config');
  8 +const logger = require('komodo-sdk/logger');
  9 +
  10 +const report = require('../report/prepaid');
  11 +const translateRc = require('../translate-rc');
  12 +const composeCallbackUrl = require('./compose-callback-url');
  13 +const dumpReqRes = require('./dump-req-res');
  14 +const axiosErrorIsSafe = require('./axios-error-is-safe');
  15 +
  16 +module.exports = async (task) => {
  17 + const xid = uniqid();
  18 +
  19 + logger.verbose(`${MODULE_NAME} 2272F01F: Processing task`, {
  20 + xid,
  21 + task,
  22 + });
  23 +
  24 + const params = {
  25 + request_id: task.trx_id,
  26 + terminal_name: config.partner.terminal_name,
  27 + password: config.partner.password,
  28 + destination: task.destination,
  29 + product_name: task.remote_product,
  30 + reverse_url: composeCallbackUrl(xid, false),
  31 + };
  32 +
  33 + // const endpointUrl = isAdvice
  34 + // ? urljoin(config.partner.url, '/trx-status')
  35 + // : urljoin(config.partner.url, '/topup');
  36 +
  37 + const endpointUrl = urljoin(config.partner.url, '/topup');
  38 + let lastResponse = null;
  39 +
  40 + try {
  41 + logger.verbose(`${MODULE_NAME} 4AAD4F99: Going to HIT prepaid endpoint`, {
  42 + xid,
  43 + endpointUrl,
  44 + params,
  45 + });
  46 +
  47 + const response = await axios.get(endpointUrl, {
  48 + headers: {
  49 + 'User-Agent': 'KOMODO-GW-HTTPGETX',
  50 + },
  51 + timeout: config.partner.hit_timeout_ms || 60 * 1000,
  52 + params,
  53 + });
  54 +
  55 + if (!response) {
  56 + const e = new Error(`${MODULE_NAME} 8CF4E04D: Empty response`);
  57 + e.rc = '68';
  58 + e.response = response;
  59 + throw e;
  60 + }
  61 +
  62 + if (!response.data) {
  63 + const e = new Error(`${MODULE_NAME} E72B5A53: Empty response data`);
  64 + e.rc = '68';
  65 + e.response = response;
  66 + throw e;
  67 + }
  68 +
  69 + if (typeof response.data !== 'object') {
  70 + const e = new Error(`${MODULE_NAME} 507680AB: Response data is not a JSON`);
  71 + e.rc = '68';
  72 + e.response = response;
  73 + throw e;
  74 + }
  75 +
  76 + lastResponse = response;
  77 +
  78 + logger.verbose(`${MODULE_NAME} E51AFBBA: Got a direct response`, {
  79 + xid,
  80 + responseBody: response.data,
  81 + });
  82 +
  83 + report(xid, {
  84 + trx_id: task.trx_id,
  85 + rc: response.data.rc ? translateRc[response.data.rc] || response.data.rc
  86 + : '68',
  87 + sn: response.data.sn || null,
  88 + amount: Number(response.data.amount) || undefined,
  89 + balance: Number(response.data.ending_balance) || undefined,
  90 + message: {
  91 + xid,
  92 + 'DIRECT-RESPONSE': response.data,
  93 + },
  94 + });
  95 + } catch (e) {
  96 + const rc = e.rc
  97 + || (axiosErrorIsSafe(e) && '91')
  98 + || '68';
  99 +
  100 + logger.warn(`${MODULE_NAME} 8E8E49F5: Exception`, {
  101 + xid,
  102 + eCode: e.code,
  103 + eMessage: e.message,
  104 + eRc: e.rc,
  105 + rc,
  106 + responseHttpStatus: e.response && e.response.status,
  107 + responseBody: e.response && e.response.data,
  108 + });
  109 +
  110 + lastResponse = e.response;
  111 +
  112 + report(xid, {
  113 + trx_id: task.trx_id,
  114 + rc,
  115 + message: {
  116 + xid,
  117 + 'KOMODO-GW-ERROR': {
  118 + eCode: e.code,
  119 + eMessage: e.message,
  120 + responseHttpStatus: e.response && e.response.status,
  121 + responseBody: e.response && e.response.data,
  122 + },
  123 + },
  124 + });
  125 + } finally {
  126 + dumpReqRes(
  127 + xid,
  128 + task,
  129 + 'GET',
  130 + endpointUrl,
  131 + params,
  132 + lastResponse && lastResponse.data,
  133 + lastResponse && lastResponse.status,
  134 + lastResponse,
  135 + false,
  136 + );
  137 + }
  138 +};
lib/hit/prepaid.js
... ... @@ -1,137 +0,0 @@
1   -const MODULE_NAME = 'HIT.PREPAID';
2   -
3   -const axios = require('axios').default;
4   -const urljoin = require('url-join');
5   -const uniqid = require('uniqid');
6   -
7   -const config = require('komodo-sdk/config');
8   -const logger = require('komodo-sdk/logger');
9   -
10   -const report = require('../report/prepaid');
11   -const translateRc = require('../translate-rc');
12   -const composeCallbackUrl = require('./compose-callback-url');
13   -const dumpReqRes = require('./dump-req-res');
14   -
15   -module.exports = async (task, isAdvice) => {
16   - const xid = uniqid();
17   -
18   - logger.verbose(`${MODULE_NAME} 2272F01F: Processing task`, {
19   - xid,
20   - isAdvice,
21   - task,
22   - });
23   -
24   - const params = {
25   - request_id: task.trx_id,
26   - terminal_name: config.partner.terminal_name,
27   - password: config.partner.password,
28   - destination: task.destination,
29   - product_name: task.remote_product,
30   - reverse_url: composeCallbackUrl(xid, false),
31   - };
32   -
33   - const endpointUrl = isAdvice
34   - ? urljoin(config.partner.url, '/trx-status')
35   - : urljoin(config.partner.url, '/topup');
36   -
37   - let lastResponse = null;
38   -
39   - try {
40   - logger.verbose(`${MODULE_NAME} 4AAD4F99: Going to HIT prepaid endpoint`, {
41   - xid,
42   - endpointUrl,
43   - params,
44   - });
45   -
46   - const response = await axios.get(endpointUrl, {
47   - headers: {
48   - 'User-Agent': 'KOMODO-GW-HTTPGETX',
49   - },
50   - timeout: config.partner.hit_timeout_ms || 60 * 1000,
51   - params,
52   - });
53   -
54   - if (!response) {
55   - const e = new Error(`${MODULE_NAME} 8CF4E04D: Empty response`);
56   - e.rc = '68';
57   - e.response = response;
58   - throw e;
59   - }
60   -
61   - if (!response.data) {
62   - const e = new Error(`${MODULE_NAME} E72B5A53: Empty response data`);
63   - e.rc = '68';
64   - e.response = response;
65   - throw e;
66   - }
67   -
68   - if (typeof response.data !== 'object') {
69   - const e = new Error(`${MODULE_NAME} 507680AB: Response data is not a JSON`);
70   - e.rc = '68';
71   - e.response = response;
72   - throw e;
73   - }
74   -
75   - lastResponse = response;
76   -
77   - logger.verbose(`${MODULE_NAME} E51AFBBA: Got a direct response`, {
78   - xid,
79   - responseBody: response.data,
80   - });
81   -
82   - report(xid, {
83   - trx_id: task.trx_id,
84   - rc: response.data.rc ? translateRc[response.data.rc] || response.data.rc
85   - : '68',
86   - sn: response.data.sn || null,
87   - amount: Number(response.data.amount) || undefined,
88   - balance: Number(response.data.ending_balance) || undefined,
89   - message: {
90   - xid,
91   - 'DIRECT-RESPONSE': response.data,
92   - 'IS-ADVICE': !!isAdvice,
93   - },
94   - });
95   - } catch (e) {
96   - const rc = e.rc || '68';
97   -
98   - logger.warn(`${MODULE_NAME} 8E8E49F5: Exception`, {
99   - xid,
100   - eCode: e.code,
101   - eMessage: e.message,
102   - eRc: e.rc,
103   - rc,
104   - isAdvice,
105   - responseHttpStatus: e.response && e.response.status,
106   - responseBody: e.response && e.response.data,
107   - });
108   -
109   - lastResponse = e.response;
110   -
111   - report(xid, {
112   - trx_id: task.trx_id,
113   - rc,
114   - message: {
115   - xid,
116   - 'KOMODO-GW-ERROR': {
117   - eCode: e.code,
118   - eMessage: e.message,
119   - responseHttpStatus: e.response && e.response.status,
120   - responseBody: e.response && e.response.data,
121   - },
122   - 'IS-ADVICE': !!isAdvice,
123   - },
124   - });
125   - } finally {
126   - dumpReqRes(
127   - xid,
128   - task,
129   - 'GET',
130   - endpointUrl,
131   - params,
132   - lastResponse && lastResponse.data,
133   - lastResponse && lastResponse.status,
134   - lastResponse,
135   - );
136   - }
137   -};
lib/partner-prepaid.js
1   -const hit = require('./hit/prepaid');
  1 +const hitAdvice = require('./hit/prepaid-advice');
  2 +const hitTopup = require('./hit/prepaid-topup');
2 3  
3 4 exports.buy = (task) => {
4   - hit(task, false);
  5 + hitTopup(task);
5 6 };
6 7  
7 8 exports.advice = (task) => {
8   - hit(task, true);
  9 + hitAdvice(task);
9 10 };