payment-kit 1.13.65 → 1.13.66
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/index.ts +4 -0
- package/api/src/integrations/blocklet/notification.ts +5 -3
- package/api/src/jobs/notification.ts +142 -0
- package/api/src/jobs/payment.ts +14 -0
- package/api/src/jobs/subscription.ts +2 -2
- package/api/src/libs/audit.ts +3 -1
- package/api/src/libs/env.ts +3 -0
- package/api/src/libs/event.ts +10 -1
- package/api/src/libs/invoice.ts +5 -0
- package/api/src/libs/notification/index.ts +23 -0
- package/api/src/libs/notification/template/base.ts +12 -0
- package/api/src/libs/notification/template/subscription-renew-failed.ts +286 -0
- package/api/src/libs/notification/template/subscription-renewed.ts +259 -0
- package/api/src/libs/notification/template/subscription-succeeded.ts +279 -0
- package/api/src/libs/notification/template/subscription-trial-start.ts +267 -0
- package/api/src/libs/notification/template/subscription-trial-will-end.ts +250 -0
- package/api/src/libs/notification/template/subscription-will-renew.ts +232 -0
- package/api/src/libs/payment.ts +100 -3
- package/api/src/libs/product.ts +19 -0
- package/api/src/libs/queue/index.ts +13 -0
- package/api/src/libs/subscription.ts +5 -0
- package/api/src/libs/time.ts +17 -0
- package/api/src/libs/util.ts +39 -0
- package/api/src/locales/en.ts +67 -0
- package/api/src/locales/zh.ts +64 -0
- package/api/src/routes/connect/collect.ts +6 -0
- package/api/src/schedule/index.ts +28 -0
- package/api/src/schedule/interface/diff.ts +9 -0
- package/api/src/schedule/subscription-trail-will-end.ts +197 -0
- package/api/src/schedule/subscription-will-renew.ts +195 -0
- package/api/src/store/models/subscription.ts +30 -12
- package/api/src/store/models/types.ts +13 -12
- package/api/third.d.ts +2 -0
- package/blocklet.yml +1 -1
- package/package.json +9 -7
- package/src/app.tsx +2 -0
- package/src/components/invoice/action.tsx +25 -7
- package/src/components/invoice/list.tsx +19 -4
- package/src/components/portal/invoice/list.tsx +1 -1
- package/src/components/portal/subscription/list.tsx +6 -5
- package/src/components/subscription/items/index.tsx +8 -4
- package/src/libs/util.ts +2 -2
- package/src/locales/en.tsx +5 -1
- package/src/locales/zh.tsx +5 -1
- package/src/pages/checkout/pricing-table.tsx +1 -1
- package/src/pages/customer/index.tsx +13 -2
- package/src/pages/customer/invoice.tsx +5 -4
- package/src/pages/customer/subscription/index.tsx +163 -0
- package/tsconfig.api.json +6 -1
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/brace-style */
|
|
2
|
+
/* eslint-disable @typescript-eslint/indent */
|
|
3
|
+
import { fromUnitToToken, toDid } from '@ocap/util';
|
|
4
|
+
import prettyMsI18n from 'pretty-ms-i18n';
|
|
5
|
+
|
|
6
|
+
import { getUserLocale } from '../../../integrations/blocklet/notification';
|
|
7
|
+
import { translate } from '../../../locales';
|
|
8
|
+
import {
|
|
9
|
+
CheckoutSession,
|
|
10
|
+
Customer,
|
|
11
|
+
Invoice,
|
|
12
|
+
NftMintItem,
|
|
13
|
+
PaymentIntent,
|
|
14
|
+
PaymentMethod,
|
|
15
|
+
Subscription,
|
|
16
|
+
} from '../../../store/models';
|
|
17
|
+
import { PaymentCurrency } from '../../../store/models/payment-currency';
|
|
18
|
+
import { getCustomerInvoicePageUrl } from '../../invoice';
|
|
19
|
+
import { getMainProductName } from '../../product';
|
|
20
|
+
import { getCustomerSubscriptionPageUrl } from '../../subscription';
|
|
21
|
+
import { formatTime, getPrettyMsI18nLocale } from '../../time';
|
|
22
|
+
import { getExplorerLink } from '../../util';
|
|
23
|
+
import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
|
|
24
|
+
|
|
25
|
+
export interface SubscriptionRenewedEmailTemplateOptions {
|
|
26
|
+
subscriptionId: string;
|
|
27
|
+
invoiceId?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface SubscriptionRenewedEmailTemplateContext {
|
|
31
|
+
locale: string;
|
|
32
|
+
productName: string;
|
|
33
|
+
at: string;
|
|
34
|
+
|
|
35
|
+
nftMintItem: NftMintItem | undefined;
|
|
36
|
+
userDid: string;
|
|
37
|
+
paymentInfo: string;
|
|
38
|
+
currentPeriodStart: string;
|
|
39
|
+
currentPeriodEnd: string;
|
|
40
|
+
duration: string;
|
|
41
|
+
|
|
42
|
+
viewSubscriptionLink: string;
|
|
43
|
+
viewInvoiceLink: string;
|
|
44
|
+
viewTxHashLink: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class SubscriptionRenewedEmailTemplate implements BaseEmailTemplate<SubscriptionRenewedEmailTemplateContext> {
|
|
48
|
+
options: SubscriptionRenewedEmailTemplateOptions;
|
|
49
|
+
|
|
50
|
+
constructor(options: SubscriptionRenewedEmailTemplateOptions) {
|
|
51
|
+
this.options = options;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getContext(): Promise<SubscriptionRenewedEmailTemplateContext> {
|
|
55
|
+
const subscription: Subscription | null = await Subscription.findByPk(this.options.subscriptionId);
|
|
56
|
+
if (!subscription) {
|
|
57
|
+
throw new Error(`Subscription not found: ${this.options.subscriptionId}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const customer = await Customer.findByPk(subscription.customer_id);
|
|
61
|
+
if (!customer) {
|
|
62
|
+
throw new Error(`Customer not found: ${subscription.customer_id}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const invoice = (
|
|
66
|
+
this.options.invoiceId
|
|
67
|
+
? await Invoice.findByPk(this.options.invoiceId)
|
|
68
|
+
: await Invoice.findByPk(subscription.latest_invoice_id)
|
|
69
|
+
) as Invoice;
|
|
70
|
+
const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
|
|
71
|
+
const paymentCurrency = (await PaymentCurrency.findOne({
|
|
72
|
+
where: {
|
|
73
|
+
id: subscription.currency_id,
|
|
74
|
+
},
|
|
75
|
+
})) as PaymentCurrency;
|
|
76
|
+
|
|
77
|
+
const checkoutSession = await CheckoutSession.findOne({
|
|
78
|
+
where: {
|
|
79
|
+
subscription_id: subscription.id,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const locale = await getUserLocale(customer.did);
|
|
84
|
+
const productName = await getMainProductName(subscription.id);
|
|
85
|
+
const at: string = formatTime(Date.now());
|
|
86
|
+
|
|
87
|
+
const hasNft: boolean = checkoutSession?.nft_mint_status === 'minted';
|
|
88
|
+
const nftMintItem: NftMintItem | undefined = hasNft
|
|
89
|
+
? checkoutSession?.nft_mint_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']
|
|
90
|
+
: undefined;
|
|
91
|
+
const paymentInfo: string = `${fromUnitToToken(invoice.amount_paid, paymentCurrency.decimal)} ${
|
|
92
|
+
paymentCurrency.symbol
|
|
93
|
+
}`;
|
|
94
|
+
const currentPeriodStart: string = formatTime(invoice.period_start * 1000);
|
|
95
|
+
const currentPeriodEnd: string = formatTime(invoice.period_end * 1000);
|
|
96
|
+
const duration: string = prettyMsI18n(
|
|
97
|
+
new Date(currentPeriodEnd).getTime() - new Date(currentPeriodStart).getTime(),
|
|
98
|
+
{
|
|
99
|
+
locale: getPrettyMsI18nLocale(locale),
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const paymentMethod: PaymentMethod | null = await PaymentMethod.findByPk(invoice.default_payment_method_id);
|
|
104
|
+
const chainHost: string | undefined =
|
|
105
|
+
paymentMethod?.settings?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.api_host;
|
|
106
|
+
const viewSubscriptionLink = getCustomerSubscriptionPageUrl(subscription.id, locale);
|
|
107
|
+
const viewInvoiceLink = getCustomerInvoicePageUrl(invoice.id, locale);
|
|
108
|
+
const txHash: string | undefined =
|
|
109
|
+
paymentIntent?.payment_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.tx_hash;
|
|
110
|
+
const viewTxHashLink: string | undefined = hasNft && txHash ? getExplorerLink(chainHost, txHash, 'tx') : undefined;
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
locale,
|
|
114
|
+
productName,
|
|
115
|
+
at,
|
|
116
|
+
|
|
117
|
+
nftMintItem,
|
|
118
|
+
userDid: customer.did,
|
|
119
|
+
paymentInfo,
|
|
120
|
+
currentPeriodStart,
|
|
121
|
+
currentPeriodEnd,
|
|
122
|
+
duration,
|
|
123
|
+
|
|
124
|
+
viewSubscriptionLink,
|
|
125
|
+
viewInvoiceLink,
|
|
126
|
+
viewTxHashLink,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async getTemplate(): Promise<BaseEmailTemplateType> {
|
|
131
|
+
const {
|
|
132
|
+
locale,
|
|
133
|
+
productName,
|
|
134
|
+
at,
|
|
135
|
+
nftMintItem,
|
|
136
|
+
userDid,
|
|
137
|
+
paymentInfo,
|
|
138
|
+
currentPeriodStart,
|
|
139
|
+
currentPeriodEnd,
|
|
140
|
+
duration,
|
|
141
|
+
viewSubscriptionLink,
|
|
142
|
+
viewInvoiceLink,
|
|
143
|
+
viewTxHashLink,
|
|
144
|
+
} = await this.getContext();
|
|
145
|
+
|
|
146
|
+
const template: BaseEmailTemplateType = {
|
|
147
|
+
title: `${translate('notification.subscriptionRenewed.title', locale, {
|
|
148
|
+
productName: `(${productName})`,
|
|
149
|
+
})}`,
|
|
150
|
+
body: `${translate('notification.subscriptionRenewed.body', locale, {
|
|
151
|
+
at,
|
|
152
|
+
productName: `(${productName})`,
|
|
153
|
+
})}`,
|
|
154
|
+
// @ts-expect-error
|
|
155
|
+
attachments: [
|
|
156
|
+
{
|
|
157
|
+
type: 'section',
|
|
158
|
+
fields: [
|
|
159
|
+
{
|
|
160
|
+
type: 'text',
|
|
161
|
+
data: {
|
|
162
|
+
type: 'plain',
|
|
163
|
+
color: '#9397A1',
|
|
164
|
+
text: translate('notification.common.account', locale),
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
type: 'text',
|
|
169
|
+
data: {
|
|
170
|
+
type: 'plain',
|
|
171
|
+
text: userDid,
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
type: 'text',
|
|
176
|
+
data: {
|
|
177
|
+
type: 'plain',
|
|
178
|
+
color: '#9397A1',
|
|
179
|
+
text: translate('notification.common.product', locale),
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: 'text',
|
|
184
|
+
data: {
|
|
185
|
+
type: 'plain',
|
|
186
|
+
text: productName,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'text',
|
|
191
|
+
data: {
|
|
192
|
+
type: 'plain',
|
|
193
|
+
color: '#9397A1',
|
|
194
|
+
text: translate('notification.common.paymentInfo', locale),
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'text',
|
|
199
|
+
data: {
|
|
200
|
+
type: 'plain',
|
|
201
|
+
text: paymentInfo,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'text',
|
|
206
|
+
data: {
|
|
207
|
+
type: 'plain',
|
|
208
|
+
color: '#9397A1',
|
|
209
|
+
text: translate('notification.common.validityPeriod', locale),
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
type: 'text',
|
|
214
|
+
data: {
|
|
215
|
+
type: 'plain',
|
|
216
|
+
text: `${currentPeriodStart} ~ ${currentPeriodEnd}(${duration})`,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
nftMintItem && {
|
|
220
|
+
type: 'text',
|
|
221
|
+
data: {
|
|
222
|
+
type: 'plain',
|
|
223
|
+
color: '#9397A1',
|
|
224
|
+
text: translate('notification.common.nftAddress', locale),
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
nftMintItem && {
|
|
228
|
+
type: 'text',
|
|
229
|
+
data: {
|
|
230
|
+
type: 'plain',
|
|
231
|
+
text: toDid(nftMintItem.address),
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
].filter(Boolean),
|
|
235
|
+
},
|
|
236
|
+
].filter(Boolean),
|
|
237
|
+
// @ts-ignore
|
|
238
|
+
actions: [
|
|
239
|
+
{
|
|
240
|
+
name: 'viewSubscription',
|
|
241
|
+
title: translate('notification.common.viewSubscription', locale),
|
|
242
|
+
link: viewSubscriptionLink,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'viewSubscription',
|
|
246
|
+
title: translate('notification.common.viewInvoice', locale),
|
|
247
|
+
link: viewInvoiceLink,
|
|
248
|
+
},
|
|
249
|
+
viewTxHashLink && {
|
|
250
|
+
name: 'viewTxHash',
|
|
251
|
+
title: translate('notification.common.viewTxHash', locale),
|
|
252
|
+
link: viewTxHashLink as string,
|
|
253
|
+
},
|
|
254
|
+
].filter(Boolean),
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
return template;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/brace-style */
|
|
2
|
+
/* eslint-disable @typescript-eslint/indent */
|
|
3
|
+
import { fromUnitToToken } from '@ocap/util';
|
|
4
|
+
import pWaitFor from 'p-wait-for';
|
|
5
|
+
import prettyMsI18n from 'pretty-ms-i18n';
|
|
6
|
+
|
|
7
|
+
import { getUserLocale } from '../../../integrations/blocklet/notification';
|
|
8
|
+
import { translate } from '../../../locales';
|
|
9
|
+
import {
|
|
10
|
+
CheckoutSession,
|
|
11
|
+
Customer,
|
|
12
|
+
NftMintItem,
|
|
13
|
+
PaymentIntent,
|
|
14
|
+
PaymentMethod,
|
|
15
|
+
Subscription,
|
|
16
|
+
} from '../../../store/models';
|
|
17
|
+
import { Invoice } from '../../../store/models/invoice';
|
|
18
|
+
import { PaymentCurrency } from '../../../store/models/payment-currency';
|
|
19
|
+
import { getCustomerInvoicePageUrl } from '../../invoice';
|
|
20
|
+
import { getMainProductName } from '../../product';
|
|
21
|
+
import { getCustomerSubscriptionPageUrl } from '../../subscription';
|
|
22
|
+
import { formatTime, getPrettyMsI18nLocale } from '../../time';
|
|
23
|
+
import { getExplorerLink } from '../../util';
|
|
24
|
+
import type { BaseEmailTemplate, BaseEmailTemplateType } from './base';
|
|
25
|
+
|
|
26
|
+
export interface SubscriptionSucceededEmailTemplateOptions {
|
|
27
|
+
subscriptionId: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface SubscriptionSucceededEmailTemplateContext {
|
|
31
|
+
locale: string;
|
|
32
|
+
productName: string;
|
|
33
|
+
at: string;
|
|
34
|
+
nftMintItem: NftMintItem | undefined;
|
|
35
|
+
chainHost: string | undefined;
|
|
36
|
+
userDid: string;
|
|
37
|
+
paymentInfo: string;
|
|
38
|
+
currentPeriodStart: string;
|
|
39
|
+
currentPeriodEnd: string;
|
|
40
|
+
duration: string;
|
|
41
|
+
viewSubscriptionLink: string;
|
|
42
|
+
viewInvoiceLink: string;
|
|
43
|
+
viewTxHashLink: string | undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class SubscriptionSucceededEmailTemplate
|
|
47
|
+
implements BaseEmailTemplate<SubscriptionSucceededEmailTemplateContext>
|
|
48
|
+
{
|
|
49
|
+
options: SubscriptionSucceededEmailTemplateOptions;
|
|
50
|
+
|
|
51
|
+
constructor(options: SubscriptionSucceededEmailTemplateOptions) {
|
|
52
|
+
this.options = options;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async getContext(): Promise<SubscriptionSucceededEmailTemplateContext> {
|
|
56
|
+
const subscription: Subscription | null = await Subscription.findByPk(this.options.subscriptionId);
|
|
57
|
+
if (!subscription) {
|
|
58
|
+
throw new Error(`Subscription not found: ${this.options.subscriptionId}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const customer = await Customer.findByPk(subscription.customer_id);
|
|
62
|
+
if (!customer) {
|
|
63
|
+
throw new Error(`Customer not found: ${subscription.customer_id}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
await pWaitFor(
|
|
67
|
+
async () => {
|
|
68
|
+
const [checkoutSession, invoice] = await Promise.all([
|
|
69
|
+
CheckoutSession.findOne({
|
|
70
|
+
where: {
|
|
71
|
+
subscription_id: subscription.id,
|
|
72
|
+
},
|
|
73
|
+
}),
|
|
74
|
+
Invoice.findOne({
|
|
75
|
+
where: {
|
|
76
|
+
subscription_id: subscription.id,
|
|
77
|
+
},
|
|
78
|
+
order: [['created_at', 'ASC']],
|
|
79
|
+
}),
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
return Boolean(
|
|
83
|
+
['minted', 'sent', 'error'].includes(checkoutSession?.nft_mint_status as string) && invoice?.payment_intent_id
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
{ timeout: 1000 * 10, interval: 1000 }
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const invoice = (await Invoice.findOne({
|
|
90
|
+
where: {
|
|
91
|
+
subscription_id: subscription.id,
|
|
92
|
+
},
|
|
93
|
+
order: [['created_at', 'ASC']],
|
|
94
|
+
})) as Invoice;
|
|
95
|
+
const paymentCurrency = (await PaymentCurrency.findOne({
|
|
96
|
+
where: {
|
|
97
|
+
id: subscription.currency_id,
|
|
98
|
+
},
|
|
99
|
+
})) as PaymentCurrency;
|
|
100
|
+
|
|
101
|
+
const checkoutSession = await CheckoutSession.findOne({
|
|
102
|
+
where: {
|
|
103
|
+
subscription_id: subscription.id,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const locale = await getUserLocale(customer.did);
|
|
108
|
+
const productName = await getMainProductName(subscription.id);
|
|
109
|
+
const at: string = formatTime(subscription.created_at);
|
|
110
|
+
|
|
111
|
+
const paymentInfo: string = `${fromUnitToToken(invoice.total, paymentCurrency.decimal)} ${paymentCurrency.symbol}`;
|
|
112
|
+
const hasNft: boolean = checkoutSession?.nft_mint_status === 'minted';
|
|
113
|
+
const nftMintItem: NftMintItem | undefined = hasNft
|
|
114
|
+
? checkoutSession?.nft_mint_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']
|
|
115
|
+
: undefined;
|
|
116
|
+
const currentPeriodStart: string = formatTime(invoice.period_start * 1000);
|
|
117
|
+
const currentPeriodEnd: string = formatTime(invoice.period_end * 1000);
|
|
118
|
+
const duration: string = prettyMsI18n(
|
|
119
|
+
new Date(currentPeriodEnd).getTime() - new Date(currentPeriodStart).getTime(),
|
|
120
|
+
{
|
|
121
|
+
locale: getPrettyMsI18nLocale(locale),
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const paymentMethod: PaymentMethod | null = await PaymentMethod.findByPk(invoice.default_payment_method_id);
|
|
126
|
+
// @FIXME: 获取 chainHost 困难的一批?
|
|
127
|
+
const chainHost: string | undefined =
|
|
128
|
+
paymentMethod?.settings?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.api_host;
|
|
129
|
+
const viewSubscriptionLink = getCustomerSubscriptionPageUrl(subscription.id, locale);
|
|
130
|
+
const viewInvoiceLink = getCustomerInvoicePageUrl(invoice.id, locale);
|
|
131
|
+
|
|
132
|
+
const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
|
|
133
|
+
const txHash: string | undefined =
|
|
134
|
+
paymentIntent?.payment_details?.[checkoutSession?.nft_mint_details?.type as 'arcblock' | 'ethereum']?.tx_hash;
|
|
135
|
+
const viewTxHashLink: string | undefined = txHash && getExplorerLink(chainHost, txHash as string, 'tx');
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
locale,
|
|
139
|
+
productName,
|
|
140
|
+
at,
|
|
141
|
+
|
|
142
|
+
userDid: customer.did,
|
|
143
|
+
nftMintItem,
|
|
144
|
+
chainHost,
|
|
145
|
+
paymentInfo,
|
|
146
|
+
currentPeriodStart,
|
|
147
|
+
currentPeriodEnd,
|
|
148
|
+
duration,
|
|
149
|
+
|
|
150
|
+
viewSubscriptionLink,
|
|
151
|
+
viewInvoiceLink,
|
|
152
|
+
viewTxHashLink,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async getTemplate(): Promise<BaseEmailTemplateType> {
|
|
157
|
+
const {
|
|
158
|
+
locale,
|
|
159
|
+
productName,
|
|
160
|
+
at,
|
|
161
|
+
nftMintItem,
|
|
162
|
+
chainHost,
|
|
163
|
+
userDid,
|
|
164
|
+
paymentInfo,
|
|
165
|
+
currentPeriodStart,
|
|
166
|
+
currentPeriodEnd,
|
|
167
|
+
duration,
|
|
168
|
+
viewSubscriptionLink,
|
|
169
|
+
viewInvoiceLink,
|
|
170
|
+
viewTxHashLink,
|
|
171
|
+
} = await this.getContext();
|
|
172
|
+
|
|
173
|
+
const template: BaseEmailTemplateType = {
|
|
174
|
+
title: `${translate('notification.subscriptionSucceed.title', locale, {
|
|
175
|
+
productName: `(${productName})`,
|
|
176
|
+
})}`,
|
|
177
|
+
body: `${translate('notification.subscriptionSucceed.body', locale, {
|
|
178
|
+
at,
|
|
179
|
+
productName: `(${productName})`,
|
|
180
|
+
})}`,
|
|
181
|
+
// @ts-expect-error
|
|
182
|
+
attachments: [
|
|
183
|
+
nftMintItem &&
|
|
184
|
+
chainHost && {
|
|
185
|
+
type: 'asset',
|
|
186
|
+
data: {
|
|
187
|
+
chainHost,
|
|
188
|
+
did: nftMintItem.address,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
type: 'section',
|
|
193
|
+
fields: [
|
|
194
|
+
{
|
|
195
|
+
type: 'text',
|
|
196
|
+
data: {
|
|
197
|
+
type: 'plain',
|
|
198
|
+
color: '#9397A1',
|
|
199
|
+
text: translate('notification.common.account', locale),
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
type: 'text',
|
|
204
|
+
data: {
|
|
205
|
+
type: 'plain',
|
|
206
|
+
text: userDid,
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
type: 'text',
|
|
211
|
+
data: {
|
|
212
|
+
type: 'plain',
|
|
213
|
+
color: '#9397A1',
|
|
214
|
+
text: translate('notification.common.product', locale),
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
type: 'text',
|
|
219
|
+
data: {
|
|
220
|
+
type: 'plain',
|
|
221
|
+
text: productName,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
type: 'text',
|
|
226
|
+
data: {
|
|
227
|
+
type: 'plain',
|
|
228
|
+
color: '#9397A1',
|
|
229
|
+
text: translate('notification.common.paymentInfo', locale),
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
type: 'text',
|
|
234
|
+
data: {
|
|
235
|
+
type: 'plain',
|
|
236
|
+
text: paymentInfo,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
type: 'text',
|
|
241
|
+
data: {
|
|
242
|
+
type: 'plain',
|
|
243
|
+
color: '#9397A1',
|
|
244
|
+
text: translate('notification.common.validityPeriod', locale),
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
type: 'text',
|
|
249
|
+
data: {
|
|
250
|
+
type: 'plain',
|
|
251
|
+
text: `${currentPeriodStart} ~ ${currentPeriodEnd}(${duration})`,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
].filter(Boolean),
|
|
255
|
+
},
|
|
256
|
+
].filter(Boolean),
|
|
257
|
+
// @ts-ignore
|
|
258
|
+
actions: [
|
|
259
|
+
{
|
|
260
|
+
name: 'viewSubscription',
|
|
261
|
+
title: translate('notification.common.viewSubscription', locale),
|
|
262
|
+
link: viewSubscriptionLink,
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'viewSubscription',
|
|
266
|
+
title: translate('notification.common.viewInvoice', locale),
|
|
267
|
+
link: viewInvoiceLink,
|
|
268
|
+
},
|
|
269
|
+
viewTxHashLink && {
|
|
270
|
+
name: 'viewTxHash',
|
|
271
|
+
title: translate('notification.common.viewTxHash', locale),
|
|
272
|
+
link: viewTxHashLink as string,
|
|
273
|
+
},
|
|
274
|
+
].filter(Boolean),
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
return template;
|
|
278
|
+
}
|
|
279
|
+
}
|