payment-kit 1.14.36 → 1.14.37

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.
@@ -204,7 +204,7 @@ export async function ensureStripeSubscription(
204
204
  currency: PaymentCurrency,
205
205
  items: TLineItemExpanded[],
206
206
  trialInDays: number = 0,
207
- trialEnds: number = 0
207
+ trialEnd: number = 0
208
208
  ) {
209
209
  const client = method.getStripeClient();
210
210
 
@@ -255,8 +255,8 @@ export async function ensureStripeSubscription(
255
255
 
256
256
  if (trialInDays) {
257
257
  props.trial_period_days = trialInDays;
258
- } else if (trialEnds) {
259
- props.trial_end = trialEnds;
258
+ } else if (trialEnd) {
259
+ props.trial_end = trialEnd;
260
260
  }
261
261
 
262
262
  stripeSubscription = await client.subscriptions.create(props);
@@ -2,6 +2,7 @@
2
2
  import component from '@blocklet/sdk/lib/component';
3
3
  import { BN } from '@ocap/util';
4
4
  import isEmpty from 'lodash/isEmpty';
5
+ import trim from 'lodash/trim';
5
6
  import pick from 'lodash/pick';
6
7
  import type { LiteralUnion } from 'type-fest';
7
8
  import { withQuery } from 'ufo';
@@ -18,6 +19,7 @@ import {
18
19
  PriceRecurring,
19
20
  Refund,
20
21
  Subscription,
22
+ SubscriptionData,
21
23
  SubscriptionItem,
22
24
  SubscriptionUpdateItem,
23
25
  TLineItemExpanded,
@@ -147,7 +149,7 @@ export function getSubscriptionCreateSetup(
147
149
  items: TLineItemExpanded[],
148
150
  currencyId: string,
149
151
  trialInDays = 0,
150
- trialEnds = 0
152
+ trialEnd = 0
151
153
  ) {
152
154
  let setup = new BN(0);
153
155
 
@@ -170,18 +172,18 @@ export function getSubscriptionCreateSetup(
170
172
  const recurring = (item?.upsell_price || item?.price)?.recurring as PriceRecurring;
171
173
  const cycle = getRecurringPeriod(recurring);
172
174
 
173
- let trialStart = 0;
174
- let trialEnd = 0;
175
- if (+trialEnds && trialEnds > now) {
176
- trialStart = now;
177
- trialEnd = trialEnds;
175
+ let trialStartAt = 0;
176
+ let trialEndAt = 0;
177
+ if (+trialEnd && trialEnd > now) {
178
+ trialStartAt = now;
179
+ trialEndAt = trialEnd;
178
180
  } else if (trialInDays) {
179
- trialStart = now;
180
- trialEnd = dayjs().add(trialInDays, 'day').unix();
181
+ trialStartAt = now;
182
+ trialEndAt = dayjs().add(trialInDays, 'day').unix();
181
183
  }
182
184
 
183
- const periodStart = trialStart || now;
184
- const periodEnd = trialEnd || dayjs().add(cycle, 'millisecond').unix();
185
+ const periodStart = trialStartAt || now;
186
+ const periodEnd = trialEndAt || dayjs().add(cycle, 'millisecond').unix();
185
187
 
186
188
  return {
187
189
  recurring,
@@ -190,8 +192,8 @@ export function getSubscriptionCreateSetup(
190
192
  anchor: periodEnd,
191
193
  },
192
194
  trial: {
193
- start: trialStart,
194
- end: trialEnd,
195
+ start: trialStartAt,
196
+ end: trialEndAt,
195
197
  },
196
198
  period: {
197
199
  start: periodStart,
@@ -787,3 +789,19 @@ export async function checkRemainingStake(
787
789
  revoked,
788
790
  };
789
791
  }
792
+
793
+ // trialing can be customized with currency_id list
794
+ export function getSubscriptionTrialSetup(data: Partial<SubscriptionData>, currencyId: string) {
795
+ let trialInDays = Number(data?.trial_period_days || 0);
796
+ let trialEnd = Number(data?.trial_end || 0);
797
+ const trialCurrencyIds = (data?.trial_currency || '').split(',').map(trim).filter(Boolean);
798
+ if (trialCurrencyIds.length > 0 && trialCurrencyIds.includes(currencyId) === false) {
799
+ trialEnd = 0;
800
+ trialInDays = 0;
801
+ }
802
+
803
+ return {
804
+ trialInDays,
805
+ trialEnd,
806
+ };
807
+ }
@@ -42,6 +42,7 @@ import {
42
42
  getDaysUntilCancel,
43
43
  getDaysUntilDue,
44
44
  getSubscriptionCreateSetup,
45
+ getSubscriptionTrialSetup,
45
46
  } from '../libs/subscription';
46
47
  import { CHECKOUT_SESSION_TTL, formatAmountPrecisionLimit, formatMetadata, getDataObjectFromQuery } from '../libs/util';
47
48
  import { invoiceQueue } from '../queues/invoice';
@@ -249,8 +250,8 @@ export async function getCheckoutSessionAmounts(checkoutSession: CheckoutSession
249
250
  const now = dayjs().unix();
250
251
  const items = await Price.expand(checkoutSession.line_items);
251
252
  const trialInDays = Number(checkoutSession.subscription_data?.trial_period_days || 0);
252
- const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
253
- const amount = getCheckoutAmount(items, checkoutSession.currency_id, trialInDays > 0 || trialEnds > now);
253
+ const trialEnd = Number(checkoutSession.subscription_data?.trial_end || 0);
254
+ const amount = getCheckoutAmount(items, checkoutSession.currency_id, trialInDays > 0 || trialEnd > now);
254
255
  return {
255
256
  amount_subtotal: amount.subtotal,
256
257
  amount_total: amount.total,
@@ -574,11 +575,16 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
574
575
  // always update payment amount in case currency has changed
575
576
  const now = dayjs().unix();
576
577
  const lineItems = await Price.expand(checkoutSession.line_items, { product: true, upsell: true });
577
- const trialInDays = Number(checkoutSession.subscription_data?.trial_period_days || 0);
578
- const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
578
+
579
+ // trialing can be customized with currency_id list
580
+ const { trialEnd, trialInDays } = getSubscriptionTrialSetup(
581
+ checkoutSession.subscription_data as any,
582
+ paymentCurrency.id
583
+ );
584
+
579
585
  const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
580
586
  const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
581
- const amount = getCheckoutAmount(lineItems, paymentCurrency.id, trialInDays > 0 || trialEnds > now);
587
+ const amount = getCheckoutAmount(lineItems, paymentCurrency.id, trialInDays > 0 || trialEnd > now);
582
588
  await checkoutSession.update({
583
589
  amount_subtotal: amount.subtotal,
584
590
  amount_total: amount.total,
@@ -770,7 +776,7 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
770
776
  .status(403)
771
777
  .json({ code: 'SUBSCRIPTION_INVALID', error: 'Checkout session subscription status unexpected' });
772
778
  }
773
- const setup = getSubscriptionCreateSetup(lineItems, paymentCurrency.id, trialInDays, trialEnds);
779
+ const setup = getSubscriptionCreateSetup(lineItems, paymentCurrency.id, trialInDays, trialEnd);
774
780
  subscription = await subscription.update({
775
781
  currency_id: paymentCurrency.id,
776
782
  customer_id: customer.id,
@@ -813,7 +819,7 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
813
819
  const recoveredFrom = recoveredFromId ? await Subscription.findByPk(recoveredFromId) : null;
814
820
 
815
821
  // FIXME: @wangshijun respect all checkoutSession.subscription_data fields
816
- const setup = getSubscriptionCreateSetup(lineItems, paymentCurrency.id, trialInDays, trialEnds);
822
+ const setup = getSubscriptionCreateSetup(lineItems, paymentCurrency.id, trialInDays, trialEnd);
817
823
  subscription = await Subscription.create({
818
824
  livemode: !!checkoutSession.livemode,
819
825
  currency_id: paymentCurrency.id,
@@ -887,7 +893,7 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
887
893
  lineItems,
888
894
  checkoutSession.mode,
889
895
  paymentCurrency.id,
890
- trialInDays > 0 || trialEnds > now
896
+ trialInDays > 0 || trialEnd > now
891
897
  );
892
898
  const paymentSettings = {
893
899
  payment_method_types: checkoutSession.payment_method_types,
@@ -964,7 +970,7 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
964
970
  paymentCurrency,
965
971
  lineItems,
966
972
  trialInDays,
967
- trialEnds
973
+ trialEnd
968
974
  );
969
975
  if (stripeSubscription && subscription?.payment_details?.stripe?.subscription_id === stripeSubscription.id) {
970
976
  if (['active', 'trialing'].includes(stripeSubscription.status) && subscription.status === 'incomplete') {
@@ -3,6 +3,7 @@ import type { CallbackArgs } from '../../libs/auth';
3
3
  import dayjs from '../../libs/dayjs';
4
4
  import logger from '../../libs/logger';
5
5
  import { isDelegationSufficientForPayment } from '../../libs/payment';
6
+ import { getSubscriptionTrialSetup } from '../../libs/subscription';
6
7
  import { getFastCheckoutAmount } from '../../libs/session';
7
8
  import { getTxMetadata } from '../../libs/util';
8
9
  import { invoiceQueue } from '../../queues/invoice';
@@ -39,9 +40,13 @@ export default {
39
40
  const claims: { [type: string]: [string, object] } = {};
40
41
  const now = dayjs().unix();
41
42
  const items = checkoutSession.line_items as TLineItemExpanded[];
42
- const trialInDays = Number(checkoutSession.subscription_data?.trial_period_days || 0);
43
- const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
44
- const trialing = trialInDays > 0 || trialEnds > now;
43
+
44
+ const { trialEnd, trialInDays } = getSubscriptionTrialSetup(
45
+ checkoutSession.subscription_data as any,
46
+ paymentCurrency.id
47
+ );
48
+
49
+ const trialing = trialInDays > 0 || trialEnd > now;
45
50
  const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
46
51
  const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
47
52
  const fastCheckoutAmount = getFastCheckoutAmount(items, checkoutSession.mode, paymentCurrency.id, trialing);
@@ -3,6 +3,7 @@ import type { CallbackArgs } from '../../libs/auth';
3
3
  import dayjs from '../../libs/dayjs';
4
4
  import logger from '../../libs/logger';
5
5
  import { isDelegationSufficientForPayment } from '../../libs/payment';
6
+ import { getSubscriptionTrialSetup } from '../../libs/subscription';
6
7
  import { getFastCheckoutAmount } from '../../libs/session';
7
8
  import { getTxMetadata } from '../../libs/util';
8
9
  import { invoiceQueue } from '../../queues/invoice';
@@ -40,9 +41,11 @@ export default {
40
41
  const claims: { [type: string]: [string, object] } = {};
41
42
  const now = dayjs().unix();
42
43
  const items = checkoutSession.line_items as TLineItemExpanded[];
43
- const trialInDays = Number(checkoutSession.subscription_data?.trial_period_days || 0);
44
- const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
45
- const trialing = trialInDays > 0 || trialEnds > now;
44
+ const { trialEnd, trialInDays } = getSubscriptionTrialSetup(
45
+ checkoutSession.subscription_data as any,
46
+ paymentCurrency.id
47
+ );
48
+ const trialing = trialInDays > 0 || trialEnd > now;
46
49
  const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
47
50
  const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
48
51
  const fastCheckoutAmount = getFastCheckoutAmount(items, checkoutSession.mode, paymentCurrency.id, trialing);
@@ -1644,7 +1644,7 @@ router.put('/:id/slash-stake', auth, async (req, res) => {
1644
1644
  });
1645
1645
  return res.json(result);
1646
1646
  } catch (err) {
1647
- logger.error('subscription slash stake failed', { subscription: subscription.id, error: err.message });
1647
+ logger.error('subscription slash stake failed', { subscription: subscription.id, error: err });
1648
1648
  return res.status(400).json({ error: err.message });
1649
1649
  }
1650
1650
  });
@@ -367,6 +367,7 @@ export type SubscriptionData = {
367
367
  metadata?: Record<string, any>;
368
368
  recovered_from?: string;
369
369
  trial_end?: number;
370
+ trial_currency?: string;
370
371
  };
371
372
 
372
373
  // Very similar to PaymentLink
@@ -7,6 +7,7 @@ import {
7
7
  getMinRetryMail,
8
8
  getSubscriptionCreateSetup,
9
9
  getSubscriptionStakeSetup,
10
+ getSubscriptionTrialSetup,
10
11
  shouldCancelSubscription,
11
12
  } from '../../src/libs/subscription';
12
13
 
@@ -183,7 +184,7 @@ describe('getSubscriptionCreateSetup', () => {
183
184
  );
184
185
  });
185
186
 
186
- it('should trialEnds overwrite trialInDays', () => {
187
+ it('should trialEnd overwrite trialInDays', () => {
187
188
  const items = [
188
189
  {
189
190
  price: { type: 'recurring', currency_options: currencies, recurring: { interval: 'day', interval_count: '1' } },
@@ -200,7 +201,7 @@ describe('getSubscriptionCreateSetup', () => {
200
201
  );
201
202
  });
202
203
 
203
- it('should calculate trial period when only trialEnds is provided', () => {
204
+ it('should calculate trial period when only trialEnd is provided', () => {
204
205
  const items = [
205
206
  {
206
207
  price: { type: 'recurring', currency_options: currencies, recurring: { interval: 'day', interval_count: '1' } },
@@ -371,8 +372,8 @@ describe('getSubscriptionStakeSetup', () => {
371
372
 
372
373
  it('should calculate staking for recurring metered price type when billingThreshold is 0 #1', () => {
373
374
  const result = getSubscriptionStakeSetup(items.slice(2, 3), 'usd', '10');
374
- expect(result.licensed.toString()).toBe('0');
375
- expect(result.metered.toString()).toBe('10');
375
+ expect(result.licensed.toString()).toBe('10');
376
+ expect(result.metered.toString()).toBe('0');
376
377
  });
377
378
 
378
379
  it('should calculate staking for recurring metered price type when billingThreshold is 0 #2', () => {
@@ -383,7 +384,30 @@ describe('getSubscriptionStakeSetup', () => {
383
384
 
384
385
  it('should calculate staking for recurring metered price type when billingThreshold is greater than 0', () => {
385
386
  const result = getSubscriptionStakeSetup(items, 'usd', '10');
386
- expect(result.licensed.toString()).toBe('2');
387
- expect(result.metered.toString()).toBe('10');
387
+ expect(result.licensed.toString()).toBe('10');
388
+ expect(result.metered.toString()).toBe('0');
389
+ });
390
+ });
391
+
392
+ describe('getSubscriptionTrialSetup', () => {
393
+ it('should return trialInDays and trialEnd when data is provided', () => {
394
+ const data: any = { trial_period_days: '10', trial_end: '20', trial_currency: 'USD,EUR' };
395
+ const currencyId = 'USD';
396
+ const result = getSubscriptionTrialSetup(data, currencyId);
397
+ expect(result).toEqual({ trialInDays: 10, trialEnd: 20 });
398
+ });
399
+
400
+ it('should set trialInDays and trialEnd to 0 if currencyId is not in the trialCurrencyIds list', () => {
401
+ const data: any = { trial_period_days: '10', trial_end: '20', trial_currency: 'USD,EUR' };
402
+ const currencyId = 'JPY'; // currency code not included in the trialCurrencyIds list
403
+ const result = getSubscriptionTrialSetup(data, currencyId);
404
+ expect(result).toEqual({ trialInDays: 0, trialEnd: 0 });
405
+ });
406
+
407
+ it('should set trialInDays and trialEnd to 0 when values are not provided', () => {
408
+ const data: any = {};
409
+ const currencyId = 'USD';
410
+ const result = getSubscriptionTrialSetup(data, currencyId);
411
+ expect(result).toEqual({ trialInDays: 0, trialEnd: 0 });
388
412
  });
389
413
  });
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.14.36
17
+ version: 1.14.37
18
18
  logo: logo.png
19
19
  files:
20
20
  - dist
@@ -39,7 +39,6 @@ interfaces:
39
39
  profileFields:
40
40
  - fullName
41
41
  - email
42
- - phone
43
42
  - avatar
44
43
  allowSwitchProfile: true
45
44
  ignoreUrls:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.14.36",
3
+ "version": "1.14.37",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "eject": "vite eject",
@@ -52,7 +52,7 @@
52
52
  "@arcblock/validator": "^1.18.132",
53
53
  "@blocklet/js-sdk": "1.16.30",
54
54
  "@blocklet/logger": "1.16.30",
55
- "@blocklet/payment-react": "1.14.36",
55
+ "@blocklet/payment-react": "1.14.37",
56
56
  "@blocklet/sdk": "1.16.30",
57
57
  "@blocklet/ui-react": "^2.10.23",
58
58
  "@blocklet/uploader": "^0.1.27",
@@ -119,7 +119,7 @@
119
119
  "devDependencies": {
120
120
  "@abtnode/types": "1.16.30",
121
121
  "@arcblock/eslint-config-ts": "^0.3.2",
122
- "@blocklet/payment-types": "1.14.36",
122
+ "@blocklet/payment-types": "1.14.37",
123
123
  "@types/cookie-parser": "^1.4.7",
124
124
  "@types/cors": "^2.8.17",
125
125
  "@types/debug": "^4.1.12",
@@ -161,5 +161,5 @@
161
161
  "parser": "typescript"
162
162
  }
163
163
  },
164
- "gitHead": "927e39d554524434d20f22a950eec503166ae529"
164
+ "gitHead": "645ae0bdbab463eec878af0521eb982b51499639"
165
165
  }