payment-kit 1.19.0 → 1.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/src/crons/index.ts +8 -0
- package/api/src/index.ts +4 -0
- package/api/src/libs/credit-grant.ts +146 -0
- package/api/src/libs/env.ts +1 -0
- package/api/src/libs/invoice.ts +4 -3
- package/api/src/libs/notification/template/base.ts +388 -2
- package/api/src/libs/notification/template/customer-credit-grant-granted.ts +149 -0
- package/api/src/libs/notification/template/customer-credit-grant-low-balance.ts +151 -0
- package/api/src/libs/notification/template/customer-credit-insufficient.ts +254 -0
- package/api/src/libs/notification/template/subscription-canceled.ts +193 -202
- package/api/src/libs/notification/template/subscription-refund-succeeded.ts +215 -237
- package/api/src/libs/notification/template/subscription-renewed.ts +130 -200
- package/api/src/libs/notification/template/subscription-succeeded.ts +100 -202
- package/api/src/libs/notification/template/subscription-trial-start.ts +142 -188
- package/api/src/libs/notification/template/subscription-trial-will-end.ts +146 -174
- package/api/src/libs/notification/template/subscription-upgraded.ts +96 -192
- package/api/src/libs/notification/template/subscription-will-canceled.ts +94 -135
- package/api/src/libs/notification/template/subscription-will-renew.ts +220 -245
- package/api/src/libs/payment.ts +69 -0
- package/api/src/libs/queue/index.ts +3 -2
- package/api/src/libs/session.ts +8 -0
- package/api/src/libs/subscription.ts +74 -3
- package/api/src/libs/ws.ts +23 -1
- package/api/src/locales/en.ts +33 -0
- package/api/src/locales/zh.ts +31 -0
- package/api/src/queues/credit-consume.ts +715 -0
- package/api/src/queues/credit-grant.ts +572 -0
- package/api/src/queues/notification.ts +173 -128
- package/api/src/queues/payment.ts +210 -122
- package/api/src/queues/subscription.ts +179 -0
- package/api/src/routes/checkout-sessions.ts +157 -9
- package/api/src/routes/connect/shared.ts +3 -2
- package/api/src/routes/credit-grants.ts +241 -0
- package/api/src/routes/credit-transactions.ts +208 -0
- package/api/src/routes/index.ts +8 -0
- package/api/src/routes/meter-events.ts +347 -0
- package/api/src/routes/meters.ts +219 -0
- package/api/src/routes/payment-currencies.ts +14 -2
- package/api/src/routes/payment-links.ts +1 -1
- package/api/src/routes/payment-methods.ts +14 -2
- package/api/src/routes/prices.ts +43 -0
- package/api/src/routes/pricing-table.ts +13 -7
- package/api/src/routes/products.ts +63 -4
- package/api/src/routes/settings.ts +1 -1
- package/api/src/routes/subscriptions.ts +4 -0
- package/api/src/store/migrations/20250610-billing-credit.ts +43 -0
- package/api/src/store/models/credit-grant.ts +486 -0
- package/api/src/store/models/credit-transaction.ts +268 -0
- package/api/src/store/models/customer.ts +8 -0
- package/api/src/store/models/index.ts +52 -1
- package/api/src/store/models/meter-event.ts +423 -0
- package/api/src/store/models/meter.ts +176 -0
- package/api/src/store/models/payment-currency.ts +66 -14
- package/api/src/store/models/price.ts +6 -0
- package/api/src/store/models/product.ts +2 -2
- package/api/src/store/models/subscription.ts +24 -0
- package/api/src/store/models/types.ts +28 -2
- package/api/tests/libs/subscription.spec.ts +53 -0
- package/blocklet.yml +9 -1
- package/package.json +4 -4
- package/scripts/sdk.js +233 -1
- package/src/app.tsx +10 -0
- package/src/components/collapse.tsx +11 -1
- package/src/components/customer/credit-grant-item-list.tsx +99 -0
- package/src/components/customer/credit-overview.tsx +233 -0
- package/src/components/customer/form.tsx +5 -2
- package/src/components/invoice/list.tsx +19 -1
- package/src/components/metadata/form.tsx +286 -90
- package/src/components/meter/actions.tsx +101 -0
- package/src/components/meter/add-usage-dialog.tsx +239 -0
- package/src/components/meter/events-list.tsx +657 -0
- package/src/components/meter/form.tsx +245 -0
- package/src/components/meter/products.tsx +264 -0
- package/src/components/meter/usage-guide.tsx +174 -0
- package/src/components/payment-currency/form.tsx +2 -0
- package/src/components/payment-intent/list.tsx +19 -1
- package/src/components/payment-link/preview.tsx +1 -1
- package/src/components/payment-link/product-select.tsx +52 -12
- package/src/components/payment-method/arcblock.tsx +2 -0
- package/src/components/payment-method/base.tsx +2 -0
- package/src/components/payment-method/bitcoin.tsx +2 -0
- package/src/components/payment-method/ethereum.tsx +2 -0
- package/src/components/payment-method/stripe.tsx +2 -0
- package/src/components/payouts/list.tsx +19 -1
- package/src/components/price/currency-select.tsx +51 -31
- package/src/components/price/form.tsx +881 -407
- package/src/components/pricing-table/preview.tsx +1 -1
- package/src/components/product/add-price.tsx +9 -7
- package/src/components/product/create.tsx +7 -4
- package/src/components/product/edit-price.tsx +21 -12
- package/src/components/product/features.tsx +17 -7
- package/src/components/product/form.tsx +104 -89
- package/src/components/refund/list.tsx +19 -1
- package/src/components/section/header.tsx +5 -18
- package/src/components/subscription/items/index.tsx +1 -1
- package/src/components/subscription/metrics.tsx +37 -5
- package/src/components/subscription/portal/actions.tsx +2 -1
- package/src/contexts/products.tsx +26 -9
- package/src/hooks/subscription.ts +34 -0
- package/src/libs/meter-utils.ts +196 -0
- package/src/libs/util.ts +4 -0
- package/src/locales/en.tsx +385 -4
- package/src/locales/zh.tsx +364 -0
- package/src/pages/admin/billing/index.tsx +61 -33
- package/src/pages/admin/billing/invoices/detail.tsx +1 -1
- package/src/pages/admin/billing/meters/create.tsx +60 -0
- package/src/pages/admin/billing/meters/detail.tsx +435 -0
- package/src/pages/admin/billing/meters/index.tsx +210 -0
- package/src/pages/admin/billing/meters/meter-event.tsx +346 -0
- package/src/pages/admin/billing/subscriptions/detail.tsx +47 -14
- package/src/pages/admin/customers/customers/credit-grant/detail.tsx +391 -0
- package/src/pages/admin/customers/customers/detail.tsx +22 -10
- package/src/pages/admin/customers/index.tsx +5 -0
- package/src/pages/admin/developers/events/detail.tsx +1 -1
- package/src/pages/admin/developers/index.tsx +1 -1
- package/src/pages/admin/payments/intents/detail.tsx +1 -1
- package/src/pages/admin/payments/payouts/detail.tsx +1 -1
- package/src/pages/admin/payments/refunds/detail.tsx +1 -1
- package/src/pages/admin/products/index.tsx +3 -2
- package/src/pages/admin/products/links/detail.tsx +1 -1
- package/src/pages/admin/products/prices/actions.tsx +16 -4
- package/src/pages/admin/products/prices/detail.tsx +30 -3
- package/src/pages/admin/products/prices/list.tsx +8 -1
- package/src/pages/admin/products/pricing-tables/detail.tsx +1 -1
- package/src/pages/admin/products/products/create.tsx +233 -57
- package/src/pages/admin/products/products/detail.tsx +2 -1
- package/src/pages/admin/settings/payment-methods/index.tsx +3 -0
- package/src/pages/customer/credit-grant/detail.tsx +308 -0
- package/src/pages/customer/index.tsx +35 -2
- package/src/pages/customer/recharge/account.tsx +5 -5
- package/src/pages/customer/subscription/change-payment.tsx +4 -2
- package/src/pages/customer/subscription/detail.tsx +48 -14
- package/src/pages/customer/subscription/embed.tsx +1 -1
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/brace-style */
|
|
2
2
|
/* eslint-disable @typescript-eslint/indent */
|
|
3
|
-
import {
|
|
3
|
+
import { toDid } from '@ocap/util';
|
|
4
4
|
import pWaitFor from 'p-wait-for';
|
|
5
|
-
import prettyMsI18n from 'pretty-ms-i18n';
|
|
6
|
-
|
|
7
5
|
import isEmpty from 'lodash/isEmpty';
|
|
8
|
-
|
|
6
|
+
|
|
9
7
|
import { translate } from '../../../locales';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Invoice,
|
|
15
|
-
NftMintItem,
|
|
16
|
-
PaymentMethod,
|
|
17
|
-
Subscription,
|
|
18
|
-
} from '../../../store/models';
|
|
19
|
-
import { PaymentCurrency } from '../../../store/models/payment-currency';
|
|
20
|
-
import { getCustomerInvoicePageUrl, getOneTimeProductInfo } from '../../invoice';
|
|
21
|
-
import { getMainProductName } from '../../product';
|
|
22
|
-
import { getCustomerSubscriptionPageUrl } from '../../subscription';
|
|
23
|
-
import { formatTime, getPrettyMsI18nLocale } from '../../time';
|
|
24
|
-
import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
|
|
25
|
-
import { getSubscriptionNotificationCustomActions } from '../../util';
|
|
8
|
+
import { CheckoutSession, NFTMintChainType, NftMintItem } from '../../../store/models';
|
|
9
|
+
import { getOneTimeProductInfo } from '../../invoice';
|
|
10
|
+
import { formatTime } from '../../time';
|
|
11
|
+
import { BaseSubscriptionEmailTemplate, BaseEmailTemplateType } from './base';
|
|
26
12
|
|
|
27
13
|
export interface SubscriptionTrialStartEmailTemplateOptions {
|
|
28
14
|
subscriptionId: string;
|
|
@@ -51,31 +37,27 @@ interface SubscriptionTrialStartEmailTemplateContext {
|
|
|
51
37
|
viewInvoiceLink: string;
|
|
52
38
|
oneTimeProductInfo?: Array<OneTimeProductInfo>;
|
|
53
39
|
customActions: any[];
|
|
40
|
+
isCreditSubscription: boolean;
|
|
54
41
|
}
|
|
55
42
|
|
|
56
|
-
export class SubscriptionTrialStartEmailTemplate
|
|
57
|
-
implements BaseEmailTemplate<SubscriptionTrialStartEmailTemplateContext>
|
|
58
|
-
{
|
|
43
|
+
export class SubscriptionTrialStartEmailTemplate extends BaseSubscriptionEmailTemplate<SubscriptionTrialStartEmailTemplateContext> {
|
|
59
44
|
options: SubscriptionTrialStartEmailTemplateOptions;
|
|
60
45
|
|
|
61
46
|
constructor(options: SubscriptionTrialStartEmailTemplateOptions) {
|
|
47
|
+
super();
|
|
62
48
|
this.options = options;
|
|
63
49
|
}
|
|
64
50
|
|
|
65
51
|
async getContext(): Promise<SubscriptionTrialStartEmailTemplateContext> {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
52
|
+
// 获取基础订阅数据
|
|
53
|
+
const basicData = await this.getSubscriptionBasicData(this.options.subscriptionId);
|
|
54
|
+
const { subscription, userDid, locale, productName, paymentCurrency, isCreditSubscription } = basicData;
|
|
55
|
+
|
|
70
56
|
if (subscription.status !== 'trialing') {
|
|
71
57
|
throw new Error(`Subscription not trialing: ${this.options.subscriptionId}`);
|
|
72
58
|
}
|
|
73
59
|
|
|
74
|
-
|
|
75
|
-
if (!customer) {
|
|
76
|
-
throw new Error(`Customer not found: ${subscription.customer_id}`);
|
|
77
|
-
}
|
|
78
|
-
|
|
60
|
+
// 等待 NFT 铸造完成
|
|
79
61
|
await pWaitFor(
|
|
80
62
|
async () => {
|
|
81
63
|
const checkoutSession = await CheckoutSession.findBySubscriptionId(subscription.id);
|
|
@@ -84,57 +66,39 @@ export class SubscriptionTrialStartEmailTemplate
|
|
|
84
66
|
{ timeout: 1000 * 10, interval: 1000 }
|
|
85
67
|
);
|
|
86
68
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
id: subscription.currency_id,
|
|
95
|
-
},
|
|
96
|
-
})) as PaymentCurrency;
|
|
97
|
-
|
|
69
|
+
// 获取 NFT 和支付信息
|
|
70
|
+
const paymentInfoResult = await this.getPaymentInfo(
|
|
71
|
+
subscription,
|
|
72
|
+
paymentCurrency,
|
|
73
|
+
isCreditSubscription,
|
|
74
|
+
subscription.latest_invoice_id
|
|
75
|
+
);
|
|
98
76
|
const oneTimeProductInfo = await getOneTimeProductInfo(subscription.latest_invoice_id as string, paymentCurrency);
|
|
99
77
|
|
|
100
78
|
const checkoutSession = await CheckoutSession.findBySubscriptionId(subscription.id);
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
const locale = await getUserLocale(userDid);
|
|
104
|
-
const productName = await getMainProductName(subscription.id);
|
|
105
|
-
const subscriptionTrialEnd: string = formatTime((subscription.trial_end as number) * 1000);
|
|
106
|
-
|
|
107
|
-
const hasNft: boolean = checkoutSession?.nft_mint_status === 'minted';
|
|
108
|
-
const nftMintItem: NftMintItem | undefined = hasNft
|
|
79
|
+
const hasNft = checkoutSession?.nft_mint_status === 'minted';
|
|
80
|
+
const nftMintItem = hasNft
|
|
109
81
|
? checkoutSession?.nft_mint_details?.[checkoutSession?.nft_mint_details?.type as NFTMintChainType]
|
|
110
82
|
: undefined;
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const paymentInfo: string = `${fromUnitToToken('0', paymentCurrency.decimal)} ${paymentCurrency.symbol}`;
|
|
115
|
-
const currentPeriodStart: string = formatTime((subscription.trial_start as number) * 1000);
|
|
116
|
-
const currentPeriodEnd: string = formatTime((subscription.trial_end as number) * 1000);
|
|
117
|
-
const duration: string = prettyMsI18n(
|
|
118
|
-
new Date(currentPeriodEnd).getTime() - new Date(currentPeriodStart).getTime(),
|
|
119
|
-
{
|
|
120
|
-
locale: getPrettyMsI18nLocale(locale),
|
|
121
|
-
}
|
|
122
|
-
);
|
|
83
|
+
const chainHost =
|
|
84
|
+
paymentInfoResult.paymentMethod?.settings?.[checkoutSession?.nft_mint_details?.type as NFTMintChainType]
|
|
85
|
+
?.api_host;
|
|
123
86
|
|
|
124
|
-
|
|
125
|
-
|
|
87
|
+
// 获取链接
|
|
88
|
+
const links = this.generateSubscriptionLinks(
|
|
89
|
+
subscription,
|
|
126
90
|
locale,
|
|
127
91
|
userDid,
|
|
128
|
-
});
|
|
129
|
-
const viewInvoiceLink = getCustomerInvoicePageUrl({
|
|
130
|
-
invoiceId: invoice.id,
|
|
131
|
-
userDid,
|
|
132
|
-
locale,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const customActions = getSubscriptionNotificationCustomActions(
|
|
136
|
-
subscription,
|
|
137
92
|
'customer.subscription.trial_start',
|
|
93
|
+
subscription.latest_invoice_id,
|
|
94
|
+
isCreditSubscription
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// 计算时间信息
|
|
98
|
+
const subscriptionTrialEnd = formatTime((subscription.trial_end as number) * 1000);
|
|
99
|
+
const periodInfo = this.formatSubscriptionPeriod(
|
|
100
|
+
subscription.trial_start as number,
|
|
101
|
+
subscription.trial_end as number,
|
|
138
102
|
locale
|
|
139
103
|
);
|
|
140
104
|
|
|
@@ -142,23 +106,22 @@ export class SubscriptionTrialStartEmailTemplate
|
|
|
142
106
|
locale,
|
|
143
107
|
productName,
|
|
144
108
|
subscriptionTrialEnd,
|
|
145
|
-
|
|
146
109
|
nftMintItem,
|
|
147
110
|
chainHost,
|
|
148
111
|
userDid,
|
|
149
|
-
paymentInfo,
|
|
150
|
-
currentPeriodStart,
|
|
151
|
-
currentPeriodEnd,
|
|
152
|
-
duration,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
viewInvoiceLink,
|
|
112
|
+
paymentInfo: '0',
|
|
113
|
+
currentPeriodStart: periodInfo.currentPeriodStart,
|
|
114
|
+
currentPeriodEnd: periodInfo.currentPeriodEnd,
|
|
115
|
+
duration: periodInfo.duration,
|
|
116
|
+
viewSubscriptionLink: links.viewSubscriptionLink,
|
|
117
|
+
viewInvoiceLink: links.viewInvoiceLink!,
|
|
156
118
|
oneTimeProductInfo,
|
|
157
|
-
customActions,
|
|
119
|
+
customActions: links.customActions,
|
|
120
|
+
isCreditSubscription,
|
|
158
121
|
};
|
|
159
122
|
}
|
|
160
123
|
|
|
161
|
-
getOneTimeProductTemplate(oneTimeProductInfo: Array<OneTimeProductInfo>, locale: string = 'en') {
|
|
124
|
+
private getOneTimeProductTemplate(oneTimeProductInfo: Array<OneTimeProductInfo>, locale: string = 'en') {
|
|
162
125
|
return [
|
|
163
126
|
{
|
|
164
127
|
type: 'divider',
|
|
@@ -226,134 +189,125 @@ export class SubscriptionTrialStartEmailTemplate
|
|
|
226
189
|
}
|
|
227
190
|
|
|
228
191
|
async getTemplate(): Promise<BaseEmailTemplateType> {
|
|
192
|
+
const context = await this.getContext();
|
|
229
193
|
const {
|
|
230
194
|
locale,
|
|
231
195
|
productName,
|
|
232
196
|
subscriptionTrialEnd,
|
|
233
|
-
|
|
234
197
|
nftMintItem,
|
|
235
198
|
chainHost,
|
|
236
199
|
userDid,
|
|
237
200
|
currentPeriodStart,
|
|
238
201
|
currentPeriodEnd,
|
|
239
202
|
duration,
|
|
240
|
-
|
|
241
203
|
viewSubscriptionLink,
|
|
242
204
|
viewInvoiceLink,
|
|
243
205
|
oneTimeProductInfo,
|
|
244
206
|
customActions,
|
|
245
|
-
|
|
207
|
+
isCreditSubscription,
|
|
208
|
+
} = context;
|
|
246
209
|
|
|
247
210
|
const hasOneTimeProduct = !isEmpty(oneTimeProductInfo);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
attachments: [
|
|
259
|
-
nftMintItem &&
|
|
260
|
-
chainHost && {
|
|
261
|
-
type: 'asset',
|
|
211
|
+
|
|
212
|
+
// 构建字段
|
|
213
|
+
const commonFields = this.buildCommonFields(userDid, productName, locale);
|
|
214
|
+
|
|
215
|
+
// 试用期字段
|
|
216
|
+
const trialPeriodFields = isCreditSubscription
|
|
217
|
+
? []
|
|
218
|
+
: [
|
|
219
|
+
{
|
|
220
|
+
type: 'text',
|
|
262
221
|
data: {
|
|
263
|
-
|
|
264
|
-
|
|
222
|
+
type: 'plain',
|
|
223
|
+
color: '#9397A1',
|
|
224
|
+
text: translate('notification.common.trialPeriod', locale),
|
|
265
225
|
},
|
|
266
226
|
},
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
type: 'section',
|
|
276
|
-
fields: [
|
|
277
|
-
{
|
|
278
|
-
type: 'text',
|
|
279
|
-
data: {
|
|
280
|
-
type: 'plain',
|
|
281
|
-
color: '#9397A1',
|
|
282
|
-
text: translate('notification.common.account', locale),
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
type: 'text',
|
|
287
|
-
data: {
|
|
288
|
-
type: 'plain',
|
|
289
|
-
text: userDid,
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
type: 'text',
|
|
294
|
-
data: {
|
|
295
|
-
type: 'plain',
|
|
296
|
-
color: '#9397A1',
|
|
297
|
-
text: translate('notification.common.product', locale),
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
type: 'text',
|
|
302
|
-
data: {
|
|
303
|
-
type: 'plain',
|
|
304
|
-
text: productName,
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
type: 'text',
|
|
309
|
-
data: {
|
|
310
|
-
type: 'plain',
|
|
311
|
-
color: '#9397A1',
|
|
312
|
-
text: translate('notification.common.trialPeriod', locale),
|
|
313
|
-
},
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
type: 'text',
|
|
317
|
-
data: {
|
|
318
|
-
type: 'plain',
|
|
319
|
-
text: `${currentPeriodStart} ~ ${currentPeriodEnd}(${duration})`,
|
|
320
|
-
},
|
|
227
|
+
{
|
|
228
|
+
type: 'text',
|
|
229
|
+
data: {
|
|
230
|
+
type: 'plain',
|
|
231
|
+
text: `${currentPeriodStart} ~ ${currentPeriodEnd}(${duration})`,
|
|
321
232
|
},
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
233
|
+
},
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
// NFT 地址字段
|
|
237
|
+
const nftFields = nftMintItem
|
|
238
|
+
? [
|
|
239
|
+
{
|
|
240
|
+
type: 'text',
|
|
241
|
+
data: {
|
|
242
|
+
type: 'plain',
|
|
243
|
+
color: '#9397A1',
|
|
244
|
+
text: translate('notification.common.nftAddress', locale),
|
|
329
245
|
},
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
type: 'text',
|
|
249
|
+
data: {
|
|
250
|
+
type: 'plain',
|
|
251
|
+
text: toDid(nftMintItem.address),
|
|
336
252
|
},
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
253
|
+
},
|
|
254
|
+
]
|
|
255
|
+
: [];
|
|
256
|
+
|
|
257
|
+
// 构建附件
|
|
258
|
+
const attachments = [
|
|
259
|
+
nftMintItem &&
|
|
260
|
+
chainHost && {
|
|
261
|
+
type: 'asset',
|
|
262
|
+
data: {
|
|
263
|
+
chainHost,
|
|
264
|
+
did: nftMintItem.address,
|
|
265
|
+
},
|
|
349
266
|
},
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
267
|
+
hasOneTimeProduct && {
|
|
268
|
+
type: 'text',
|
|
269
|
+
data: {
|
|
270
|
+
type: 'plain',
|
|
271
|
+
text: translate('notification.common.trialProduct', locale),
|
|
354
272
|
},
|
|
355
|
-
|
|
356
|
-
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
type: 'section',
|
|
276
|
+
fields: [...commonFields, ...trialPeriodFields, ...nftFields].filter(Boolean),
|
|
277
|
+
},
|
|
278
|
+
...(hasOneTimeProduct
|
|
279
|
+
? this.getOneTimeProductTemplate(oneTimeProductInfo as Array<OneTimeProductInfo>, locale)
|
|
280
|
+
: []),
|
|
281
|
+
].filter(Boolean);
|
|
282
|
+
|
|
283
|
+
// 构建操作按钮
|
|
284
|
+
const actions = [
|
|
285
|
+
{
|
|
286
|
+
name: translate('notification.common.viewSubscription', locale),
|
|
287
|
+
title: translate('notification.common.viewSubscription', locale),
|
|
288
|
+
link: viewSubscriptionLink,
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
name: translate('notification.common.viewInvoice', locale),
|
|
292
|
+
title: translate('notification.common.viewInvoice', locale),
|
|
293
|
+
link: viewInvoiceLink,
|
|
294
|
+
},
|
|
295
|
+
...customActions,
|
|
296
|
+
].filter(Boolean);
|
|
297
|
+
|
|
298
|
+
const template: BaseEmailTemplateType = {
|
|
299
|
+
title: translate('notification.subscriptionTrialStart.title', locale, {
|
|
300
|
+
productName,
|
|
301
|
+
}),
|
|
302
|
+
body: translate('notification.subscriptionTrialStart.body', locale, {
|
|
303
|
+
subscriptionTrialEnd,
|
|
304
|
+
productName,
|
|
305
|
+
trialDuration: duration,
|
|
306
|
+
}),
|
|
307
|
+
// @ts-expect-error
|
|
308
|
+
attachments,
|
|
309
|
+
// @ts-ignore
|
|
310
|
+
actions,
|
|
357
311
|
};
|
|
358
312
|
|
|
359
313
|
return template;
|