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.
Files changed (37) hide show
  1. package/api/src/index.ts +2 -0
  2. package/api/src/libs/invoice.ts +5 -3
  3. package/api/src/libs/notification/template/customer-reward-succeeded.ts +32 -14
  4. package/api/src/libs/session.ts +9 -1
  5. package/api/src/libs/util.ts +12 -4
  6. package/api/src/routes/checkout-sessions.ts +286 -120
  7. package/api/src/routes/connect/change-payment.ts +9 -1
  8. package/api/src/routes/connect/change-plan.ts +9 -1
  9. package/api/src/routes/connect/collect-batch.ts +7 -5
  10. package/api/src/routes/connect/pay.ts +1 -1
  11. package/api/src/routes/connect/recharge-account.ts +124 -0
  12. package/api/src/routes/connect/setup.ts +8 -1
  13. package/api/src/routes/connect/shared.ts +175 -54
  14. package/api/src/routes/connect/subscribe.ts +11 -1
  15. package/api/src/routes/customers.ts +150 -7
  16. package/api/src/routes/donations.ts +1 -1
  17. package/api/src/routes/invoices.ts +47 -1
  18. package/api/src/routes/subscriptions.ts +0 -3
  19. package/blocklet.yml +2 -1
  20. package/package.json +16 -16
  21. package/src/app.tsx +11 -3
  22. package/src/components/info-card.tsx +6 -2
  23. package/src/components/info-row.tsx +1 -0
  24. package/src/components/invoice/recharge.tsx +85 -56
  25. package/src/components/invoice/table.tsx +7 -1
  26. package/src/components/subscription/portal/actions.tsx +1 -1
  27. package/src/components/subscription/portal/list.tsx +6 -0
  28. package/src/locales/en.tsx +9 -0
  29. package/src/locales/zh.tsx +9 -0
  30. package/src/pages/admin/payments/payouts/detail.tsx +16 -5
  31. package/src/pages/customer/index.tsx +226 -284
  32. package/src/pages/customer/invoice/detail.tsx +24 -16
  33. package/src/pages/customer/invoice/past-due.tsx +46 -23
  34. package/src/pages/customer/payout/detail.tsx +16 -5
  35. package/src/pages/customer/recharge/account.tsx +513 -0
  36. package/src/pages/customer/{recharge.tsx → recharge/subscription.tsx} +22 -19
  37. 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);
@@ -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.livemode,
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
- const customer = await Customer.findByPk(cs.customer_id);
81
- if (!customer) {
82
- throw new Error(`Customer not found: ${cs.customer_id}`);
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 = getCustomerInvoicePageUrl({
145
- invoiceId: checkoutSession.invoice_id!,
146
- userDid,
147
- locale,
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
  }
@@ -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
+ }
@@ -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: joinURL(process.env.BLOCKLET_APP_URL!, '.well-known/service/blocklet/logo'),
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: user?.fullName,
257
- avatar: joinURL(process.env.BLOCKLET_APP_URL!, user?.avatar),
264
+ name: 'anonymous',
265
+ avatar: getUrl('/methods/default.png'),
258
266
  type: 'user',
259
267
  url: getCustomerProfileUrl({ userDid: address, locale: 'en' }),
260
268
  };