payment-kit 1.19.0 → 1.19.2
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/index.ts +8 -0
- package/api/src/index.ts +4 -0
- package/api/src/libs/credit-grant.ts +146 -0
- package/api/src/libs/env.ts +1 -0
- package/api/src/libs/invoice.ts +4 -3
- package/api/src/libs/notification/template/base.ts +388 -2
- package/api/src/libs/notification/template/customer-credit-grant-granted.ts +149 -0
- package/api/src/libs/notification/template/customer-credit-grant-low-balance.ts +151 -0
- package/api/src/libs/notification/template/customer-credit-insufficient.ts +254 -0
- package/api/src/libs/notification/template/subscription-canceled.ts +193 -202
- package/api/src/libs/notification/template/subscription-refund-succeeded.ts +215 -237
- package/api/src/libs/notification/template/subscription-renewed.ts +130 -200
- package/api/src/libs/notification/template/subscription-succeeded.ts +100 -202
- package/api/src/libs/notification/template/subscription-trial-start.ts +142 -188
- package/api/src/libs/notification/template/subscription-trial-will-end.ts +146 -174
- package/api/src/libs/notification/template/subscription-upgraded.ts +96 -192
- package/api/src/libs/notification/template/subscription-will-canceled.ts +94 -135
- package/api/src/libs/notification/template/subscription-will-renew.ts +220 -245
- package/api/src/libs/payment.ts +69 -0
- package/api/src/libs/queue/index.ts +3 -2
- package/api/src/libs/session.ts +8 -0
- package/api/src/libs/subscription.ts +74 -3
- package/api/src/libs/util.ts +3 -1
- package/api/src/libs/ws.ts +23 -1
- package/api/src/locales/en.ts +33 -0
- package/api/src/locales/zh.ts +31 -0
- package/api/src/queues/credit-consume.ts +728 -0
- package/api/src/queues/credit-grant.ts +572 -0
- package/api/src/queues/notification.ts +173 -128
- package/api/src/queues/payment.ts +210 -122
- package/api/src/queues/subscription.ts +179 -0
- package/api/src/routes/checkout-sessions.ts +157 -9
- package/api/src/routes/connect/shared.ts +3 -2
- package/api/src/routes/credit-grants.ts +241 -0
- package/api/src/routes/credit-transactions.ts +208 -0
- package/api/src/routes/customers.ts +34 -5
- package/api/src/routes/index.ts +8 -0
- package/api/src/routes/meter-events.ts +347 -0
- package/api/src/routes/meters.ts +219 -0
- package/api/src/routes/payment-currencies.ts +20 -2
- package/api/src/routes/payment-links.ts +1 -1
- package/api/src/routes/payment-methods.ts +14 -2
- package/api/src/routes/prices.ts +43 -0
- package/api/src/routes/pricing-table.ts +13 -7
- package/api/src/routes/products.ts +63 -4
- package/api/src/routes/settings.ts +1 -1
- package/api/src/routes/subscriptions.ts +4 -0
- package/api/src/routes/webhook-endpoints.ts +0 -3
- package/api/src/store/migrations/20250610-billing-credit.ts +43 -0
- package/api/src/store/models/credit-grant.ts +486 -0
- package/api/src/store/models/credit-transaction.ts +268 -0
- package/api/src/store/models/customer.ts +8 -0
- package/api/src/store/models/index.ts +52 -1
- package/api/src/store/models/meter-event.ts +423 -0
- package/api/src/store/models/meter.ts +176 -0
- package/api/src/store/models/payment-currency.ts +66 -14
- package/api/src/store/models/price.ts +6 -0
- package/api/src/store/models/product.ts +2 -2
- package/api/src/store/models/subscription.ts +24 -0
- package/api/src/store/models/types.ts +28 -2
- package/api/tests/libs/subscription.spec.ts +53 -0
- package/blocklet.yml +9 -1
- package/package.json +4 -4
- package/scripts/sdk.js +233 -1
- package/src/app.tsx +10 -0
- package/src/components/collapse.tsx +11 -1
- package/src/components/conditional-section.tsx +87 -0
- package/src/components/customer/credit-grant-item-list.tsx +99 -0
- package/src/components/customer/credit-overview.tsx +246 -0
- package/src/components/customer/form.tsx +7 -3
- package/src/components/invoice/list.tsx +19 -1
- package/src/components/metadata/form.tsx +287 -91
- package/src/components/meter/actions.tsx +101 -0
- package/src/components/meter/add-usage-dialog.tsx +239 -0
- package/src/components/meter/events-list.tsx +657 -0
- package/src/components/meter/form.tsx +245 -0
- package/src/components/meter/products.tsx +264 -0
- package/src/components/meter/usage-guide.tsx +174 -0
- package/src/components/payment-currency/form.tsx +2 -0
- package/src/components/payment-intent/list.tsx +19 -1
- package/src/components/payment-link/item.tsx +2 -2
- package/src/components/payment-link/preview.tsx +1 -1
- package/src/components/payment-link/product-select.tsx +52 -12
- package/src/components/payment-method/arcblock.tsx +2 -0
- package/src/components/payment-method/base.tsx +2 -0
- package/src/components/payment-method/bitcoin.tsx +2 -0
- package/src/components/payment-method/ethereum.tsx +2 -0
- package/src/components/payment-method/stripe.tsx +2 -0
- package/src/components/payouts/list.tsx +19 -1
- package/src/components/payouts/portal/list.tsx +6 -11
- package/src/components/price/currency-select.tsx +56 -32
- package/src/components/price/form.tsx +912 -407
- package/src/components/pricing-table/preview.tsx +1 -1
- package/src/components/product/add-price.tsx +9 -7
- package/src/components/product/create.tsx +7 -4
- package/src/components/product/edit-price.tsx +21 -12
- package/src/components/product/features.tsx +17 -7
- package/src/components/product/form.tsx +100 -90
- package/src/components/refund/list.tsx +19 -1
- package/src/components/section/header.tsx +5 -18
- package/src/components/subscription/items/index.tsx +1 -1
- package/src/components/subscription/metrics.tsx +37 -5
- package/src/components/subscription/portal/actions.tsx +2 -1
- package/src/contexts/products.tsx +26 -9
- package/src/hooks/subscription.ts +34 -0
- package/src/libs/meter-utils.ts +196 -0
- package/src/libs/util.ts +4 -0
- package/src/locales/en.tsx +389 -5
- package/src/locales/zh.tsx +368 -1
- package/src/pages/admin/billing/index.tsx +61 -33
- package/src/pages/admin/billing/invoices/detail.tsx +1 -1
- package/src/pages/admin/billing/meters/create.tsx +60 -0
- package/src/pages/admin/billing/meters/detail.tsx +435 -0
- package/src/pages/admin/billing/meters/index.tsx +210 -0
- package/src/pages/admin/billing/meters/meter-event.tsx +346 -0
- package/src/pages/admin/billing/subscriptions/detail.tsx +47 -14
- package/src/pages/admin/customers/customers/credit-grant/detail.tsx +391 -0
- package/src/pages/admin/customers/customers/detail.tsx +14 -10
- package/src/pages/admin/customers/index.tsx +5 -0
- package/src/pages/admin/developers/events/detail.tsx +1 -1
- package/src/pages/admin/developers/index.tsx +1 -1
- package/src/pages/admin/payments/intents/detail.tsx +1 -1
- package/src/pages/admin/payments/payouts/detail.tsx +1 -1
- package/src/pages/admin/payments/refunds/detail.tsx +1 -1
- package/src/pages/admin/products/index.tsx +3 -2
- package/src/pages/admin/products/links/detail.tsx +1 -1
- package/src/pages/admin/products/prices/actions.tsx +16 -4
- package/src/pages/admin/products/prices/detail.tsx +30 -3
- package/src/pages/admin/products/prices/list.tsx +8 -1
- package/src/pages/admin/products/pricing-tables/detail.tsx +1 -1
- package/src/pages/admin/products/products/create.tsx +233 -57
- package/src/pages/admin/products/products/detail.tsx +2 -1
- package/src/pages/admin/settings/payment-methods/index.tsx +3 -0
- package/src/pages/customer/credit-grant/detail.tsx +308 -0
- package/src/pages/customer/index.tsx +44 -9
- package/src/pages/customer/recharge/account.tsx +5 -5
- package/src/pages/customer/subscription/change-payment.tsx +4 -2
- package/src/pages/customer/subscription/detail.tsx +48 -14
- package/src/pages/customer/subscription/embed.tsx +1 -1
package/src/locales/zh.tsx
CHANGED
|
@@ -7,10 +7,16 @@ export default flat({
|
|
|
7
7
|
estimated: '预估',
|
|
8
8
|
metadata: {
|
|
9
9
|
label: '元数据',
|
|
10
|
+
description: '添加自定义键值对以存储有关此计量器的其他信息。',
|
|
10
11
|
add: '添加更多元数据',
|
|
11
12
|
edit: '编辑元数据',
|
|
12
13
|
empty: '无元数据',
|
|
13
14
|
emptyTip: '您还没有添加任何元数据,您可以添加它',
|
|
15
|
+
formMode: '切换到表单模式',
|
|
16
|
+
jsonMode: '切换到JSON模式',
|
|
17
|
+
jsonPlaceholder: '输入JSON数据...',
|
|
18
|
+
invalidJson: 'JSON格式无效,请检查您的输入',
|
|
19
|
+
formatJson: '格式化JSON',
|
|
14
20
|
},
|
|
15
21
|
price: '价格',
|
|
16
22
|
add: '添加',
|
|
@@ -50,6 +56,19 @@ export default flat({
|
|
|
50
56
|
saturday: '星期六',
|
|
51
57
|
},
|
|
52
58
|
maxAmount: '最大金额为 {max}',
|
|
59
|
+
name: '名称',
|
|
60
|
+
status: '状态',
|
|
61
|
+
remainingCredit: '剩余额度',
|
|
62
|
+
scope: '适用范围',
|
|
63
|
+
effectiveDate: '生效时间',
|
|
64
|
+
expirationDate: '过期时间',
|
|
65
|
+
creditGrant: '信用额度',
|
|
66
|
+
subscription: '订阅',
|
|
67
|
+
meterEvent: '计量事件',
|
|
68
|
+
creditAmount: '额度',
|
|
69
|
+
createdAt: '创建时间',
|
|
70
|
+
general: '通用',
|
|
71
|
+
specific: '指定使用范围',
|
|
53
72
|
},
|
|
54
73
|
notification: {
|
|
55
74
|
preferences: {
|
|
@@ -87,6 +106,203 @@ export default flat({
|
|
|
87
106
|
billing: '订阅和账单',
|
|
88
107
|
invoices: '账单',
|
|
89
108
|
subscriptions: '订阅',
|
|
109
|
+
meters: '计量器',
|
|
110
|
+
meterEvents: {
|
|
111
|
+
title: '计量事件',
|
|
112
|
+
},
|
|
113
|
+
meter: {
|
|
114
|
+
add: '添加计量器',
|
|
115
|
+
edit: '编辑计量器',
|
|
116
|
+
save: '保存计量器',
|
|
117
|
+
saved: '计量器保存成功',
|
|
118
|
+
activate: '激活计量器',
|
|
119
|
+
activated: '计量器激活成功',
|
|
120
|
+
deactivate: '停用计量器',
|
|
121
|
+
deactivated: '计量器停用成功',
|
|
122
|
+
deleted: '计量器删除成功',
|
|
123
|
+
deleteConfirm: '确定要删除此计量器吗?此操作无法撤销。',
|
|
124
|
+
activateConfirm: '确定要激活此计量器吗?它将开始收集使用数据。',
|
|
125
|
+
deactivateConfirm:
|
|
126
|
+
'停用后,此计量器将无法接收更多事件。尝试为此计量器创建事件将返回错误。之前报告的使用数据将保留。您可以随时重新激活。',
|
|
127
|
+
view: '查看计量器',
|
|
128
|
+
basicInfo: '基本信息',
|
|
129
|
+
basicInfoDescription: '配置计量器的核心设置以跟踪使用事件。',
|
|
130
|
+
editDescription: '更新计量器名称、描述和元数据。事件名称和聚合方法等核心设置无法更改。',
|
|
131
|
+
inactive: '计量器未激活',
|
|
132
|
+
inactiveTip: '此计量器未收集使用数据。激活它以开始跟踪事件。',
|
|
133
|
+
name: {
|
|
134
|
+
label: '计量器名称',
|
|
135
|
+
required: '计量器名称为必填项',
|
|
136
|
+
placeholder: 'API 请求',
|
|
137
|
+
help: '此计量器的描述性名称,将在您的仪表板中显示。',
|
|
138
|
+
},
|
|
139
|
+
eventName: {
|
|
140
|
+
label: '事件名称',
|
|
141
|
+
required: '事件名称为必填项',
|
|
142
|
+
placeholder: 'api_request',
|
|
143
|
+
help: '将发送到此计量器的事件名称',
|
|
144
|
+
editHelp: '为保持数据一致性,计量器创建后无法更改事件名称。',
|
|
145
|
+
},
|
|
146
|
+
aggregationMethod: {
|
|
147
|
+
label: '聚合方法',
|
|
148
|
+
required: '聚合方法为必填项',
|
|
149
|
+
sum: '求和',
|
|
150
|
+
sumHint: '将所有事件值相加',
|
|
151
|
+
sumDescription: '求和聚合方法将所有使用事件值相加,并报告事件摘要和计费的总计。',
|
|
152
|
+
count: '计数',
|
|
153
|
+
countHint: '计算事件数量',
|
|
154
|
+
countDescription: '计数聚合方法计算接收到的事件数量,并报告事件摘要和计费的总计数。',
|
|
155
|
+
last: '最后值',
|
|
156
|
+
lastHint: '使用最近的事件值',
|
|
157
|
+
lastDescription: '最后值聚合方法使用接收到的最近事件值,并报告该值用于事件摘要和计费。',
|
|
158
|
+
editHelp: '为保持数据一致性,计量器创建后无法更改聚合方法。',
|
|
159
|
+
},
|
|
160
|
+
unit: {
|
|
161
|
+
label: '计量单位',
|
|
162
|
+
required: '计量单位为必填项',
|
|
163
|
+
placeholder: '请求',
|
|
164
|
+
help: '此计量器的测量单位',
|
|
165
|
+
editHelp: '为保持数据一致性,计量器创建后无法更改计量单位。',
|
|
166
|
+
},
|
|
167
|
+
description: {
|
|
168
|
+
label: '描述',
|
|
169
|
+
placeholder: '跟踪 API 使用情况以进行计费',
|
|
170
|
+
help: '可选描述,帮助您和您的团队了解此计量器跟踪的内容。',
|
|
171
|
+
},
|
|
172
|
+
events: {
|
|
173
|
+
title: '事件',
|
|
174
|
+
dailyEventCount: '每日事件数量',
|
|
175
|
+
dailyTotalValue: '每日总使用量',
|
|
176
|
+
eventName: '事件名称',
|
|
177
|
+
value: '使用量',
|
|
178
|
+
customer: '客户',
|
|
179
|
+
subscription: '订阅',
|
|
180
|
+
reportTime: '上报时间',
|
|
181
|
+
count: '共 {count} 个事件',
|
|
182
|
+
empty: '暂无事件数据',
|
|
183
|
+
emptyTip: '当有事件上报时,数据将显示在这里',
|
|
184
|
+
filterByCustomer: '按客户筛选',
|
|
185
|
+
eventCount: '事件数量',
|
|
186
|
+
totalValue: '总使用量',
|
|
187
|
+
hourly: '按小时',
|
|
188
|
+
totalEvents: '总事件数',
|
|
189
|
+
timeRange: '时间粒度',
|
|
190
|
+
hourlyView: '小时视图',
|
|
191
|
+
dailyView: '日视图',
|
|
192
|
+
},
|
|
193
|
+
usageGuide: {
|
|
194
|
+
title: '如何报告使用情况',
|
|
195
|
+
description: '使用事件名称 "{eventName}" 向此计量器发送事件。计量器将{method}值并以{unit}为单位跟踪使用情况。',
|
|
196
|
+
tip: '使用事件名称 "{eventName}" 向此计量器发送事件。计量器将{aggregationMethodHint},并以{unit}为单位跟踪使用情况。',
|
|
197
|
+
apiEndpoint: 'API 端点',
|
|
198
|
+
curlExample: 'cURL 示例',
|
|
199
|
+
jsExample: 'JavaScript 示例',
|
|
200
|
+
pythonExample: 'Python 示例',
|
|
201
|
+
important: '重要提示',
|
|
202
|
+
tip1: '将 YOUR_API_KEY 替换为您的实际 API 密钥',
|
|
203
|
+
tip2: '事件名称必须完全匹配:{eventName}',
|
|
204
|
+
tip3: '包含时间戳以进行准确跟踪',
|
|
205
|
+
moreInfo: '更多信息,请参阅我们的',
|
|
206
|
+
apiDocs: 'API 文档',
|
|
207
|
+
},
|
|
208
|
+
products: {
|
|
209
|
+
count: '{count} 个关联产品',
|
|
210
|
+
create: '创建产品',
|
|
211
|
+
created: '产品创建成功',
|
|
212
|
+
createPrompt: '输入产品名称:',
|
|
213
|
+
manage: '管理',
|
|
214
|
+
empty: '无产品',
|
|
215
|
+
title: '产品',
|
|
216
|
+
emptyTip: '此计量器尚未关联任何产品。',
|
|
217
|
+
meterService: '计量服务',
|
|
218
|
+
creditCharge: 'Credit 计费',
|
|
219
|
+
},
|
|
220
|
+
creditProducts: {
|
|
221
|
+
emptyTip: '此计量器尚未关联任何 Credit 产品。',
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
creditProduct: {
|
|
225
|
+
create: '创建 Credit 产品',
|
|
226
|
+
defaultName: '{name} 额度充值包',
|
|
227
|
+
defaultDescription: '{name} 额度充值包',
|
|
228
|
+
defaultNickname: 'Credit 充值',
|
|
229
|
+
unitLabel: '单位',
|
|
230
|
+
settings: 'Credit 设置',
|
|
231
|
+
name: {
|
|
232
|
+
placeholder: '输入 Credit 产品名称',
|
|
233
|
+
},
|
|
234
|
+
description: {
|
|
235
|
+
placeholder: '描述此 Credit 产品的用途和价值',
|
|
236
|
+
},
|
|
237
|
+
priceNotice: 'Credit 产品用于为用户提供可消费的额度,支持一次性购买和套餐包两种模式。',
|
|
238
|
+
creditAmount: {
|
|
239
|
+
label: 'Credit 数量',
|
|
240
|
+
placeholder: '用户购买此价格获得的 Credit 数量',
|
|
241
|
+
help: '留空表示按单价售卖,填入数字表示固定套餐包',
|
|
242
|
+
description: '用户购买数量决定获得的 Credit',
|
|
243
|
+
},
|
|
244
|
+
validDuration: {
|
|
245
|
+
label: '可用时长',
|
|
246
|
+
help: 'Credit 的有效期限,从购买时开始计算',
|
|
247
|
+
description: '设置为 0 表示永不过期',
|
|
248
|
+
hours: '小时',
|
|
249
|
+
days: '天',
|
|
250
|
+
weeks: '周',
|
|
251
|
+
months: '月',
|
|
252
|
+
years: '年',
|
|
253
|
+
},
|
|
254
|
+
associatedPrices: {
|
|
255
|
+
label: '关联价格',
|
|
256
|
+
placeholder: '选择此 Credit 可用于的服务价格',
|
|
257
|
+
help: '选择后,购买的 Credit 只能用于指定的服务',
|
|
258
|
+
description: '不选择任何价格表示 Credit 可用于所有服务',
|
|
259
|
+
},
|
|
260
|
+
priority: {
|
|
261
|
+
label: '使用优先级',
|
|
262
|
+
help: '当用户有多个 Credit 时的使用顺序,数字越小优先级越高',
|
|
263
|
+
description: '范围:0-100,0 为最高优先级,50 为默认值',
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
meterEvent: {
|
|
267
|
+
title: '计量事件详情',
|
|
268
|
+
totalEvents: '总事件数:{count}',
|
|
269
|
+
noEvents: '暂无事件',
|
|
270
|
+
noEventsHint: '您可以在测试模式下手动添加测试事件。',
|
|
271
|
+
identifier: '标识符',
|
|
272
|
+
customer: '客户',
|
|
273
|
+
customerId: '客户ID',
|
|
274
|
+
value: '数值',
|
|
275
|
+
subscription: '订阅',
|
|
276
|
+
creditConsumed: '消耗额度',
|
|
277
|
+
usageValue: '使用量',
|
|
278
|
+
reportedAt: '上报时间',
|
|
279
|
+
processedAt: '处理时间',
|
|
280
|
+
eventIdentifier: '事件标识符',
|
|
281
|
+
usageDetails: '使用详情',
|
|
282
|
+
chart: {
|
|
283
|
+
eventCount: '每日事件数',
|
|
284
|
+
totalValue: '每日用量总数',
|
|
285
|
+
},
|
|
286
|
+
filter: {
|
|
287
|
+
customer: '筛选客户',
|
|
288
|
+
},
|
|
289
|
+
add: {
|
|
290
|
+
button: '添加用量',
|
|
291
|
+
title: '添加用量',
|
|
292
|
+
customerId: '客户',
|
|
293
|
+
customerIdPlaceholder: '选择客户',
|
|
294
|
+
value: '数值',
|
|
295
|
+
valuePlaceholder: '输入用量数值',
|
|
296
|
+
subscriptionId: '订阅',
|
|
297
|
+
subscriptionIdPlaceholder: '输入订阅ID(可选)',
|
|
298
|
+
subscriptionIdHint: '可选 - 将此用量关联到特定订阅',
|
|
299
|
+
timestamp: '时间',
|
|
300
|
+
timestampHint: '此用量发生的时间',
|
|
301
|
+
validation: '客户和数值为必填项',
|
|
302
|
+
success: '用量事件添加成功',
|
|
303
|
+
submit: '提交',
|
|
304
|
+
},
|
|
305
|
+
},
|
|
90
306
|
developers: '开发者工具箱',
|
|
91
307
|
webhooks: '钩子',
|
|
92
308
|
events: '事件',
|
|
@@ -100,6 +316,7 @@ export default flat({
|
|
|
100
316
|
business: '企业设置',
|
|
101
317
|
summary: '摘要',
|
|
102
318
|
product: {
|
|
319
|
+
empty: '暂无产品',
|
|
103
320
|
info: '产品信息',
|
|
104
321
|
add: '添加产品',
|
|
105
322
|
view: '查看产品详情',
|
|
@@ -144,21 +361,43 @@ export default flat({
|
|
|
144
361
|
},
|
|
145
362
|
unit_label: {
|
|
146
363
|
label: '单位标签',
|
|
147
|
-
placeholder: '
|
|
364
|
+
placeholder: '单位',
|
|
365
|
+
},
|
|
366
|
+
billingType: {
|
|
367
|
+
label: '计费类型',
|
|
368
|
+
standard: '标准计费',
|
|
369
|
+
metered: '计量计费',
|
|
370
|
+
help: '选择如何向客户收费',
|
|
371
|
+
},
|
|
372
|
+
meter: {
|
|
373
|
+
label: '计量器',
|
|
374
|
+
placeholder: '选择计量器来跟踪使用情况',
|
|
375
|
+
required: '计量计费需要选择一个计量器',
|
|
376
|
+
help: '选择用于跟踪此产品使用情况的计量器',
|
|
377
|
+
pricingNote: '对于计量产品,定价会自动基于所选计量器跟踪的使用情况。您只需要设置单价和计费周期。',
|
|
148
378
|
},
|
|
149
379
|
cross_sell: {
|
|
150
380
|
title: '交叉销售',
|
|
151
381
|
to: '交叉销售',
|
|
152
382
|
tip: '',
|
|
153
383
|
},
|
|
384
|
+
type: {
|
|
385
|
+
label: '产品类型',
|
|
386
|
+
service: '服务',
|
|
387
|
+
credit: 'Credit',
|
|
388
|
+
good: '商品',
|
|
389
|
+
},
|
|
154
390
|
},
|
|
155
391
|
price: {
|
|
156
392
|
name: '价格',
|
|
157
393
|
type: '使用类型',
|
|
158
394
|
info: '价格信息',
|
|
395
|
+
plan: '价格方案',
|
|
159
396
|
lookupKey: '查找键',
|
|
160
397
|
setAsDefault: '设置为默认价格',
|
|
161
398
|
detail: '定价详情',
|
|
399
|
+
addAnother: '添加价格方案',
|
|
400
|
+
order: '方案 {order}',
|
|
162
401
|
add: '添加另一个价格',
|
|
163
402
|
view: '查看价格详情',
|
|
164
403
|
additional: '附加选项',
|
|
@@ -185,6 +424,7 @@ export default flat({
|
|
|
185
424
|
lookup_key: {
|
|
186
425
|
label: '查找键',
|
|
187
426
|
placeholder: '',
|
|
427
|
+
description: '查找键用于在API中识别价格',
|
|
188
428
|
},
|
|
189
429
|
recurring: {
|
|
190
430
|
interval: '计费周期',
|
|
@@ -200,15 +440,42 @@ export default flat({
|
|
|
200
440
|
},
|
|
201
441
|
models: {
|
|
202
442
|
standard: '标准定价',
|
|
443
|
+
standardDesc: '单一固定价格',
|
|
203
444
|
package: '套餐定价',
|
|
445
|
+
packageDesc: '按单位数量定价',
|
|
204
446
|
graduated: '毕业定价',
|
|
205
447
|
volume: '量价定价',
|
|
206
448
|
custom: '客户自定义价格',
|
|
449
|
+
usageBased: '基于使用量',
|
|
450
|
+
creditMetered: 'Credit 计量计费',
|
|
451
|
+
},
|
|
452
|
+
creditMetered: {
|
|
453
|
+
label: 'Credit 计量计费',
|
|
454
|
+
placeholder: '选择计量器来跟踪使用情况',
|
|
455
|
+
required: 'Credit 计量计费需要选择一个计量器',
|
|
456
|
+
help: '选择用于跟踪此产品使用情况的计量器',
|
|
457
|
+
selectMeter: '选择计量器',
|
|
458
|
+
pricingNote: '对于计量产品,定价会自动基于所选计量器跟踪的使用情况。',
|
|
459
|
+
description: 'Credit 计量计费的订阅需要有对应的 Credit 消费,如果 Credit 消耗完,对应的服务会停止。',
|
|
207
460
|
},
|
|
208
461
|
types: {
|
|
209
462
|
onetime: '一次性',
|
|
463
|
+
onetimeDesc: '收取一次性费用',
|
|
210
464
|
recurring: '周期性',
|
|
465
|
+
recurringDesc: '收取持续费用',
|
|
211
466
|
},
|
|
467
|
+
paymentType: '付费类型',
|
|
468
|
+
billingModel: '计费模式',
|
|
469
|
+
pricing: '定价',
|
|
470
|
+
additionalCurrencies: '其他货币',
|
|
471
|
+
advanced: '高级设置',
|
|
472
|
+
customInterval: '自定义间隔',
|
|
473
|
+
perUnit: '每单位',
|
|
474
|
+
choosePricingModel: '选择定价模式',
|
|
475
|
+
usage: '使用量',
|
|
476
|
+
usageDesc: '根据用户数量、单位或席位定价。需要记录以便Stripe跟踪客户服务使用情况。',
|
|
477
|
+
meter: '计量器',
|
|
478
|
+
billingPeriod: '计费周期',
|
|
212
479
|
aggregate: {
|
|
213
480
|
sum: '在周期内的使用值总和',
|
|
214
481
|
max: '周期内的最大使用值',
|
|
@@ -229,6 +496,7 @@ export default flat({
|
|
|
229
496
|
format: '可售{num}件',
|
|
230
497
|
noLimit: '不限制可售数量',
|
|
231
498
|
valid: '可售数量不得少于已售数量',
|
|
499
|
+
description: '输入可售数量,0表示不限制可售数量',
|
|
232
500
|
},
|
|
233
501
|
quantitySold: {
|
|
234
502
|
label: '已售数量',
|
|
@@ -239,6 +507,7 @@ export default flat({
|
|
|
239
507
|
placeholder: '0表示无限制',
|
|
240
508
|
format: '单次最多购买{num}件',
|
|
241
509
|
noLimit: '不限制单次购买数量',
|
|
510
|
+
description: '输入限制单次购买的最大数量, 0表示无限制',
|
|
242
511
|
},
|
|
243
512
|
inventory: '库存设置',
|
|
244
513
|
},
|
|
@@ -246,6 +515,7 @@ export default flat({
|
|
|
246
515
|
create: '创建优惠券',
|
|
247
516
|
view: '查看优惠券',
|
|
248
517
|
},
|
|
518
|
+
|
|
249
519
|
paymentLink: {
|
|
250
520
|
view: '查看支付链接',
|
|
251
521
|
info: '支付链接信息',
|
|
@@ -490,6 +760,21 @@ export default flat({
|
|
|
490
760
|
webhooks: '钩子调用',
|
|
491
761
|
type: '类型',
|
|
492
762
|
pendingWebhooks: '待处理的钩子',
|
|
763
|
+
events: {
|
|
764
|
+
dailyEventCount: '每日事件数量',
|
|
765
|
+
dailyTotalValue: '每日总使用量',
|
|
766
|
+
eventName: '事件名称',
|
|
767
|
+
value: '值',
|
|
768
|
+
customer: '客户',
|
|
769
|
+
subscription: '订阅',
|
|
770
|
+
reportTime: '上报时间',
|
|
771
|
+
count: '共 {count} 个事件',
|
|
772
|
+
empty: '暂无事件数据',
|
|
773
|
+
emptyTip: '当有事件上报时,数据将显示在这里',
|
|
774
|
+
filterByCustomer: '按客户筛选',
|
|
775
|
+
eventCount: '事件数量',
|
|
776
|
+
totalValue: '总使用量',
|
|
777
|
+
},
|
|
493
778
|
},
|
|
494
779
|
invoice: {
|
|
495
780
|
view: '查看账单',
|
|
@@ -641,6 +926,42 @@ export default flat({
|
|
|
641
926
|
line2: '详细地址',
|
|
642
927
|
postal_code: '邮政编码',
|
|
643
928
|
},
|
|
929
|
+
creditGrants: {
|
|
930
|
+
title: '信用额度',
|
|
931
|
+
summary: '额度汇总',
|
|
932
|
+
noGrants: '未找到信用额度',
|
|
933
|
+
grantDetail: '信用额度详情',
|
|
934
|
+
overview: '额度概览',
|
|
935
|
+
overviewDescription: '监控所有货币的信用余额、使用情况和未偿债务。',
|
|
936
|
+
availableBalance: '可用余额',
|
|
937
|
+
usage: '使用情况',
|
|
938
|
+
viewGrants: '查看额度',
|
|
939
|
+
viewUsage: '查看使用情况',
|
|
940
|
+
recentActivity: '最近活动',
|
|
941
|
+
quickStats: '快速统计',
|
|
942
|
+
activeGrants: '活跃额度',
|
|
943
|
+
totalCreditValue: '总信用价值',
|
|
944
|
+
outstandingDebt: '未偿债务',
|
|
945
|
+
buyCredits: '购买额度',
|
|
946
|
+
viewAllActivity: '查看所有活动',
|
|
947
|
+
creditBalance: '信用余额',
|
|
948
|
+
totalAmount: '总额度',
|
|
949
|
+
pendingAmount: '欠费额度',
|
|
950
|
+
grantCount: '额度数量',
|
|
951
|
+
noGrantsDescription: '您还没有任何信用额度',
|
|
952
|
+
status: {
|
|
953
|
+
granted: '生效中',
|
|
954
|
+
pending: '待生效',
|
|
955
|
+
expired: '已过期',
|
|
956
|
+
depleted: '已耗尽',
|
|
957
|
+
voided: '已作废',
|
|
958
|
+
},
|
|
959
|
+
originalAmount: '原始金额',
|
|
960
|
+
grantId: '额度ID',
|
|
961
|
+
grants: '额度',
|
|
962
|
+
addCredit: '添加额度',
|
|
963
|
+
viewDetails: '查看详情',
|
|
964
|
+
},
|
|
644
965
|
},
|
|
645
966
|
passport: {
|
|
646
967
|
intro: '管理应用通行证的付款设置,必须同时设置商品和购买入口',
|
|
@@ -781,6 +1102,50 @@ export default flat({
|
|
|
781
1102
|
depositFailed: '申请转入冷钱包失败',
|
|
782
1103
|
appBalance: '热钱包余额',
|
|
783
1104
|
},
|
|
1105
|
+
creditGrants: {
|
|
1106
|
+
title: '信用额度',
|
|
1107
|
+
summary: '额度汇总',
|
|
1108
|
+
noGrants: '未找到信用额度',
|
|
1109
|
+
grantDetail: '信用额度详情',
|
|
1110
|
+
overview: '额度概览',
|
|
1111
|
+
overviewDescription: '监控所有货币的信用余额、使用情况和未偿债务。',
|
|
1112
|
+
availableBalance: '可用余额',
|
|
1113
|
+
usage: '使用情况',
|
|
1114
|
+
viewGrants: '查看额度',
|
|
1115
|
+
viewUsage: '查看使用情况',
|
|
1116
|
+
recentActivity: '最近活动',
|
|
1117
|
+
quickStats: '快速统计',
|
|
1118
|
+
activeGrants: '活跃额度',
|
|
1119
|
+
totalCreditValue: '总信用价值',
|
|
1120
|
+
outstandingDebt: '未偿债务',
|
|
1121
|
+
buyCredits: '购买额度',
|
|
1122
|
+
viewAllActivity: '查看所有活动',
|
|
1123
|
+
creditBalance: '信用余额',
|
|
1124
|
+
totalAmount: '总额度',
|
|
1125
|
+
pendingAmount: '欠费额度',
|
|
1126
|
+
grantCount: '额度数量',
|
|
1127
|
+
noGrantsDescription: '您还没有任何信用额度',
|
|
1128
|
+
status: {
|
|
1129
|
+
granted: '生效中',
|
|
1130
|
+
pending: '待生效',
|
|
1131
|
+
expired: '已过期',
|
|
1132
|
+
depleted: '已耗尽',
|
|
1133
|
+
voided: '已作废',
|
|
1134
|
+
},
|
|
1135
|
+
originalAmount: '原始金额',
|
|
1136
|
+
grantId: '额度ID',
|
|
1137
|
+
grants: '额度',
|
|
1138
|
+
addCredit: '添加额度',
|
|
1139
|
+
viewDetails: '查看详情',
|
|
1140
|
+
},
|
|
1141
|
+
creditTransactions: {
|
|
1142
|
+
title: '额度账单',
|
|
1143
|
+
summary: '账单汇总',
|
|
1144
|
+
noTransactions: '未找到额度账单',
|
|
1145
|
+
totalTransactions: '总账单数',
|
|
1146
|
+
totalCreditUsed: '总使用额度',
|
|
1147
|
+
transactionDate: '交易时间',
|
|
1148
|
+
},
|
|
784
1149
|
},
|
|
785
1150
|
empty: {
|
|
786
1151
|
image: '无图片',
|
|
@@ -806,6 +1171,7 @@ export default flat({
|
|
|
806
1171
|
subscription: {
|
|
807
1172
|
manage: '管理订阅',
|
|
808
1173
|
cancel: '取消订阅',
|
|
1174
|
+
title: '订阅',
|
|
809
1175
|
},
|
|
810
1176
|
invoiceHistory: '历史账单',
|
|
811
1177
|
product: {
|
|
@@ -870,6 +1236,7 @@ export default flat({
|
|
|
870
1236
|
},
|
|
871
1237
|
unpaidInvoicesWarning: '您当前有未支付的账单,请先付清账单。',
|
|
872
1238
|
unpaidInvoicesWarningTip: '您当前有未支付的账单,请及时付清。',
|
|
1239
|
+
pendingAmountWarningTip: '您有 {amount} {symbol} 的使用费用因额度不足无法处理,请及时充值。',
|
|
873
1240
|
invoice: {
|
|
874
1241
|
relatedInvoice: '关联账单',
|
|
875
1242
|
donation: '打赏记录',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
2
|
import Tabs from '@arcblock/ux/lib/Tabs';
|
|
3
|
-
|
|
3
|
+
import { Box, Stack } from '@mui/material';
|
|
4
4
|
import React, { isValidElement } from 'react';
|
|
5
5
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
6
6
|
|
|
@@ -8,10 +8,14 @@ import { useTransitionContext } from '../../../components/progress-bar';
|
|
|
8
8
|
|
|
9
9
|
const SubscriptionDetail = React.lazy(() => import('./subscriptions/detail'));
|
|
10
10
|
const InvoiceDetail = React.lazy(() => import('./invoices/detail'));
|
|
11
|
+
const MeterDetail = React.lazy(() => import('./meters/detail'));
|
|
12
|
+
const MeterCreate = React.lazy(() => import('./meters/create'));
|
|
13
|
+
const MeterEventDetail = React.lazy(() => import('./meters/meter-event'));
|
|
11
14
|
|
|
12
15
|
const pages = {
|
|
13
16
|
invoices: React.lazy(() => import('./invoices')),
|
|
14
17
|
subscriptions: React.lazy(() => import('./subscriptions')),
|
|
18
|
+
meters: React.lazy(() => import('./meters')),
|
|
15
19
|
};
|
|
16
20
|
|
|
17
21
|
export default function BillingIndex() {
|
|
@@ -28,6 +32,14 @@ export default function BillingIndex() {
|
|
|
28
32
|
return <InvoiceDetail id={page} />;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
if (page.startsWith('mtr_')) {
|
|
36
|
+
return <MeterDetail id={page} />;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (page.startsWith('mevt_')) {
|
|
40
|
+
return <MeterEventDetail id={page} />;
|
|
41
|
+
}
|
|
42
|
+
|
|
31
43
|
const onTabChange = (newTab: string) => {
|
|
32
44
|
startTransition(() => {
|
|
33
45
|
navigate(`/admin/billing/${newTab}`);
|
|
@@ -39,42 +51,58 @@ export default function BillingIndex() {
|
|
|
39
51
|
const tabs = [
|
|
40
52
|
{ label: t('admin.invoices'), value: 'invoices' },
|
|
41
53
|
{ label: t('admin.subscriptions'), value: 'subscriptions' },
|
|
54
|
+
{ label: t('admin.meters'), value: 'meters' },
|
|
42
55
|
];
|
|
43
56
|
|
|
57
|
+
let extra = null;
|
|
58
|
+
if (page === 'meters') {
|
|
59
|
+
extra = <MeterCreate />;
|
|
60
|
+
}
|
|
61
|
+
|
|
44
62
|
return (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
{/* @ts-ignore */}
|
|
50
|
-
<Tabs
|
|
51
|
-
// @ts-ignore
|
|
52
|
-
tabs={tabs}
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
current={page}
|
|
55
|
-
// @ts-ignore
|
|
56
|
-
onChange={onTabChange}
|
|
57
|
-
scrollButtons="auto"
|
|
63
|
+
<>
|
|
64
|
+
<Stack
|
|
65
|
+
direction="row"
|
|
66
|
+
spacing={1}
|
|
58
67
|
sx={{
|
|
59
|
-
'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
alignItems: 'flex-start',
|
|
69
|
+
justifyContent: 'end',
|
|
70
|
+
flexWrap: 'wrap',
|
|
71
|
+
}}>
|
|
72
|
+
{/* @ts-ignore */}
|
|
73
|
+
<Tabs
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
tabs={tabs}
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
current={page}
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
onChange={onTabChange}
|
|
80
|
+
scrollButtons="auto"
|
|
81
|
+
variant="scrollable"
|
|
82
|
+
sx={{
|
|
83
|
+
flex: '1 0 auto',
|
|
84
|
+
maxWidth: '100%',
|
|
85
|
+
'.MuiTab-root': {
|
|
86
|
+
color: 'text.lighter',
|
|
87
|
+
},
|
|
88
|
+
'.MuiTabs-indicator': {
|
|
89
|
+
display: 'none',
|
|
90
|
+
},
|
|
91
|
+
'.Mui-selected': {
|
|
92
|
+
fontSize: 24,
|
|
93
|
+
color: 'text.primary',
|
|
94
|
+
},
|
|
95
|
+
'.MuiTabs-hideScrollbar': {
|
|
96
|
+
border: 'none !important',
|
|
97
|
+
},
|
|
98
|
+
'.MuiTouchRipple-root': {
|
|
99
|
+
display: 'none',
|
|
100
|
+
},
|
|
101
|
+
}}
|
|
102
|
+
/>
|
|
103
|
+
<Box>{extra}</Box>
|
|
104
|
+
</Stack>
|
|
77
105
|
{isValidElement(TabComponent) ? TabComponent : <TabComponent />}
|
|
78
|
-
|
|
106
|
+
</>
|
|
79
107
|
);
|
|
80
108
|
}
|
|
@@ -406,7 +406,7 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
406
406
|
</Box>
|
|
407
407
|
<Divider />
|
|
408
408
|
<Box className="section">
|
|
409
|
-
<SectionHeader title={t('admin.events')} />
|
|
409
|
+
<SectionHeader title={t('admin.events.title')} />
|
|
410
410
|
<Box className="section-body">
|
|
411
411
|
<EventList
|
|
412
412
|
features={{ toolbar: false }}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
+
import { AddOutlined } from '@mui/icons-material';
|
|
3
|
+
import { Button } from '@mui/material';
|
|
4
|
+
import { api, formatError, usePaymentContext } from '@blocklet/payment-react';
|
|
5
|
+
import { useForm, FormProvider } from 'react-hook-form';
|
|
6
|
+
import Toast from '@arcblock/ux/lib/Toast';
|
|
7
|
+
import { dispatch } from 'use-bus';
|
|
8
|
+
|
|
9
|
+
import type { TMeter } from '@blocklet/payment-types';
|
|
10
|
+
import MeterForm from '../../../../components/meter/form';
|
|
11
|
+
import DrawerForm from '../../../../components/drawer-form';
|
|
12
|
+
|
|
13
|
+
export default function MeterCreate() {
|
|
14
|
+
const { t } = useLocaleContext();
|
|
15
|
+
const { refresh } = usePaymentContext();
|
|
16
|
+
const methods = useForm<TMeter>({
|
|
17
|
+
defaultValues: {
|
|
18
|
+
name: '',
|
|
19
|
+
event_name: '',
|
|
20
|
+
aggregation_method: 'sum',
|
|
21
|
+
unit: '',
|
|
22
|
+
description: '',
|
|
23
|
+
metadata: {},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const { handleSubmit, reset, clearErrors } = methods;
|
|
28
|
+
|
|
29
|
+
const onSubmit = async (data: TMeter) => {
|
|
30
|
+
try {
|
|
31
|
+
await api.post('/api/meters', data);
|
|
32
|
+
Toast.success(t('admin.meter.saved'));
|
|
33
|
+
reset();
|
|
34
|
+
clearErrors();
|
|
35
|
+
dispatch('meter.created');
|
|
36
|
+
dispatch('drawer.submitted');
|
|
37
|
+
refresh(true);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error(err);
|
|
40
|
+
Toast.error(formatError(err));
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<DrawerForm
|
|
46
|
+
icon={<AddOutlined />}
|
|
47
|
+
text={t('admin.meter.add')}
|
|
48
|
+
onClose={() => clearErrors()}
|
|
49
|
+
width={640}
|
|
50
|
+
addons={
|
|
51
|
+
<Button variant="contained" size="small" onClick={handleSubmit(onSubmit)}>
|
|
52
|
+
{t('admin.meter.save')}
|
|
53
|
+
</Button>
|
|
54
|
+
}>
|
|
55
|
+
<FormProvider {...methods}>
|
|
56
|
+
<MeterForm />
|
|
57
|
+
</FormProvider>
|
|
58
|
+
</DrawerForm>
|
|
59
|
+
);
|
|
60
|
+
}
|