payment-kit 1.18.15 → 1.18.17
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/api/src/index.ts +2 -0
- package/api/src/libs/invoice.ts +5 -3
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +32 -14
- package/api/src/libs/session.ts +9 -1
- package/api/src/libs/util.ts +12 -4
- package/api/src/routes/checkout-sessions.ts +286 -120
- package/api/src/routes/connect/change-payment.ts +9 -1
- package/api/src/routes/connect/change-plan.ts +9 -1
- package/api/src/routes/connect/collect-batch.ts +7 -5
- package/api/src/routes/connect/pay.ts +1 -1
- package/api/src/routes/connect/recharge-account.ts +124 -0
- package/api/src/routes/connect/setup.ts +8 -1
- package/api/src/routes/connect/shared.ts +175 -54
- package/api/src/routes/connect/subscribe.ts +11 -1
- package/api/src/routes/customers.ts +150 -7
- package/api/src/routes/donations.ts +1 -1
- package/api/src/routes/invoices.ts +47 -1
- package/api/src/routes/subscriptions.ts +0 -3
- package/blocklet.yml +2 -1
- package/package.json +16 -16
- package/src/app.tsx +11 -3
- package/src/components/info-card.tsx +6 -2
- package/src/components/info-row.tsx +1 -0
- package/src/components/invoice/recharge.tsx +85 -56
- package/src/components/invoice/table.tsx +7 -1
- package/src/components/subscription/portal/actions.tsx +1 -1
- package/src/components/subscription/portal/list.tsx +6 -0
- package/src/locales/en.tsx +9 -0
- package/src/locales/zh.tsx +9 -0
- package/src/pages/admin/payments/payouts/detail.tsx +16 -5
- package/src/pages/customer/index.tsx +226 -284
- package/src/pages/customer/invoice/detail.tsx +24 -16
- package/src/pages/customer/invoice/past-due.tsx +46 -23
- package/src/pages/customer/payout/detail.tsx +16 -5
- package/src/pages/customer/recharge/account.tsx +513 -0
- package/src/pages/customer/{recharge.tsx → recharge/subscription.tsx} +22 -19
- package/src/pages/customer/subscription/embed.tsx +16 -1
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '@blocklet/payment-react';
|
|
18
18
|
import type { TCheckoutSession, TInvoiceExpanded, TPaymentLink } from '@blocklet/payment-types';
|
|
19
19
|
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
20
|
-
import { Alert, Box, Button, CircularProgress, Divider, Stack, Typography } from '@mui/material';
|
|
20
|
+
import { Alert, Box, Button, CircularProgress, Divider, Stack, Tooltip, Typography } from '@mui/material';
|
|
21
21
|
import { styled } from '@mui/system';
|
|
22
22
|
import { useRequest, useSetState } from 'ahooks';
|
|
23
23
|
import { useEffect } from 'react';
|
|
@@ -204,9 +204,31 @@ export default function CustomerInvoiceDetail() {
|
|
|
204
204
|
}}>
|
|
205
205
|
<InfoMetric
|
|
206
206
|
label={t('common.status')}
|
|
207
|
-
value={
|
|
207
|
+
value={
|
|
208
|
+
<Tooltip
|
|
209
|
+
title={data.status === 'void' ? t('payment.customer.invoice.noPaymentRequired') : ''}
|
|
210
|
+
arrow
|
|
211
|
+
placement="top">
|
|
212
|
+
<span>
|
|
213
|
+
<Status label={data.status} color={getInvoiceStatusColor(data.status)} />
|
|
214
|
+
</span>
|
|
215
|
+
</Tooltip>
|
|
216
|
+
}
|
|
208
217
|
divider
|
|
209
218
|
/>
|
|
219
|
+
{data.subscription && (
|
|
220
|
+
<InfoMetric
|
|
221
|
+
label={t('admin.subscription.name')}
|
|
222
|
+
value={
|
|
223
|
+
<Link to={`/customer/subscription/${data.subscription.id}`}>
|
|
224
|
+
<Typography variant="body1" color="text.link">
|
|
225
|
+
{data.subscription.description || data.subscription.id}
|
|
226
|
+
</Typography>
|
|
227
|
+
</Link>
|
|
228
|
+
}
|
|
229
|
+
divider
|
|
230
|
+
/>
|
|
231
|
+
)}
|
|
210
232
|
<InfoMetric label={t('common.createdAt')} value={formatTime(data.created_at)} divider />
|
|
211
233
|
{data.period_start > 0 && data.period_end > 0 && (
|
|
212
234
|
<InfoMetric
|
|
@@ -301,20 +323,6 @@ export default function CustomerInvoiceDetail() {
|
|
|
301
323
|
alignItems={InfoAlignItems}
|
|
302
324
|
/>
|
|
303
325
|
)}
|
|
304
|
-
{data.subscription && (
|
|
305
|
-
<InfoRow
|
|
306
|
-
label={t('admin.subscription.name')}
|
|
307
|
-
value={
|
|
308
|
-
<Link to={`/customer/subscription/${data.subscription.id}`}>
|
|
309
|
-
<Typography variant="body1" color="text.link">
|
|
310
|
-
{data.subscription.description || data.subscription.id}
|
|
311
|
-
</Typography>
|
|
312
|
-
</Link>
|
|
313
|
-
}
|
|
314
|
-
direction={InfoDirection}
|
|
315
|
-
alignItems={InfoAlignItems}
|
|
316
|
-
/>
|
|
317
|
-
)}
|
|
318
326
|
{data?.relatedInvoice && (
|
|
319
327
|
<InfoRow
|
|
320
328
|
label={t('customer.invoice.relatedInvoice')}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getPrefix,
|
|
7
7
|
getQueryParams,
|
|
8
8
|
usePaymentContext,
|
|
9
|
+
OverdueInvoicePayment,
|
|
9
10
|
} from '@blocklet/payment-react';
|
|
10
11
|
import type { TCustomerExpanded } from '@blocklet/payment-types';
|
|
11
12
|
import { ArrowBackOutlined } from '@mui/icons-material';
|
|
@@ -29,9 +30,10 @@ const fetchData = (): Promise<TCustomerExpanded> => {
|
|
|
29
30
|
export default function CustomerInvoicePastDue() {
|
|
30
31
|
const { t } = useLocaleContext();
|
|
31
32
|
const { events } = useSessionContext();
|
|
32
|
-
const { connect } = usePaymentContext();
|
|
33
|
+
const { connect, session } = usePaymentContext();
|
|
33
34
|
const [params] = useSearchParams();
|
|
34
|
-
const [
|
|
35
|
+
const [hasUnpaidInvoices, setHasUnpaidInvoices] = useState(false);
|
|
36
|
+
const [showOverduePayment, setShowOverduePayment] = useState(false);
|
|
35
37
|
|
|
36
38
|
const { loading, error, data, runAsync } = useRequest(fetchData);
|
|
37
39
|
|
|
@@ -60,27 +62,31 @@ export default function CustomerInvoicePastDue() {
|
|
|
60
62
|
const subscriptionId = params.get('subscription') || '';
|
|
61
63
|
const currencyId = params.get('currency') || '';
|
|
62
64
|
const handleBatchPay = () => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
if (subscriptionId && currencyId) {
|
|
66
|
+
connect.open({
|
|
67
|
+
containerEl: undefined as unknown as Element,
|
|
68
|
+
saveConnect: false,
|
|
69
|
+
action: 'collect-batch',
|
|
70
|
+
prefix: joinURL(getPrefix(), '/api/did'),
|
|
71
|
+
extraParams: { subscriptionId, currencyId },
|
|
72
|
+
onSuccess: () => {
|
|
73
|
+
connect.close();
|
|
74
|
+
},
|
|
75
|
+
onClose: () => {
|
|
76
|
+
connect.close();
|
|
77
|
+
},
|
|
78
|
+
onError: (err: any) => {
|
|
79
|
+
Toast.error(formatError(err));
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
setShowOverduePayment(true);
|
|
84
|
+
}
|
|
79
85
|
};
|
|
80
86
|
|
|
81
87
|
const onTableDataChange = (tableData: any, prevData: any) => {
|
|
82
88
|
if (isEmpty(tableData) || tableData?.count === 0) {
|
|
83
|
-
|
|
89
|
+
setHasUnpaidInvoices(false);
|
|
84
90
|
if (prevData?.count > 0) {
|
|
85
91
|
// paid all invoices
|
|
86
92
|
const referer = getQueryParams(window.location.href)?.referer;
|
|
@@ -92,7 +98,7 @@ export default function CustomerInvoicePastDue() {
|
|
|
92
98
|
}
|
|
93
99
|
return;
|
|
94
100
|
}
|
|
95
|
-
|
|
101
|
+
setHasUnpaidInvoices(true);
|
|
96
102
|
};
|
|
97
103
|
|
|
98
104
|
return (
|
|
@@ -110,12 +116,28 @@ export default function CustomerInvoicePastDue() {
|
|
|
110
116
|
</Stack>
|
|
111
117
|
</Stack>
|
|
112
118
|
<Root direction="column" spacing={3}>
|
|
113
|
-
{
|
|
119
|
+
{hasUnpaidInvoices && <Alert severity="error">{t('payment.customer.pastDue.warning')}</Alert>}
|
|
120
|
+
{showOverduePayment && (
|
|
121
|
+
<OverdueInvoicePayment
|
|
122
|
+
customerId={session.user.did}
|
|
123
|
+
onPaid={() => {
|
|
124
|
+
setShowOverduePayment(false);
|
|
125
|
+
}}
|
|
126
|
+
successToast={false}
|
|
127
|
+
dialogProps={{
|
|
128
|
+
open: showOverduePayment,
|
|
129
|
+
onClose: () => setShowOverduePayment(false),
|
|
130
|
+
}}
|
|
131
|
+
detailLinkOptions={{
|
|
132
|
+
enabled: false,
|
|
133
|
+
}}
|
|
134
|
+
/>
|
|
135
|
+
)}
|
|
114
136
|
|
|
115
137
|
<Box className="section">
|
|
116
138
|
<SectionHeader title={t('payment.customer.pastDue.invoices')} mb={0}>
|
|
117
|
-
{
|
|
118
|
-
<Button size="small" variant="contained" color="
|
|
139
|
+
{hasUnpaidInvoices && (
|
|
140
|
+
<Button size="small" variant="contained" color="primary" onClick={handleBatchPay}>
|
|
119
141
|
{t('admin.subscription.batchPay.button')}
|
|
120
142
|
</Button>
|
|
121
143
|
)}
|
|
@@ -131,6 +153,7 @@ export default function CustomerInvoicePastDue() {
|
|
|
131
153
|
action="pay"
|
|
132
154
|
type="table"
|
|
133
155
|
onTableDataChange={onTableDataChange}
|
|
156
|
+
relatedSubscription
|
|
134
157
|
/>
|
|
135
158
|
</Box>
|
|
136
159
|
</Box>
|
|
@@ -59,6 +59,8 @@ export default function PayoutDetail() {
|
|
|
59
59
|
const currency = data.paymentCurrency;
|
|
60
60
|
const total = [formatBNStr(data?.amount, currency.decimal), currency.symbol].join(' ');
|
|
61
61
|
const { paymentIntent, paymentLink } = data || {};
|
|
62
|
+
|
|
63
|
+
const isAnonymousPayer = paymentIntent?.customer?.metadata?.anonymous;
|
|
62
64
|
return (
|
|
63
65
|
<Root direction="column" spacing={2.5} mb={4}>
|
|
64
66
|
<Box>
|
|
@@ -160,23 +162,32 @@ export default function PayoutDetail() {
|
|
|
160
162
|
: '',
|
|
161
163
|
48
|
|
162
164
|
)}
|
|
165
|
+
logoName={paymentIntent?.customer?.metadata?.anonymous ? '' : paymentIntent?.customer?.name}
|
|
163
166
|
name={
|
|
164
167
|
<Typography
|
|
165
168
|
variant="subtitle2"
|
|
166
169
|
sx={{
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
...(isAnonymousPayer
|
|
171
|
+
? {}
|
|
172
|
+
: {
|
|
173
|
+
cursor: 'pointer',
|
|
174
|
+
'&:hover': {
|
|
175
|
+
color: 'text.link',
|
|
176
|
+
},
|
|
177
|
+
}),
|
|
171
178
|
}}
|
|
172
179
|
onClick={() => {
|
|
180
|
+
if (isAnonymousPayer) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
173
183
|
const url = getCustomerProfileUrl({
|
|
174
184
|
userDid: paymentIntent?.customer?.did,
|
|
175
185
|
locale: 'zh',
|
|
176
186
|
});
|
|
177
187
|
window.open(url, '_blank');
|
|
178
188
|
}}>
|
|
179
|
-
{paymentIntent?.customer?.name}
|
|
189
|
+
{paymentIntent?.customer?.name}
|
|
190
|
+
{paymentIntent?.customer?.email ? ` (${paymentIntent?.customer?.email})` : ''}
|
|
180
191
|
</Typography>
|
|
181
192
|
}
|
|
182
193
|
description={
|