payment-kit 1.14.36 → 1.14.38

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.
@@ -189,6 +189,7 @@ export async function getStakeSummaryByDid(did: string, livemode: boolean = true
189
189
  return {};
190
190
  }
191
191
 
192
+ // FIXME: should use listStakes to find all stakes and summarize here
192
193
  const address = toStakeAddress(did, wallet.address);
193
194
  const results: GroupedBN = {};
194
195
  await Promise.all(
@@ -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,
@@ -28,7 +30,7 @@ import dayjs from './dayjs';
28
30
  import env from './env';
29
31
  import logger from './logger';
30
32
  import { getPriceCurrencyOptions, getPriceUintAmountByCurrency, getRecurringPeriod } from './session';
31
- import { getConnectQueryParam } from './util';
33
+ import { getConnectQueryParam, getCustomerStakeAddress } from './util';
32
34
 
33
35
  export function getCustomerSubscriptionPageUrl({
34
36
  subscriptionId,
@@ -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,
@@ -698,16 +700,25 @@ export async function getSubscriptionRemainingStakeSetup(
698
700
  paymentMethod: PaymentMethod,
699
701
  action: 'return' | 'slash' = 'return'
700
702
  ) {
703
+ const currency = await PaymentCurrency.findByPk(subscription.currency_id);
704
+ if (!currency) {
705
+ return {
706
+ total: '0',
707
+ return_amount: '0',
708
+ sender: '',
709
+ };
710
+ }
711
+
701
712
  const client = paymentMethod.getOcapClient();
702
713
  const { state } = await client.getStakeState({ address });
703
- const currency = await PaymentCurrency.findByPk(subscription.currency_id);
704
- if (!state.tokens || !currency) {
714
+ if (!state) {
705
715
  return {
706
716
  total: '0',
707
717
  return_amount: '0',
708
718
  sender: '',
709
719
  };
710
720
  }
721
+
711
722
  let total = new BN(state.tokens.find((x: any) => x.address === currency.contract)?.value || '0');
712
723
  if (action === 'slash') {
713
724
  // add revoked tokens to total
@@ -761,17 +772,18 @@ export async function checkRemainingStake(
761
772
  revoked: '0',
762
773
  };
763
774
  }
775
+
764
776
  const client = paymentMethod.getOcapClient();
765
777
  const { state } = await client.getStakeState({ address });
766
-
767
778
  if (!state) {
768
- logger.warn('getStakeState failed in checkRemainingStake', { address, paymentMethod, paymentCurrency });
779
+ logger.warn('getStakeState failed in checkRemainingStake', { address });
769
780
  return {
770
781
  enough: false,
771
782
  staked: '0',
772
783
  revoked: '0',
773
784
  };
774
785
  }
786
+
775
787
  const staked = state.tokens?.find((x: any) => x.address === paymentCurrency.contract);
776
788
  const revoked = state.revokedTokens?.find((x: any) => x.address === paymentCurrency.contract);
777
789
  let total = new BN(0);
@@ -781,9 +793,33 @@ export async function checkRemainingStake(
781
793
  if (revoked) {
782
794
  total = total.add(new BN(revoked?.value || '0'));
783
795
  }
796
+
784
797
  return {
785
798
  enough: total.gte(new BN(amount)),
786
799
  staked,
787
800
  revoked,
788
801
  };
789
802
  }
803
+
804
+ // trialing can be customized with currency_id list
805
+ export function getSubscriptionTrialSetup(data: Partial<SubscriptionData>, currencyId: string) {
806
+ let trialInDays = Number(data?.trial_period_days || 0);
807
+ let trialEnd = Number(data?.trial_end || 0);
808
+ const trialCurrencyIds = (data?.trial_currency || '').split(',').map(trim).filter(Boolean);
809
+ if (trialCurrencyIds.length > 0 && trialCurrencyIds.includes(currencyId) === false) {
810
+ trialEnd = 0;
811
+ trialInDays = 0;
812
+ }
813
+
814
+ return {
815
+ trialInDays,
816
+ trialEnd,
817
+ };
818
+ }
819
+
820
+ export async function getSubscriptionStakeAddress(subscription: Subscription, customerDid: string) {
821
+ return (
822
+ subscription.payment_details?.arcblock?.staking?.address ||
823
+ (await getCustomerStakeAddress(customerDid, subscription.id))
824
+ );
825
+ }
@@ -2,11 +2,14 @@ import crypto from 'crypto';
2
2
 
3
3
  import { getUrl } from '@blocklet/sdk/lib/component';
4
4
  import env from '@blocklet/sdk/lib/env';
5
+ import { getWalletDid } from '@blocklet/sdk/lib/did';
6
+ import { toStakeAddress } from '@arcblock/did-util';
5
7
  import { customAlphabet } from 'nanoid';
6
8
  import type { LiteralUnion } from 'type-fest';
7
9
  import { withQuery } from 'ufo';
8
10
 
9
11
  import dayjs from './dayjs';
12
+ import { blocklet, wallet } from './auth';
10
13
 
11
14
  export const OCAP_PAYMENT_TX_TYPE = 'fg:t:transfer_v2';
12
15
 
@@ -260,3 +263,12 @@ export function formatAmountPrecisionLimit(
260
263
  }
261
264
  return '';
262
265
  }
266
+
267
+ export async function getCustomerStakeAddress(customerDid: string, nonce?: string) {
268
+ const { user } = await blocklet.getUser(customerDid, { enableConnectedAccount: true });
269
+ if (user) {
270
+ return toStakeAddress(getWalletDid(user), wallet.address, nonce);
271
+ }
272
+
273
+ return toStakeAddress(customerDid, wallet.address, nonce);
274
+ }
@@ -1,6 +1,5 @@
1
1
  import isEmpty from 'lodash/isEmpty';
2
2
 
3
- import { toStakeAddress } from '@arcblock/did-util';
4
3
  import { ensureStakedForGas } from '../integrations/arcblock/stake';
5
4
  import { transferErc20FromUser } from '../integrations/ethereum/token';
6
5
  import { createEvent } from '../libs/audit';
@@ -19,6 +18,7 @@ import {
19
18
  getMaxRetryCount,
20
19
  getMinRetryMail,
21
20
  getSubscriptionCreateSetup,
21
+ getSubscriptionStakeAddress,
22
22
  shouldCancelSubscription,
23
23
  } from '../libs/subscription';
24
24
  import { MAX_RETRY_COUNT, MIN_RETRY_MAIL, getNextRetry } from '../libs/util';
@@ -402,7 +402,7 @@ const handleStakeSlash = async (
402
402
  return;
403
403
  }
404
404
 
405
- const address = toStakeAddress(customer.did, wallet.address, subscription.id);
405
+ const address = await getSubscriptionStakeAddress(subscription, customer.did);
406
406
  const slashAmount = paymentIntent.amount;
407
407
  const stakeEnough = await checkRemainingStake(paymentMethod, paymentCurrency, address, slashAmount);
408
408
  if (!stakeEnough.enough) {
@@ -432,7 +432,7 @@ const handleStakeSlash = async (
432
432
  const signed = await client.signSlashStakeTx({
433
433
  tx: {
434
434
  itx: {
435
- address: toStakeAddress(customer.did, wallet.address, subscription.id),
435
+ address,
436
436
  outputs: [{ owner: wallet.address, tokens: [{ address: paymentCurrency.contract, value: slashAmount }] }],
437
437
  message: 'stake_slash_on_subscription_cancel',
438
438
  data: {
@@ -1,6 +1,5 @@
1
- import { toStakeAddress } from '@arcblock/did-util';
2
- import { isRefundReasonSupportedByStripe } from '@api/libs/refund';
3
- import { checkRemainingStake } from '@api/libs/subscription';
1
+ import { isRefundReasonSupportedByStripe } from '../libs/refund';
2
+ import { checkRemainingStake, getSubscriptionStakeAddress } from '../libs/subscription';
4
3
  import { sendErc20ToUser } from '../integrations/ethereum/token';
5
4
  import { wallet } from '../libs/auth';
6
5
  import CustomError from '../libs/error';
@@ -14,6 +13,7 @@ import { PaymentCurrency } from '../store/models/payment-currency';
14
13
  import { PaymentIntent } from '../store/models/payment-intent';
15
14
  import { PaymentMethod } from '../store/models/payment-method';
16
15
  import { Refund } from '../store/models/refund';
16
+ import { Subscription } from '../store/models/subscription';
17
17
  import type { PaymentError } from '../store/models/types';
18
18
 
19
19
  type RefundJob = {
@@ -313,7 +313,8 @@ const handleStakeReturnJob = async (
313
313
  return;
314
314
  }
315
315
  const client = paymentMethod.getOcapClient();
316
- const address = toStakeAddress(customer.did, wallet.address, refund.subscription_id);
316
+ const subscription = await Subscription.findByPk(refund.subscription_id);
317
+ const address = await getSubscriptionStakeAddress(subscription!, customer.did);
317
318
  const stakeEnough = await checkRemainingStake(paymentMethod, paymentCurrency, address, refund.amount);
318
319
  if (!stakeEnough.enough) {
319
320
  logger.warn('Stake return aborted because stake is not enough ', {
@@ -1,4 +1,3 @@
1
- import { toStakeAddress } from '@arcblock/did-util';
2
1
  import type { LiteralUnion } from 'type-fest';
3
2
 
4
3
  import { ensurePassportRevoked } from '../integrations/blocklet/passport';
@@ -15,6 +14,7 @@ import {
15
14
  checkRemainingStake,
16
15
  getSubscriptionCycleAmount,
17
16
  getSubscriptionCycleSetup,
17
+ getSubscriptionStakeAddress,
18
18
  getSubscriptionStakeReturnSetup,
19
19
  getSubscriptionStakeSlashSetup,
20
20
  shouldCancelSubscription,
@@ -329,7 +329,7 @@ const handleStakeSlashAfterCancel = async (subscription: Subscription) => {
329
329
 
330
330
  // check the staking
331
331
  const client = method.getOcapClient();
332
- const address = toStakeAddress(customer.did, wallet.address, subscription.id);
332
+ const address = await getSubscriptionStakeAddress(subscription, customer.did);
333
333
  const { state } = await client.getStakeState({ address });
334
334
  if (!state || !state.data?.value) {
335
335
  logger.warn('Stake slashing aborted because no staking state', {
@@ -374,7 +374,7 @@ const handleStakeSlashAfterCancel = async (subscription: Subscription) => {
374
374
  const signed = await client.signSlashStakeTx({
375
375
  tx: {
376
376
  itx: {
377
- address: toStakeAddress(customer.did, wallet.address, subscription.id),
377
+ address,
378
378
  outputs: [{ owner: wallet.address, tokens: [{ address: currency.contract, value: invoice.amount_remaining }] }],
379
379
  message: 'uncollectible_past_due_invoice',
380
380
  data: {
@@ -530,7 +530,6 @@ const slashStakeOnCancel = async (subscription: Subscription) => {
530
530
  });
531
531
  return;
532
532
  }
533
- const address = toStakeAddress(customer.did, wallet.address, subscription.id);
534
533
  const currency = await PaymentCurrency.findByPk(subscription.currency_id);
535
534
  if (!currency) {
536
535
  logger.warn('Stake slashing skipped because currency not found', {
@@ -539,6 +538,7 @@ const slashStakeOnCancel = async (subscription: Subscription) => {
539
538
  });
540
539
  return;
541
540
  }
541
+ const address = await getSubscriptionStakeAddress(subscription, customer.did);
542
542
  const result = await getSubscriptionStakeSlashSetup(subscription, address, paymentMethod);
543
543
  const stakeEnough = await checkRemainingStake(paymentMethod, currency, address, result.return_amount);
544
544
  if (!stakeEnough.enough) {
@@ -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);
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/indent */
2
2
  /* eslint-disable prettier/prettier */
3
3
  import { toTypeInfo } from '@arcblock/did';
4
- import { toDelegateAddress, toStakeAddress } from '@arcblock/did-util';
4
+ import { toDelegateAddress } from '@arcblock/did-util';
5
5
  import type { Transaction } from '@ocap/client';
6
6
  import { BN, fromTokenToUnit, toBase58 } from '@ocap/util';
7
7
  import { fromPublicKey } from '@ocap/wallet';
@@ -21,7 +21,7 @@ import {
21
21
  getSubscriptionItemPrice,
22
22
  getSubscriptionStakeSetup,
23
23
  } from '../../libs/subscription';
24
- import { OCAP_PAYMENT_TX_TYPE } from '../../libs/util';
24
+ import { getCustomerStakeAddress, OCAP_PAYMENT_TX_TYPE } from '../../libs/util';
25
25
  import { invoiceQueue } from '../../queues/invoice';
26
26
  import type { TLineItemExpanded } from '../../store/models';
27
27
  import { CheckoutSession } from '../../store/models/checkout-session';
@@ -745,7 +745,7 @@ export async function getStakeTxClaim({
745
745
  if (paymentMethod.type === 'arcblock') {
746
746
  // create staking data
747
747
  const client = paymentMethod.getOcapClient();
748
- const address = toStakeAddress(userDid, wallet.address, subscription.id);
748
+ const address = await getCustomerStakeAddress(userDid, subscription.id);
749
749
  const { state } = await client.getStakeState({ address });
750
750
  const data = {
751
751
  type: 'json',
@@ -1026,7 +1026,7 @@ export async function executeOcapTransactions(
1026
1026
  type: 'delegate',
1027
1027
  staking: {
1028
1028
  tx_hash: stakingTxHash,
1029
- address: toStakeAddress(userDid, wallet.address, nonce),
1029
+ address: await getCustomerStakeAddress(userDid, nonce),
1030
1030
  },
1031
1031
  };
1032
1032
  }
@@ -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.38
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.38",
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.38",
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.38",
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": "f572122a40f30619bd736d8df20e362b6cdab420"
165
165
  }