payment-kit 1.13.88 → 1.13.90
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/integrations/stripe/handlers/setup-intent.ts +1 -1
- package/api/src/libs/audit.ts +2 -2
- package/api/src/libs/session.ts +2 -1
- package/api/src/queues/invoice.ts +1 -1
- package/api/src/queues/notification.ts +8 -9
- package/api/src/queues/payment.ts +12 -13
- package/api/src/routes/connect/collect.ts +6 -2
- package/api/src/routes/subscriptions.ts +5 -4
- package/api/src/store/models/subscription.ts +21 -0
- package/blocklet.yml +1 -1
- package/package.json +20 -20
|
@@ -19,7 +19,7 @@ export async function handleSetupIntentEvent(event: TEventExpanded, _: Stripe) {
|
|
|
19
19
|
|
|
20
20
|
if (event.type === 'setup_intent.succeeded') {
|
|
21
21
|
if (subscription.status === 'incomplete') {
|
|
22
|
-
await subscription.
|
|
22
|
+
await subscription.start();
|
|
23
23
|
logger.info('subscription become active on stripe intent succeeded', subscription.id);
|
|
24
24
|
}
|
|
25
25
|
|
package/api/src/libs/audit.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { events } from './event';
|
|
|
7
7
|
|
|
8
8
|
const API_VERSION = '2023-09-05';
|
|
9
9
|
|
|
10
|
-
export async function createEvent(scope: string, type: LiteralUnion<EventType, string>, model: any, options: any) {
|
|
10
|
+
export async function createEvent(scope: string, type: LiteralUnion<EventType, string>, model: any, options: any = {}) {
|
|
11
11
|
// console.log('createEvent', scope, type, model, options);
|
|
12
12
|
const data: any = {
|
|
13
13
|
object: model.dataValues,
|
|
@@ -44,7 +44,7 @@ export async function createStatusEvent(
|
|
|
44
44
|
prefix: string,
|
|
45
45
|
config: Record<string, string>,
|
|
46
46
|
model: any,
|
|
47
|
-
options: any
|
|
47
|
+
options: any = {}
|
|
48
48
|
) {
|
|
49
49
|
// console.log('createStatusEvent', scope, prefix, config, model, options);
|
|
50
50
|
if (options.fields.includes('status') === false) {
|
package/api/src/libs/session.ts
CHANGED
|
@@ -298,6 +298,7 @@ export function getFastCheckoutAmount(
|
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
const { total, renew } = getCheckoutAmount(items, currencyId, includeFreeTrial);
|
|
301
|
+
|
|
301
302
|
if (mode === 'payment') {
|
|
302
303
|
return total;
|
|
303
304
|
}
|
|
@@ -307,7 +308,7 @@ export function getFastCheckoutAmount(
|
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
if (mode === 'subscription') {
|
|
310
|
-
return new BN(total).add(new BN(renew).mul(new BN(minimumCycle - 1))).toString();
|
|
311
|
+
return new BN(total).add(new BN(renew).mul(new BN(includeFreeTrial ? minimumCycle : minimumCycle - 1))).toString();
|
|
311
312
|
}
|
|
312
313
|
|
|
313
314
|
return '0';
|
|
@@ -58,7 +58,7 @@ export const handleInvoice = async (job: InvoiceJob) => {
|
|
|
58
58
|
if (invoice.subscription_id) {
|
|
59
59
|
const subscription = await Subscription.findByPk(invoice.subscription_id);
|
|
60
60
|
if (subscription && subscription.status === 'incomplete') {
|
|
61
|
-
await subscription.
|
|
61
|
+
await subscription.start();
|
|
62
62
|
logger.info('invoice subscription updated', subscription.id);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -26,9 +26,8 @@ import {
|
|
|
26
26
|
SubscriptionWillRenewEmailTemplate,
|
|
27
27
|
SubscriptionWillRenewEmailTemplateOptions,
|
|
28
28
|
} from '../libs/notification/template/subscription-will-renew';
|
|
29
|
-
import type { SufficientForPaymentResult } from '../libs/payment';
|
|
30
29
|
import createQueue from '../libs/queue';
|
|
31
|
-
import
|
|
30
|
+
import { EventType, Invoice, Subscription } from '../store/models';
|
|
32
31
|
|
|
33
32
|
export type NotificationQueueJobOptions = any;
|
|
34
33
|
export type NotificationQueueJob = {
|
|
@@ -113,30 +112,30 @@ export async function startNotificationQueue() {
|
|
|
113
112
|
}
|
|
114
113
|
});
|
|
115
114
|
|
|
116
|
-
events.on('customer.subscription.renewed', (subscription: Subscription
|
|
115
|
+
events.on('customer.subscription.renewed', (subscription: Subscription) => {
|
|
117
116
|
notificationQueue.push({
|
|
118
117
|
job: {
|
|
119
118
|
type: 'customer.subscription.renewed',
|
|
120
119
|
options: {
|
|
121
120
|
subscriptionId: subscription.id,
|
|
122
|
-
invoiceId:
|
|
121
|
+
invoiceId: subscription.latest_invoice_id,
|
|
123
122
|
} as SubscriptionRenewedEmailTemplateOptions,
|
|
124
123
|
},
|
|
125
124
|
});
|
|
126
125
|
});
|
|
127
126
|
|
|
128
|
-
events.on(
|
|
129
|
-
|
|
130
|
-
(
|
|
127
|
+
events.on('customer.subscription.renew_failed', async (subscription: Subscription) => {
|
|
128
|
+
const invoice = await Invoice.findByPk(subscription.latest_invoice_id);
|
|
129
|
+
if (invoice && subscription.metadata.renew_failed_reason) {
|
|
131
130
|
notificationQueue.push({
|
|
132
131
|
job: {
|
|
133
132
|
type: 'customer.subscription.renew_failed',
|
|
134
133
|
options: {
|
|
135
134
|
invoice,
|
|
136
|
-
result,
|
|
135
|
+
result: subscription.metadata.renew_failed_reason,
|
|
137
136
|
},
|
|
138
137
|
},
|
|
139
138
|
});
|
|
140
139
|
}
|
|
141
|
-
);
|
|
140
|
+
});
|
|
142
141
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ensureStakedForGas } from '../integrations/blockchain/stake';
|
|
2
|
+
import { createEvent } from '../libs/audit';
|
|
2
3
|
import { wallet } from '../libs/auth';
|
|
3
4
|
import dayjs from '../libs/dayjs';
|
|
4
5
|
import CustomError from '../libs/error';
|
|
@@ -60,14 +61,7 @@ export const handlePaymentSucceed = async (paymentIntent: PaymentIntent, invoice
|
|
|
60
61
|
const subscription = await Subscription.findByPk(invoice.subscription_id);
|
|
61
62
|
if (subscription) {
|
|
62
63
|
if (subscription.status === 'incomplete') {
|
|
63
|
-
await subscription.
|
|
64
|
-
|
|
65
|
-
if (subscription.trail_end) {
|
|
66
|
-
events.emit('customer.subscription.trial_start', subscription);
|
|
67
|
-
} else {
|
|
68
|
-
events.emit('customer.subscription.started', subscription);
|
|
69
|
-
}
|
|
70
|
-
|
|
64
|
+
await subscription.start();
|
|
71
65
|
logger.info(`Subscription ${subscription.id} updated on payment done ${invoice.id}`);
|
|
72
66
|
} else if (subscription.status === 'past_due') {
|
|
73
67
|
if (subscription.cancel_at_period_end && subscription.cancelation_details?.reason === 'payment_failed') {
|
|
@@ -82,7 +76,7 @@ export const handlePaymentSucceed = async (paymentIntent: PaymentIntent, invoice
|
|
|
82
76
|
}
|
|
83
77
|
|
|
84
78
|
if (invoice.billing_reason === 'subscription_cycle') {
|
|
85
|
-
|
|
79
|
+
createEvent('Subscription', 'customer.subscription.renewed', subscription).catch(console.error);
|
|
86
80
|
}
|
|
87
81
|
}
|
|
88
82
|
|
|
@@ -412,10 +406,15 @@ export const handlePayment = async (job: PaymentJob) => {
|
|
|
412
406
|
|
|
413
407
|
// 只有在重试次数超过阈值的时候才发送邮件,不然邮件频率太高了,初次邮件时首次失败 6 小时后
|
|
414
408
|
if (attemptCount >= MIN_RETRY_MAIL && invoice.billing_reason === 'subscription_cycle') {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
409
|
+
const subscription = await Subscription.findByPk(invoice.subscription_id);
|
|
410
|
+
if (subscription) {
|
|
411
|
+
await subscription.update({
|
|
412
|
+
metadata: Object.assign(subscription.metadata, {
|
|
413
|
+
renew_failed_reason: result || { sufficient: false, reason: 'TX_SEND_FAILED' },
|
|
414
|
+
}),
|
|
415
|
+
});
|
|
416
|
+
createEvent('Subscription', 'customer.subscription.renew_failed', subscription);
|
|
417
|
+
}
|
|
419
418
|
}
|
|
420
419
|
|
|
421
420
|
const updates = await handlePaymentFailed(paymentIntent, invoice, error);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Transaction, TransferV3Tx } from '@ocap/client';
|
|
2
2
|
import { fromAddress } from '@ocap/wallet';
|
|
3
3
|
|
|
4
|
+
import { createEvent } from '../../libs/audit';
|
|
4
5
|
import type { CallbackArgs } from '../../libs/auth';
|
|
5
6
|
import { wallet } from '../../libs/auth';
|
|
6
|
-
import { events } from '../../libs/event';
|
|
7
7
|
import { getGasPayerExtra } from '../../libs/payment';
|
|
8
8
|
import { getTxMetadata } from '../../libs/util';
|
|
9
9
|
import { invoiceQueue } from '../../queues/invoice';
|
|
@@ -101,7 +101,11 @@ export default {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
if (invoice.subscription_id) {
|
|
104
|
-
|
|
104
|
+
createEvent(
|
|
105
|
+
'Subscription',
|
|
106
|
+
'customer.subscription.renewed',
|
|
107
|
+
await Subscription.findByPk(invoice.subscription_id)
|
|
108
|
+
);
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
return { hash: txHash };
|
|
@@ -458,10 +458,6 @@ router.put('/:id', auth, async (req, res) => {
|
|
|
458
458
|
updates.proration_behavior = req.body.proration_behavior;
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
const lastInvoice = await Invoice.findByPk(subscription.latest_invoice_id);
|
|
462
|
-
if (!lastInvoice) {
|
|
463
|
-
throw new Error('Subscription should have latest invoice');
|
|
464
|
-
}
|
|
465
461
|
const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
|
|
466
462
|
if (!paymentCurrency) {
|
|
467
463
|
throw new Error('Subscription should have payment currency');
|
|
@@ -562,6 +558,11 @@ router.put('/:id', auth, async (req, res) => {
|
|
|
562
558
|
// handle proration
|
|
563
559
|
const prorationBehavior = updates.proration_behavior || subscription.proration_behavior || 'none';
|
|
564
560
|
if (prorationBehavior === 'create_prorations') {
|
|
561
|
+
const lastInvoice = await Invoice.findByPk(subscription.latest_invoice_id);
|
|
562
|
+
if (!lastInvoice) {
|
|
563
|
+
throw new Error('Subscription should have latest invoice');
|
|
564
|
+
}
|
|
565
|
+
|
|
565
566
|
// 0. get last invoice, and invoice items, filter invoice items that are in licensed recurring mode
|
|
566
567
|
const invoiceItems = await InvoiceItem.findAll({ where: { invoice_id: lastInvoice.id } });
|
|
567
568
|
const invoiceItemsExpanded = await Price.expand(invoiceItems.map((x) => x.toJSON()));
|
|
@@ -4,6 +4,7 @@ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes,
|
|
|
4
4
|
import type { LiteralUnion } from 'type-fest';
|
|
5
5
|
|
|
6
6
|
import { createCustomEvent, createEvent, createStatusEvent } from '../../libs/audit';
|
|
7
|
+
import logger from '../../libs/logger';
|
|
7
8
|
import { createIdGenerator } from '../../libs/util';
|
|
8
9
|
import { Invoice } from './invoice';
|
|
9
10
|
import type { PaymentDetails, PaymentSettings, PriceRecurring } from './types';
|
|
@@ -358,6 +359,26 @@ export class Subscription extends Model<InferAttributes<Subscription>, InferCrea
|
|
|
358
359
|
public isActive() {
|
|
359
360
|
return ['active', 'trialing'].includes(this.status);
|
|
360
361
|
}
|
|
362
|
+
|
|
363
|
+
public async start() {
|
|
364
|
+
if (this.isActive()) {
|
|
365
|
+
logger.warn(`subscription already started: ${this.id}`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (this.isImmutable()) {
|
|
370
|
+
logger.warn(`subscription is immutable: ${this.id}`);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (this.trail_end) {
|
|
375
|
+
await this.update({ status: 'trialing' });
|
|
376
|
+
createEvent('Subscription', 'customer.subscription.trial_start', this).catch(console.error);
|
|
377
|
+
} else {
|
|
378
|
+
await this.update({ status: 'active' });
|
|
379
|
+
createEvent('Subscription', 'customer.subscription.started', this).catch(console.error);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
361
382
|
}
|
|
362
383
|
|
|
363
384
|
export type TSubscription = InferAttributes<Subscription>;
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.90",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -42,27 +42,27 @@
|
|
|
42
42
|
]
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@abtnode/cron": "1.16.21
|
|
46
|
-
"@arcblock/did": "^1.18.
|
|
45
|
+
"@abtnode/cron": "1.16.21",
|
|
46
|
+
"@arcblock/did": "^1.18.108",
|
|
47
47
|
"@arcblock/did-auth-storage-nedb": "^1.7.1",
|
|
48
|
-
"@arcblock/did-connect": "^2.
|
|
49
|
-
"@arcblock/did-util": "^1.18.
|
|
50
|
-
"@arcblock/jwt": "^1.18.
|
|
51
|
-
"@arcblock/ux": "^2.
|
|
52
|
-
"@blocklet/logger": "1.16.21
|
|
53
|
-
"@blocklet/sdk": "1.16.21
|
|
54
|
-
"@blocklet/ui-react": "^2.
|
|
55
|
-
"@blocklet/uploader": "^0.0.
|
|
48
|
+
"@arcblock/did-connect": "^2.9.6",
|
|
49
|
+
"@arcblock/did-util": "^1.18.108",
|
|
50
|
+
"@arcblock/jwt": "^1.18.108",
|
|
51
|
+
"@arcblock/ux": "^2.9.6",
|
|
52
|
+
"@blocklet/logger": "1.16.21",
|
|
53
|
+
"@blocklet/sdk": "1.16.21",
|
|
54
|
+
"@blocklet/ui-react": "^2.9.6",
|
|
55
|
+
"@blocklet/uploader": "^0.0.62",
|
|
56
56
|
"@mui/icons-material": "^5.14.19",
|
|
57
57
|
"@mui/lab": "^5.0.0-alpha.155",
|
|
58
58
|
"@mui/material": "^5.14.20",
|
|
59
59
|
"@mui/styles": "^5.14.20",
|
|
60
60
|
"@mui/system": "^5.14.20",
|
|
61
|
-
"@ocap/asset": "^1.18.
|
|
62
|
-
"@ocap/client": "^1.18.
|
|
63
|
-
"@ocap/mcrypto": "^1.18.
|
|
64
|
-
"@ocap/util": "^1.18.
|
|
65
|
-
"@ocap/wallet": "^1.18.
|
|
61
|
+
"@ocap/asset": "^1.18.108",
|
|
62
|
+
"@ocap/client": "^1.18.108",
|
|
63
|
+
"@ocap/mcrypto": "^1.18.108",
|
|
64
|
+
"@ocap/util": "^1.18.108",
|
|
65
|
+
"@ocap/wallet": "^1.18.108",
|
|
66
66
|
"@stripe/react-stripe-js": "^2.4.0",
|
|
67
67
|
"@stripe/stripe-js": "^2.2.0",
|
|
68
68
|
"ahooks": "^3.7.8",
|
|
@@ -107,10 +107,10 @@
|
|
|
107
107
|
"validator": "^13.11.0"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
110
|
-
"@abtnode/types": "1.16.21
|
|
110
|
+
"@abtnode/types": "1.16.21",
|
|
111
111
|
"@arcblock/eslint-config": "^0.2.4",
|
|
112
112
|
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
113
|
-
"@did-pay/types": "1.13.
|
|
113
|
+
"@did-pay/types": "1.13.90",
|
|
114
114
|
"@types/cookie-parser": "^1.4.6",
|
|
115
115
|
"@types/cors": "^2.8.17",
|
|
116
116
|
"@types/dotenv-flow": "^3.3.3",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"type-fest": "^4.8.3",
|
|
135
135
|
"typescript": "^4.9.5",
|
|
136
136
|
"vite": "^4.5.1",
|
|
137
|
-
"vite-plugin-blocklet": "^0.
|
|
137
|
+
"vite-plugin-blocklet": "^0.7.2",
|
|
138
138
|
"vite-plugin-node-polyfills": "^0.7.0",
|
|
139
139
|
"vite-plugin-svgr": "^2.4.0",
|
|
140
140
|
"zx": "^7.2.3"
|
|
@@ -149,5 +149,5 @@
|
|
|
149
149
|
"parser": "typescript"
|
|
150
150
|
}
|
|
151
151
|
},
|
|
152
|
-
"gitHead": "
|
|
152
|
+
"gitHead": "da8ffc51e425abacf0bc215606c9e2a747d8cee0"
|
|
153
153
|
}
|