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.
Files changed (139) hide show
  1. package/api/src/crons/index.ts +8 -0
  2. package/api/src/index.ts +4 -0
  3. package/api/src/libs/credit-grant.ts +146 -0
  4. package/api/src/libs/env.ts +1 -0
  5. package/api/src/libs/invoice.ts +4 -3
  6. package/api/src/libs/notification/template/base.ts +388 -2
  7. package/api/src/libs/notification/template/customer-credit-grant-granted.ts +149 -0
  8. package/api/src/libs/notification/template/customer-credit-grant-low-balance.ts +151 -0
  9. package/api/src/libs/notification/template/customer-credit-insufficient.ts +254 -0
  10. package/api/src/libs/notification/template/subscription-canceled.ts +193 -202
  11. package/api/src/libs/notification/template/subscription-refund-succeeded.ts +215 -237
  12. package/api/src/libs/notification/template/subscription-renewed.ts +130 -200
  13. package/api/src/libs/notification/template/subscription-succeeded.ts +100 -202
  14. package/api/src/libs/notification/template/subscription-trial-start.ts +142 -188
  15. package/api/src/libs/notification/template/subscription-trial-will-end.ts +146 -174
  16. package/api/src/libs/notification/template/subscription-upgraded.ts +96 -192
  17. package/api/src/libs/notification/template/subscription-will-canceled.ts +94 -135
  18. package/api/src/libs/notification/template/subscription-will-renew.ts +220 -245
  19. package/api/src/libs/payment.ts +69 -0
  20. package/api/src/libs/queue/index.ts +3 -2
  21. package/api/src/libs/session.ts +8 -0
  22. package/api/src/libs/subscription.ts +74 -3
  23. package/api/src/libs/util.ts +3 -1
  24. package/api/src/libs/ws.ts +23 -1
  25. package/api/src/locales/en.ts +33 -0
  26. package/api/src/locales/zh.ts +31 -0
  27. package/api/src/queues/credit-consume.ts +728 -0
  28. package/api/src/queues/credit-grant.ts +572 -0
  29. package/api/src/queues/notification.ts +173 -128
  30. package/api/src/queues/payment.ts +210 -122
  31. package/api/src/queues/subscription.ts +179 -0
  32. package/api/src/routes/checkout-sessions.ts +157 -9
  33. package/api/src/routes/connect/shared.ts +3 -2
  34. package/api/src/routes/credit-grants.ts +241 -0
  35. package/api/src/routes/credit-transactions.ts +208 -0
  36. package/api/src/routes/customers.ts +34 -5
  37. package/api/src/routes/index.ts +8 -0
  38. package/api/src/routes/meter-events.ts +347 -0
  39. package/api/src/routes/meters.ts +219 -0
  40. package/api/src/routes/payment-currencies.ts +20 -2
  41. package/api/src/routes/payment-links.ts +1 -1
  42. package/api/src/routes/payment-methods.ts +14 -2
  43. package/api/src/routes/prices.ts +43 -0
  44. package/api/src/routes/pricing-table.ts +13 -7
  45. package/api/src/routes/products.ts +63 -4
  46. package/api/src/routes/settings.ts +1 -1
  47. package/api/src/routes/subscriptions.ts +4 -0
  48. package/api/src/routes/webhook-endpoints.ts +0 -3
  49. package/api/src/store/migrations/20250610-billing-credit.ts +43 -0
  50. package/api/src/store/models/credit-grant.ts +486 -0
  51. package/api/src/store/models/credit-transaction.ts +268 -0
  52. package/api/src/store/models/customer.ts +8 -0
  53. package/api/src/store/models/index.ts +52 -1
  54. package/api/src/store/models/meter-event.ts +423 -0
  55. package/api/src/store/models/meter.ts +176 -0
  56. package/api/src/store/models/payment-currency.ts +66 -14
  57. package/api/src/store/models/price.ts +6 -0
  58. package/api/src/store/models/product.ts +2 -2
  59. package/api/src/store/models/subscription.ts +24 -0
  60. package/api/src/store/models/types.ts +28 -2
  61. package/api/tests/libs/subscription.spec.ts +53 -0
  62. package/blocklet.yml +9 -1
  63. package/package.json +4 -4
  64. package/scripts/sdk.js +233 -1
  65. package/src/app.tsx +10 -0
  66. package/src/components/collapse.tsx +11 -1
  67. package/src/components/conditional-section.tsx +87 -0
  68. package/src/components/customer/credit-grant-item-list.tsx +99 -0
  69. package/src/components/customer/credit-overview.tsx +246 -0
  70. package/src/components/customer/form.tsx +7 -3
  71. package/src/components/invoice/list.tsx +19 -1
  72. package/src/components/metadata/form.tsx +287 -91
  73. package/src/components/meter/actions.tsx +101 -0
  74. package/src/components/meter/add-usage-dialog.tsx +239 -0
  75. package/src/components/meter/events-list.tsx +657 -0
  76. package/src/components/meter/form.tsx +245 -0
  77. package/src/components/meter/products.tsx +264 -0
  78. package/src/components/meter/usage-guide.tsx +174 -0
  79. package/src/components/payment-currency/form.tsx +2 -0
  80. package/src/components/payment-intent/list.tsx +19 -1
  81. package/src/components/payment-link/item.tsx +2 -2
  82. package/src/components/payment-link/preview.tsx +1 -1
  83. package/src/components/payment-link/product-select.tsx +52 -12
  84. package/src/components/payment-method/arcblock.tsx +2 -0
  85. package/src/components/payment-method/base.tsx +2 -0
  86. package/src/components/payment-method/bitcoin.tsx +2 -0
  87. package/src/components/payment-method/ethereum.tsx +2 -0
  88. package/src/components/payment-method/stripe.tsx +2 -0
  89. package/src/components/payouts/list.tsx +19 -1
  90. package/src/components/payouts/portal/list.tsx +6 -11
  91. package/src/components/price/currency-select.tsx +56 -32
  92. package/src/components/price/form.tsx +912 -407
  93. package/src/components/pricing-table/preview.tsx +1 -1
  94. package/src/components/product/add-price.tsx +9 -7
  95. package/src/components/product/create.tsx +7 -4
  96. package/src/components/product/edit-price.tsx +21 -12
  97. package/src/components/product/features.tsx +17 -7
  98. package/src/components/product/form.tsx +100 -90
  99. package/src/components/refund/list.tsx +19 -1
  100. package/src/components/section/header.tsx +5 -18
  101. package/src/components/subscription/items/index.tsx +1 -1
  102. package/src/components/subscription/metrics.tsx +37 -5
  103. package/src/components/subscription/portal/actions.tsx +2 -1
  104. package/src/contexts/products.tsx +26 -9
  105. package/src/hooks/subscription.ts +34 -0
  106. package/src/libs/meter-utils.ts +196 -0
  107. package/src/libs/util.ts +4 -0
  108. package/src/locales/en.tsx +389 -5
  109. package/src/locales/zh.tsx +368 -1
  110. package/src/pages/admin/billing/index.tsx +61 -33
  111. package/src/pages/admin/billing/invoices/detail.tsx +1 -1
  112. package/src/pages/admin/billing/meters/create.tsx +60 -0
  113. package/src/pages/admin/billing/meters/detail.tsx +435 -0
  114. package/src/pages/admin/billing/meters/index.tsx +210 -0
  115. package/src/pages/admin/billing/meters/meter-event.tsx +346 -0
  116. package/src/pages/admin/billing/subscriptions/detail.tsx +47 -14
  117. package/src/pages/admin/customers/customers/credit-grant/detail.tsx +391 -0
  118. package/src/pages/admin/customers/customers/detail.tsx +14 -10
  119. package/src/pages/admin/customers/index.tsx +5 -0
  120. package/src/pages/admin/developers/events/detail.tsx +1 -1
  121. package/src/pages/admin/developers/index.tsx +1 -1
  122. package/src/pages/admin/payments/intents/detail.tsx +1 -1
  123. package/src/pages/admin/payments/payouts/detail.tsx +1 -1
  124. package/src/pages/admin/payments/refunds/detail.tsx +1 -1
  125. package/src/pages/admin/products/index.tsx +3 -2
  126. package/src/pages/admin/products/links/detail.tsx +1 -1
  127. package/src/pages/admin/products/prices/actions.tsx +16 -4
  128. package/src/pages/admin/products/prices/detail.tsx +30 -3
  129. package/src/pages/admin/products/prices/list.tsx +8 -1
  130. package/src/pages/admin/products/pricing-tables/detail.tsx +1 -1
  131. package/src/pages/admin/products/products/create.tsx +233 -57
  132. package/src/pages/admin/products/products/detail.tsx +2 -1
  133. package/src/pages/admin/settings/payment-methods/index.tsx +3 -0
  134. package/src/pages/customer/credit-grant/detail.tsx +308 -0
  135. package/src/pages/customer/index.tsx +44 -9
  136. package/src/pages/customer/recharge/account.tsx +5 -5
  137. package/src/pages/customer/subscription/change-payment.tsx +4 -2
  138. package/src/pages/customer/subscription/detail.tsx +48 -14
  139. package/src/pages/customer/subscription/embed.tsx +1 -1
@@ -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
- // import { Typography } from '@mui/material';
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
- <div>
46
- {/* <Typography variant="h5" sx={{ mb: 1, fontWeight: 600 }}>
47
- {t('admin.billing')}
48
- </Typography> */}
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
- '.MuiTab-root': {
60
- color: 'text.lighter',
61
- },
62
- '.MuiTabs-indicator': {
63
- display: 'none',
64
- },
65
- '.Mui-selected': {
66
- fontSize: 24,
67
- color: 'text.primary',
68
- },
69
- '.MuiTabs-hideScrollbar': {
70
- border: 'none !important',
71
- },
72
- '.MuiTouchRipple-root': {
73
- display: 'none',
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
- </div>
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
+ }