payment-kit 1.13.170 → 1.13.171

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.
@@ -1,10 +1,11 @@
1
1
  import Cron from '@abtnode/cron';
2
2
 
3
- import { batchHandleStripeInvoices } from '../integrations/stripe/resource';
3
+ import { batchHandleStripeInvoices, batchHandleStripeSubscriptions } from '../integrations/stripe/resource';
4
4
  import {
5
5
  expiredSessionCleanupCronTime,
6
6
  notificationCronTime,
7
7
  stripeInvoiceCronTime,
8
+ stripeSubscriptionCronTime,
8
9
  subscriptionCronTime,
9
10
  } from '../libs/env';
10
11
  import logger from '../libs/logger';
@@ -57,6 +58,12 @@ function init() {
57
58
  fn: batchHandleStripeInvoices,
58
59
  options: { runOnInit: false },
59
60
  },
61
+ {
62
+ name: 'stripe.subscription.sync',
63
+ time: stripeSubscriptionCronTime,
64
+ fn: batchHandleStripeSubscriptions,
65
+ options: { runOnInit: false },
66
+ },
60
67
  ],
61
68
  onError: (error: Error, name: string) => {
62
69
  logger.error('run job failed', { name, error: error.message, stack: error.stack });
@@ -43,7 +43,7 @@ export async function handleSubscriptionEvent(event: TEventExpanded, _: Stripe)
43
43
  return;
44
44
  }
45
45
 
46
- const fields = ['cancel_at', 'cancel_at_period_end', 'canceled_at'];
46
+ const fields = ['cancel_at', 'cancel_at_period_end', 'canceled_at', 'current_period_start', 'current_period_end'];
47
47
  if (subscription.payment_settings?.payment_method_types?.includes('stripe')) {
48
48
  fields.push('pause_collection');
49
49
  }
@@ -1,5 +1,9 @@
1
+ /* eslint-disable no-continue */
2
+ /* eslint-disable no-await-in-loop */
1
3
  import env from '@blocklet/sdk/lib/env';
2
4
  import merge from 'lodash/merge';
5
+ import omit from 'lodash/omit';
6
+ import pick from 'lodash/pick';
3
7
  import { Op } from 'sequelize';
4
8
 
5
9
  import logger from '../../libs/logger';
@@ -347,15 +351,15 @@ export async function batchHandleStripeInvoices() {
347
351
  },
348
352
  });
349
353
 
350
- stripeInvoices.forEach(async (invoice) => {
354
+ for (const invoice of stripeInvoices) {
351
355
  const stripeInvoiceId = invoice.metadata?.stripe_id;
352
356
  if (!stripeInvoiceId) {
353
- return;
357
+ continue;
354
358
  }
355
359
 
356
360
  const method = stripeMethods.find((m) => m.livemode === invoice.livemode);
357
361
  if (!method) {
358
- return;
362
+ continue;
359
363
  }
360
364
 
361
365
  const client = method.getStripeClient();
@@ -369,8 +373,6 @@ export async function batchHandleStripeInvoices() {
369
373
  await client.invoices.pay(stripeInvoiceId);
370
374
  logger.info('stripe invoice payment requested', { local: invoice.id, stripe: stripeInvoiceId });
371
375
 
372
- await sleep(5000);
373
-
374
376
  await syncStripeInvoice(invoice);
375
377
 
376
378
  if (invoice.payment_intent_id) {
@@ -392,5 +394,66 @@ export async function batchHandleStripeInvoices() {
392
394
  logger.error('stripe invoice finalize error', error);
393
395
  }
394
396
  }
397
+
398
+ await sleep(5000);
399
+ }
400
+ }
401
+
402
+ export async function batchHandleStripeSubscriptions() {
403
+ const stripeMethods = await PaymentMethod.findAll({ where: { type: 'stripe' } });
404
+ if (stripeMethods.length === 0) {
405
+ return;
406
+ }
407
+
408
+ const subscriptions = await Subscription.findAll({
409
+ where: {
410
+ status: { [Op.not]: ['canceled', 'incomplete', 'incomplete_expired'] },
411
+ 'payment_details.stripe.subscription_id': { [Op.not]: null },
412
+ },
395
413
  });
414
+
415
+ for (const subscription of subscriptions) {
416
+ const subscriptionId = subscription.payment_details?.stripe?.subscription_id;
417
+ if (!subscriptionId) {
418
+ continue;
419
+ }
420
+
421
+ const method = stripeMethods.find((m) => m.livemode === subscription.livemode);
422
+ if (!method) {
423
+ continue;
424
+ }
425
+
426
+ const client = method.getStripeClient();
427
+ try {
428
+ const exist = await client.subscriptions.retrieve(subscriptionId);
429
+ if (exist) {
430
+ const fields = [
431
+ 'cancel_at',
432
+ 'cancel_at_period_end',
433
+ 'canceled_at',
434
+ 'current_period_start',
435
+ 'current_period_end',
436
+ ];
437
+ if (subscription.payment_settings?.payment_method_types?.includes('stripe')) {
438
+ fields.push('pause_collection');
439
+ }
440
+ await subscription.update(pick(exist, fields) as any);
441
+ logger.warn('stripe subscription synced', { local: subscription.id, stripe: subscriptionId });
442
+ } else {
443
+ logger.warn('stripe subscription missing', { local: subscription.id, stripe: subscriptionId });
444
+ }
445
+ } catch (error) {
446
+ logger.error('stripe subscription sync error', { error, local: subscription.id, stripe: subscriptionId });
447
+ if (error.message.includes('No such subscription')) {
448
+ await subscription.update({
449
+ payment_details: {
450
+ ...subscription.payment_details,
451
+ stripe: omit(subscription.payment_details?.stripe, ['subscription_id']),
452
+ },
453
+ });
454
+ }
455
+ }
456
+
457
+ await sleep(3000);
458
+ }
396
459
  }
@@ -4,7 +4,8 @@ export const subscriptionCronTime: string = process.env.SUBSCRIPTION_CRON_TIME |
4
4
  export const notificationCronTime: string = process.env.NOTIFICATION_CRON_TIME || '0 5 */6 * * *'; // 默认每6个小时执行一次
5
5
  export const expiredSessionCleanupCronTime: string = process.env.EXPIRED_SESSION_CLEANUP_CRON_TIME || '0 1 */2 * * *'; // 默认每2个小时执行一次
6
6
  export const notificationCronConcurrency: number = Number(process.env.NOTIFICATION_CRON_CONCURRENCY) || 8; // 默认并发数为 8
7
- export const stripeInvoiceCronTime: string = process.env.PAYMENT_STRIPE_CRON_TIME || '0 */30 * * * *'; // 默认每 30min 执行一次
7
+ export const stripeInvoiceCronTime: string = process.env.STRIPE_INVOICE_CRON_TIME || '0 */30 * * * *'; // 默认每 30min 执行一次
8
+ export const stripeSubscriptionCronTime: string = process.env.STRIPE_SUBSCRIPTION_CRON_TIME || '0 10 */8 * * *'; // 默认每 8小时 执行一次
8
9
 
9
10
  export default {
10
11
  ...env,
@@ -1,6 +1,7 @@
1
1
  import type { LiteralUnion } from 'type-fest';
2
2
 
3
3
  import { ensurePassportRevoked } from '../integrations/blocklet/passport';
4
+ import { batchHandleStripeSubscriptions } from '../integrations/stripe/resource';
4
5
  import dayjs from '../libs/dayjs';
5
6
  import { events } from '../libs/event';
6
7
  import { getLock } from '../libs/lock';
@@ -391,6 +392,8 @@ export const startSubscriptionQueue = async () => {
391
392
  }
392
393
  await addSubscriptionJob(x, 'cycle');
393
394
  });
395
+
396
+ await batchHandleStripeSubscriptions();
394
397
  };
395
398
 
396
399
  export async function addSubscriptionJob(
package/blocklet.yml CHANGED
@@ -14,7 +14,7 @@ repository:
14
14
  type: git
15
15
  url: git+https://github.com/blocklet/payment-kit.git
16
16
  specVersion: 1.2.8
17
- version: 1.13.170
17
+ version: 1.13.171
18
18
  logo: logo.png
19
19
  files:
20
20
  - dist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.13.170",
3
+ "version": "1.13.171",
4
4
  "scripts": {
5
5
  "dev": "cross-env COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev --open",
6
6
  "eject": "vite eject",
@@ -50,7 +50,7 @@
50
50
  "@arcblock/jwt": "^1.18.110",
51
51
  "@arcblock/ux": "^2.9.39",
52
52
  "@blocklet/logger": "1.16.23",
53
- "@blocklet/payment-react": "1.13.170",
53
+ "@blocklet/payment-react": "1.13.171",
54
54
  "@blocklet/sdk": "1.16.23",
55
55
  "@blocklet/ui-react": "^2.9.39",
56
56
  "@blocklet/uploader": "^0.0.74",
@@ -110,7 +110,7 @@
110
110
  "devDependencies": {
111
111
  "@abtnode/types": "1.16.23",
112
112
  "@arcblock/eslint-config-ts": "^0.2.4",
113
- "@blocklet/payment-types": "1.13.170",
113
+ "@blocklet/payment-types": "1.13.171",
114
114
  "@types/cookie-parser": "^1.4.6",
115
115
  "@types/cors": "^2.8.17",
116
116
  "@types/dotenv-flow": "^3.3.3",
@@ -149,5 +149,5 @@
149
149
  "parser": "typescript"
150
150
  }
151
151
  },
152
- "gitHead": "4a04bc6c92a74d683a6e84035972beb914f355ce"
152
+ "gitHead": "88712f035a9b1b2f6cec912520f58066fdb2b97f"
153
153
  }