payment-kit 1.21.13 → 1.21.15
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/crons/payment-stat.ts +31 -23
- package/api/src/libs/invoice.ts +29 -4
- package/api/src/libs/product.ts +28 -4
- package/api/src/routes/checkout-sessions.ts +46 -1
- package/api/src/routes/index.ts +2 -0
- package/api/src/routes/invoices.ts +63 -2
- package/api/src/routes/payment-stats.ts +244 -22
- package/api/src/routes/products.ts +3 -0
- package/api/src/routes/tax-rates.ts +220 -0
- package/api/src/store/migrations/20251001-add-tax-code-to-products.ts +20 -0
- package/api/src/store/migrations/20251001-create-tax-rates.ts +17 -0
- package/api/src/store/migrations/20251007-relate-tax-rate-to-invoice.ts +24 -0
- package/api/src/store/migrations/20251009-add-tax-behavior.ts +21 -0
- package/api/src/store/models/index.ts +3 -0
- package/api/src/store/models/invoice-item.ts +10 -0
- package/api/src/store/models/price.ts +7 -0
- package/api/src/store/models/product.ts +7 -0
- package/api/src/store/models/tax-rate.ts +352 -0
- package/api/tests/models/tax-rate.spec.ts +777 -0
- package/blocklet.yml +2 -2
- package/package.json +6 -6
- package/public/currencies/dollar.png +0 -0
- package/src/components/collapse.tsx +3 -2
- package/src/components/drawer-form.tsx +2 -1
- package/src/components/invoice/list.tsx +38 -3
- package/src/components/invoice/table.tsx +48 -2
- package/src/components/metadata/form.tsx +2 -2
- package/src/components/payment-intent/list.tsx +19 -3
- package/src/components/payouts/list.tsx +19 -3
- package/src/components/price/currency-select.tsx +105 -48
- package/src/components/price/form.tsx +3 -1
- package/src/components/product/form.tsx +79 -5
- package/src/components/refund/list.tsx +20 -3
- package/src/components/subscription/items/actions.tsx +25 -15
- package/src/components/subscription/list.tsx +15 -3
- package/src/components/tax/actions.tsx +140 -0
- package/src/components/tax/filter-toolbar.tsx +230 -0
- package/src/components/tax/tax-code-select.tsx +633 -0
- package/src/components/tax/tax-rate-form.tsx +177 -0
- package/src/components/tax/tax-utils.ts +38 -0
- package/src/components/tax/taxCodes.json +10882 -0
- package/src/components/uploader.tsx +3 -0
- package/src/hooks/cache-state.ts +84 -0
- package/src/locales/en.tsx +152 -0
- package/src/locales/zh.tsx +149 -0
- package/src/pages/admin/billing/invoices/detail.tsx +1 -1
- package/src/pages/admin/index.tsx +2 -0
- package/src/pages/admin/overview.tsx +1114 -322
- package/src/pages/admin/products/vendors/index.tsx +4 -2
- package/src/pages/admin/tax/create.tsx +104 -0
- package/src/pages/admin/tax/detail.tsx +476 -0
- package/src/pages/admin/tax/edit.tsx +126 -0
- package/src/pages/admin/tax/index.tsx +86 -0
- package/src/pages/admin/tax/list.tsx +334 -0
- package/src/pages/customer/subscription/change-payment.tsx +1 -1
- package/src/pages/home.tsx +6 -3
|
@@ -3,6 +3,7 @@ import { Stack, styled } from '@mui/system';
|
|
|
3
3
|
import { lazy, Suspense, useCallback, useEffect, useRef } from 'react';
|
|
4
4
|
import { CloudUpload, Delete, Edit } from '@mui/icons-material';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
6
7
|
|
|
7
8
|
const UploaderComponent = lazy(() =>
|
|
8
9
|
import(/* webpackChunkName: "blocklet-uploader" */ '@blocklet/uploader').then((res) => ({
|
|
@@ -27,6 +28,7 @@ export default function Uploader({
|
|
|
27
28
|
allowedFileExts = ['.png', '.jpeg', '.webp', '.svg', '.jpg'],
|
|
28
29
|
disabled = false,
|
|
29
30
|
}: Props) {
|
|
31
|
+
const { locale } = useLocaleContext();
|
|
30
32
|
const uploaderRef = useRef<any>(null);
|
|
31
33
|
const handleOpen = useCallback(() => {
|
|
32
34
|
if (!uploaderRef.current) return;
|
|
@@ -72,6 +74,7 @@ export default function Uploader({
|
|
|
72
74
|
uploader: '/api/uploads',
|
|
73
75
|
companion: '/api/companion',
|
|
74
76
|
}}
|
|
77
|
+
locale={locale}
|
|
75
78
|
/>
|
|
76
79
|
</Suspense>
|
|
77
80
|
);
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
type StorageType = 'localStorage' | 'sessionStorage' | 'cookie';
|
|
4
|
+
|
|
5
|
+
interface CacheStateOptions<T> {
|
|
6
|
+
defaultValue: T;
|
|
7
|
+
storage?: StorageType;
|
|
8
|
+
getUrlParams?: () => Partial<T>;
|
|
9
|
+
clearUrlParams?: () => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const getStorageValue = <T>(key: string, storage: StorageType): T | undefined => {
|
|
13
|
+
try {
|
|
14
|
+
if (storage === 'cookie') {
|
|
15
|
+
const matches = document.cookie.match(
|
|
16
|
+
new RegExp(`(?:^|; )${key.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1')}=([^;]*)`)
|
|
17
|
+
);
|
|
18
|
+
return matches?.[1] ? JSON.parse(decodeURIComponent(matches[1])) : undefined;
|
|
19
|
+
}
|
|
20
|
+
const storageObj = storage === 'sessionStorage' ? sessionStorage : localStorage;
|
|
21
|
+
const value = storageObj.getItem(key);
|
|
22
|
+
return value ? JSON.parse(value) : undefined;
|
|
23
|
+
} catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const setStorageValue = <T>(key: string, value: T, storage: StorageType): void => {
|
|
29
|
+
try {
|
|
30
|
+
const serialized = JSON.stringify(value);
|
|
31
|
+
if (storage === 'cookie') {
|
|
32
|
+
document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(serialized)}; path=/`;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const storageObj = storage === 'sessionStorage' ? sessionStorage : localStorage;
|
|
36
|
+
storageObj.setItem(key, serialized);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(`Failed to set ${storage} value:`, error);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const getInitialValue = <T>(
|
|
43
|
+
key: string,
|
|
44
|
+
storage: StorageType,
|
|
45
|
+
defaultValue: T,
|
|
46
|
+
getUrlParams?: () => Partial<T>,
|
|
47
|
+
clearUrlParams?: () => void
|
|
48
|
+
): T => {
|
|
49
|
+
const cachedValue = getStorageValue<T>(key, storage);
|
|
50
|
+
const urlParams = getUrlParams?.();
|
|
51
|
+
|
|
52
|
+
if (urlParams && Object.keys(urlParams).length > 0) {
|
|
53
|
+
const mergedValue = {
|
|
54
|
+
...(cachedValue || defaultValue),
|
|
55
|
+
...urlParams,
|
|
56
|
+
};
|
|
57
|
+
setStorageValue(key, mergedValue, storage);
|
|
58
|
+
clearUrlParams?.();
|
|
59
|
+
return mergedValue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return cachedValue !== undefined ? cachedValue : defaultValue;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const useCacheState = <T = any>(key: string, options: CacheStateOptions<T>) => {
|
|
66
|
+
const { defaultValue, storage = 'localStorage', getUrlParams, clearUrlParams } = options;
|
|
67
|
+
|
|
68
|
+
const [state, setState] = useState<T>(() =>
|
|
69
|
+
getInitialValue(key, storage, defaultValue, getUrlParams, clearUrlParams)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const setStateAndStorage = useCallback(
|
|
73
|
+
(value: T | ((prev: T) => T)) => {
|
|
74
|
+
setState((prevState) => {
|
|
75
|
+
const nextState = typeof value === 'function' ? (value as (prev: T) => T)(prevState) : value;
|
|
76
|
+
setStorageValue(key, nextState, storage);
|
|
77
|
+
return nextState;
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
[key, storage]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return [state, setStateAndStorage] as const;
|
|
84
|
+
};
|
package/src/locales/en.tsx
CHANGED
|
@@ -5,6 +5,7 @@ export default flat({
|
|
|
5
5
|
redirecting: 'Redirecting...',
|
|
6
6
|
title: 'Name',
|
|
7
7
|
estimated: 'Estimated',
|
|
8
|
+
total: 'Total',
|
|
8
9
|
active: 'Active',
|
|
9
10
|
inactive: 'Inactive',
|
|
10
11
|
metadata: {
|
|
@@ -41,18 +42,28 @@ export default flat({
|
|
|
41
42
|
quickStart: 'Quick Start Guides',
|
|
42
43
|
advancedFeatures: 'Advanced Features',
|
|
43
44
|
quickStarts: 'Quick Starts',
|
|
45
|
+
homeTagline: 'A decentralized Stripe-like payment solution for Blocklets',
|
|
46
|
+
adminDashboard: 'Admin Dashboard',
|
|
47
|
+
customerPortal: 'Customer Portal',
|
|
44
48
|
copy: 'Copy',
|
|
45
49
|
copied: 'Copied',
|
|
46
50
|
copySuccess: 'Copied successfully',
|
|
47
51
|
copyFailed: 'Copy failed',
|
|
48
52
|
copyTip: 'Please copy manually',
|
|
49
53
|
save: 'Save',
|
|
54
|
+
saving: 'Saving...',
|
|
50
55
|
cancel: 'Cancel',
|
|
56
|
+
back: 'Back',
|
|
51
57
|
know: 'I Know',
|
|
52
58
|
confirm: 'Confirm',
|
|
53
59
|
edit: 'Edit',
|
|
60
|
+
view: 'View',
|
|
61
|
+
select: 'Select',
|
|
62
|
+
clear: 'Clear',
|
|
54
63
|
delete: 'Delete',
|
|
55
64
|
deleting: 'Deleting...',
|
|
65
|
+
activate: 'Activate',
|
|
66
|
+
deactivate: 'Deactivate',
|
|
56
67
|
yes: 'Yes',
|
|
57
68
|
no: 'No',
|
|
58
69
|
never: 'Never',
|
|
@@ -95,6 +106,7 @@ export default flat({
|
|
|
95
106
|
viewInvoice: 'View Invoice',
|
|
96
107
|
viewSourceData: 'View Source',
|
|
97
108
|
goToConfigure: 'Go to Configure',
|
|
109
|
+
noData: 'No data',
|
|
98
110
|
},
|
|
99
111
|
notification: {
|
|
100
112
|
preferences: {
|
|
@@ -120,6 +132,52 @@ export default flat({
|
|
|
120
132
|
metrics: 'Metrics',
|
|
121
133
|
attention: 'Attention',
|
|
122
134
|
overview: 'Overview',
|
|
135
|
+
overviewPage: {
|
|
136
|
+
financialIndicatorsTitle: 'Financial Indicators',
|
|
137
|
+
businessMonitoringTitle: 'Business Monitoring',
|
|
138
|
+
filters: {
|
|
139
|
+
dateRange: 'Select Date Range',
|
|
140
|
+
currencyLabel: 'Currencies',
|
|
141
|
+
productLabel: 'Products',
|
|
142
|
+
regionLabel: 'Regions',
|
|
143
|
+
allCurrencies: 'All Currencies',
|
|
144
|
+
allProducts: 'All Products',
|
|
145
|
+
allRegions: 'All Regions',
|
|
146
|
+
},
|
|
147
|
+
financialIndicators: {
|
|
148
|
+
totalIncome: {
|
|
149
|
+
title: 'Total Income',
|
|
150
|
+
subtitle: "User's actual payment",
|
|
151
|
+
},
|
|
152
|
+
costOfGoods: {
|
|
153
|
+
title: 'Cost of Goods',
|
|
154
|
+
subtitle: 'Supplier share',
|
|
155
|
+
},
|
|
156
|
+
netRevenue: {
|
|
157
|
+
title: 'Net Revenue',
|
|
158
|
+
subtitle: 'Revenue after vendor costs',
|
|
159
|
+
},
|
|
160
|
+
promotionCost: {
|
|
161
|
+
title: 'Promotion Cost',
|
|
162
|
+
subtitle: 'Discount',
|
|
163
|
+
},
|
|
164
|
+
taxedRevenue: {
|
|
165
|
+
title: 'Taxed Revenue',
|
|
166
|
+
subtitle: 'Revenue with tax',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
charts: {
|
|
170
|
+
title: 'Transaction Trends',
|
|
171
|
+
payments: 'Payments',
|
|
172
|
+
payouts: 'Payouts',
|
|
173
|
+
refunds: 'Refunds',
|
|
174
|
+
allCurrencies: 'All currencies',
|
|
175
|
+
},
|
|
176
|
+
metrics: {
|
|
177
|
+
transaction: 'Transaction Metrics',
|
|
178
|
+
essential: 'Essential Metrics',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
123
181
|
payments: 'Payments',
|
|
124
182
|
connections: 'Connections',
|
|
125
183
|
back: 'Back',
|
|
@@ -136,6 +194,69 @@ export default flat({
|
|
|
136
194
|
invoiceItems: 'Invoice Items',
|
|
137
195
|
pricing: 'Pricing',
|
|
138
196
|
coupons: 'Coupons',
|
|
197
|
+
tax: 'Tax',
|
|
198
|
+
taxRates: 'Tax Rates',
|
|
199
|
+
taxRate: {
|
|
200
|
+
create: 'Create Tax Rate',
|
|
201
|
+
createTitle: 'Create Tax Rate',
|
|
202
|
+
createAction: 'Add Tax Rate',
|
|
203
|
+
created: 'Tax rate created successfully',
|
|
204
|
+
updated: 'Tax rate updated successfully',
|
|
205
|
+
deleted: 'Tax rate deleted successfully',
|
|
206
|
+
label: 'Tax Rate',
|
|
207
|
+
view: 'View Tax Rate',
|
|
208
|
+
displayName: 'Display Name',
|
|
209
|
+
displayNamePlaceholder: 'Name shown on invoices and reports',
|
|
210
|
+
displayNameAuto: 'Auto-generated if left empty',
|
|
211
|
+
displayNameRequired: 'Display name is required',
|
|
212
|
+
description: 'Description',
|
|
213
|
+
descriptionPlaceholder: 'Optional description',
|
|
214
|
+
country: 'Country',
|
|
215
|
+
countryRequired: 'Country is required',
|
|
216
|
+
state: 'State/Province',
|
|
217
|
+
postalCode: 'Postal Code',
|
|
218
|
+
taxCode: 'Product Tax Code',
|
|
219
|
+
taxCodeDescription:
|
|
220
|
+
'Tax codes are used to calculate automatic taxes based on product type and location. You can ',
|
|
221
|
+
taxCodeDescriptionLink: 'manage tax rates',
|
|
222
|
+
taxCodeDescriptionSuffix: ' to create custom tax rates for specific tax codes and regions.',
|
|
223
|
+
selectTaxCode: 'Select product tax code',
|
|
224
|
+
percentage: 'Tax Rate (%)',
|
|
225
|
+
percentageRequired: 'Tax rate percentage is required',
|
|
226
|
+
percentageMin: 'Tax rate must be 0% or higher',
|
|
227
|
+
percentageMax: 'Tax rate must be less than 100%',
|
|
228
|
+
active: 'Active by default',
|
|
229
|
+
location: 'Region',
|
|
230
|
+
advanced: 'Advanced options',
|
|
231
|
+
search: 'Search tax rates',
|
|
232
|
+
searchCountry: 'Search country',
|
|
233
|
+
back: 'Back to tax rates',
|
|
234
|
+
associatedInvoices: 'Related Invoices',
|
|
235
|
+
deleteTitle: 'Delete Tax Rate',
|
|
236
|
+
deleteMessage: 'Are you sure you want to delete tax rate “{name}”? This action cannot be undone.',
|
|
237
|
+
deactivateTitle: 'Deactivate Tax Rate',
|
|
238
|
+
deactivateMessage: 'Deactivate “{name}”? It will no longer apply automatically to invoices.',
|
|
239
|
+
activateTitle: 'Activate Tax Rate',
|
|
240
|
+
activateMessage: 'Activate “{name}”? It will be available for future invoices.',
|
|
241
|
+
createTitleShort: 'Add tax rate',
|
|
242
|
+
edit: 'Edit',
|
|
243
|
+
editTitle: 'Edit Tax Rate',
|
|
244
|
+
selectTaxCodeHint: "We'll use this tax code to calculate automatic tax on invoices.",
|
|
245
|
+
searchPlaceholder: 'Search by product or tax code',
|
|
246
|
+
previewPlaceholder: 'Select a tax code to see details.',
|
|
247
|
+
usePreset: 'Use preset',
|
|
248
|
+
noPreset: 'No preset selected',
|
|
249
|
+
noSuggestions: 'No tax codes match your search.',
|
|
250
|
+
relatedInvoiceNum: 'Related Invoices',
|
|
251
|
+
notUsed: 'Not used',
|
|
252
|
+
taxCodeLabel: 'Tax code: {code}',
|
|
253
|
+
types: {
|
|
254
|
+
general: 'General',
|
|
255
|
+
digital: 'Digital products',
|
|
256
|
+
services: 'Services',
|
|
257
|
+
physical: 'Physical goods',
|
|
258
|
+
},
|
|
259
|
+
},
|
|
139
260
|
pricingTables: 'Pricing tables',
|
|
140
261
|
vendors: 'Vendors',
|
|
141
262
|
billing: 'Billing',
|
|
@@ -449,8 +570,12 @@ export default flat({
|
|
|
449
570
|
type: {
|
|
450
571
|
label: 'Product Type',
|
|
451
572
|
service: 'Service',
|
|
573
|
+
serviceDesc: 'Digital services or subscriptions',
|
|
452
574
|
credit: 'Credit',
|
|
575
|
+
creditDesc: 'Credit top-up product for credit-based billing scenarios',
|
|
576
|
+
creditDescLink: 'Create meters first',
|
|
453
577
|
good: 'Good',
|
|
578
|
+
goodDesc: 'Physical products or tangible goods',
|
|
454
579
|
},
|
|
455
580
|
vendorConfig: {
|
|
456
581
|
title: 'Vendor Configuration',
|
|
@@ -489,6 +614,7 @@ export default flat({
|
|
|
489
614
|
additional: 'Additional options',
|
|
490
615
|
model: 'Pricing model',
|
|
491
616
|
amount: 'Price',
|
|
617
|
+
amountDescription: 'This is the tax-inclusive price that customers will pay.',
|
|
492
618
|
locked: 'This price is locked because it is used by a subscription or a payment.',
|
|
493
619
|
amountTip: 'Choose recurring for subscriptions and one-time for everything else.',
|
|
494
620
|
duplicate: 'Duplicate price',
|
|
@@ -898,6 +1024,11 @@ export default flat({
|
|
|
898
1024
|
view: 'View payment detail',
|
|
899
1025
|
empty: 'No payment intent',
|
|
900
1026
|
refund: 'Refund payment',
|
|
1027
|
+
status: {
|
|
1028
|
+
active: 'Active',
|
|
1029
|
+
paid: 'Paid',
|
|
1030
|
+
succeeded: 'Succeeded',
|
|
1031
|
+
},
|
|
901
1032
|
received: 'Received',
|
|
902
1033
|
attention: 'Failed payments',
|
|
903
1034
|
refundError: 'Failed to refund payment',
|
|
@@ -928,6 +1059,11 @@ export default flat({
|
|
|
928
1059
|
view: 'View payout',
|
|
929
1060
|
empty: 'No payout',
|
|
930
1061
|
attention: 'Failed payouts',
|
|
1062
|
+
status: {
|
|
1063
|
+
active: 'Active',
|
|
1064
|
+
paid: 'Paid',
|
|
1065
|
+
succeeded: 'Succeeded',
|
|
1066
|
+
},
|
|
931
1067
|
},
|
|
932
1068
|
paymentMethod: {
|
|
933
1069
|
_name: 'Payment Method',
|
|
@@ -1074,7 +1210,13 @@ export default flat({
|
|
|
1074
1210
|
invoice: {
|
|
1075
1211
|
view: 'View invoice',
|
|
1076
1212
|
attention: 'Uncollectible invoices',
|
|
1213
|
+
metric: 'Paid invoices',
|
|
1077
1214
|
name: 'Invoice',
|
|
1215
|
+
status: {
|
|
1216
|
+
active: 'Active',
|
|
1217
|
+
paid: 'Paid',
|
|
1218
|
+
succeeded: 'Succeeded',
|
|
1219
|
+
},
|
|
1078
1220
|
from: 'Billed from',
|
|
1079
1221
|
empty: 'No invoices',
|
|
1080
1222
|
number: 'Invoice Number',
|
|
@@ -1181,6 +1323,11 @@ export default flat({
|
|
|
1181
1323
|
view: 'View subscription',
|
|
1182
1324
|
name: 'Subscription',
|
|
1183
1325
|
empty: 'No subscriptions',
|
|
1326
|
+
status: {
|
|
1327
|
+
active: 'Active',
|
|
1328
|
+
paid: 'Paid',
|
|
1329
|
+
succeeded: 'Succeeded',
|
|
1330
|
+
},
|
|
1184
1331
|
viewAll: 'View all subscriptions',
|
|
1185
1332
|
noActiveEmpty: 'You currently have no active subscriptions. You can choose to view your subscription history.',
|
|
1186
1333
|
includedServices: 'Included Services',
|
|
@@ -1389,6 +1536,11 @@ export default flat({
|
|
|
1389
1536
|
name: 'Refunds',
|
|
1390
1537
|
view: 'View refund detail',
|
|
1391
1538
|
attention: 'Failed refunds',
|
|
1539
|
+
status: {
|
|
1540
|
+
active: 'Active',
|
|
1541
|
+
paid: 'Paid',
|
|
1542
|
+
succeeded: 'Succeeded',
|
|
1543
|
+
},
|
|
1392
1544
|
},
|
|
1393
1545
|
usageRecord: {
|
|
1394
1546
|
empty: 'No usage records',
|
package/src/locales/zh.tsx
CHANGED
|
@@ -5,6 +5,7 @@ export default flat({
|
|
|
5
5
|
redirecting: '跳转中...',
|
|
6
6
|
title: '名称',
|
|
7
7
|
estimated: '预估',
|
|
8
|
+
total: '总量',
|
|
8
9
|
active: '生效中',
|
|
9
10
|
metadata: {
|
|
10
11
|
label: '元数据',
|
|
@@ -39,18 +40,28 @@ export default flat({
|
|
|
39
40
|
quickStart: '快速入门指南',
|
|
40
41
|
advancedFeatures: '高级功能',
|
|
41
42
|
quickStarts: '快速入门',
|
|
43
|
+
homeTagline: '为 Blocklet 构建的去中心化支付解决方案',
|
|
44
|
+
adminDashboard: '管理后台',
|
|
45
|
+
customerPortal: '客户门户',
|
|
42
46
|
copy: '复制',
|
|
43
47
|
copied: '已复制',
|
|
44
48
|
copySuccess: '复制成功',
|
|
45
49
|
copyFailed: '复制失败',
|
|
46
50
|
copyTip: '请手动复制',
|
|
47
51
|
save: '保存',
|
|
52
|
+
saving: '保存中...',
|
|
48
53
|
cancel: '取消',
|
|
54
|
+
back: '返回',
|
|
49
55
|
know: '知道了',
|
|
50
56
|
confirm: '确认',
|
|
51
57
|
edit: '编辑',
|
|
58
|
+
view: '查看',
|
|
59
|
+
select: '选择',
|
|
60
|
+
clear: '清除',
|
|
52
61
|
delete: '删除',
|
|
53
62
|
deleting: '删除中...',
|
|
63
|
+
activate: '启用',
|
|
64
|
+
deactivate: '停用',
|
|
54
65
|
yes: '是',
|
|
55
66
|
no: '否',
|
|
56
67
|
never: '永不',
|
|
@@ -94,6 +105,7 @@ export default flat({
|
|
|
94
105
|
viewInvoice: '查看账单',
|
|
95
106
|
viewSourceData: '查看来源',
|
|
96
107
|
goToConfigure: '前往配置',
|
|
108
|
+
noData: '暂无数据',
|
|
97
109
|
},
|
|
98
110
|
notification: {
|
|
99
111
|
preferences: {
|
|
@@ -119,6 +131,52 @@ export default flat({
|
|
|
119
131
|
metrics: '指标',
|
|
120
132
|
attention: '注意',
|
|
121
133
|
overview: '总览',
|
|
134
|
+
overviewPage: {
|
|
135
|
+
financialIndicatorsTitle: '财务指标',
|
|
136
|
+
businessMonitoringTitle: '业务监控',
|
|
137
|
+
filters: {
|
|
138
|
+
dateRange: '选择日期范围',
|
|
139
|
+
currencyLabel: '币种',
|
|
140
|
+
productLabel: '产品',
|
|
141
|
+
regionLabel: '地区',
|
|
142
|
+
allCurrencies: '全部币种',
|
|
143
|
+
allProducts: '全部产品',
|
|
144
|
+
allRegions: '全部地区',
|
|
145
|
+
},
|
|
146
|
+
financialIndicators: {
|
|
147
|
+
totalIncome: {
|
|
148
|
+
title: '总收入',
|
|
149
|
+
subtitle: '用户实际支付',
|
|
150
|
+
},
|
|
151
|
+
costOfGoods: {
|
|
152
|
+
title: '进货成本',
|
|
153
|
+
subtitle: '供应商分成',
|
|
154
|
+
},
|
|
155
|
+
netRevenue: {
|
|
156
|
+
title: '净收入',
|
|
157
|
+
subtitle: '扣除供货成本后的收入',
|
|
158
|
+
},
|
|
159
|
+
promotionCost: {
|
|
160
|
+
title: '促销成本',
|
|
161
|
+
subtitle: '折扣',
|
|
162
|
+
},
|
|
163
|
+
taxedRevenue: {
|
|
164
|
+
title: '含税收入',
|
|
165
|
+
subtitle: '包含税费的收入',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
charts: {
|
|
169
|
+
title: '交易趋势',
|
|
170
|
+
payments: '付款',
|
|
171
|
+
payouts: '出款',
|
|
172
|
+
refunds: '退款',
|
|
173
|
+
allCurrencies: '全部币种',
|
|
174
|
+
},
|
|
175
|
+
metrics: {
|
|
176
|
+
transaction: '交易指标',
|
|
177
|
+
essential: '关键指标',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
122
180
|
payments: '支付管理',
|
|
123
181
|
connections: '连接',
|
|
124
182
|
back: '返回',
|
|
@@ -134,6 +192,67 @@ export default flat({
|
|
|
134
192
|
products: '产品定价',
|
|
135
193
|
invoiceItems: '账单明细',
|
|
136
194
|
coupons: '优惠券',
|
|
195
|
+
tax: '税务',
|
|
196
|
+
taxRates: '税率',
|
|
197
|
+
taxRate: {
|
|
198
|
+
create: '创建税率',
|
|
199
|
+
createTitle: '新建税率',
|
|
200
|
+
createAction: '添加税率',
|
|
201
|
+
created: '税率创建成功',
|
|
202
|
+
updated: '税率更新成功',
|
|
203
|
+
deleted: '税率删除成功',
|
|
204
|
+
label: '税率',
|
|
205
|
+
view: '查看税率',
|
|
206
|
+
displayName: '显示名称',
|
|
207
|
+
displayNamePlaceholder: '显示在账单和报表上的名称',
|
|
208
|
+
displayNameAuto: '留空则自动生成',
|
|
209
|
+
displayNameRequired: '请填写显示名称',
|
|
210
|
+
description: '描述',
|
|
211
|
+
descriptionPlaceholder: '可选描述信息',
|
|
212
|
+
country: '国家/地区',
|
|
213
|
+
countryRequired: '请选择国家/地区',
|
|
214
|
+
state: '州 / 省',
|
|
215
|
+
postalCode: '邮政编码',
|
|
216
|
+
taxCode: '产品税码',
|
|
217
|
+
taxCodeDescription: '产品税码用于根据产品类型和地区自动计算税费。您可以',
|
|
218
|
+
taxCodeDescriptionLink: '管理税率',
|
|
219
|
+
taxCodeDescriptionSuffix: '以创建针对特定税码和地区的自定义税率。',
|
|
220
|
+
selectTaxCode: '选择产品税码',
|
|
221
|
+
percentage: '税率 (%)',
|
|
222
|
+
percentageRequired: '请填写税率',
|
|
223
|
+
percentageMin: '税率需大于或等于 0%',
|
|
224
|
+
percentageMax: '税率需小于 100%',
|
|
225
|
+
active: '默认启用',
|
|
226
|
+
location: '适用区域',
|
|
227
|
+
advanced: '高级选项',
|
|
228
|
+
search: '搜索税率',
|
|
229
|
+
searchCountry: '搜索国家/地区',
|
|
230
|
+
back: '返回税率列表',
|
|
231
|
+
associatedInvoices: '关联账单',
|
|
232
|
+
deleteTitle: '删除税率',
|
|
233
|
+
deleteMessage: '确定要删除税率“{name}”吗?该操作无法撤销。',
|
|
234
|
+
deactivateTitle: '停用税率',
|
|
235
|
+
deactivateMessage: '确定要停用“{name}”吗?停用后将不再自动应用。',
|
|
236
|
+
activateTitle: '启用税率',
|
|
237
|
+
activateMessage: '确定要启用"{name}"吗?启用后可用于新的账单。',
|
|
238
|
+
edit: '编辑',
|
|
239
|
+
editTitle: '编辑税率',
|
|
240
|
+
selectTaxCodeHint: '税率将用于自动计算账单中的税费。',
|
|
241
|
+
searchPlaceholder: '按产品或税码搜索',
|
|
242
|
+
previewPlaceholder: '请选择税码以查看详情。',
|
|
243
|
+
usePreset: '默认税码',
|
|
244
|
+
noPreset: '暂无默认税码',
|
|
245
|
+
noSuggestions: '没有符合搜索条件的税码。',
|
|
246
|
+
relatedInvoiceNum: '关联账单数',
|
|
247
|
+
notUsed: '未使用',
|
|
248
|
+
taxCodeLabel: '税码:{code}',
|
|
249
|
+
types: {
|
|
250
|
+
general: '通用类别',
|
|
251
|
+
digital: '数字产品',
|
|
252
|
+
services: '服务类',
|
|
253
|
+
physical: '实物商品',
|
|
254
|
+
},
|
|
255
|
+
},
|
|
137
256
|
pricing: '定价',
|
|
138
257
|
pricingTables: '定价表',
|
|
139
258
|
vendors: '供应商',
|
|
@@ -422,8 +541,12 @@ export default flat({
|
|
|
422
541
|
type: {
|
|
423
542
|
label: '产品类型',
|
|
424
543
|
service: '服务',
|
|
544
|
+
serviceDesc: '数字服务或订阅',
|
|
425
545
|
credit: 'Credit',
|
|
546
|
+
creditDesc: '用于基于 Credit 计费场景的充值产品',
|
|
547
|
+
creditDescLink: '请先创建计量器',
|
|
426
548
|
good: '商品',
|
|
549
|
+
goodDesc: '实体商品或有形产品',
|
|
427
550
|
},
|
|
428
551
|
vendorConfig: {
|
|
429
552
|
title: '供应商配置',
|
|
@@ -460,6 +583,7 @@ export default flat({
|
|
|
460
583
|
additional: '附加选项',
|
|
461
584
|
model: '定价模型',
|
|
462
585
|
amount: '价格',
|
|
586
|
+
amountDescription: '这是客户将支付的含税价格。',
|
|
463
587
|
locked: '此价格已锁定,因为它用于订阅或支付。',
|
|
464
588
|
amountTip: '对于订阅选择周期,对于其他所有选择一次性。',
|
|
465
589
|
duplicate: '复制价格',
|
|
@@ -836,6 +960,11 @@ export default flat({
|
|
|
836
960
|
view: '查看对外支付',
|
|
837
961
|
empty: '没有记录',
|
|
838
962
|
attention: '失败的对外支付',
|
|
963
|
+
status: {
|
|
964
|
+
active: '生效中',
|
|
965
|
+
paid: '已支付',
|
|
966
|
+
succeeded: '成功',
|
|
967
|
+
},
|
|
839
968
|
},
|
|
840
969
|
pricingTable: {
|
|
841
970
|
view: '查看定价表',
|
|
@@ -864,6 +993,11 @@ export default flat({
|
|
|
864
993
|
view: '查看付款详情',
|
|
865
994
|
empty: '没有付款记录',
|
|
866
995
|
refund: '退款',
|
|
996
|
+
status: {
|
|
997
|
+
active: '生效中',
|
|
998
|
+
paid: '已支付',
|
|
999
|
+
succeeded: '成功',
|
|
1000
|
+
},
|
|
867
1001
|
received: '实收金额',
|
|
868
1002
|
attention: '失败的付款',
|
|
869
1003
|
refundError: '退款申请失败',
|
|
@@ -1048,6 +1182,11 @@ export default flat({
|
|
|
1048
1182
|
name: '账单',
|
|
1049
1183
|
from: '账单来自',
|
|
1050
1184
|
empty: '没有账单',
|
|
1185
|
+
status: {
|
|
1186
|
+
active: '生效中',
|
|
1187
|
+
paid: '已支付',
|
|
1188
|
+
succeeded: '成功',
|
|
1189
|
+
},
|
|
1051
1190
|
number: '账单编号',
|
|
1052
1191
|
description: '账单说明',
|
|
1053
1192
|
dueDate: '截止日期',
|
|
@@ -1153,6 +1292,11 @@ export default flat({
|
|
|
1153
1292
|
view: '查看订阅',
|
|
1154
1293
|
name: '订阅',
|
|
1155
1294
|
empty: '没有订阅',
|
|
1295
|
+
status: {
|
|
1296
|
+
active: '生效中',
|
|
1297
|
+
paid: '已支付',
|
|
1298
|
+
succeeded: '成功',
|
|
1299
|
+
},
|
|
1156
1300
|
viewAll: '查看历史订阅',
|
|
1157
1301
|
noActiveEmpty: '您当前没有服务中的订阅,您可以选择查看历史订阅',
|
|
1158
1302
|
includedServices: '包含的服务',
|
|
@@ -1351,6 +1495,11 @@ export default flat({
|
|
|
1351
1495
|
name: '退款',
|
|
1352
1496
|
attention: '失败的退款',
|
|
1353
1497
|
view: '查看退款详情',
|
|
1498
|
+
status: {
|
|
1499
|
+
active: '生效中',
|
|
1500
|
+
paid: '已支付',
|
|
1501
|
+
succeeded: '成功',
|
|
1502
|
+
},
|
|
1354
1503
|
},
|
|
1355
1504
|
usageRecord: {
|
|
1356
1505
|
empty: '用量记录为空',
|
|
@@ -389,7 +389,7 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
389
389
|
<Box className="section">
|
|
390
390
|
<SectionHeader title={t('admin.summary')} />
|
|
391
391
|
<Box className="section-body">
|
|
392
|
-
<InvoiceTable invoice={data} emptyNodeText={t('empty.summary')} />
|
|
392
|
+
<InvoiceTable invoice={data} emptyNodeText={t('empty.summary')} mode="admin" />
|
|
393
393
|
</Box>
|
|
394
394
|
</Box>
|
|
395
395
|
<Divider />
|
|
@@ -14,6 +14,7 @@ const groups = {
|
|
|
14
14
|
customers: React.lazy(() => import('./customers/index')),
|
|
15
15
|
products: React.lazy(() => import('./products/index')),
|
|
16
16
|
billing: React.lazy(() => import('./billing/index')),
|
|
17
|
+
tax: React.lazy(() => import('./tax')),
|
|
17
18
|
developers: React.lazy(() => import('./developers/index')),
|
|
18
19
|
settings: React.lazy(() => import('./settings/index')),
|
|
19
20
|
};
|
|
@@ -64,6 +65,7 @@ function Admin() {
|
|
|
64
65
|
{ label: t('admin.payments'), value: 'payments' },
|
|
65
66
|
{ label: t('admin.customers'), value: 'customers' },
|
|
66
67
|
{ label: t('admin.products'), value: 'products' },
|
|
68
|
+
{ label: t('admin.tax'), value: 'tax' },
|
|
67
69
|
{ label: t('admin.billing'), value: 'billing' },
|
|
68
70
|
{ label: t('admin.settings'), value: 'settings' },
|
|
69
71
|
];
|