@opengis/pay 1.1.13 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/module/pay/cls/billing.payment_status.json +8 -3
- package/module/pay/select/billing.subscription_id.sql +1 -0
- package/module/pay1/cls/billing.payment_status.json +22 -0
- package/module/pay1/pt/marketplace-service-payment-client-template.html +147 -0
- package/module/pay1/select/billing.account_id.sql +1 -0
- package/module/pay1/select/billing.service_id.sql +1 -0
- package/module/pay1/select/billing.subscription_id.sql +1 -0
- package/module/pay1/select/billing.user_id.sql +1 -0
- package/package.json +3 -2
- package/plugin.js +4 -22
- package/server/migrations/5_payments.sql +3 -1
- package/server/plugins/cron.js +2 -2
- package/server/routes/liqpay/controllers/liqpay.redirect.js +142 -0
- package/server/routes/liqpay/controllers/liqpay.status.js +168 -0
- package/server/routes/liqpay/index.mjs +22 -0
- package/server/routes/portmone/controllers/payment.info.js +45 -0
- package/server/routes/{portmone.redirect.js → portmone/controllers/portmone.redirect.js} +23 -18
- package/server/routes/{portmone.status.js → portmone/controllers/portmone.status.js} +16 -3
- package/server/routes/portmone/index.mjs +30 -0
- /package/module/{pay → pay1}/card/billing.accounts.table/general_info.hbs +0 -0
- /package/module/{pay → pay1}/card/billing.accounts.table/index.yml +0 -0
- /package/module/{pay → pay1}/card/billing.accounts.table/users.hbs +0 -0
- /package/module/{pay → pay1}/card/billing.payments.table/general_info.hbs +0 -0
- /package/module/{pay → pay1}/card/billing.payments.table/index.yml +0 -0
- /package/module/{pay → pay1}/card/billing.users.table/general_info.hbs +0 -0
- /package/module/{pay → pay1}/card/billing.users.table/index.yml +0 -0
- /package/module/{pay → pay1}/form/billing.account_user.form.json +0 -0
- /package/module/{pay → pay1}/form/billing.accounts.form.json +0 -0
- /package/module/{pay → pay1}/form/billing.payment.form.json +0 -0
- /package/module/{pay → pay1}/form/billing.users.form.json +0 -0
- /package/module/{pay → pay1}/menu.json +0 -0
- /package/module/{pay → pay1}/table/billing.accounts.table.json +0 -0
- /package/module/{pay → pay1}/table/billing.payments.table.json +0 -0
- /package/module/{pay → pay1}/table/billing.users.table.json +0 -0
- /package/server/routes/{utils → portmone/utils}/portmone.check.status.js +0 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"id": "inprogress",
|
|
4
|
-
"text": "
|
|
5
|
-
"color": "
|
|
4
|
+
"text": "В процесі",
|
|
5
|
+
"color": "blue"
|
|
6
6
|
},
|
|
7
7
|
{
|
|
8
8
|
"id": "success",
|
|
9
9
|
"text": "Оплачено",
|
|
10
10
|
"color": "green"
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
"id": "unpaid",
|
|
14
|
+
"text": "Не оплачено",
|
|
15
|
+
"color": "gray"
|
|
16
|
+
},
|
|
12
17
|
{
|
|
13
18
|
"id": "error",
|
|
14
|
-
"text": "Помилка
|
|
19
|
+
"text": "Помилка оплати",
|
|
15
20
|
"color": "red"
|
|
16
21
|
}
|
|
17
22
|
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select subscription_id,coalesce((select name from billing.products where product_id=a.product_id),'')||' '||coalesce(product_plan_type,'') from billing.subscriptions a
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "inprogress",
|
|
4
|
+
"text": "В процесі",
|
|
5
|
+
"color": "blue"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "success",
|
|
9
|
+
"text": "Оплачено",
|
|
10
|
+
"color": "green"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "unpaid",
|
|
14
|
+
"text": "Не оплачено",
|
|
15
|
+
"color": "gray"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "error",
|
|
19
|
+
"text": "Помилка оплати",
|
|
20
|
+
"color": "red"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<div>
|
|
2
|
+
<br>
|
|
3
|
+
</div>
|
|
4
|
+
<div>
|
|
5
|
+
<table style="width:100%;">
|
|
6
|
+
<tbody>
|
|
7
|
+
<tr>
|
|
8
|
+
<td style="width:20px;"> </td>
|
|
9
|
+
<td align="center">
|
|
10
|
+
<table style="width:100%" bgcolor="#ffffff">
|
|
11
|
+
<tbody>
|
|
12
|
+
<tr>
|
|
13
|
+
<td align="center"><a href="//{{domain}}" class="logo"><img src="https://softpro.ua/tpl/img/logo.svg"/></a>
|
|
14
|
+
</td>
|
|
15
|
+
</tr>
|
|
16
|
+
|
|
17
|
+
<tr>
|
|
18
|
+
<td style="padding:7px 0" align="center"><span style="color:#555454;font-family:'Open-sans',sans-serif;font-size:small">
|
|
19
|
+
<span style="font-weight:500;font-size:16px;text-transform:uppercase;line-height:25px">{{select account_id data="billing.account_id"}}, дякуємо за здійснення замовлення на порталі <a href="//{{domain}}">{{domain}}</a></span> </span>
|
|
20
|
+
</td>
|
|
21
|
+
</tr>
|
|
22
|
+
<tr>
|
|
23
|
+
<td style="padding:0"> </td>
|
|
24
|
+
</tr>
|
|
25
|
+
<tr>
|
|
26
|
+
<td style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);padding:7px 0;border-radius:30px">
|
|
27
|
+
<table style="width:100%">
|
|
28
|
+
<tbody>
|
|
29
|
+
<tr >
|
|
30
|
+
<td style="padding:7px 0" width="10"> </td>
|
|
31
|
+
<td style="padding:7px 0">
|
|
32
|
+
<span style="color:#555454;font-family:'Open-sans',sans-serif;font-size:small"> </span>
|
|
33
|
+
{{#if service_id}}
|
|
34
|
+
<p style="color:#61677b;border-bottom:1px solid #61677b;margin:3px 0 7px;text-transform:uppercase;font-weight:500;font-size:18px;padding-bottom:10px">Послуга: {{service_id_text}}</p>
|
|
35
|
+
{{/if}}
|
|
36
|
+
<br>
|
|
37
|
+
<span style="color:#61677b"><strong>Дата замовлення:</strong> {{formatDate cdate format='dd.mm.yy hh:mi'}}</span>
|
|
38
|
+
<br>
|
|
39
|
+
<span style="color:#61677b"><strong>Статус замовлення:</strong> {{select payment_status data="billing.payment_status"}}</span>
|
|
40
|
+
{{#if withdrawal_sum}}
|
|
41
|
+
<br>
|
|
42
|
+
<span style="color:#61677b"><strong>Вартість послуги:</strong> {{num_format withdrawal_sum dec="2"}}</span>
|
|
43
|
+
{{/if}}
|
|
44
|
+
{{#if payment_amount}}
|
|
45
|
+
<br>
|
|
46
|
+
<span style="color:#61677b"><strong>Поповнення рахунку:</strong> {{num_format payment_amount dec="2"}}</span>
|
|
47
|
+
{{/if}}
|
|
48
|
+
{{#if total_balance}}
|
|
49
|
+
<br>
|
|
50
|
+
<span style="color:#61677b"><strong>Поточний баланс:</strong> {{num_format total_balance dec="2"}}</span>
|
|
51
|
+
{{/if}}
|
|
52
|
+
</td>
|
|
53
|
+
<td style="padding:7px 0" width="10"> </td>
|
|
54
|
+
</tr>
|
|
55
|
+
</tbody>
|
|
56
|
+
</table>
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
|
|
60
|
+
<tr>
|
|
61
|
+
<td style="padding:7px 0">
|
|
62
|
+
<span style="color:#555454;font-family:'Open-sans',sans-serif;font-size:small"> </span>
|
|
63
|
+
<table style="width:100%;border-collapse:collapse" bgcolor="#ffffff">
|
|
64
|
+
<tbody>
|
|
65
|
+
<tr>
|
|
66
|
+
<th style="border:1px solid #d6d4d4;background-color:#fbfbfb;color:#61677b;font-family:Arial;font-size:13px;padding:10px" bgcolor="#f8f8f8">Назва послуги</th>
|
|
67
|
+
<th style="border:1px solid #d6d4d4;background-color:#fbfbfb;color:#61677b;font-family:Arial;font-size:13px;padding:10px" bgcolor="#f8f8f8" width="17%">Ціна послуги</th>
|
|
68
|
+
</tr>
|
|
69
|
+
<tr>
|
|
70
|
+
<td style="border:1px solid #d6d4d4">
|
|
71
|
+
<table>
|
|
72
|
+
<tbody>
|
|
73
|
+
<tr>
|
|
74
|
+
<td style="padding: 0 10px">
|
|
75
|
+
<font size="2" face="Open-sans, sans-serif" color="#555454">
|
|
76
|
+
<strong>
|
|
77
|
+
{{#if service_id}}
|
|
78
|
+
{{service_id_text}}
|
|
79
|
+
{{^}}
|
|
80
|
+
Поповнення рахунку
|
|
81
|
+
{{/if}}
|
|
82
|
+
</strong>
|
|
83
|
+
</font>
|
|
84
|
+
</td>
|
|
85
|
+
</tr>
|
|
86
|
+
</tbody>
|
|
87
|
+
</table>
|
|
88
|
+
</td>
|
|
89
|
+
<td style="border:1px solid #d6d4d4">
|
|
90
|
+
<table>
|
|
91
|
+
<tbody>
|
|
92
|
+
<tr>
|
|
93
|
+
<td width="10"> </td>
|
|
94
|
+
<td align="right">
|
|
95
|
+
<font size="2" face="Open-sans, sans-serif" color="#555454"> {{num_format (coalesce withdrawal_sum payment_amount)}} грн.</font>
|
|
96
|
+
</td>
|
|
97
|
+
<td width="10"> </td>
|
|
98
|
+
</tr>
|
|
99
|
+
</tbody>
|
|
100
|
+
</table>
|
|
101
|
+
</td>
|
|
102
|
+
</tr>
|
|
103
|
+
|
|
104
|
+
<tr>
|
|
105
|
+
<td colspan="2" style="border:1px solid #d6d4d4;text-align:center;color:#777;padding:7px 0"> </td>
|
|
106
|
+
</tr>
|
|
107
|
+
|
|
108
|
+
<tr>
|
|
109
|
+
<td colspan="1" style="border:1px solid #d6d4d4;color:#61677b;padding:7px 0" bgcolor="#f8f8f8">
|
|
110
|
+
<table style="width:100%;border-collapse:collapse">
|
|
111
|
+
<tbody>
|
|
112
|
+
<tr>
|
|
113
|
+
<td style="color:#61677b;padding:0" width="10"> </td>
|
|
114
|
+
<td style="color:#61677b;padding:0" align="right"><span style="color:#555454;font-family:'Open-sans',sans-serif;font-size:small"> <strong>Поточний баланс</strong> </span></td>
|
|
115
|
+
<td style="color:#61677b;padding:0" width="10"> </td>
|
|
116
|
+
</tr>
|
|
117
|
+
</tbody>
|
|
118
|
+
</table>
|
|
119
|
+
</td>
|
|
120
|
+
<td colspan="1" style="border:1px solid #d6d4d4;color:#61677b;padding:7px 0" bgcolor="#f8f8f8">
|
|
121
|
+
<table style="width:100%;border-collapse:collapse">
|
|
122
|
+
<tbody>
|
|
123
|
+
<tr>
|
|
124
|
+
<td style="color:#61677b;padding:0" width="10"> </td>
|
|
125
|
+
<td style="color:#61677b;padding:0" align="right"><span style="color:#555454;font-family:'Open-sans',sans-serif;font-size:large">{{total_balance}} грн. </span></td>
|
|
126
|
+
<td style="color:#61677b;padding:0" width="10"> </td>
|
|
127
|
+
</tr>
|
|
128
|
+
</tbody>
|
|
129
|
+
</table>
|
|
130
|
+
</td>
|
|
131
|
+
</tr>
|
|
132
|
+
</tbody>
|
|
133
|
+
</table>
|
|
134
|
+
</td>
|
|
135
|
+
</tr>
|
|
136
|
+
|
|
137
|
+
<tr>
|
|
138
|
+
<td style="border-top:4px solid #61677b;padding:7px 0"><span><a href="//{{domain}}"><img src="https://softpro.ua/tpl/img/logo.svg"/></a></span></td>
|
|
139
|
+
</tr>
|
|
140
|
+
</tbody>
|
|
141
|
+
</table>
|
|
142
|
+
</td>
|
|
143
|
+
<td style="width:20px;"> </td>
|
|
144
|
+
</tr>
|
|
145
|
+
</tbody>
|
|
146
|
+
</table>
|
|
147
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select account_id, account_name from billing.accounts order by account_name
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select service_id, service_name from billing.service order by service_name
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select subscription_id,coalesce((select name from billing.products where product_id=a.product_id),'')||' '||coalesce(product_plan_type,'') from billing.subscriptions a
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
select user_id, user_name || coalesce(login,'') as name from billing.users order by user_name
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengis/pay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "pay plugins for billing",
|
|
6
6
|
"main": "plugin.js",
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@opengis/admin": "^0.2.14",
|
|
24
|
-
"@opengis/fastify-table": "^1.
|
|
24
|
+
"@opengis/fastify-table": "^1.2.64",
|
|
25
25
|
"cross-env": "^7.0.3",
|
|
26
26
|
"fastify": "^4.26.1",
|
|
27
27
|
"fastify-plugin": "^4.0.0",
|
|
28
|
+
"liqpayjs-sdk": "^3.3.1",
|
|
28
29
|
"request-promise": "^4.2.6"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
package/plugin.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import fp from 'fastify-plugin';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
|
|
3
4
|
import { config, execMigrations } from '@opengis/fastify-table/utils.js';
|
|
4
5
|
|
|
5
6
|
const { prefix = '/api' } = config;
|
|
6
7
|
|
|
7
|
-
import portmoneRedirect from './server/routes/portmone.redirect.js';
|
|
8
|
-
import portmoneStatus from './server/routes/portmone.status.js';
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
9
|
* This plugins adds some utilities to handle http errors
|
|
12
10
|
*
|
|
@@ -15,26 +13,10 @@ import portmoneStatus from './server/routes/portmone.status.js';
|
|
|
15
13
|
|
|
16
14
|
async function plugin(app) {
|
|
17
15
|
app.register(import('./server/plugins/cron.js'));
|
|
16
|
+
app.register(import('./server/routes/portmone/index.mjs'), { prefix });
|
|
17
|
+
app.register(import('./server/routes/liqpay/index.mjs'), { prefix });
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
method: 'GET',
|
|
21
|
-
url: `${prefix}/portmone-redirect`,
|
|
22
|
-
config: {
|
|
23
|
-
policy: ['site'],
|
|
24
|
-
},
|
|
25
|
-
handler: portmoneRedirect,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
app.route({
|
|
29
|
-
method: 'POST',
|
|
30
|
-
url: `${prefix}/portmone/:id/:status`,
|
|
31
|
-
config: {
|
|
32
|
-
policy: ['public'],
|
|
33
|
-
},
|
|
34
|
-
handler: portmoneStatus,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
execMigrations().catch(err => console.log(err));
|
|
19
|
+
execMigrations(path.join(process.cwd(), 'server/migrations')).catch(err => console.log(err));
|
|
38
20
|
}
|
|
39
21
|
|
|
40
22
|
export default fp(plugin);
|
|
@@ -11,6 +11,7 @@ alter table billing.payments add column if not exists payment_status text NOT NU
|
|
|
11
11
|
alter table billing.payments add column if not exists success_date timestamp with time zone;
|
|
12
12
|
alter table billing.payments add column if not exists payment_data json;
|
|
13
13
|
alter table billing.payments add column if not exists payment_amount numeric;
|
|
14
|
+
alter table billing.payments add column if not exists payment_service text;
|
|
14
15
|
alter table billing.payments add column if not exists total_balance numeric;
|
|
15
16
|
alter table billing.payments add column if not exists referer_url text;
|
|
16
17
|
alter table billing.payments add column if not exists cdate timestamp without time zone DEFAULT now();
|
|
@@ -24,7 +25,8 @@ COMMENT ON COLUMN billing.payments.payment_id IS 'ID';
|
|
|
24
25
|
COMMENT ON COLUMN billing.payments.account_id IS 'ID акаунту клієнта';
|
|
25
26
|
COMMENT ON COLUMN billing.payments.payment_status IS 'Статус транзації';
|
|
26
27
|
COMMENT ON COLUMN billing.payments.success_date IS 'Дата успішного завершення транзакції';
|
|
27
|
-
COMMENT ON COLUMN billing.payments.payment_data IS 'Дані від
|
|
28
|
+
COMMENT ON COLUMN billing.payments.payment_data IS 'Дані від сервісу оплати';
|
|
29
|
+
COMMENT ON COLUMN billing.payments.payment_service IS 'Сервіс оплати (portmone, liqpay)';
|
|
28
30
|
COMMENT ON COLUMN billing.payments.payment_amount IS 'Сума поповнення рахунку';
|
|
29
31
|
COMMENT ON COLUMN billing.payments.total_balance IS 'Поточний баланс';
|
|
30
32
|
COMMENT ON COLUMN billing.payments.referer_url IS 'Посилання';
|
package/server/plugins/cron.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { addCron, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
2
|
|
|
3
|
-
import updateTrxStatus from '../routes/utils/portmone.check.status.js';
|
|
3
|
+
import updateTrxStatus from '../routes/portmone/utils/portmone.check.status.js';
|
|
4
4
|
|
|
5
5
|
async function updateOldTrxsStatus() {
|
|
6
6
|
const inprogress = pgClients.client.pk?.['billing.payments']
|
|
@@ -18,5 +18,5 @@ async function updateOldTrxsStatus() {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export default async function cron() {
|
|
21
|
-
// addCron(updateOldTrxsStatus, 60 * 60 * 24);
|
|
21
|
+
// addCron(updateOldTrxsStatus, 60 * 60 * 24);
|
|
22
22
|
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import request from 'request-promise';
|
|
2
|
+
import LiqPay from 'liqpayjs-sdk';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
config, logger, pgClients, dataInsert, dataUpdate, handlebarsSync,
|
|
6
|
+
} from '@opengis/fastify-table/utils.js';
|
|
7
|
+
|
|
8
|
+
const { prefix = '/api' } = config;
|
|
9
|
+
|
|
10
|
+
const { publicKey, privateKey, paymentRedirect } = config.integrations?.liqpay || {};
|
|
11
|
+
const liqpay = new LiqPay(publicKey, privateKey);
|
|
12
|
+
|
|
13
|
+
const host = 'https://www.liqpay.ua';
|
|
14
|
+
|
|
15
|
+
export default async function liqpayRedirect(req, reply) {
|
|
16
|
+
const {
|
|
17
|
+
pg = pgClients.client, query = {}, user = {}, headers = {},
|
|
18
|
+
} = req;
|
|
19
|
+
|
|
20
|
+
if (!publicKey || !privateKey) {
|
|
21
|
+
return reply.status(400).send('invalid liqpay integration settings');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const domain = req.hostname.split(':').shift();
|
|
25
|
+
|
|
26
|
+
const data = query.id ? await pg.query('select payment_id, account_id, payment_amount, payment_status from billing.payments where payment_id=$1', [query.id])
|
|
27
|
+
.then(el => el.rows?.[0] || {}) : {};
|
|
28
|
+
|
|
29
|
+
if (data.payment_status && data.payment_status === 'success') {
|
|
30
|
+
return { message: 'already processed', status: 400 };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const paymentAmount = data.payment_amount || query.price;
|
|
34
|
+
|
|
35
|
+
if (!paymentAmount) {
|
|
36
|
+
return { message: 'price is required', status: 400 };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const accountId = data.account_id
|
|
40
|
+
|| (user?.uid ? await pg.query('select account_id from billing.account_user where user_id=$1 limit 1', [user?.uid]).then(el => el.rows?.[0]?.account_id) : null);
|
|
41
|
+
|
|
42
|
+
if (!accountId) {
|
|
43
|
+
return { message: 'account_id is required', status: 400 };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { payment_id: paymentId } = !data.payment_id
|
|
47
|
+
? await dataInsert({
|
|
48
|
+
table: 'billing.payments',
|
|
49
|
+
data: {
|
|
50
|
+
payment_amount: paymentAmount,
|
|
51
|
+
account_id: accountId,
|
|
52
|
+
payment_service: 'liqpay',
|
|
53
|
+
payment_status: 'inprogress',
|
|
54
|
+
},
|
|
55
|
+
uid: user?.uid || '0',
|
|
56
|
+
}).then(el => el.rows?.[0] || {})
|
|
57
|
+
: { payment_id: data.payment_id };
|
|
58
|
+
|
|
59
|
+
if (!paymentId) {
|
|
60
|
+
return { message: 'payment not found', status: 404 };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await dataUpdate({
|
|
64
|
+
table: 'billing.payments',
|
|
65
|
+
id: paymentId,
|
|
66
|
+
data: {
|
|
67
|
+
referer_url: paymentRedirect ? handlebarsSync.compile(paymentRedirect)({ id: paymentId }) : headers?.referer,
|
|
68
|
+
payment_status: 'inprogress',
|
|
69
|
+
},
|
|
70
|
+
uid: user?.uid || '0',
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const protocol = headers?.referer?.split?.('://')?.shift?.() || req.protocol || 'https';
|
|
74
|
+
const rootPageUrl = `${protocol || 'https'}://${domain}${config.port ? `:${config.port}` : ''}`;
|
|
75
|
+
|
|
76
|
+
const resultUrl = paymentRedirect
|
|
77
|
+
? `${rootPageUrl}${handlebarsSync.compile(paymentRedirect)({ id: paymentId })}`
|
|
78
|
+
: headers?.referer || `${rootPageUrl}`;
|
|
79
|
+
const serverUrl = `${rootPageUrl}${prefix}/liqpay/${paymentId}/success`;
|
|
80
|
+
|
|
81
|
+
const html = liqpay.cnb_form({
|
|
82
|
+
action: 'pay',
|
|
83
|
+
amount: paymentAmount,
|
|
84
|
+
currency: 'UAH',
|
|
85
|
+
description: 'regular payment',
|
|
86
|
+
order_id: paymentId,
|
|
87
|
+
version: '3',
|
|
88
|
+
server_url: serverUrl, // update payment info - api url
|
|
89
|
+
result_url: resultUrl, // redirect user after payment - page url
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const logObj = {
|
|
93
|
+
type: 'redirect',
|
|
94
|
+
paymentId,
|
|
95
|
+
accountId,
|
|
96
|
+
price: paymentAmount,
|
|
97
|
+
service: 'liqpay',
|
|
98
|
+
domain,
|
|
99
|
+
paymentRedirectUrl: resultUrl,
|
|
100
|
+
serverUrl,
|
|
101
|
+
uid: user?.uid || '0',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (config.debug && query?.debug) {
|
|
105
|
+
return reply.status(302).headers({ 'Content-Type': 'text/html' }).send(html);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const body = {
|
|
109
|
+
data: html.match(/<input type="hidden" name="data" value="([^"]+)"/)?.[1],
|
|
110
|
+
signature: html.match(/<input type="hidden" name="signature" value="([^"]+)"/)?.[1],
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const response = await request({
|
|
115
|
+
url: `${host}/api/3/checkout`,
|
|
116
|
+
method: 'POST',
|
|
117
|
+
form: body,
|
|
118
|
+
followAllRedirects: false,
|
|
119
|
+
jar: true,
|
|
120
|
+
timeout: 6000,
|
|
121
|
+
simple: false, // prevent not 2xx code trigger catch
|
|
122
|
+
resolveWithFullResponse: true,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (response.statusCode !== 302 || !response.headers?.location) {
|
|
126
|
+
throw new Error(response);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (response.headers?.location?.includes?.('throw_error')) {
|
|
130
|
+
throw new Error(response.headers?.location);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Object.assign(logObj, { paymentId, redirect: response.headers?.location, status: 302 });
|
|
134
|
+
logger.file('payments', logObj);
|
|
135
|
+
return reply.redirect(response.headers.location);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
Object.assign(logObj, { error: err.toString() });
|
|
139
|
+
logger.file('payments/error', logObj);
|
|
140
|
+
return reply.status(500).send(err.toString());
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import LiqPay from 'liqpayjs-sdk';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
config, logger, pgClients, dataUpdate, getTemplate,
|
|
5
|
+
} from '@opengis/fastify-table/utils.js';
|
|
6
|
+
|
|
7
|
+
import { sendNotification } from '@opengis/admin/utils.js';
|
|
8
|
+
|
|
9
|
+
const newDate = () => {
|
|
10
|
+
const date = new Date();
|
|
11
|
+
const tzOffset = date.getTimezoneOffset();
|
|
12
|
+
const currentTimeWithTimezome = date - tzOffset * 60 * 1000;
|
|
13
|
+
return new Date(currentTimeWithTimezome).toISOString();
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const { publicKey, privateKey } = config.integrations?.liqpay || {};
|
|
17
|
+
const liqpay = new LiqPay(publicKey, privateKey);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Апі перенаправлює з liqpay назад на сторінку замовлення
|
|
21
|
+
*
|
|
22
|
+
* @method POST
|
|
23
|
+
* @alias liqpayStatus
|
|
24
|
+
* @summary redirect з liqpay на сторінку замовлення
|
|
25
|
+
* @type api
|
|
26
|
+
* @param {String} paymentId - Ідентифікатор замовлення
|
|
27
|
+
* @param {String} refillSum - Сума поповнення рахунку
|
|
28
|
+
* @returns {Number} status - номер помилки. Повертається, якщо була допущенна помилка в отриманих параметрах, або з бази. Це може бути 400 або 500
|
|
29
|
+
* @returns {String} error - опис помилки
|
|
30
|
+
* @returns {String} redirect - шлях до переадресації
|
|
31
|
+
* @returns {String} message - повідомлення про успішне виконання і передача певних даних або помилку
|
|
32
|
+
* @returns {String} headers - заголовки HTTP
|
|
33
|
+
* @returns {String} file - шлях файла або його назва
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export default async function liqpayStatus(req, reply) {
|
|
37
|
+
const {
|
|
38
|
+
pg = pgClients.client, params = {}, headers = {}, body = {}, user = {}, unittest,
|
|
39
|
+
} = req;
|
|
40
|
+
|
|
41
|
+
if (!publicKey || !privateKey) {
|
|
42
|
+
return reply.status(400).send('invalid liqpay integration settings');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!body?.data || !body?.signature) {
|
|
46
|
+
return reply.status(400).send('not enough body params: data, signature');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const sign = liqpay.str_to_sign(
|
|
50
|
+
privateKey
|
|
51
|
+
+ body.data
|
|
52
|
+
+ privateKey,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const origin = headers?.origin || headers?.referer;
|
|
56
|
+
const { status: responseStatus, id: paymentId } = params;
|
|
57
|
+
|
|
58
|
+
if (body.signature !== sign) {
|
|
59
|
+
logger.file('payments/warn', {
|
|
60
|
+
type: 'status',
|
|
61
|
+
service: 'liqpay',
|
|
62
|
+
paymentId,
|
|
63
|
+
origin,
|
|
64
|
+
uid: user?.uid || '0',
|
|
65
|
+
message: 'Transaction signature does not match',
|
|
66
|
+
});
|
|
67
|
+
return reply.status(403).send('access restricted: signature mismatch');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const data = await pg.query('select * from billing.payments where payment_id=$1', [paymentId])
|
|
71
|
+
.then(el => el.rows?.[0] || {});
|
|
72
|
+
|
|
73
|
+
const {
|
|
74
|
+
payment_id: trx,
|
|
75
|
+
payment_amount: refillSum = 0,
|
|
76
|
+
referer_url: redirectUrl,
|
|
77
|
+
payment_status: trxStatus,
|
|
78
|
+
payment_service: paymentService,
|
|
79
|
+
account_id: accountId,
|
|
80
|
+
} = data;
|
|
81
|
+
|
|
82
|
+
if (trxStatus === 'success') {
|
|
83
|
+
logger.file('payments/skip', {
|
|
84
|
+
type: 'status',
|
|
85
|
+
service: 'liqpay',
|
|
86
|
+
paymentId,
|
|
87
|
+
origin,
|
|
88
|
+
uid: user?.uid || '0',
|
|
89
|
+
message: 'Transaction was already processed',
|
|
90
|
+
});
|
|
91
|
+
return reply.status(400).send('Transaction was already processed');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!trx) {
|
|
95
|
+
return reply.status(404).send('Transaction not found');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (paymentService !== 'liqpay') {
|
|
99
|
+
return reply.status(400).send('Payment not registered via liqpay service');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
logger.file('payments', {
|
|
103
|
+
type: 'status',
|
|
104
|
+
service: 'liqpay',
|
|
105
|
+
paymentId,
|
|
106
|
+
origin,
|
|
107
|
+
uid: user?.uid || '0',
|
|
108
|
+
refill: refillSum,
|
|
109
|
+
body,
|
|
110
|
+
params,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// last trx contains total balance
|
|
114
|
+
const { total_balance: totalBalance = 0 } = await pg.query(`select total_balance from billing.payments
|
|
115
|
+
where account_id=$1
|
|
116
|
+
and payment_status in ('success', 'error')
|
|
117
|
+
and total_balance is not null
|
|
118
|
+
order by cdate desc limit 1`, [accountId]).then(el => el.rows?.[0] || {});
|
|
119
|
+
|
|
120
|
+
await dataUpdate({
|
|
121
|
+
table: 'billing.payments',
|
|
122
|
+
data: {
|
|
123
|
+
payment_data: body,
|
|
124
|
+
payment_status: responseStatus,
|
|
125
|
+
total_balance: +refillSum + +totalBalance,
|
|
126
|
+
success_date: newDate(),
|
|
127
|
+
},
|
|
128
|
+
id: paymentId,
|
|
129
|
+
uid: user?.uid || '0',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (unittest) {
|
|
133
|
+
console.log(`id:${trx}, status: ${responseStatus}, before: ${totalBalance || 0}, after: ${+refillSum + +totalBalance} (${refillSum})`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const { account_email: to } = await pg.query('select account_email from billing.accounts where account_id=$1', [accountId])
|
|
137
|
+
.then(el => el.rows?.[0] || {});
|
|
138
|
+
|
|
139
|
+
logger.file('payments', {
|
|
140
|
+
type: 'status',
|
|
141
|
+
service: 'liqpay',
|
|
142
|
+
paymentId,
|
|
143
|
+
responseStatus,
|
|
144
|
+
to,
|
|
145
|
+
origin,
|
|
146
|
+
redirect: redirectUrl,
|
|
147
|
+
uid: user.uid || '0',
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
Object.assign(data, {
|
|
151
|
+
domain: req.hostname,
|
|
152
|
+
total_balance: +refillSum + +totalBalance,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (to) {
|
|
156
|
+
const pt = await getTemplate('pt', 'marketplace-service-payment-client-template');
|
|
157
|
+
const options = {
|
|
158
|
+
pg,
|
|
159
|
+
to,
|
|
160
|
+
title: `Поповнення рахунку на порталі ${req.hostname}`,
|
|
161
|
+
template: pt?.html || pt,
|
|
162
|
+
data,
|
|
163
|
+
nocache: config?.local,
|
|
164
|
+
};
|
|
165
|
+
await sendNotification(options);
|
|
166
|
+
}
|
|
167
|
+
return reply.redirect(redirectUrl || '/');
|
|
168
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import liqpayRedirect from './controllers/liqpay.redirect.js';
|
|
2
|
+
import liqpayStatus from './controllers/liqpay.status.js';
|
|
3
|
+
|
|
4
|
+
export default async function plugin(app, opts) {
|
|
5
|
+
app.route({
|
|
6
|
+
method: 'GET',
|
|
7
|
+
url: '/liqpay-redirect',
|
|
8
|
+
config: {
|
|
9
|
+
policy: ['site'],
|
|
10
|
+
},
|
|
11
|
+
handler: liqpayRedirect,
|
|
12
|
+
});
|
|
13
|
+
// /payment-info/:id
|
|
14
|
+
app.route({
|
|
15
|
+
method: 'POST',
|
|
16
|
+
url: '/liqpay/:id/:status',
|
|
17
|
+
config: {
|
|
18
|
+
policy: ['public'],
|
|
19
|
+
},
|
|
20
|
+
handler: liqpayStatus,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { metaFormat, pgClients } from '@opengis/fastify-table/utils.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Апі для отримання інформації за ID
|
|
5
|
+
*
|
|
6
|
+
* @method GET
|
|
7
|
+
* @alias paymentInfo
|
|
8
|
+
* @type api
|
|
9
|
+
* @param {String} params.id - ID платежу
|
|
10
|
+
* @returns {Number} status - номер помилки. Повертається, якщо була допущенна помилка в отриманих параметрах, або з бази. Це може бути 400 або 500
|
|
11
|
+
* @returns {String} error - опис помилки
|
|
12
|
+
* @returns {String} message - повідомлення про успішне виконання і передача певних даних або помилку
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export default async function paymentInfo({
|
|
16
|
+
pg = pgClients.client, user = {}, params = {},
|
|
17
|
+
}) {
|
|
18
|
+
if (!user?.uid) {
|
|
19
|
+
return { message: 'unauthorized', status: 401 };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!params?.id) {
|
|
23
|
+
return { message: 'not enough query params: id', status: 400 };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { rows = [] } = await pg.query(`select
|
|
27
|
+
payment_id,
|
|
28
|
+
account_id,
|
|
29
|
+
payment_amount,
|
|
30
|
+
payment_status,
|
|
31
|
+
total_balance,
|
|
32
|
+
payment_num,
|
|
33
|
+
subscription_id
|
|
34
|
+
from billing.payments
|
|
35
|
+
where payment_id = $1
|
|
36
|
+
and account_id in (select account_id from billing.account_user where user_id = $2)`, [params.id, user.uid]);
|
|
37
|
+
|
|
38
|
+
if (!rows.length) {
|
|
39
|
+
return { message: 'payment not found', status: 404 };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await metaFormat({ rows, cls: { account_id: 'billing.account_id', payment_status: 'billing.payment_status', subscription_id: 'billing.subscription_id' } });
|
|
43
|
+
|
|
44
|
+
return rows[0];
|
|
45
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import request from 'request-promise';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
config, pgClients, logger, dataInsert, dataUpdate,
|
|
4
|
+
config, pgClients, logger, dataInsert, dataUpdate, handlebarsSync,
|
|
5
5
|
} from '@opengis/fastify-table/utils.js';
|
|
6
6
|
|
|
7
|
+
const { host, payeeId, paymentRedirect = config.paymentRedirect } = config.integrations?.pay || {};
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Апі перенаправлює до стороннього сервісу оплати карткою онлайн
|
|
9
11
|
*
|
|
@@ -25,9 +27,6 @@ export default async function PortmoneRedirect(req, reply) {
|
|
|
25
27
|
pg = pgClients.client, user = {}, query = {}, headers = {},
|
|
26
28
|
} = req;
|
|
27
29
|
|
|
28
|
-
const { host, payeeId } = config.integrations?.pay || {};
|
|
29
|
-
const domain = req.hostname.split(':').shift();
|
|
30
|
-
|
|
31
30
|
if (!host) {
|
|
32
31
|
return { message: 'empty integration host', status: 400 };
|
|
33
32
|
}
|
|
@@ -36,6 +35,8 @@ export default async function PortmoneRedirect(req, reply) {
|
|
|
36
35
|
return { message: 'empty integration payeeId', status: 400 };
|
|
37
36
|
}
|
|
38
37
|
|
|
38
|
+
const domain = req.hostname.split(':').shift();
|
|
39
|
+
|
|
39
40
|
const data = query.id ? await pg.query('select payment_id, account_id, payment_amount, payment_status from billing.payments where payment_id=$1', [query.id])
|
|
40
41
|
.then(el => el.rows?.[0] || {}) : {};
|
|
41
42
|
|
|
@@ -58,36 +59,38 @@ export default async function PortmoneRedirect(req, reply) {
|
|
|
58
59
|
|
|
59
60
|
if ((!headers?.referer || !headers.referer.includes(domain))) {
|
|
60
61
|
logger.file('payments/warn', {
|
|
61
|
-
message: 'invalid referer', domain, referer: headers?.referer, uid: user?.uid,
|
|
62
|
+
message: 'invalid referer', service: 'portmone', domain, referer: headers?.referer, uid: user?.uid,
|
|
62
63
|
});
|
|
63
64
|
if (!config.auth?.disableRestricted) return { message: 'access restricted: referer', status: 403 };
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
const { payment_id: paymentId } = data.payment_id
|
|
67
|
-
? await
|
|
68
|
-
table: 'billing.payments',
|
|
69
|
-
id: data.payment_id,
|
|
70
|
-
data: {
|
|
71
|
-
referer_url: headers?.referer,
|
|
72
|
-
payment_status: 'inprogress',
|
|
73
|
-
},
|
|
74
|
-
uid: user?.uid || '0',
|
|
75
|
-
})
|
|
76
|
-
: await dataInsert({
|
|
67
|
+
const { payment_id: paymentId } = !data.payment_id
|
|
68
|
+
? await dataInsert({
|
|
77
69
|
table: 'billing.payments',
|
|
78
70
|
data: {
|
|
79
71
|
payment_amount: paymentAmount,
|
|
80
72
|
account_id: accountId,
|
|
81
|
-
|
|
73
|
+
payment_service: 'portmone',
|
|
82
74
|
payment_status: 'inprogress',
|
|
83
75
|
},
|
|
84
76
|
uid: user?.uid || '0',
|
|
85
|
-
}).then(el => el.rows?.[0] || {})
|
|
77
|
+
}).then(el => el.rows?.[0] || {})
|
|
78
|
+
: { payment_id: data.payment_id };
|
|
86
79
|
|
|
87
80
|
if (!paymentId) {
|
|
88
81
|
return { message: 'payment not found', status: 404 };
|
|
89
82
|
}
|
|
90
83
|
|
|
84
|
+
await dataUpdate({
|
|
85
|
+
table: 'billing.payments',
|
|
86
|
+
id: paymentId,
|
|
87
|
+
data: {
|
|
88
|
+
referer_url: paymentRedirect ? handlebarsSync.compile(paymentRedirect)({ id: paymentId }) : headers?.referer,
|
|
89
|
+
payment_status: 'inprogress',
|
|
90
|
+
},
|
|
91
|
+
uid: user?.uid || '0',
|
|
92
|
+
});
|
|
93
|
+
|
|
91
94
|
const protocol = headers?.referer.split('://').shift();
|
|
92
95
|
|
|
93
96
|
const formData = {
|
|
@@ -102,11 +105,13 @@ export default async function PortmoneRedirect(req, reply) {
|
|
|
102
105
|
|
|
103
106
|
const logObj = {
|
|
104
107
|
type: 'redirect',
|
|
108
|
+
service: 'portmone',
|
|
105
109
|
payeeId,
|
|
106
110
|
paymentId,
|
|
107
111
|
accountId,
|
|
108
112
|
price: paymentAmount,
|
|
109
113
|
domain,
|
|
114
|
+
paymentRedirectUrl: paymentRedirect ? handlebarsSync.compile(paymentRedirect)({ id: paymentId }) : headers?.referer,
|
|
110
115
|
uid: user?.uid || '0',
|
|
111
116
|
};
|
|
112
117
|
|
|
@@ -4,6 +4,15 @@ import {
|
|
|
4
4
|
|
|
5
5
|
import { sendNotification } from '@opengis/admin/utils.js';
|
|
6
6
|
|
|
7
|
+
const newDate = () => {
|
|
8
|
+
const date = new Date();
|
|
9
|
+
const tzOffset = date.getTimezoneOffset();
|
|
10
|
+
const currentTimeWithTimezome = date - tzOffset * 60 * 1000;
|
|
11
|
+
return new Date(currentTimeWithTimezome).toISOString();
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const { host } = config.integrations?.pay || {};
|
|
15
|
+
|
|
7
16
|
/**
|
|
8
17
|
* Апі перенаправлює з portmone назад на сторінку замовлення
|
|
9
18
|
*
|
|
@@ -25,7 +34,6 @@ export default async function portmoneStatus(req, reply) {
|
|
|
25
34
|
const {
|
|
26
35
|
pg = pgClients.client, params = {}, headers = {}, body = {}, user = {}, unittest,
|
|
27
36
|
} = req;
|
|
28
|
-
const { host } = config.integrations?.pay || {};
|
|
29
37
|
|
|
30
38
|
if (!host) {
|
|
31
39
|
return { message: 'empty integration host', status: 400 };
|
|
@@ -50,6 +58,7 @@ export default async function portmoneStatus(req, reply) {
|
|
|
50
58
|
if (trxStatus === 'success') {
|
|
51
59
|
logger.file('payments/skip', {
|
|
52
60
|
type: 'status',
|
|
61
|
+
service: 'portmone',
|
|
53
62
|
paymentId,
|
|
54
63
|
origin,
|
|
55
64
|
uid: user?.uid || '0',
|
|
@@ -68,6 +77,7 @@ export default async function portmoneStatus(req, reply) {
|
|
|
68
77
|
if (!origin?.startsWith(host)) {
|
|
69
78
|
logger.file('payments/warn', {
|
|
70
79
|
type: 'status',
|
|
80
|
+
service: 'portmone',
|
|
71
81
|
paymentId,
|
|
72
82
|
origin,
|
|
73
83
|
uid: user?.uid || '0',
|
|
@@ -79,6 +89,7 @@ export default async function portmoneStatus(req, reply) {
|
|
|
79
89
|
|
|
80
90
|
logger.file('payments', {
|
|
81
91
|
type: 'status',
|
|
92
|
+
service: 'portmone',
|
|
82
93
|
paymentId,
|
|
83
94
|
origin,
|
|
84
95
|
uid: user?.uid || '0',
|
|
@@ -98,7 +109,7 @@ export default async function portmoneStatus(req, reply) {
|
|
|
98
109
|
payment_data: body,
|
|
99
110
|
payment_status: responseStatus,
|
|
100
111
|
total_balance: +(refill) + (+totalBalance || 0),
|
|
101
|
-
success_date:
|
|
112
|
+
success_date: newDate(),
|
|
102
113
|
},
|
|
103
114
|
id: paymentId,
|
|
104
115
|
uid: user?.uid || '0',
|
|
@@ -113,6 +124,7 @@ export default async function portmoneStatus(req, reply) {
|
|
|
113
124
|
|
|
114
125
|
logger.file('payments', {
|
|
115
126
|
type: 'status',
|
|
127
|
+
service: 'portmone',
|
|
116
128
|
paymentId,
|
|
117
129
|
responseStatus,
|
|
118
130
|
to,
|
|
@@ -143,12 +155,13 @@ export default async function portmoneStatus(req, reply) {
|
|
|
143
155
|
catch (err) {
|
|
144
156
|
logger.file('payments/error', {
|
|
145
157
|
type: 'status',
|
|
158
|
+
service: 'portmone',
|
|
146
159
|
paymentId,
|
|
147
160
|
origin,
|
|
148
161
|
responseStatus,
|
|
149
162
|
uid: user?.uid || '0',
|
|
150
163
|
error: err.toString(),
|
|
151
164
|
});
|
|
152
|
-
return
|
|
165
|
+
return reply.status(500).send(err.toString());
|
|
153
166
|
}
|
|
154
167
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import portmoneRedirect from './controllers/portmone.redirect.js';
|
|
2
|
+
import portmoneStatus from './controllers/portmone.status.js';
|
|
3
|
+
import paymentInfo from './controllers/payment.info.js';
|
|
4
|
+
|
|
5
|
+
export default async function plugin(app, opts) {
|
|
6
|
+
app.route({
|
|
7
|
+
method: 'GET',
|
|
8
|
+
url: '/portmone-redirect',
|
|
9
|
+
config: {
|
|
10
|
+
policy: ['site'],
|
|
11
|
+
},
|
|
12
|
+
handler: portmoneRedirect,
|
|
13
|
+
});
|
|
14
|
+
app.route({
|
|
15
|
+
method: 'GET',
|
|
16
|
+
url: '/payment-info/:id',
|
|
17
|
+
config: {
|
|
18
|
+
policy: ['site'],
|
|
19
|
+
},
|
|
20
|
+
handler: paymentInfo,
|
|
21
|
+
});
|
|
22
|
+
app.route({
|
|
23
|
+
method: 'POST',
|
|
24
|
+
url: '/portmone/:id/:status',
|
|
25
|
+
config: {
|
|
26
|
+
policy: ['public'],
|
|
27
|
+
},
|
|
28
|
+
handler: portmoneStatus,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|