payment-kit 1.18.30 → 1.18.31
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/metering-subscription-detection.ts +9 -0
- package/api/src/integrations/arcblock/nft.ts +1 -0
- package/api/src/integrations/blocklet/passport.ts +1 -1
- package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
- package/api/src/integrations/stripe/handlers/setup-intent.ts +29 -1
- package/api/src/integrations/stripe/handlers/subscription.ts +19 -15
- package/api/src/integrations/stripe/resource.ts +81 -1
- package/api/src/libs/audit.ts +42 -0
- package/api/src/libs/invoice.ts +54 -7
- package/api/src/libs/notification/index.ts +72 -4
- package/api/src/libs/notification/template/base.ts +2 -0
- package/api/src/libs/notification/template/subscription-renew-failed.ts +1 -5
- package/api/src/libs/notification/template/subscription-renewed.ts +1 -5
- package/api/src/libs/notification/template/subscription-succeeded.ts +8 -18
- package/api/src/libs/notification/template/subscription-trial-start.ts +2 -10
- package/api/src/libs/notification/template/subscription-upgraded.ts +1 -5
- package/api/src/libs/payment.ts +47 -14
- package/api/src/libs/product.ts +1 -4
- package/api/src/libs/session.ts +600 -8
- package/api/src/libs/setting.ts +172 -0
- package/api/src/libs/subscription.ts +7 -69
- package/api/src/libs/ws.ts +5 -0
- package/api/src/queues/checkout-session.ts +42 -36
- package/api/src/queues/notification.ts +3 -2
- package/api/src/queues/payment.ts +33 -6
- package/api/src/queues/usage-record.ts +2 -10
- package/api/src/routes/checkout-sessions.ts +324 -187
- package/api/src/routes/connect/shared.ts +160 -38
- package/api/src/routes/connect/subscribe.ts +123 -64
- package/api/src/routes/payment-currencies.ts +3 -6
- package/api/src/routes/payment-links.ts +11 -1
- package/api/src/routes/payment-stats.ts +2 -2
- package/api/src/routes/payouts.ts +2 -1
- package/api/src/routes/settings.ts +45 -0
- package/api/src/routes/subscriptions.ts +1 -2
- package/api/src/store/migrations/20250408-subscription-grouping.ts +39 -0
- package/api/src/store/migrations/20250419-subscription-grouping.ts +69 -0
- package/api/src/store/models/checkout-session.ts +52 -0
- package/api/src/store/models/index.ts +1 -0
- package/api/src/store/models/payment-link.ts +6 -0
- package/api/src/store/models/subscription.ts +8 -6
- package/api/src/store/models/types.ts +31 -1
- package/api/tests/libs/session.spec.ts +423 -0
- package/api/tests/libs/subscription.spec.ts +0 -110
- package/blocklet.yml +3 -1
- package/package.json +20 -19
- package/scripts/sdk.js +486 -155
- package/src/locales/en.tsx +1 -1
- package/src/locales/zh.tsx +1 -1
- package/src/pages/admin/settings/vault-config/edit-form.tsx +1 -1
- package/src/pages/customer/subscription/change-payment.tsx +8 -3
package/scripts/sdk.js
CHANGED
|
@@ -1,161 +1,492 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
// run sdk test: # pnpm run sdk-test
|
|
2
3
|
|
|
3
4
|
/* eslint-disable import/no-extraneous-dependencies */
|
|
4
5
|
/* eslint-disable no-console */
|
|
5
|
-
const
|
|
6
|
+
const { spawn } = require('child_process');
|
|
7
|
+
const payment = require('../../../packages/client/lib').default;
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
function getAppId() {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
let appId = '';
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < args.length; i++) {
|
|
14
|
+
if (args[i] === '--app-id' && i + 1 < args.length) {
|
|
15
|
+
appId = args[i + 1];
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!appId) {
|
|
21
|
+
appId =
|
|
22
|
+
process.env.BLOCKLET_DEV_APP_DID?.split(':').pop() ||
|
|
23
|
+
process.env.BLOCKLET_APP_ID ||
|
|
24
|
+
'zNKuN3XwXN7xq2NsJQjjfwujyqCxx26DhwgV';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return appId;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const checkoutModule = {
|
|
31
|
+
// 订阅级别管理通知
|
|
32
|
+
async createWithNotification() {
|
|
33
|
+
const checkoutSession = await payment.checkout.sessions.create({
|
|
34
|
+
mode: 'subscription',
|
|
35
|
+
line_items: [{ price_id: 'price_fQFIS12yi0JR3KePLmitjrhA', quantity: 1 }],
|
|
36
|
+
subscription_data: {
|
|
37
|
+
notification_settings: {
|
|
38
|
+
self_handle: true,
|
|
39
|
+
include_events: ['customer.subscription.started'],
|
|
40
|
+
},
|
|
41
|
+
no_stake: true,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
console.log('createWithNotification', checkoutSession);
|
|
45
|
+
return checkoutSession;
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// 批量订阅 + 免质押
|
|
49
|
+
async createBatchSubscription() {
|
|
50
|
+
const checkoutSession = await payment.checkout.sessions.create({
|
|
51
|
+
mode: 'subscription',
|
|
52
|
+
line_items: [
|
|
53
|
+
{
|
|
54
|
+
price_id: 'price_fQFIS12yi0JR3KePLmitjrhA',
|
|
55
|
+
quantity: 1,
|
|
56
|
+
subscription_data: {
|
|
57
|
+
metadata: { test: 'test price_fQFIS12yi0JR3KePLmitjrhA' },
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
price_id: 'price_PXyI9Duz99eqty1AqbaEc73u',
|
|
62
|
+
quantity: 1,
|
|
63
|
+
subscription_data: {
|
|
64
|
+
metadata: { test: 'test price_PXyI9Duz99eqty1AqbaEc73u' },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
enable_subscription_grouping: true,
|
|
69
|
+
subscription_data: {
|
|
70
|
+
no_stake: true,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
console.log('createBatchSubscription', checkoutSession);
|
|
74
|
+
return checkoutSession;
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// 批量订阅 + 试用 + 免质押
|
|
78
|
+
async createWithTrial() {
|
|
79
|
+
const checkoutSession = await payment.checkout.sessions.create({
|
|
80
|
+
mode: 'subscription',
|
|
81
|
+
line_items: [
|
|
82
|
+
{ price_id: 'price_dsjm7m1qzxEg370uLAjma4zS', quantity: 2 },
|
|
83
|
+
{ price_id: 'price_n9xjC3M2cILR3iWez7ToMRjd', quantity: 1 },
|
|
84
|
+
{ price_id: 'price_6P2bJXtWx8Awk65NC4f1PAsf', quantity: 1 },
|
|
85
|
+
],
|
|
86
|
+
enable_subscription_grouping: true,
|
|
87
|
+
subscription_data: {
|
|
88
|
+
no_stake: true,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
console.log('createWithTrial', checkoutSession);
|
|
92
|
+
return checkoutSession;
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
// 创建通知设置
|
|
96
|
+
async createNotificationSetting() {
|
|
97
|
+
const setting = await payment.settings.create({
|
|
98
|
+
type: 'notification',
|
|
99
|
+
mountLocation: 'core.sdk.test',
|
|
100
|
+
description: 'test',
|
|
101
|
+
settings: {
|
|
102
|
+
self_handle: true,
|
|
103
|
+
include_events: ['customer.subscription.started'],
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
console.log('createNotificationSetting', setting);
|
|
107
|
+
return setting;
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// 应用级别管理通知
|
|
111
|
+
async createCheckoutWithSettingId() {
|
|
112
|
+
// 先创建设置
|
|
113
|
+
const NOTIFICATION_MOUNT_LOCATION = 'core.sdk.test';
|
|
114
|
+
const setting = await payment.settings.create({
|
|
115
|
+
type: 'notification',
|
|
116
|
+
mountLocation: NOTIFICATION_MOUNT_LOCATION,
|
|
117
|
+
description: 'test',
|
|
118
|
+
settings: {
|
|
119
|
+
self_handle: true,
|
|
120
|
+
include_events: ['customer.subscription.started'],
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
console.log('createNotificationSetting', setting);
|
|
124
|
+
// 使用设置ID创建结账会话
|
|
125
|
+
const checkoutSession = await payment.checkout.sessions.create({
|
|
126
|
+
mode: 'subscription',
|
|
127
|
+
line_items: [{ price_id: 'price_fQFIS12yi0JR3KePLmitjrhA', quantity: 1 }],
|
|
128
|
+
metadata: {
|
|
129
|
+
setting_id: NOTIFICATION_MOUNT_LOCATION, // 也可以是 setting.id
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
console.log('createCheckoutWithSettingId', checkoutSession);
|
|
133
|
+
return { setting, checkoutSession };
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const paymentModule = {
|
|
138
|
+
// 获取支付意图
|
|
139
|
+
async retrievePaymentIntent() {
|
|
140
|
+
const paymentIntent = await payment.paymentIntents.retrieve('pi_ybTOCWweEnb9grWZsTH7MCVi');
|
|
141
|
+
console.log('retrievePaymentIntent', paymentIntent);
|
|
142
|
+
return paymentIntent;
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// === 退款相关测试 ===
|
|
146
|
+
|
|
147
|
+
// 创建退款
|
|
148
|
+
async createRefund() {
|
|
149
|
+
const paymentIntentId = 'pi_ybTOCWweEnb9grWZsTH7MCVi';
|
|
150
|
+
|
|
151
|
+
const refundResult = await payment.paymentIntents.refund(paymentIntentId, {
|
|
152
|
+
amount: '0.001',
|
|
153
|
+
reason: 'requested_by_customer',
|
|
154
|
+
description: 'Refund Test',
|
|
155
|
+
});
|
|
156
|
+
console.log('createRefund', refundResult);
|
|
157
|
+
return refundResult;
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// 获取退款详情
|
|
161
|
+
async retrieveRefund() {
|
|
162
|
+
const refund = await payment.refunds.retrieve('re_loHv143R78cSe38uGjxRBsfv');
|
|
163
|
+
console.log('retrieveRefund', refund);
|
|
164
|
+
return refund;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
// 获取退款列表
|
|
168
|
+
async listRefunds() {
|
|
169
|
+
const paymentIntentId = 'pi_ybTOCWweEnb9grWZsTH7MCVi';
|
|
170
|
+
const paymentIntent = await payment.paymentIntents.retrieve(paymentIntentId);
|
|
171
|
+
|
|
172
|
+
const refunds = await payment.refunds.list({
|
|
173
|
+
invoice_id: paymentIntent.invoice_id,
|
|
174
|
+
});
|
|
175
|
+
console.log('listRefunds', refunds);
|
|
176
|
+
return refunds;
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
// 创建自定义退款
|
|
180
|
+
async createCustomRefund() {
|
|
181
|
+
const paymentIntentId = 'pi_ybTOCWweEnb9grWZsTH7MCVi';
|
|
182
|
+
const paymentIntent = await payment.paymentIntents.retrieve(paymentIntentId);
|
|
183
|
+
|
|
184
|
+
const refundData = {
|
|
185
|
+
amount: '0.001',
|
|
186
|
+
reason: 'requested_by_admin',
|
|
187
|
+
description: 'Custom Refund Test',
|
|
188
|
+
invoice_id: paymentIntent.invoice_id,
|
|
189
|
+
payment_intent_id: paymentIntent.id,
|
|
190
|
+
currency_id: paymentIntent.currency_id,
|
|
191
|
+
payment_method_id: paymentIntent.payment_method_id,
|
|
192
|
+
customer_id: paymentIntent.customer_id,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const customRefund = await payment.refunds.create(refundData);
|
|
196
|
+
console.log('createCustomRefund', customRefund);
|
|
197
|
+
return customRefund;
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// 完整支付和退款流程
|
|
201
|
+
async paymentAndRefundFlow() {
|
|
202
|
+
// 注意:测试中使用已有的支付意图,实际应用中应先创建支付意图
|
|
203
|
+
const paymentIntentId = 'pi_ybTOCWweEnb9grWZsTH7MCVi';
|
|
204
|
+
const paymentIntent = await payment.paymentIntents.retrieve(paymentIntentId);
|
|
205
|
+
|
|
206
|
+
const partialRefund = await payment.paymentIntents.refund(paymentIntentId, {
|
|
207
|
+
amount: '0.0005', // 部分金额
|
|
208
|
+
reason: 'requested_by_customer',
|
|
209
|
+
description: 'Partial Refund Test',
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const refunds = await payment.refunds.list({
|
|
213
|
+
invoice_id: paymentIntent.invoice_id,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
console.log('paymentAndRefundFlow', {
|
|
217
|
+
paymentIntent,
|
|
218
|
+
partialRefund,
|
|
219
|
+
refundsList: refunds,
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
paymentIntent,
|
|
223
|
+
partialRefund,
|
|
224
|
+
refundsList: refunds,
|
|
225
|
+
};
|
|
226
|
+
},
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const productModule = {
|
|
230
|
+
// 创建单个产品
|
|
231
|
+
async createProduct() {
|
|
232
|
+
const product = await payment.products.create({
|
|
233
|
+
name: 'Test SDK product',
|
|
234
|
+
description: 'test',
|
|
235
|
+
});
|
|
236
|
+
console.log('createProduct', product);
|
|
237
|
+
return product;
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
// === 价格相关测试 ===
|
|
241
|
+
|
|
242
|
+
// 方式1:创建产品时一并创建价格
|
|
243
|
+
async createProductWithPrice() {
|
|
244
|
+
const product = await payment.products.create({
|
|
245
|
+
name: 'Test One-time Price Product',
|
|
246
|
+
description: 'Product for one-time price test',
|
|
247
|
+
type: 'good',
|
|
248
|
+
prices: [
|
|
249
|
+
{
|
|
250
|
+
type: 'one_time',
|
|
251
|
+
unit_amount: '1',
|
|
252
|
+
currency_id: 'pc_9l5sh8bcjbLU',
|
|
253
|
+
lookup_key: 'test_one_time_price',
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
});
|
|
257
|
+
console.log('createProductWithPrice', product);
|
|
258
|
+
return product;
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// 方式2:先创建产品,再创建价格
|
|
262
|
+
async createOneTimePrice() {
|
|
263
|
+
const product = await payment.products.create({
|
|
264
|
+
name: 'Test Separate Price Product',
|
|
265
|
+
description: 'Product for separate price creation test',
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const price = await payment.prices.create({
|
|
269
|
+
product_id: product.id,
|
|
270
|
+
type: 'one_time',
|
|
271
|
+
unit_amount: '1',
|
|
272
|
+
currency_id: 'pc_9l5sh8bcjbLU',
|
|
273
|
+
});
|
|
274
|
+
console.log('createOneTimePrice', { product, price });
|
|
275
|
+
return { product, price };
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
// 创建循环订阅价格
|
|
279
|
+
async createRecurringPrice() {
|
|
280
|
+
const productId = 'prod_Acj9sSjFaABVQm'; // 使用已存在的产品ID
|
|
281
|
+
|
|
282
|
+
const price = await payment.prices.create({
|
|
283
|
+
locked: false,
|
|
284
|
+
model: 'standard',
|
|
285
|
+
billing_scheme: '',
|
|
286
|
+
currency_id: 'pc_aW2zy2y8yoi7',
|
|
287
|
+
nickname: '',
|
|
288
|
+
type: 'recurring',
|
|
289
|
+
unit_amount: '0.001',
|
|
290
|
+
lookup_key: '',
|
|
291
|
+
recurring: {
|
|
292
|
+
interval_config: 'month_1',
|
|
293
|
+
interval: 'month',
|
|
294
|
+
interval_count: 1,
|
|
295
|
+
usage_type: 'licensed',
|
|
296
|
+
aggregate_usage: 'sum',
|
|
297
|
+
},
|
|
298
|
+
transform_quantity: { divide_by: 1, round: 'up' },
|
|
299
|
+
tiers: [],
|
|
300
|
+
metadata: [],
|
|
301
|
+
custom_unit_amount: null,
|
|
302
|
+
currency_options: [],
|
|
303
|
+
tiers_mode: null,
|
|
304
|
+
quantity_available: 10,
|
|
305
|
+
quantity_limit_per_checkout: '2',
|
|
306
|
+
product_id: productId,
|
|
307
|
+
});
|
|
308
|
+
console.log('createRecurringPrice', price);
|
|
309
|
+
return price;
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
// 价格库存管理
|
|
313
|
+
async updateInventory() {
|
|
314
|
+
const inventoryPrice = await payment.prices.inventory('price_xUd1QXTwhoIdOfHa9WT6MdBe', {
|
|
315
|
+
quantity: 1,
|
|
316
|
+
action: 'decrement',
|
|
317
|
+
});
|
|
318
|
+
console.log('updateInventory', inventoryPrice);
|
|
319
|
+
return inventoryPrice;
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
// 完整流程:展示两种创建方式
|
|
323
|
+
async createProductWithPrices() {
|
|
324
|
+
// 方式1:内联价格
|
|
325
|
+
const productWithInlinePrices = await payment.products.create({
|
|
326
|
+
name: 'Product with Inline Prices',
|
|
327
|
+
description: 'Product with prices defined inline',
|
|
328
|
+
prices: [
|
|
329
|
+
{
|
|
330
|
+
type: 'one_time',
|
|
331
|
+
unit_amount: '15',
|
|
332
|
+
currency_id: 'pc_9l5sh8bcjbLU',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
type: 'recurring',
|
|
336
|
+
unit_amount: '7.5',
|
|
337
|
+
currency_id: 'pc_aW2zy2y8yoi7',
|
|
338
|
+
recurring: {
|
|
339
|
+
interval_config: 'month_1',
|
|
340
|
+
interval: 'month',
|
|
341
|
+
interval_count: 1,
|
|
342
|
+
usage_type: 'licensed',
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// 方式2:分步创建
|
|
349
|
+
const product = await payment.products.create({
|
|
350
|
+
name: 'Product with Separate Prices',
|
|
351
|
+
description: 'Product with separately defined prices',
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const oneTimePrice = await payment.prices.create({
|
|
355
|
+
product_id: product.id,
|
|
356
|
+
type: 'one_time',
|
|
357
|
+
unit_amount: '10',
|
|
358
|
+
currency_id: 'pc_9l5sh8bcjbLU',
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const subscriptionPrice = await payment.prices.create({
|
|
362
|
+
product_id: product.id,
|
|
363
|
+
type: 'recurring',
|
|
364
|
+
unit_amount: '5',
|
|
365
|
+
currency_id: 'pc_aW2zy2y8yoi7',
|
|
366
|
+
recurring: {
|
|
367
|
+
interval_config: 'month_1',
|
|
368
|
+
interval: 'month',
|
|
369
|
+
interval_count: 1,
|
|
370
|
+
usage_type: 'licensed',
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
console.log('createProductWithPrices', {
|
|
374
|
+
inlineMethod: productWithInlinePrices,
|
|
375
|
+
separateMethod: {
|
|
376
|
+
product,
|
|
377
|
+
prices: {
|
|
378
|
+
oneTime: oneTimePrice,
|
|
379
|
+
subscription: subscriptionPrice,
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
return {
|
|
384
|
+
inlineMethod: productWithInlinePrices,
|
|
385
|
+
separateMethod: {
|
|
386
|
+
product,
|
|
387
|
+
prices: {
|
|
388
|
+
oneTime: oneTimePrice,
|
|
389
|
+
subscription: subscriptionPrice,
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const subscriptionModule = {
|
|
397
|
+
// 获取所有订阅
|
|
398
|
+
async listSubscriptions() {
|
|
399
|
+
const subscriptions = await payment.subscriptions.list({
|
|
400
|
+
order: 'updated_at:ASC',
|
|
401
|
+
// 支持Sequelize排序格式
|
|
402
|
+
// order: [
|
|
403
|
+
// ['status', 'DESC'],
|
|
404
|
+
// ['updated_at', 'ASC'],
|
|
405
|
+
// ],
|
|
406
|
+
activeFirst: true,
|
|
407
|
+
});
|
|
408
|
+
console.log('listSubscriptions', subscriptions);
|
|
409
|
+
return subscriptions;
|
|
410
|
+
},
|
|
411
|
+
|
|
412
|
+
// 上报用量
|
|
413
|
+
async createUsageRecord() {
|
|
414
|
+
const record = {
|
|
415
|
+
subscription_item_id: 'si_Tq4c2KsC40uPq7',
|
|
416
|
+
quantity: 1,
|
|
417
|
+
action: 'increment',
|
|
418
|
+
livemode: false,
|
|
419
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const result = await payment.subscriptionItems.createUsageRecord(record);
|
|
423
|
+
console.log('createUsageRecord', result);
|
|
424
|
+
return result;
|
|
425
|
+
},
|
|
426
|
+
|
|
427
|
+
// 并发上报
|
|
428
|
+
async createBatchUsageRecords() {
|
|
429
|
+
const records = [
|
|
430
|
+
{
|
|
431
|
+
subscription_item_id: 'si_Tq4c2KsC40uPq7',
|
|
432
|
+
quantity: 1,
|
|
433
|
+
action: 'increment',
|
|
434
|
+
livemode: false,
|
|
435
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
subscription_item_id: 'si_Tq4c2KsC40uPq7',
|
|
439
|
+
quantity: 2,
|
|
440
|
+
action: 'increment',
|
|
441
|
+
livemode: false,
|
|
442
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
443
|
+
},
|
|
444
|
+
];
|
|
445
|
+
|
|
446
|
+
const results = await Promise.allSettled(
|
|
447
|
+
records.map((record) => payment.subscriptionItems.createUsageRecord(record))
|
|
448
|
+
);
|
|
449
|
+
console.log('createBatchUsageRecords', results);
|
|
450
|
+
return results;
|
|
451
|
+
},
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// 测试模块注册
|
|
455
|
+
const testModules = {
|
|
456
|
+
checkout: checkoutModule,
|
|
457
|
+
payment: paymentModule,
|
|
458
|
+
product: productModule,
|
|
459
|
+
subscription: subscriptionModule,
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
async function runTest() {
|
|
8
463
|
payment.environments.setTestMode(true);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
464
|
+
await testModules.checkout.createBatchSubscription();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
async function main() {
|
|
468
|
+
if (process.env.BLOCKLET_APP_ID) {
|
|
469
|
+
await runTest();
|
|
470
|
+
process.exit(0);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const appId = getAppId();
|
|
474
|
+
const args = process.argv.slice(2).filter((arg) => arg !== '--app-id' && arg !== appId);
|
|
475
|
+
|
|
476
|
+
console.log(`Running with blocklet exec, app-id: ${appId}`);
|
|
477
|
+
|
|
478
|
+
const child = spawn('blocklet', ['exec', '/scripts/sdk.js', '--app-id', appId, ...args], {
|
|
479
|
+
stdio: 'inherit',
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
child.on('exit', (code) => {
|
|
483
|
+
process.exit(code || 0);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (require.main === module) {
|
|
488
|
+
main().catch((error) => {
|
|
489
|
+
console.error('Error:', error);
|
|
490
|
+
process.exit(1);
|
|
16
491
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// const paymentIntent = await payment.paymentIntents.retrieve('pi_ybTOCWweEnb9grWZsTH7MCVi');
|
|
20
|
-
|
|
21
|
-
// console.log('paymentIntent', paymentIntent);
|
|
22
|
-
|
|
23
|
-
// const refundResult = await payment.paymentIntents.refund('pi_ybTOCWweEnb9grWZsTH7MCVi', {
|
|
24
|
-
// amount: '0.001',
|
|
25
|
-
// reason: 'requested_by_customer',
|
|
26
|
-
// description: 'Refund Test',
|
|
27
|
-
// });
|
|
28
|
-
// console.log('refundResult', refundResult);
|
|
29
|
-
|
|
30
|
-
// const refund = await payment.refunds.retrieve('re_loHv143R78cSe38uGjxRBsfv');
|
|
31
|
-
// console.log('🚀 ~ refund:', refund);
|
|
32
|
-
|
|
33
|
-
// const refunds = await payment.refunds.list({
|
|
34
|
-
// invoice_id: paymentIntent.invoice_id,
|
|
35
|
-
// });
|
|
36
|
-
// console.log('🚀 ~ refunds:', refunds);
|
|
37
|
-
|
|
38
|
-
// const customRefundResult = await payment.refunds.create({
|
|
39
|
-
// amount: '0.001',
|
|
40
|
-
// reason: 'requested_by_admin',
|
|
41
|
-
// description: 'Custom Refund Test',
|
|
42
|
-
// invoice_id: paymentIntent.invoice_id,
|
|
43
|
-
// payment_intent_id: paymentIntent.id,
|
|
44
|
-
// currency_id: paymentIntent.currency_id,
|
|
45
|
-
// payment_method_id: paymentIntent.payment_method_id,
|
|
46
|
-
// customer_id: paymentIntent.customer_id,
|
|
47
|
-
// });
|
|
48
|
-
// console.log('🚀 ~ customRefundResult:', customRefundResult);
|
|
49
|
-
|
|
50
|
-
// const price = await payment.prices.create({
|
|
51
|
-
// locked: false,
|
|
52
|
-
// model: 'standard',
|
|
53
|
-
// billing_scheme: '',
|
|
54
|
-
// currency_id: 'pc_aW2zy2y8yoi7',
|
|
55
|
-
// nickname: '',
|
|
56
|
-
// type: 'recurring',
|
|
57
|
-
// unit_amount: '0.001',
|
|
58
|
-
// lookup_key: '',
|
|
59
|
-
// recurring: {
|
|
60
|
-
// interval_config: 'month_1',
|
|
61
|
-
// interval: 'month',
|
|
62
|
-
// interval_count: 1,
|
|
63
|
-
// usage_type: 'licensed',
|
|
64
|
-
// aggregate_usage: 'sum',
|
|
65
|
-
// },
|
|
66
|
-
// transform_quantity: { divide_by: 1, round: 'up' },
|
|
67
|
-
// tiers: [],
|
|
68
|
-
// metadata: [],
|
|
69
|
-
// custom_unit_amount: null,
|
|
70
|
-
// currency_options: [],
|
|
71
|
-
// tiers_mode: null,
|
|
72
|
-
// quantity_available: 10,
|
|
73
|
-
// quantity_limit_per_checkout: '2',
|
|
74
|
-
// product_id: 'prod_Acj9sSjFaABVQm',
|
|
75
|
-
// });
|
|
76
|
-
// console.log('🚀 ~ price:', price);
|
|
77
|
-
// const inventoryPrice = await payment.prices.inventory('price_xUd1QXTwhoIdOfHa9WT6MdBe', {
|
|
78
|
-
// quantity: 1,
|
|
79
|
-
// action: 'decrement',
|
|
80
|
-
// });
|
|
81
|
-
// console.log('inventoryPrice', inventoryPrice);
|
|
82
|
-
|
|
83
|
-
// const checkoutSession = await payment.checkout.sessions.create({
|
|
84
|
-
// success_url:
|
|
85
|
-
// 'https://bbqa2t5pfyfroyobmzknmktshckzto4btkfagxyjqwy.did.abtnet.io/store/api/payment/success?redirect=https://bbqa2t5pfyfroyobmzknmktshckzto4btkfagxyjqwy.did.abtnet.io/maker/mint/z3CtLCSchoZj4H5gqwyATSAEdvfd1m88VnDUZ',
|
|
86
|
-
// cancel_url:
|
|
87
|
-
// 'https://bbqa2t5pfyfroyobmzknmktshckzto4btkfagxyjqwy.did.abtnet.io/store/api/payment/cancel?redirect=https://bbqa2t5pfyfroyobmzknmktshckzto4btkfagxyjqwy.did.abtnet.io/maker/mint/z3CtLCSchoZj4H5gqwyATSAEdvfd1m88VnDUZ',
|
|
88
|
-
// mode: 'payment',
|
|
89
|
-
// line_items: [
|
|
90
|
-
// { price_id: 'price_G7TE6QZbvqkIaqzDJVb2afws', quantity: 2 },
|
|
91
|
-
// { price_id: 'price_rOUdD9fQrBGqn6M3YywXdDeK', quantity: 2 },
|
|
92
|
-
// ],
|
|
93
|
-
// subscription_data: {
|
|
94
|
-
// service_actions: [
|
|
95
|
-
// {
|
|
96
|
-
// type: 'notification',
|
|
97
|
-
// text: {
|
|
98
|
-
// zh: '查看文档',
|
|
99
|
-
// en: 'View Documentation',
|
|
100
|
-
// },
|
|
101
|
-
// link: 'https://www.arcblock.io/docs/createblocklet/en/quick-start',
|
|
102
|
-
// triggerEvents: ['customer.subscription.started', 'customer.subscription.deleted'],
|
|
103
|
-
// },
|
|
104
|
-
// {
|
|
105
|
-
// type: 'notification',
|
|
106
|
-
// text: {
|
|
107
|
-
// zh: '社区提问',
|
|
108
|
-
// en: 'Ask in Community',
|
|
109
|
-
// },
|
|
110
|
-
// link: 'https://community.arcblock.io/?locale=en',
|
|
111
|
-
// triggerEvents: ['customer.subscription.started', 'customer.subscription.renewed'],
|
|
112
|
-
// },
|
|
113
|
-
// {
|
|
114
|
-
// type: 'custom',
|
|
115
|
-
// text: {
|
|
116
|
-
// zh: '查看',
|
|
117
|
-
// en: 'View',
|
|
118
|
-
// },
|
|
119
|
-
// link: 'https://www.arcblock.io/docs/createblocklet/en/quick-start',
|
|
120
|
-
// color: 'primary',
|
|
121
|
-
// variant: 'outlined',
|
|
122
|
-
// },
|
|
123
|
-
// ],
|
|
124
|
-
// },
|
|
125
|
-
// expires_at: 1729243800,
|
|
126
|
-
// });
|
|
127
|
-
// console.log('checkoutSession', checkoutSession);
|
|
128
|
-
// const product = await payment.products.create({
|
|
129
|
-
// name: 'Test SDK product',
|
|
130
|
-
// description: 'test',
|
|
131
|
-
// });
|
|
132
|
-
// console.log('🚀 ~ product:', product);
|
|
133
|
-
// const paymentPrice = await payment.prices.create({
|
|
134
|
-
// product_id: product.id,
|
|
135
|
-
// type: 'one_time',
|
|
136
|
-
// unit_amount: '1',
|
|
137
|
-
// currency_id: 'pc_9l5sh8bcjbLU',
|
|
138
|
-
// });
|
|
139
|
-
// console.log('🚀 ~ paymentPrice:', paymentPrice);
|
|
140
|
-
|
|
141
|
-
// 测试下并发上报
|
|
142
|
-
// const promises = [
|
|
143
|
-
// {
|
|
144
|
-
// subscription_item_id: 'si_Tq4c2KsC40uPq7',
|
|
145
|
-
// quantity: 1,
|
|
146
|
-
// action: 'increment',
|
|
147
|
-
// livemode: false,
|
|
148
|
-
// timestamp: 1730692388,
|
|
149
|
-
// },
|
|
150
|
-
// // {
|
|
151
|
-
// // subscription_item_id: 'si_Tq4c2KsC40uPq7',
|
|
152
|
-
// // quantity: 2,
|
|
153
|
-
// // action: 'increment',
|
|
154
|
-
// // livemode: false,
|
|
155
|
-
// // timestamp: 1730692388,
|
|
156
|
-
// // },
|
|
157
|
-
// ];
|
|
158
|
-
// const results = await Promise.allSettled(promises.map((p) => payment.subscriptionItems.createUsageRecord(p)));
|
|
159
|
-
// console.log('🚀 ~ results:', results);
|
|
160
|
-
process.exit(0);
|
|
161
|
-
})();
|
|
492
|
+
}
|
package/src/locales/en.tsx
CHANGED
|
@@ -762,7 +762,7 @@ export default flat({
|
|
|
762
762
|
bufferThreshold: 'Buffer Threshold',
|
|
763
763
|
bufferThresholdHelp:
|
|
764
764
|
'Only when the amount exceeding the deposit threshold reaches the buffer threshold will the collection operation be triggered.',
|
|
765
|
-
bufferThresholdInvalid: 'Buffer threshold must be greater than 0',
|
|
765
|
+
bufferThresholdInvalid: 'Buffer threshold must be greater than or equal to 0',
|
|
766
766
|
edit: 'Configure',
|
|
767
767
|
enable: 'Enable',
|
|
768
768
|
editTitle: 'Configure {currency} Vault Settings',
|
package/src/locales/zh.tsx
CHANGED
|
@@ -743,7 +743,7 @@ export default flat({
|
|
|
743
743
|
withdrawThreshold: '提取阈值',
|
|
744
744
|
bufferThreshold: '差额阈值',
|
|
745
745
|
bufferThresholdHelp: '只有当超出存入阈值的金额达到差额阈值时,才会触发归集操作.',
|
|
746
|
-
bufferThresholdInvalid: '
|
|
746
|
+
bufferThresholdInvalid: '差额阈值不能小于0',
|
|
747
747
|
edit: '配置',
|
|
748
748
|
enable: '启用',
|
|
749
749
|
editTitle: '配置 {currency} 冷钱包设置',
|
|
@@ -220,7 +220,7 @@ function EditForm({ item, onClose, onSuccess, isOwner }: EditFormProps) {
|
|
|
220
220
|
rules={{
|
|
221
221
|
required: true,
|
|
222
222
|
validate: (value) => {
|
|
223
|
-
if (Number(value)
|
|
223
|
+
if (Number(value) < 0) {
|
|
224
224
|
return t('admin.vaultConfig.bufferThresholdInvalid');
|
|
225
225
|
}
|
|
226
226
|
const validPrecision = formatAmountPrecisionLimit(value.toString(), locale, item.decimal || 6);
|
|
@@ -242,11 +242,16 @@ function CustomerSubscriptionChangePayment({ subscription, customer, onComplete
|
|
|
242
242
|
<Controller
|
|
243
243
|
name="payment_currency"
|
|
244
244
|
control={control}
|
|
245
|
-
render={() => (
|
|
245
|
+
render={({ field }) => (
|
|
246
246
|
<CurrencySelector
|
|
247
|
-
value={
|
|
247
|
+
value={field.value}
|
|
248
248
|
currencies={currencies}
|
|
249
|
-
onChange={
|
|
249
|
+
onChange={(currencyId: string) => {
|
|
250
|
+
const index = currencies.findIndex((x) => x.id === currencyId);
|
|
251
|
+
if (index >= 0) {
|
|
252
|
+
setSelectedCurrencyIndex(index);
|
|
253
|
+
}
|
|
254
|
+
}}
|
|
250
255
|
/>
|
|
251
256
|
)}
|
|
252
257
|
/>
|