payment-kit 1.18.15 → 1.18.17
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 +2 -0
- package/api/src/libs/invoice.ts +5 -3
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +32 -14
- package/api/src/libs/session.ts +9 -1
- package/api/src/libs/util.ts +12 -4
- package/api/src/routes/checkout-sessions.ts +286 -120
- package/api/src/routes/connect/change-payment.ts +9 -1
- package/api/src/routes/connect/change-plan.ts +9 -1
- package/api/src/routes/connect/collect-batch.ts +7 -5
- package/api/src/routes/connect/pay.ts +1 -1
- package/api/src/routes/connect/recharge-account.ts +124 -0
- package/api/src/routes/connect/setup.ts +8 -1
- package/api/src/routes/connect/shared.ts +175 -54
- package/api/src/routes/connect/subscribe.ts +11 -1
- package/api/src/routes/customers.ts +150 -7
- package/api/src/routes/donations.ts +1 -1
- package/api/src/routes/invoices.ts +47 -1
- package/api/src/routes/subscriptions.ts +0 -3
- package/blocklet.yml +2 -1
- package/package.json +16 -16
- package/src/app.tsx +11 -3
- package/src/components/info-card.tsx +6 -2
- package/src/components/info-row.tsx +1 -0
- package/src/components/invoice/recharge.tsx +85 -56
- package/src/components/invoice/table.tsx +7 -1
- package/src/components/subscription/portal/actions.tsx +1 -1
- package/src/components/subscription/portal/list.tsx +6 -0
- package/src/locales/en.tsx +9 -0
- package/src/locales/zh.tsx +9 -0
- package/src/pages/admin/payments/payouts/detail.tsx +16 -5
- package/src/pages/customer/index.tsx +226 -284
- package/src/pages/customer/invoice/detail.tsx +24 -16
- package/src/pages/customer/invoice/past-due.tsx +46 -23
- package/src/pages/customer/payout/detail.tsx +16 -5
- package/src/pages/customer/recharge/account.tsx +513 -0
- package/src/pages/customer/{recharge.tsx → recharge/subscription.tsx} +22 -19
- package/src/pages/customer/subscription/embed.tsx +16 -1
package/api/src/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ import setupHandlers from './routes/connect/setup';
|
|
|
39
39
|
import subscribeHandlers from './routes/connect/subscribe';
|
|
40
40
|
import delegationHandlers from './routes/connect/delegation';
|
|
41
41
|
import overdraftProtectionHandlers from './routes/connect/overdraft-protection';
|
|
42
|
+
import rechargeAccountHandlers from './routes/connect/recharge-account';
|
|
42
43
|
import { initialize } from './store/models';
|
|
43
44
|
import { sequelize } from './store/sequelize';
|
|
44
45
|
import { initUserHandler } from './integrations/blocklet/user';
|
|
@@ -74,6 +75,7 @@ handlers.attach(Object.assign({ app: router }, subscribeHandlers));
|
|
|
74
75
|
handlers.attach(Object.assign({ app: router }, changePaymentHandlers));
|
|
75
76
|
handlers.attach(Object.assign({ app: router }, changePlanHandlers));
|
|
76
77
|
handlers.attach(Object.assign({ app: router }, rechargeHandlers));
|
|
78
|
+
handlers.attach(Object.assign({ app: router }, rechargeAccountHandlers));
|
|
77
79
|
handlers.attach(Object.assign({ app: router }, delegationHandlers));
|
|
78
80
|
handlers.attach(Object.assign({ app: router }, overdraftProtectionHandlers));
|
|
79
81
|
router.use('/api', routes);
|
package/api/src/libs/invoice.ts
CHANGED
|
@@ -363,7 +363,7 @@ export async function getStakingInvoices(subscription: Subscription): Promise<In
|
|
|
363
363
|
|
|
364
364
|
type BaseInvoiceProps = {
|
|
365
365
|
customer: Customer;
|
|
366
|
-
subscription?: Subscription;
|
|
366
|
+
subscription?: Subscription | null;
|
|
367
367
|
currency_id: string;
|
|
368
368
|
livemode: boolean;
|
|
369
369
|
period_start: number;
|
|
@@ -660,17 +660,19 @@ export async function ensureRechargeInvoice(
|
|
|
660
660
|
currency_id: string;
|
|
661
661
|
metadata?: any;
|
|
662
662
|
payment_settings?: any;
|
|
663
|
+
livemode?: boolean;
|
|
663
664
|
},
|
|
664
|
-
subscription: Subscription,
|
|
665
|
+
subscription: Subscription | null,
|
|
665
666
|
paymentMethod: PaymentMethod,
|
|
666
667
|
customer: Customer
|
|
667
668
|
) {
|
|
668
669
|
try {
|
|
670
|
+
const { livemode = true } = invoiceProps;
|
|
669
671
|
const { invoice } = await createInvoiceWithItems({
|
|
670
672
|
customer,
|
|
671
673
|
subscription,
|
|
672
674
|
currency_id: invoiceProps.currency_id,
|
|
673
|
-
livemode: subscription
|
|
675
|
+
livemode: subscription?.livemode ?? livemode,
|
|
674
676
|
period_start: dayjs().unix(),
|
|
675
677
|
period_end: dayjs().unix(),
|
|
676
678
|
status: 'paid',
|
|
@@ -77,9 +77,12 @@ export class CustomerRewardSucceededEmailTemplate
|
|
|
77
77
|
throw new Error(`CheckoutSession(${this.options.checkoutSessionId}) mode must be payment`);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
80
|
+
let userDid = '';
|
|
81
|
+
if (cs.customer_id) {
|
|
82
|
+
const customer = await Customer.findByPk(cs.customer_id);
|
|
83
|
+
if (customer) {
|
|
84
|
+
userDid = customer.did;
|
|
85
|
+
}
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
await pWaitFor(
|
|
@@ -114,17 +117,31 @@ export class CustomerRewardSucceededEmailTemplate
|
|
|
114
117
|
},
|
|
115
118
|
})) as PaymentCurrency;
|
|
116
119
|
|
|
117
|
-
const userDid: string = customer.did;
|
|
118
|
-
const locale = await getUserLocale(userDid);
|
|
119
|
-
const at: string = formatTime(checkoutSession.created_at);
|
|
120
|
-
|
|
121
|
-
const paymentInfo: string = `${fromUnitToToken(checkoutSession?.amount_total, paymentCurrency.decimal)} ${paymentCurrency.symbol}`;
|
|
122
120
|
const paymentIntent = await PaymentIntent.findByPk(checkoutSession!.payment_intent_id);
|
|
123
121
|
if (!paymentIntent) {
|
|
124
122
|
throw new Error(
|
|
125
123
|
`Payment intent cannot be found for checkoutSession.payment_intent_id${checkoutSession!.payment_intent_id}`
|
|
126
124
|
);
|
|
127
125
|
}
|
|
126
|
+
|
|
127
|
+
// 如果没有从customer获取到userDid,尝试从支付详情中获取
|
|
128
|
+
if (!userDid) {
|
|
129
|
+
const paymentMethod = await PaymentMethod.findByPk(paymentIntent.payment_method_id);
|
|
130
|
+
if (paymentMethod) {
|
|
131
|
+
// @ts-expect-error
|
|
132
|
+
userDid = paymentIntent.payment_details?.[paymentMethod.type]?.payer || '';
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!userDid) {
|
|
137
|
+
throw new Error('User DID not found for reward notification');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const locale = await getUserLocale(userDid);
|
|
141
|
+
const at: string = formatTime(checkoutSession.created_at);
|
|
142
|
+
|
|
143
|
+
const paymentInfo: string = `${fromUnitToToken(checkoutSession?.amount_total, paymentCurrency.decimal)} ${paymentCurrency.symbol}`;
|
|
144
|
+
|
|
128
145
|
const rewardDetail = await this.getRewardDetail({
|
|
129
146
|
paymentIntent,
|
|
130
147
|
paymentCurrency,
|
|
@@ -141,11 +158,13 @@ export class CustomerRewardSucceededEmailTemplate
|
|
|
141
158
|
const paymentMethod: PaymentMethod | null = await PaymentMethod.findByPk(paymentIntent!.payment_method_id);
|
|
142
159
|
// @ts-expect-error
|
|
143
160
|
const chainHost: string | undefined = paymentMethod?.settings?.[paymentMethod.type]?.api_host;
|
|
144
|
-
const viewInvoiceLink =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
161
|
+
const viewInvoiceLink = checkoutSession.invoice_id
|
|
162
|
+
? getCustomerInvoicePageUrl({
|
|
163
|
+
invoiceId: checkoutSession.invoice_id,
|
|
164
|
+
userDid,
|
|
165
|
+
locale,
|
|
166
|
+
})
|
|
167
|
+
: '';
|
|
149
168
|
|
|
150
169
|
// @ts-expect-error
|
|
151
170
|
const txHash: string | undefined = paymentIntent?.payment_details?.[paymentMethod.type]?.tx_hash;
|
|
@@ -330,7 +349,6 @@ export class CustomerRewardSucceededEmailTemplate
|
|
|
330
349
|
},
|
|
331
350
|
].filter(Boolean),
|
|
332
351
|
};
|
|
333
|
-
|
|
334
352
|
return template;
|
|
335
353
|
}
|
|
336
354
|
}
|
package/api/src/libs/session.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { BN } from '@ocap/util';
|
|
|
4
4
|
import cloneDeep from 'lodash/cloneDeep';
|
|
5
5
|
import isEqual from 'lodash/isEqual';
|
|
6
6
|
|
|
7
|
-
import type { TLineItemExpanded, TPaymentCurrency, TPaymentMethodExpanded } from '../store/models';
|
|
7
|
+
import type { CheckoutSession, TLineItemExpanded, TPaymentCurrency, TPaymentMethodExpanded } from '../store/models';
|
|
8
8
|
import type { Price, TPrice } from '../store/models/price';
|
|
9
9
|
import type { Product } from '../store/models/product';
|
|
10
10
|
import type { PaymentBeneficiary, PriceCurrency, PriceRecurring } from '../store/models/types';
|
|
@@ -375,3 +375,11 @@ export function createPaymentOutput(
|
|
|
375
375
|
},
|
|
376
376
|
];
|
|
377
377
|
}
|
|
378
|
+
|
|
379
|
+
export function isDonationCheckoutSession(checkoutSession: CheckoutSession): boolean {
|
|
380
|
+
return (
|
|
381
|
+
checkoutSession.submit_type === 'donate' ||
|
|
382
|
+
checkoutSession.metadata?.type === 'donation' ||
|
|
383
|
+
!!checkoutSession.metadata?.is_donation
|
|
384
|
+
);
|
|
385
|
+
}
|
package/api/src/libs/util.ts
CHANGED
|
@@ -220,7 +220,7 @@ export async function getBlockletJson(url?: string) {
|
|
|
220
220
|
componentMountPoints: BLOCKLET_MOUNT_POINTS,
|
|
221
221
|
appId: process.env.BLOCKLET_APP_ID,
|
|
222
222
|
appName: process.env.BLOCKLET_APP_NAME,
|
|
223
|
-
appLogo:
|
|
223
|
+
appLogo: '/.well-known/service/blocklet/logo',
|
|
224
224
|
appUrl: process.env.BLOCKLET_APP_URL,
|
|
225
225
|
};
|
|
226
226
|
}
|
|
@@ -236,7 +236,7 @@ export async function getUserOrAppInfo(
|
|
|
236
236
|
if (blockletJson?.appId === address) {
|
|
237
237
|
return {
|
|
238
238
|
name: blockletJson?.appName,
|
|
239
|
-
avatar: blockletJson?.appLogo
|
|
239
|
+
avatar: `${blockletJson?.appUrl}${blockletJson?.appLogo}`,
|
|
240
240
|
type: 'dapp',
|
|
241
241
|
url: blockletJson?.appUrl,
|
|
242
242
|
};
|
|
@@ -252,9 +252,17 @@ export async function getUserOrAppInfo(
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
const { user } = await blocklet.getUser(address);
|
|
255
|
+
if (user) {
|
|
256
|
+
return {
|
|
257
|
+
name: user?.fullName,
|
|
258
|
+
avatar: joinURL(process.env.BLOCKLET_APP_URL!, user?.avatar),
|
|
259
|
+
type: 'user',
|
|
260
|
+
url: getCustomerProfileUrl({ userDid: address, locale: 'en' }),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
255
263
|
return {
|
|
256
|
-
name:
|
|
257
|
-
avatar:
|
|
264
|
+
name: 'anonymous',
|
|
265
|
+
avatar: getUrl('/methods/default.png'),
|
|
258
266
|
type: 'user',
|
|
259
267
|
url: getCustomerProfileUrl({ userDid: address, locale: 'en' }),
|
|
260
268
|
};
|