payment-kit 1.13.89 → 1.13.91

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.
@@ -19,7 +19,7 @@ export async function handleSetupIntentEvent(event: TEventExpanded, _: Stripe) {
19
19
 
20
20
  if (event.type === 'setup_intent.succeeded') {
21
21
  if (subscription.status === 'incomplete') {
22
- await subscription.update({ status: subscription.trail_end ? 'trialing' : 'active' });
22
+ await subscription.start();
23
23
  logger.info('subscription become active on stripe intent succeeded', subscription.id);
24
24
  }
25
25
 
@@ -7,7 +7,7 @@ import { events } from './event';
7
7
 
8
8
  const API_VERSION = '2023-09-05';
9
9
 
10
- export async function createEvent(scope: string, type: LiteralUnion<EventType, string>, model: any, options: any) {
10
+ export async function createEvent(scope: string, type: LiteralUnion<EventType, string>, model: any, options: any = {}) {
11
11
  // console.log('createEvent', scope, type, model, options);
12
12
  const data: any = {
13
13
  object: model.dataValues,
@@ -44,7 +44,7 @@ export async function createStatusEvent(
44
44
  prefix: string,
45
45
  config: Record<string, string>,
46
46
  model: any,
47
- options: any
47
+ options: any = {}
48
48
  ) {
49
49
  // console.log('createStatusEvent', scope, prefix, config, model, options);
50
50
  if (options.fields.includes('status') === false) {
@@ -298,6 +298,7 @@ export function getFastCheckoutAmount(
298
298
  }
299
299
 
300
300
  const { total, renew } = getCheckoutAmount(items, currencyId, includeFreeTrial);
301
+
301
302
  if (mode === 'payment') {
302
303
  return total;
303
304
  }
@@ -307,7 +308,7 @@ export function getFastCheckoutAmount(
307
308
  }
308
309
 
309
310
  if (mode === 'subscription') {
310
- return new BN(total).add(new BN(renew).mul(new BN(minimumCycle - 1))).toString();
311
+ return new BN(total).add(new BN(renew).mul(new BN(includeFreeTrial ? minimumCycle : minimumCycle - 1))).toString();
311
312
  }
312
313
 
313
314
  return '0';
@@ -58,7 +58,7 @@ export const handleInvoice = async (job: InvoiceJob) => {
58
58
  if (invoice.subscription_id) {
59
59
  const subscription = await Subscription.findByPk(invoice.subscription_id);
60
60
  if (subscription && subscription.status === 'incomplete') {
61
- await subscription.update({ status: subscription.trail_end ? 'trialing' : 'active' });
61
+ await subscription.start();
62
62
  logger.info('invoice subscription updated', subscription.id);
63
63
  }
64
64
  }
@@ -26,9 +26,8 @@ import {
26
26
  SubscriptionWillRenewEmailTemplate,
27
27
  SubscriptionWillRenewEmailTemplateOptions,
28
28
  } from '../libs/notification/template/subscription-will-renew';
29
- import type { SufficientForPaymentResult } from '../libs/payment';
30
29
  import createQueue from '../libs/queue';
31
- import type { EventType, Invoice, Subscription } from '../store/models';
30
+ import { EventType, Invoice, Subscription } from '../store/models';
32
31
 
33
32
  export type NotificationQueueJobOptions = any;
34
33
  export type NotificationQueueJob = {
@@ -113,30 +112,30 @@ export async function startNotificationQueue() {
113
112
  }
114
113
  });
115
114
 
116
- events.on('customer.subscription.renewed', (subscription: Subscription, invoice: Invoice) => {
115
+ events.on('customer.subscription.renewed', (subscription: Subscription) => {
117
116
  notificationQueue.push({
118
117
  job: {
119
118
  type: 'customer.subscription.renewed',
120
119
  options: {
121
120
  subscriptionId: subscription.id,
122
- invoiceId: invoice?.id,
121
+ invoiceId: subscription.latest_invoice_id,
123
122
  } as SubscriptionRenewedEmailTemplateOptions,
124
123
  },
125
124
  });
126
125
  });
127
126
 
128
- events.on(
129
- 'customer.subscription.renew_failed',
130
- ({ invoice, result }: { invoice: Invoice; result: SufficientForPaymentResult }) => {
127
+ events.on('customer.subscription.renew_failed', async (subscription: Subscription) => {
128
+ const invoice = await Invoice.findByPk(subscription.latest_invoice_id);
129
+ if (invoice && subscription.metadata.renew_failed_reason) {
131
130
  notificationQueue.push({
132
131
  job: {
133
132
  type: 'customer.subscription.renew_failed',
134
133
  options: {
135
134
  invoice,
136
- result,
135
+ result: subscription.metadata.renew_failed_reason,
137
136
  },
138
137
  },
139
138
  });
140
139
  }
141
- );
140
+ });
142
141
  }
@@ -1,4 +1,5 @@
1
1
  import { ensureStakedForGas } from '../integrations/blockchain/stake';
2
+ import { createEvent } from '../libs/audit';
2
3
  import { wallet } from '../libs/auth';
3
4
  import dayjs from '../libs/dayjs';
4
5
  import CustomError from '../libs/error';
@@ -60,14 +61,7 @@ export const handlePaymentSucceed = async (paymentIntent: PaymentIntent, invoice
60
61
  const subscription = await Subscription.findByPk(invoice.subscription_id);
61
62
  if (subscription) {
62
63
  if (subscription.status === 'incomplete') {
63
- await subscription.update({ status: subscription.trail_end ? 'trialing' : 'active' });
64
-
65
- if (subscription.trail_end) {
66
- events.emit('customer.subscription.trial_start', subscription);
67
- } else {
68
- events.emit('customer.subscription.started', subscription);
69
- }
70
-
64
+ await subscription.start();
71
65
  logger.info(`Subscription ${subscription.id} updated on payment done ${invoice.id}`);
72
66
  } else if (subscription.status === 'past_due') {
73
67
  if (subscription.cancel_at_period_end && subscription.cancelation_details?.reason === 'payment_failed') {
@@ -82,7 +76,7 @@ export const handlePaymentSucceed = async (paymentIntent: PaymentIntent, invoice
82
76
  }
83
77
 
84
78
  if (invoice.billing_reason === 'subscription_cycle') {
85
- events.emit('customer.subscription.renewed', subscription, invoice);
79
+ createEvent('Subscription', 'customer.subscription.renewed', subscription).catch(console.error);
86
80
  }
87
81
  }
88
82
 
@@ -412,10 +406,15 @@ export const handlePayment = async (job: PaymentJob) => {
412
406
 
413
407
  // 只有在重试次数超过阈值的时候才发送邮件,不然邮件频率太高了,初次邮件时首次失败 6 小时后
414
408
  if (attemptCount >= MIN_RETRY_MAIL && invoice.billing_reason === 'subscription_cycle') {
415
- events.emit('customer.subscription.renew_failed', {
416
- invoice,
417
- result: result || { sufficient: false, reason: 'TX_SEND_FAILED' },
418
- });
409
+ const subscription = await Subscription.findByPk(invoice.subscription_id);
410
+ if (subscription) {
411
+ await subscription.update({
412
+ metadata: Object.assign(subscription.metadata, {
413
+ renew_failed_reason: result || { sufficient: false, reason: 'TX_SEND_FAILED' },
414
+ }),
415
+ });
416
+ createEvent('Subscription', 'customer.subscription.renew_failed', subscription);
417
+ }
419
418
  }
420
419
 
421
420
  const updates = await handlePaymentFailed(paymentIntent, invoice, error);
@@ -1,9 +1,9 @@
1
1
  import type { Transaction, TransferV3Tx } from '@ocap/client';
2
2
  import { fromAddress } from '@ocap/wallet';
3
3
 
4
+ import { createEvent } from '../../libs/audit';
4
5
  import type { CallbackArgs } from '../../libs/auth';
5
6
  import { wallet } from '../../libs/auth';
6
- import { events } from '../../libs/event';
7
7
  import { getGasPayerExtra } from '../../libs/payment';
8
8
  import { getTxMetadata } from '../../libs/util';
9
9
  import { invoiceQueue } from '../../queues/invoice';
@@ -101,7 +101,11 @@ export default {
101
101
  }
102
102
 
103
103
  if (invoice.subscription_id) {
104
- events.emit('customer.subscription.renewed', await Subscription.findByPk(invoice.subscription_id), invoice);
104
+ createEvent(
105
+ 'Subscription',
106
+ 'customer.subscription.renewed',
107
+ await Subscription.findByPk(invoice.subscription_id)
108
+ );
105
109
  }
106
110
 
107
111
  return { hash: txHash };
@@ -24,10 +24,12 @@ const authPortal = authenticate<Customer>({
24
24
  const schema = Joi.object<{
25
25
  page: number;
26
26
  pageSize: number;
27
+ did?: string;
27
28
  livemode?: boolean;
28
29
  }>({
29
30
  page: Joi.number().integer().min(1).default(1),
30
31
  pageSize: Joi.number().integer().min(1).max(100).default(20),
32
+ did: Joi.string().empty(''),
31
33
  livemode: Joi.boolean().empty(''),
32
34
  });
33
35
  router.get('/', auth, async (req, res) => {
@@ -37,6 +39,9 @@ router.get('/', auth, async (req, res) => {
37
39
  if (typeof query.livemode === 'boolean') {
38
40
  where.livemode = query.livemode;
39
41
  }
42
+ if (query.did) {
43
+ where.did = query.did;
44
+ }
40
45
 
41
46
  try {
42
47
  const { rows: list, count } = await Customer.findAndCountAll({
@@ -4,6 +4,7 @@ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes,
4
4
  import type { LiteralUnion } from 'type-fest';
5
5
 
6
6
  import { createCustomEvent, createEvent, createStatusEvent } from '../../libs/audit';
7
+ import logger from '../../libs/logger';
7
8
  import { createIdGenerator } from '../../libs/util';
8
9
  import { Invoice } from './invoice';
9
10
  import type { PaymentDetails, PaymentSettings, PriceRecurring } from './types';
@@ -358,6 +359,26 @@ export class Subscription extends Model<InferAttributes<Subscription>, InferCrea
358
359
  public isActive() {
359
360
  return ['active', 'trialing'].includes(this.status);
360
361
  }
362
+
363
+ public async start() {
364
+ if (this.isActive()) {
365
+ logger.warn(`subscription already started: ${this.id}`);
366
+ return;
367
+ }
368
+
369
+ if (this.isImmutable()) {
370
+ logger.warn(`subscription is immutable: ${this.id}`);
371
+ return;
372
+ }
373
+
374
+ if (this.trail_end) {
375
+ await this.update({ status: 'trialing' });
376
+ createEvent('Subscription', 'customer.subscription.trial_start', this).catch(console.error);
377
+ } else {
378
+ await this.update({ status: 'active' });
379
+ createEvent('Subscription', 'customer.subscription.started', this).catch(console.error);
380
+ }
381
+ }
361
382
  }
362
383
 
363
384
  export type TSubscription = InferAttributes<Subscription>;
@@ -9,9 +9,6 @@ export type Pagination<T = any> = T & {
9
9
  // TODO: cursor based
10
10
  starting_after?: string;
11
11
  ending_before?: string;
12
-
13
- // extra
14
- [key: string]: any;
15
12
  };
16
13
 
17
14
  export type Searchable<T = any> = Pagination<T> & {
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.89
17
+ version: 1.13.91
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.89",
3
+ "version": "1.13.91",
4
4
  "scripts": {
5
5
  "dev": "COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev",
6
6
  "eject": "vite eject",
@@ -110,7 +110,7 @@
110
110
  "@abtnode/types": "1.16.21",
111
111
  "@arcblock/eslint-config": "^0.2.4",
112
112
  "@arcblock/eslint-config-ts": "^0.2.4",
113
- "@did-pay/types": "1.13.89",
113
+ "@did-pay/types": "1.13.91",
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": "309312b8ffce48cd121af0a5b75494a1ae5dada0"
152
+ "gitHead": "970a705a07b5b34cb04f54c5e76797c96c500d81"
153
153
  }