payment-kit 1.13.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.
Files changed (222) hide show
  1. package/.eslintrc.js +15 -0
  2. package/README.md +3 -0
  3. package/api/dev.ts +6 -0
  4. package/api/hooks/pre-start.js +12 -0
  5. package/api/src/hooks/pre-start.ts +21 -0
  6. package/api/src/index.ts +92 -0
  7. package/api/src/jobs/event.ts +72 -0
  8. package/api/src/jobs/invoice.ts +148 -0
  9. package/api/src/jobs/payment.ts +208 -0
  10. package/api/src/jobs/subscription.ts +301 -0
  11. package/api/src/jobs/webhook.ts +113 -0
  12. package/api/src/libs/audit.ts +73 -0
  13. package/api/src/libs/auth.ts +40 -0
  14. package/api/src/libs/chain/arcblock.ts +13 -0
  15. package/api/src/libs/dayjs.ts +17 -0
  16. package/api/src/libs/env.ts +5 -0
  17. package/api/src/libs/hooks.ts +42 -0
  18. package/api/src/libs/logger.ts +27 -0
  19. package/api/src/libs/middleware.ts +12 -0
  20. package/api/src/libs/payment.ts +53 -0
  21. package/api/src/libs/queue/index.ts +263 -0
  22. package/api/src/libs/queue/store.ts +47 -0
  23. package/api/src/libs/security.ts +95 -0
  24. package/api/src/libs/session.ts +164 -0
  25. package/api/src/libs/util.ts +93 -0
  26. package/api/src/locales/en.ts +3 -0
  27. package/api/src/locales/index.ts +37 -0
  28. package/api/src/locales/zh.ts +3 -0
  29. package/api/src/routes/checkout-sessions.ts +536 -0
  30. package/api/src/routes/connect/collect.ts +109 -0
  31. package/api/src/routes/connect/pay.ts +116 -0
  32. package/api/src/routes/connect/setup.ts +121 -0
  33. package/api/src/routes/connect/shared.ts +410 -0
  34. package/api/src/routes/connect/subscribe.ts +128 -0
  35. package/api/src/routes/customers.ts +70 -0
  36. package/api/src/routes/events.ts +76 -0
  37. package/api/src/routes/index.ts +59 -0
  38. package/api/src/routes/invoices.ts +126 -0
  39. package/api/src/routes/payment-currencies.ts +38 -0
  40. package/api/src/routes/payment-intents.ts +122 -0
  41. package/api/src/routes/payment-links.ts +221 -0
  42. package/api/src/routes/payment-methods.ts +39 -0
  43. package/api/src/routes/prices.ts +134 -0
  44. package/api/src/routes/products.ts +191 -0
  45. package/api/src/routes/settings.ts +33 -0
  46. package/api/src/routes/subscription-items.ts +148 -0
  47. package/api/src/routes/subscriptions.ts +254 -0
  48. package/api/src/routes/usage-records.ts +120 -0
  49. package/api/src/routes/webhook-attempts.ts +57 -0
  50. package/api/src/routes/webhook-endpoints.ts +105 -0
  51. package/api/src/store/migrate.ts +16 -0
  52. package/api/src/store/migrations/20230905-genesis.ts +52 -0
  53. package/api/src/store/migrations/20230911-seeding.ts +145 -0
  54. package/api/src/store/models/checkout-session.ts +395 -0
  55. package/api/src/store/models/coupon.ts +137 -0
  56. package/api/src/store/models/customer.ts +199 -0
  57. package/api/src/store/models/discount.ts +116 -0
  58. package/api/src/store/models/event.ts +111 -0
  59. package/api/src/store/models/index.ts +165 -0
  60. package/api/src/store/models/invoice-item.ts +185 -0
  61. package/api/src/store/models/invoice.ts +492 -0
  62. package/api/src/store/models/job.ts +75 -0
  63. package/api/src/store/models/payment-currency.ts +139 -0
  64. package/api/src/store/models/payment-intent.ts +282 -0
  65. package/api/src/store/models/payment-link.ts +219 -0
  66. package/api/src/store/models/payment-method.ts +169 -0
  67. package/api/src/store/models/price.ts +266 -0
  68. package/api/src/store/models/product.ts +162 -0
  69. package/api/src/store/models/promotion-code.ts +112 -0
  70. package/api/src/store/models/setup-intent.ts +206 -0
  71. package/api/src/store/models/subscription-item.ts +103 -0
  72. package/api/src/store/models/subscription-schedule.ts +157 -0
  73. package/api/src/store/models/subscription.ts +307 -0
  74. package/api/src/store/models/types.ts +406 -0
  75. package/api/src/store/models/usage-record.ts +132 -0
  76. package/api/src/store/models/webhook-attempt.ts +96 -0
  77. package/api/src/store/models/webhook-endpoint.ts +96 -0
  78. package/api/src/store/sequelize.ts +15 -0
  79. package/api/third.d.ts +28 -0
  80. package/blocklet.md +3 -0
  81. package/blocklet.yml +89 -0
  82. package/index.html +14 -0
  83. package/logo.png +0 -0
  84. package/package.json +133 -0
  85. package/public/.gitkeep +0 -0
  86. package/screenshots/.gitkeep +0 -0
  87. package/screenshots/1-subscription.png +0 -0
  88. package/screenshots/2-customer-1.png +0 -0
  89. package/screenshots/3-customer-2.png +0 -0
  90. package/screenshots/4-admin-3.png +0 -0
  91. package/screenshots/5-admin-4.png +0 -0
  92. package/scripts/build-clean.js +6 -0
  93. package/scripts/bump-version.mjs +35 -0
  94. package/src/app.tsx +68 -0
  95. package/src/components/actions.tsx +85 -0
  96. package/src/components/blockchain/tx.tsx +29 -0
  97. package/src/components/checkout/amount.tsx +24 -0
  98. package/src/components/checkout/error.tsx +30 -0
  99. package/src/components/checkout/footer.tsx +12 -0
  100. package/src/components/checkout/form/address.tsx +38 -0
  101. package/src/components/checkout/form/index.tsx +295 -0
  102. package/src/components/checkout/header.tsx +23 -0
  103. package/src/components/checkout/pay.tsx +222 -0
  104. package/src/components/checkout/product-card.tsx +56 -0
  105. package/src/components/checkout/product-item.tsx +37 -0
  106. package/src/components/checkout/skeleton/overview.tsx +21 -0
  107. package/src/components/checkout/skeleton/payment.tsx +35 -0
  108. package/src/components/checkout/success.tsx +183 -0
  109. package/src/components/checkout/summary.tsx +34 -0
  110. package/src/components/collapse.tsx +50 -0
  111. package/src/components/confirm.tsx +55 -0
  112. package/src/components/copyable.tsx +38 -0
  113. package/src/components/currency.tsx +15 -0
  114. package/src/components/customer/actions.tsx +73 -0
  115. package/src/components/data.tsx +20 -0
  116. package/src/components/drawer-form.tsx +77 -0
  117. package/src/components/error-fallback.tsx +7 -0
  118. package/src/components/error.tsx +39 -0
  119. package/src/components/event/list.tsx +217 -0
  120. package/src/components/info-card.tsx +40 -0
  121. package/src/components/info-metric.tsx +35 -0
  122. package/src/components/info-row.tsx +28 -0
  123. package/src/components/input.tsx +40 -0
  124. package/src/components/invoice/action.tsx +94 -0
  125. package/src/components/invoice/list.tsx +225 -0
  126. package/src/components/invoice/table.tsx +110 -0
  127. package/src/components/layout.tsx +70 -0
  128. package/src/components/livemode.tsx +23 -0
  129. package/src/components/metadata/editor.tsx +57 -0
  130. package/src/components/metadata/form.tsx +45 -0
  131. package/src/components/payment-intent/actions.tsx +81 -0
  132. package/src/components/payment-intent/list.tsx +204 -0
  133. package/src/components/payment-link/actions.tsx +114 -0
  134. package/src/components/payment-link/after-pay.tsx +87 -0
  135. package/src/components/payment-link/before-pay.tsx +175 -0
  136. package/src/components/payment-link/item.tsx +135 -0
  137. package/src/components/payment-link/product-select.tsx +66 -0
  138. package/src/components/payment-link/rename.tsx +64 -0
  139. package/src/components/portal/invoice/list.tsx +110 -0
  140. package/src/components/portal/subscription/cancel.tsx +83 -0
  141. package/src/components/portal/subscription/list.tsx +232 -0
  142. package/src/components/price/actions.tsx +21 -0
  143. package/src/components/price/form.tsx +292 -0
  144. package/src/components/product/actions.tsx +125 -0
  145. package/src/components/product/add-price.tsx +59 -0
  146. package/src/components/product/create.tsx +97 -0
  147. package/src/components/product/edit-price.tsx +75 -0
  148. package/src/components/product/edit.tsx +67 -0
  149. package/src/components/product/features.tsx +32 -0
  150. package/src/components/product/form.tsx +76 -0
  151. package/src/components/relative-time.tsx +41 -0
  152. package/src/components/section/header.tsx +29 -0
  153. package/src/components/status.tsx +12 -0
  154. package/src/components/subscription/actions/cancel.tsx +66 -0
  155. package/src/components/subscription/actions/index.tsx +172 -0
  156. package/src/components/subscription/actions/pause.tsx +83 -0
  157. package/src/components/subscription/items/actions.tsx +31 -0
  158. package/src/components/subscription/items/index.tsx +107 -0
  159. package/src/components/subscription/list.tsx +200 -0
  160. package/src/components/switch.tsx +48 -0
  161. package/src/components/table.tsx +66 -0
  162. package/src/components/uploader.tsx +81 -0
  163. package/src/components/webhook/attempts.tsx +149 -0
  164. package/src/contexts/products.tsx +42 -0
  165. package/src/contexts/session.ts +10 -0
  166. package/src/contexts/settings.tsx +54 -0
  167. package/src/env.d.ts +17 -0
  168. package/src/global.css +97 -0
  169. package/src/hooks/mobile.ts +15 -0
  170. package/src/index.tsx +6 -0
  171. package/src/libs/api.ts +19 -0
  172. package/src/libs/dayjs.ts +17 -0
  173. package/src/libs/util.ts +474 -0
  174. package/src/locales/en.tsx +395 -0
  175. package/src/locales/index.tsx +8 -0
  176. package/src/locales/zh.tsx +389 -0
  177. package/src/pages/admin/billing/index.tsx +56 -0
  178. package/src/pages/admin/billing/invoices/detail.tsx +215 -0
  179. package/src/pages/admin/billing/invoices/index.tsx +5 -0
  180. package/src/pages/admin/billing/subscriptions/detail.tsx +237 -0
  181. package/src/pages/admin/billing/subscriptions/index.tsx +5 -0
  182. package/src/pages/admin/customers/customers/detail.tsx +209 -0
  183. package/src/pages/admin/customers/customers/index.tsx +109 -0
  184. package/src/pages/admin/customers/index.tsx +47 -0
  185. package/src/pages/admin/developers/events/detail.tsx +77 -0
  186. package/src/pages/admin/developers/events/index.tsx +5 -0
  187. package/src/pages/admin/developers/index.tsx +60 -0
  188. package/src/pages/admin/developers/logs.tsx +3 -0
  189. package/src/pages/admin/developers/overview.tsx +3 -0
  190. package/src/pages/admin/developers/webhooks/detail.tsx +109 -0
  191. package/src/pages/admin/developers/webhooks/index.tsx +102 -0
  192. package/src/pages/admin/index.tsx +120 -0
  193. package/src/pages/admin/overview.tsx +3 -0
  194. package/src/pages/admin/payments/index.tsx +65 -0
  195. package/src/pages/admin/payments/intents/detail.tsx +205 -0
  196. package/src/pages/admin/payments/intents/index.tsx +5 -0
  197. package/src/pages/admin/payments/links/create.tsx +141 -0
  198. package/src/pages/admin/payments/links/detail.tsx +318 -0
  199. package/src/pages/admin/payments/links/index.tsx +167 -0
  200. package/src/pages/admin/products/coupons/index.tsx +3 -0
  201. package/src/pages/admin/products/index.tsx +81 -0
  202. package/src/pages/admin/products/prices/actions.tsx +151 -0
  203. package/src/pages/admin/products/prices/detail.tsx +203 -0
  204. package/src/pages/admin/products/prices/list.tsx +95 -0
  205. package/src/pages/admin/products/pricing-tables.tsx +3 -0
  206. package/src/pages/admin/products/products/create.tsx +105 -0
  207. package/src/pages/admin/products/products/detail.tsx +246 -0
  208. package/src/pages/admin/products/products/index.tsx +154 -0
  209. package/src/pages/admin/settings/branding.tsx +3 -0
  210. package/src/pages/admin/settings/business.tsx +3 -0
  211. package/src/pages/admin/settings/index.tsx +47 -0
  212. package/src/pages/admin/settings/payment-methods.tsx +80 -0
  213. package/src/pages/checkout/index.tsx +38 -0
  214. package/src/pages/checkout/pay.tsx +89 -0
  215. package/src/pages/customer/index.tsx +93 -0
  216. package/src/pages/customer/invoice.tsx +147 -0
  217. package/src/pages/home.tsx +9 -0
  218. package/tsconfig.api.json +9 -0
  219. package/tsconfig.eslint.json +7 -0
  220. package/tsconfig.json +99 -0
  221. package/tsconfig.types.json +11 -0
  222. package/vite.config.ts +19 -0
@@ -0,0 +1,389 @@
1
+ import flat from 'flat';
2
+
3
+ export default flat({
4
+ common: {
5
+ id: '标识',
6
+ url: '链接',
7
+ createdAt: '创建于',
8
+ updatedAt: '更新于',
9
+ resumesAt: '恢复于',
10
+ actions: '操作',
11
+ options: '选项',
12
+ advanced: '高级选项',
13
+ settings: '设置',
14
+ preview: '预览',
15
+ required: '必填',
16
+ setup: '设置',
17
+ days: '天',
18
+ name: '名称',
19
+ amount: '金额',
20
+ total: '总计',
21
+ status: '状态',
22
+ livemode: '测试模式',
23
+ afterTime: '在{time}之后',
24
+ timeAgo: '{time}前',
25
+ save: '保存',
26
+ saved: '更改已保存',
27
+ remove: '删除',
28
+ removed: '资源已删除',
29
+ confirm: '确认',
30
+ cancel: '取消',
31
+ every: '每',
32
+ per: '每',
33
+ unit: '单位',
34
+ edit: '编辑',
35
+ quantity: '数量',
36
+ yes: '是',
37
+ no: '否',
38
+ email: '邮箱',
39
+ did: 'DID',
40
+ txHash: '交易哈希',
41
+ customer: '客户',
42
+ description: '描述',
43
+ statementDescriptor: '账单描述',
44
+ loadMore: '查看更多{resource}',
45
+ loadingMore: '正在加载更多{resource}...',
46
+ noMore: '没有更多{resource}',
47
+ metadata: {
48
+ label: '元数据',
49
+ add: '添加更多元数据',
50
+ edit: '编辑元数据',
51
+ empty: '无元数据',
52
+ },
53
+ },
54
+ admin: {
55
+ overview: '概览',
56
+ payments: '支付',
57
+ connections: '连接',
58
+ paymentLinks: '支付链接',
59
+ paymentMethods: '支付方式',
60
+ customers: '客户',
61
+ products: '产品',
62
+ coupons: '优惠券',
63
+ pricingTables: '定价表',
64
+ billing: '计费',
65
+ invoices: '发票',
66
+ subscriptions: '订阅',
67
+ developers: '开发者',
68
+ webhooks: 'Web钩子',
69
+ events: '事件',
70
+ logs: '日志',
71
+ details: '详情',
72
+ settings: '设置',
73
+ branding: '品牌',
74
+ business: '业务',
75
+ summary: '摘要',
76
+ product: {
77
+ info: '产品信息',
78
+ add: '添加产品',
79
+ view: '查看产品详情',
80
+ save: '保存产品',
81
+ saved: '产品已成功保存',
82
+ additional: '附加选项',
83
+ edit: '编辑产品',
84
+ pricing: '定价',
85
+ archive: '存档产品',
86
+ archiveTip: '存档将隐藏该产品不再允许新购买。您确定要存档此产品吗?',
87
+ unarchive: '取消存档产品',
88
+ unarchiveTip: '取消存档将允许该产品再次购买。您确定要取消存档此产品吗?',
89
+ remove: '删除产品',
90
+ removeTip: '删除将隐藏该产品不再允许新购买。您确定要删除此产品吗?',
91
+ archived: '此产品已存档',
92
+ archivedTip:
93
+ '此产品无法添加到新的发票、订阅、支付链接或定价表中。任何现有的包含此产品的订阅将保持活动状态,直到取消,任何现有的支付链接或定价表都将停用。',
94
+ image: {
95
+ label: '图片',
96
+ add: '添加图片',
97
+ },
98
+ features: {
99
+ label: '特性',
100
+ add: '添加其他特性',
101
+ },
102
+ name: {
103
+ label: '名称',
104
+ required: '产品名称是必填的',
105
+ placeholder: '高级套餐',
106
+ },
107
+ description: {
108
+ label: '描述',
109
+ required: '产品描述是必填的',
110
+ placeholder: '结账、发票页面上显示的产品描述',
111
+ },
112
+ statement_descriptor: {
113
+ label: '账单描述',
114
+ placeholder: 'ArcBlock',
115
+ },
116
+ unit_label: {
117
+ label: '单位标签',
118
+ placeholder: '座位',
119
+ },
120
+ },
121
+ price: {
122
+ name: '价格',
123
+ type: '使用类型',
124
+ info: '价格信息',
125
+ lookupKey: '查找键',
126
+ setAsDefault: '设置为默认价格',
127
+ detail: '定价详情',
128
+ add: '添加其他价格',
129
+ view: '查看价格详情',
130
+ additional: '附加选项',
131
+ model: '定价模型',
132
+ amount: '价格',
133
+ duplicate: '复制价格',
134
+ edit: '编辑价格',
135
+ archive: '存档价格',
136
+ archiveTip: '存档将隐藏该价格不再允许新购买。您确定要存档此价格吗?',
137
+ remove: '删除价格',
138
+ removeTip: '删除将隐藏该价格不再允许新购买。您确定要删除此价格吗?',
139
+ unit_amount: {
140
+ required: '价格是必填的',
141
+ positive: '价格必须是正数',
142
+ },
143
+ nickname: {
144
+ label: '价格描述',
145
+ placeholder: '',
146
+ },
147
+ lookup_key: {
148
+ label: '查找键',
149
+ placeholder: '',
150
+ },
151
+ recurring: {
152
+ interval: '计费周期',
153
+ metered: '使用是否计费?',
154
+ aggregate: '按何方式计费',
155
+ },
156
+ },
157
+ coupon: {
158
+ create: '创建优惠券',
159
+ view: '查看优惠券',
160
+ },
161
+ paymentLink: {
162
+ view: '查看支付链接',
163
+ info: '支付链接信息',
164
+ add: '创建支付链接',
165
+ save: '创建链接',
166
+ saved: '支付链接创建成功',
167
+ additional: '附加选项',
168
+ beforePay: '支付页面',
169
+ afterPay: '支付后',
170
+ products: '产品',
171
+ addProduct: '添加其他产品',
172
+ requireBillingAddress: '收集客户账单地址',
173
+ requirePhoneNumber: '收集客户电话号码',
174
+ allowPromotionCodes: '允许促销代码',
175
+ includeFreeTrail: '包含免费试用',
176
+ includeCustomFields: '添加自定义字段',
177
+ confirmPage: '确认页面',
178
+ showConfirmPage: '显示确认页面',
179
+ customMessage: '用自定义消息替代默认消息',
180
+ customMessageTip: '包括任何您认为合适的详细信息,如交付信息。',
181
+ noConfirmPage: '不显示确认页面',
182
+ createInvoice: '为相关支付创建发票。',
183
+ adjustable: '可调整数量',
184
+ adjustableQuantity: '允许客户调整数量',
185
+ noProducts: '支付链接必须至少包含一个产品',
186
+ noRedirectUrl: '支付链接必须具有重定向URL',
187
+ noSubscriptionTrialDays: '您必须指定订阅的试用期',
188
+ notAligned: '所有行项目上的价格必须具有相同的重复周期',
189
+ edit: '编辑支付链接',
190
+ rename: '更改名称',
191
+ archive: '存档支付链接',
192
+ archiveTip: '存档将隐藏该支付链接不再允许新购买。您确定要存档此支付链接吗?',
193
+ remove: '删除支付链接',
194
+ removeTip: '删除将隐藏该支付链接不再允许新购买。您确定要删除此支付链接吗?',
195
+ name: {
196
+ label: '名称',
197
+ placeholder: '不面向消费者',
198
+ },
199
+ },
200
+ paymentIntent: {
201
+ name: '支付',
202
+ view: '查看支付详情',
203
+ empty: '没有支付意向',
204
+ refund: '退款支付',
205
+ },
206
+ paymentMethod: {
207
+ name: '支付方式',
208
+ type: '类型',
209
+ },
210
+ paymentCurrency: {
211
+ name: '支付货币',
212
+ },
213
+ event: {
214
+ empty: '没有事件',
215
+ view: '查看事件',
216
+ data: '事件数据',
217
+ webhooks: 'Web钩子尝试',
218
+ type: '类型',
219
+ pendingWebhooks: '待处理的Web钩子',
220
+ },
221
+ invoice: {
222
+ view: '查看发票',
223
+ name: '发票',
224
+ from: '来自',
225
+ empty: '没有发票',
226
+ number: '发票编号',
227
+ dueDate: '截止日期',
228
+ finalizedAt: '完成时间',
229
+ paidAt: '付款日期',
230
+ summary: '摘要',
231
+ customer: '寄送至',
232
+ billing: '计费方式',
233
+ download: '下载PDF',
234
+ edit: '编辑发票',
235
+ duplicate: '复制发票',
236
+ },
237
+ subscription: {
238
+ view: '查看订阅',
239
+ name: '订阅',
240
+ empty: '没有订阅',
241
+ product: '产品',
242
+ collectionMethod: '计费',
243
+ currentPeriod: '当前周期',
244
+ trialingPeriod: '试用期',
245
+ discount: '折扣',
246
+ startedAt: '开始时间',
247
+ nextInvoice: '下一个发票',
248
+ itemId: '订阅项目ID',
249
+ update: '更新订阅',
250
+ resume: '恢复支付收款',
251
+ resumeTip: '您确定要恢复收款吗?此订阅的未来发票将恢复收款。',
252
+ cancel: {
253
+ schedule: '计划取消',
254
+ title: '取消订阅',
255
+ required: '需要自定义取消时间',
256
+ at: {
257
+ title: '取消',
258
+ now: '立即({date})',
259
+ current_period_end: '当前周期结束时({date})',
260
+ custom: '自定义日期',
261
+ },
262
+ },
263
+ pause: {
264
+ title: '暂停支付收款',
265
+ required: '需要自定义恢复时间',
266
+ type: {
267
+ title: '暂停持续时间',
268
+ never: '无限期',
269
+ custom: '直到自定义日期',
270
+ },
271
+ behavior: {
272
+ title: '发票行为',
273
+ keep_as_draft: '保留发票为草稿',
274
+ keep_as_draft_tip: '对于目前提供服务但等待收款的企业。',
275
+ mark_uncollectible: '标记发票为不可收款',
276
+ mark_uncollectible_tip: '对于目前免费提供服务的企业。',
277
+ void: '作废发票',
278
+ voidTip: '对于目前不提供服务的企业。',
279
+ },
280
+ },
281
+ },
282
+ customer: {
283
+ view: '查看客户',
284
+ edit: '编辑信息',
285
+ spent: '已花费金额',
286
+ refund: '退款金额',
287
+ dispute: '争议金额',
288
+ name: '姓名',
289
+ email: '邮箱',
290
+ phone: '电话',
291
+ invoicePrefix: '发票前缀',
292
+ address: {
293
+ label: '地址',
294
+ country: '国家',
295
+ state: '州或省',
296
+ city: '城市或镇',
297
+ line1: '地址',
298
+ line2: '地址2',
299
+ postal_code: '邮政编码',
300
+ },
301
+ },
302
+ webhookEndpoint: {
303
+ hosted: '托管端点',
304
+ add: '添加端点',
305
+ addTip: '设置您的Web钩子端点以接收实时事件',
306
+ listen: '监听',
307
+ version: 'API版本',
308
+ attempts: 'Web钩子尝试',
309
+ url: {
310
+ label: 'URL',
311
+ description: '端点URL',
312
+ },
313
+ description: {
314
+ label: '描述',
315
+ description: '用于说明此端点用途的可选描述。',
316
+ },
317
+ events: {
318
+ label: '选择要监听的事件',
319
+ description: '',
320
+ },
321
+ },
322
+ },
323
+ checkout: {
324
+ contact: '联系信息',
325
+ method: '支付方式',
326
+ processing: '处理中',
327
+ payment: '支付',
328
+ subscription: '订阅',
329
+ setup: '订阅',
330
+ connect: '连接并{action}',
331
+ portal: '管理订阅',
332
+ completed: {
333
+ payment: '感谢您的购买',
334
+ subscription: '感谢您的订阅',
335
+ setup: '感谢您的订阅',
336
+ tip: '已完成向{payee}的付款。您可以在您的账户中查看此付款的详细信息。',
337
+ },
338
+ confirm: '通过确认您的订阅,您允许{payee}按照其条款对您的账户进行收费。您随时可以取消您的订阅。',
339
+ billing: {
340
+ auto: '国家',
341
+ required: '账单地址',
342
+ country: '国家',
343
+ state: '州或省',
344
+ city: '城市或镇',
345
+ line1: '地址',
346
+ line2: '地址2',
347
+ postal_code: '邮政编码',
348
+ },
349
+ customer: {
350
+ name: '姓名',
351
+ email: '邮箱',
352
+ phone: '电话',
353
+ phoneTip: '以防需要联系您有关您的订单',
354
+ },
355
+ },
356
+ customer: {
357
+ subscriptions: '当前订阅',
358
+ invoices: '发票历史',
359
+ details: '账单详情',
360
+ update: '更新',
361
+ cancel: {
362
+ button: '取消',
363
+ title: '取消您的订阅',
364
+ description: '您的订阅将被取消,但仍然在您的当前计费周期结束于{date}之前可用',
365
+ feedback: {
366
+ tip: '我们很愿意听取您的反馈,这将帮助我们改进我们的服务',
367
+ too_expensive: '服务太昂贵',
368
+ missing_features: '此服务缺少功能',
369
+ switched_service: '我已切换到其他服务',
370
+ unused: '我不再使用此服务',
371
+ customer_service: '客户服务不佳',
372
+ too_complex: '服务太复杂',
373
+ low_quality: '服务质量不佳',
374
+ other: '其他原因',
375
+ },
376
+ },
377
+ recover: {
378
+ button: '续订',
379
+ title: '续订您的订阅',
380
+ description: '您的订阅将不再被取消,将在{date}续订',
381
+ },
382
+ invoice: {
383
+ summary: '摘要',
384
+ details: '详情',
385
+ download: '下载PDF',
386
+ pay: '支付此发票',
387
+ },
388
+ },
389
+ });
@@ -0,0 +1,56 @@
1
+ import Center from '@arcblock/ux/lib/Center';
2
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
+ import Tabs from '@arcblock/ux/lib/Tabs';
4
+ import { CircularProgress, Typography } from '@mui/material';
5
+ import React, { Suspense, isValidElement } from 'react';
6
+ import { useNavigate, useParams } from 'react-router-dom';
7
+
8
+ const SubscriptionDetail = React.lazy(() => import('./subscriptions/detail'));
9
+ const InvoiceDetail = React.lazy(() => import('./invoices/detail'));
10
+
11
+ const pages = {
12
+ subscriptions: React.lazy(() => import('./subscriptions')),
13
+ invoices: React.lazy(() => import('./invoices')),
14
+ };
15
+
16
+ export default function BillingIndex() {
17
+ const navigate = useNavigate();
18
+ const { t } = useLocaleContext();
19
+ const { page = 'subscriptions' } = useParams();
20
+
21
+ if (page.startsWith('sub_')) {
22
+ return <SubscriptionDetail id={page} />;
23
+ }
24
+
25
+ if (page.startsWith('in_')) {
26
+ return <InvoiceDetail id={page} />;
27
+ }
28
+
29
+ const onTabChange = (newTab: string) => {
30
+ navigate(`/admin/billing/${newTab}`);
31
+ };
32
+
33
+ // @ts-ignore
34
+ const TabComponent = pages[page] || pages.subscriptions;
35
+ const tabs = [
36
+ { label: t('admin.subscriptions'), value: 'subscriptions' },
37
+ { label: t('admin.invoices'), value: 'invoices' },
38
+ ];
39
+
40
+ return (
41
+ <div>
42
+ <Typography variant="h5" sx={{ mb: 1, fontWeight: 600 }}>
43
+ {t('admin.billing')}
44
+ </Typography>
45
+ <Tabs tabs={tabs} current={page} onChange={onTabChange} scrollButtons="auto" />
46
+ <Suspense
47
+ fallback={
48
+ <Center relative="parent">
49
+ <CircularProgress />
50
+ </Center>
51
+ }>
52
+ {isValidElement(TabComponent) ? TabComponent : <TabComponent />}
53
+ </Suspense>
54
+ </div>
55
+ );
56
+ }
@@ -0,0 +1,215 @@
1
+ /* eslint-disable react/no-unstable-nested-components */
2
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
+ import Toast from '@arcblock/ux/lib/Toast';
4
+ import type { TInvoice, TInvoiceExpanded } from '@did-pay/types';
5
+ import { ArrowBackOutlined, Edit } from '@mui/icons-material';
6
+ import { Alert, Box, Button, CircularProgress, Stack, Typography } from '@mui/material';
7
+ import { styled } from '@mui/system';
8
+ import { fromUnitToToken } from '@ocap/util';
9
+ import { useRequest, useSetState } from 'ahooks';
10
+ import { isEmpty } from 'lodash';
11
+ import { Link } from 'react-router-dom';
12
+
13
+ import Copyable from '../../../../components/copyable';
14
+ import Currency from '../../../../components/currency';
15
+ import EventList from '../../../../components/event/list';
16
+ import InfoRow from '../../../../components/info-row';
17
+ import InvoiceActions from '../../../../components/invoice/action';
18
+ import InvoiceTable from '../../../../components/invoice/table';
19
+ import MetadataEditor from '../../../../components/metadata/editor';
20
+ import PaymentList from '../../../../components/payment-intent/list';
21
+ import SectionHeader from '../../../../components/section/header';
22
+ import Status from '../../../../components/status';
23
+ import api from '../../../../libs/api';
24
+ import { formatError, formatTime, getInvoiceStatusColor } from '../../../../libs/util';
25
+
26
+ const fetchData = (id: string): Promise<TInvoiceExpanded> => {
27
+ return api.get(`/api/invoices/${id}`).then((res) => res.data);
28
+ };
29
+
30
+ export default function InvoiceDetail(props: { id: string }) {
31
+ const { t } = useLocaleContext();
32
+ const [state, setState] = useSetState({
33
+ adding: {
34
+ price: false,
35
+ },
36
+ editing: {
37
+ metadata: false,
38
+ product: false,
39
+ },
40
+ loading: {
41
+ metadata: false,
42
+ price: false,
43
+ product: false,
44
+ },
45
+ });
46
+
47
+ const { loading, error, data, runAsync } = useRequest(() => fetchData(props.id));
48
+
49
+ if (error) {
50
+ return <Alert severity="error">{error.message}</Alert>;
51
+ }
52
+
53
+ if (loading || !data) {
54
+ return <CircularProgress />;
55
+ }
56
+
57
+ const createUpdater = (key: string) => async (updates: TInvoice) => {
58
+ try {
59
+ setState((prev) => ({ loading: { ...prev.loading, [key]: true } }));
60
+ await api.put(`/api/invoices/${props.id}`, updates).then((res) => res.data);
61
+ Toast.success(t('common.saved'));
62
+ runAsync();
63
+ } catch (err) {
64
+ console.error(err);
65
+ Toast.error(formatError(err));
66
+ } finally {
67
+ setState((prev) => ({ loading: { ...prev.loading, [key]: false } }));
68
+ }
69
+ };
70
+
71
+ const onUpdateMetadata = createUpdater('metadata');
72
+
73
+ return (
74
+ <Root direction="column" spacing={4} sx={{ mb: 4 }}>
75
+ <Box>
76
+ <Stack className="page-header" direction="row" justifyContent="space-between" alignItems="center">
77
+ <Link to="/admin/billing/invoices">
78
+ <Stack direction="row" alignItems="center" sx={{ fontWeight: 'normal' }}>
79
+ <ArrowBackOutlined fontSize="small" sx={{ mr: 0.5, color: 'text.secondary' }} />
80
+ <Typography variant="h6" sx={{ color: 'text.secondary', fontWeight: 'normal' }}>
81
+ {t('admin.invoices')}
82
+ </Typography>
83
+ </Stack>
84
+ </Link>
85
+ <Copyable text={props.id} style={{ marginLeft: 4 }} />
86
+ </Stack>
87
+ <Box mt={2}>
88
+ <Stack direction="row" justifyContent="space-between" alignItems="center">
89
+ <Stack direction="row" alignItems="center">
90
+ <Typography variant="h5" sx={{ fontWeight: 600 }}>
91
+ {data.number}
92
+ </Typography>
93
+ <Typography sx={{ mx: 1 }}>for</Typography>
94
+ <Typography variant="h5" sx={{ fontWeight: 600 }}>
95
+ {fromUnitToToken(data.total, data.paymentCurrency.decimal)} {data.paymentCurrency.symbol}
96
+ </Typography>
97
+ <Status label={data.status} color={getInvoiceStatusColor(data.status)} sx={{ ml: 1 }} />
98
+ </Stack>
99
+ <InvoiceActions data={data} onChange={runAsync} variant="normal" />
100
+ </Stack>
101
+ </Box>
102
+ </Box>
103
+ <Box className="section">
104
+ <SectionHeader title={t('admin.details')} />
105
+ <Stack>
106
+ <InfoRow label={t('admin.invoice.number')} value={data.number} />
107
+ <InfoRow
108
+ label={t('admin.invoice.customer')}
109
+ value={<Link to={`/admin/customers/${data.customer.id}`}>{data.customer.name}</Link>}
110
+ />
111
+ <InfoRow
112
+ label={t('admin.subscription.currentPeriod')}
113
+ value={
114
+ data.period_start && data.period_end
115
+ ? [formatTime(data.period_start * 1000), formatTime(data.period_end * 1000)].join(' ~ ')
116
+ : ''
117
+ }
118
+ />
119
+ <InfoRow label={t('common.createdAt')} value={formatTime(data.created_at)} />
120
+ {data.status_transitions?.finalized_at && (
121
+ <InfoRow
122
+ label={t('admin.invoice.finalizedAt')}
123
+ value={formatTime(data.status_transitions.finalized_at * 1000)}
124
+ />
125
+ )}
126
+ {data.status_transitions?.paid_at && (
127
+ <InfoRow label={t('admin.invoice.paidAt')} value={formatTime(data.status_transitions.paid_at * 1000)} />
128
+ )}
129
+ <InfoRow label={t('admin.invoice.billing')} value={data.collection_method} />
130
+ <InfoRow
131
+ label={t('admin.paymentMethod.name')}
132
+ value={<Currency logo={data.paymentMethod.logo} name={data.paymentMethod.name} />}
133
+ />
134
+ <InfoRow
135
+ label={t('admin.paymentCurrency.name')}
136
+ value={<Currency logo={data.paymentCurrency.logo} name={data.paymentCurrency.symbol} />}
137
+ />
138
+ </Stack>
139
+ </Box>
140
+ <Box className="section">
141
+ <SectionHeader title={t('admin.summary')} mb={0} />
142
+ <Box className="section-body">
143
+ <InvoiceTable invoice={data} />
144
+ </Box>
145
+ </Box>
146
+ <Box className="section">
147
+ <SectionHeader title={t('admin.payments')} mb={0} />
148
+ <Box className="section-body">
149
+ <PaymentList features={{ customer: false, toolbar: false }} invoice_id={data.id} />
150
+ </Box>
151
+ </Box>
152
+ <Box className="section">
153
+ <SectionHeader title={t('admin.connections')} />
154
+ <Stack>
155
+ <InfoRow
156
+ label={t('admin.subscription.name')}
157
+ value={
158
+ data.subscription ? <Link to={`/admin/billing/${data.subscription.id}`}>{data.subscription.id}</Link> : ''
159
+ }
160
+ />
161
+ <InfoRow
162
+ label={t('admin.paymentIntent.name')}
163
+ value={
164
+ data.payment_intent_id ? (
165
+ <Link to={`/admin/payments/${data.payment_intent_id}`}>{data.payment_intent_id}</Link>
166
+ ) : (
167
+ ''
168
+ )
169
+ }
170
+ />
171
+ </Stack>
172
+ </Box>
173
+ <Box className="section">
174
+ <SectionHeader title={t('common.metadata.label')}>
175
+ <Button
176
+ variant="outlined"
177
+ color="inherit"
178
+ size="small"
179
+ disabled={state.editing.metadata}
180
+ onClick={() => setState((prev) => ({ editing: { ...prev.editing, metadata: true } }))}>
181
+ <Edit fontSize="small" sx={{ mr: 0.5 }} />
182
+ {t('common.metadata.edit')}
183
+ </Button>
184
+ </SectionHeader>
185
+ <Box className="section-body">
186
+ {!state.editing.metadata &&
187
+ (isEmpty(data.metadata) ? (
188
+ <Typography color="text.secondary">{t('common.metadata.empty')}</Typography>
189
+ ) : (
190
+ Object.keys(data.metadata || {}).map((key) => (
191
+ // @ts-ignore
192
+ <InfoRow key={key} label={key} value={data.metadata[key]} />
193
+ ))
194
+ ))}
195
+ {state.editing.metadata && (
196
+ <MetadataEditor
197
+ data={data}
198
+ loading={state.loading.metadata}
199
+ onSave={onUpdateMetadata}
200
+ onCancel={() => setState((prev) => ({ editing: { ...prev.editing, metadata: false } }))}
201
+ />
202
+ )}
203
+ </Box>
204
+ </Box>
205
+ <Box className="section">
206
+ <SectionHeader title={t('admin.events')} />
207
+ <Box className="section-body">
208
+ <EventList features={{ toolbar: false }} object_id={data.id} />
209
+ </Box>
210
+ </Box>
211
+ </Root>
212
+ );
213
+ }
214
+
215
+ const Root = styled(Stack)``;
@@ -0,0 +1,5 @@
1
+ import InvoiceList from '../../../../components/invoice/list';
2
+
3
+ export default function InvoicesList() {
4
+ return <InvoiceList features={{ customer: true, toolbar: true }} />;
5
+ }