payment-kit 1.14.3 → 1.14.5

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.
package/README.md CHANGED
@@ -11,15 +11,19 @@ The decentralized stripe for blocklet platform.
11
11
  3. run `cd blocklets/core && blocklet dev`
12
12
 
13
13
  ##### when error
14
+
14
15
  1. pre-start error component xxx is not running or unreachable
15
- - create .env.local file in this root
16
- - add BLOCKLET_DEV_APP_DID="did:abt:your payment kit server did"
17
- - add BLOCKLET_DEV_MOUNT_POINT="/example"
18
- - copy .env.local to be under the /core
19
- - edit BLOCKLET_DEV_MOUNT_POINT="/"
16
+
17
+ - create .env.local file in this root
18
+ - add BLOCKLET_DEV_APP_DID="did:abt:your payment kit server did"
19
+ - add BLOCKLET_DEV_MOUNT_POINT="/example"
20
+ - copy .env.local to be under the /core
21
+ - edit BLOCKLET_DEV_MOUNT_POINT="/"
22
+
20
23
  2. Insufficient fund to pay for tx cost from xxx, expected 1.0020909, got 0
21
24
  - copy BLOCKLET_DEV_APP_DID
22
25
  - transfer 2 TBA in your DID Wallet to your copied address
26
+
23
27
  ### Debug Stripe
24
28
 
25
29
  1. Install and login with instructions from: https://stripe.com/docs/stripe-cli
@@ -37,5 +41,6 @@ None public environment variables used in the code, can change the behavior of t
37
41
  - PAYMENT_CHANGE_LOCKED_PRICE: allow change locked price, must be set to "1" to work
38
42
  - PAYMENT_RELOAD_SUBSCRIPTION_JOBS: reload subscription jobs on start, must be set to "1" to work
39
43
  - PAYMENT_BILLING_THRESHOLD: global default billing threshold, must be a number
44
+ - PAYMENT_MIN_STAKE_AMOUNT: global min stake amount limit, must be a number
40
45
  - PAYMENT_DAYS_UNTIL_DUE: global default days until due, must be a number
41
46
  - PAYMENT_DAYS_UNTIL_CANCEL: global default days until cancel, must be a number
@@ -299,6 +299,22 @@ export function getBillingThreshold(config: Record<string, any> = {}) {
299
299
  return 0;
300
300
  }
301
301
 
302
+ export function getMinStakeAmount(config: Record<string, any> = {}) {
303
+ if (config?.min_stake_amount) {
304
+ const threshold = +(config.min_stake_amount as string);
305
+ if (threshold > 0) {
306
+ return threshold;
307
+ }
308
+ }
309
+
310
+ const threshold = +(process.env.PAYMENT_MIN_STAKE_AMOUNT as string);
311
+ if (threshold > 0) {
312
+ return threshold;
313
+ }
314
+
315
+ return 0;
316
+ }
317
+
302
318
  export function canPayWithDelegation(beneficiaries: PaymentBeneficiary[]) {
303
319
  return beneficiaries.length === 0 || beneficiaries.every((x) => x.address === wallet.address);
304
320
  }
@@ -30,6 +30,7 @@ import {
30
30
  getCheckoutAmount,
31
31
  getCheckoutMode,
32
32
  getFastCheckoutAmount,
33
+ getMinStakeAmount,
33
34
  getStatementDescriptor,
34
35
  getSupportedPaymentCurrencies,
35
36
  getSupportedPaymentMethods,
@@ -146,6 +147,7 @@ export const formatCheckoutSession = async (payload: any, throwOnEmptyItems = tr
146
147
  description: '',
147
148
  trial_period_days: 0,
148
149
  billing_threshold_amount: 0,
150
+ min_stake_amount: 0,
149
151
  trial_end: 0,
150
152
  },
151
153
  payment_intent_data: {},
@@ -373,6 +375,7 @@ export async function startCheckoutSessionFromPaymentLink(id: string, req: Reque
373
375
  raw.payment_link_id = link.id;
374
376
  raw.subscription_data = merge(link.subscription_data, getDataObjectFromQuery(req.query, 'subscription_data'), {
375
377
  billing_threshold_amount: getBillingThreshold(link.subscription_data),
378
+ min_stake_amount: getMinStakeAmount(link.subscription_data),
376
379
  });
377
380
 
378
381
  if (link.after_completion?.hosted_confirmation?.custom_message) {
@@ -559,6 +562,7 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
559
562
  const trialInDays = Number(checkoutSession.subscription_data?.trial_period_days || 0);
560
563
  const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
561
564
  const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
565
+ const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
562
566
  const amount = getCheckoutAmount(lineItems, paymentCurrency.id, trialInDays > 0 || trialEnds > now);
563
567
  await checkoutSession.update({
564
568
  amount_subtotal: amount.subtotal,
@@ -809,10 +813,11 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
809
813
  missing_payment_method: 'create_invoice',
810
814
  },
811
815
  },
812
- // @ts-ignore
813
- billing_thresholds: billingThreshold
814
- ? { amount_gte: billingThreshold, reset_billing_cycle_anchor: false } // prettier-ignore
815
- : null,
816
+ billing_thresholds: {
817
+ amount_gte: billingThreshold,
818
+ stake_gte: minStakeAmount,
819
+ reset_billing_cycle_anchor: false,
820
+ },
816
821
  pending_invoice_item_interval: setup.recurring,
817
822
  pending_setup_intent: setupIntent?.id,
818
823
  default_payment_method_id: paymentMethod.id,
@@ -43,6 +43,7 @@ export default {
43
43
  const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
44
44
  const trialing = trialInDays > 0 || trialEnds > now;
45
45
  const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
46
+ const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
46
47
  const fastCheckoutAmount = getFastCheckoutAmount(items, checkoutSession.mode, paymentCurrency.id, trialing);
47
48
 
48
49
  if (paymentMethod.type === 'arcblock') {
@@ -65,7 +66,7 @@ export default {
65
66
  paymentCurrency,
66
67
  paymentMethod,
67
68
  trialing,
68
- billingThreshold,
69
+ billingThreshold: Math.max(minStakeAmount, billingThreshold),
69
70
  items,
70
71
  }),
71
72
  ];
@@ -732,8 +732,10 @@ export async function getStakeTxClaim({
732
732
  paymentMethod: PaymentMethod;
733
733
  }) {
734
734
  // create staking amount
735
- const billingThreshold = fromTokenToUnit(subscription.billing_thresholds?.amount_gte || 0, paymentCurrency.decimal);
736
- const staking = getSubscriptionStakeSetup(items, paymentCurrency.id, billingThreshold.toString());
735
+ const billingThreshold = Number(subscription.billing_thresholds?.amount_gte || 0);
736
+ const minStakeAmount = Number(subscription.billing_thresholds?.stake_gte || 0);
737
+ const threshold = fromTokenToUnit(Math.max(billingThreshold, minStakeAmount), paymentCurrency.decimal);
738
+ const staking = getSubscriptionStakeSetup(items, paymentCurrency.id, threshold.toString());
737
739
  const amount = staking.licensed.add(staking.metered).toString();
738
740
 
739
741
  if (paymentMethod.type === 'arcblock') {
@@ -44,6 +44,7 @@ export default {
44
44
  const trialEnds = Number(checkoutSession.subscription_data?.trial_end || 0);
45
45
  const trialing = trialInDays > 0 || trialEnds > now;
46
46
  const billingThreshold = Number(checkoutSession.subscription_data?.billing_threshold_amount || 0);
47
+ const minStakeAmount = Number(checkoutSession.subscription_data?.min_stake_amount || 0);
47
48
  const fastCheckoutAmount = getFastCheckoutAmount(items, checkoutSession.mode, paymentCurrency.id, trialing);
48
49
 
49
50
  if (paymentMethod.type === 'arcblock') {
@@ -67,7 +68,7 @@ export default {
67
68
  paymentCurrency,
68
69
  paymentMethod,
69
70
  trialing,
70
- billingThreshold,
71
+ billingThreshold: Math.max(minStakeAmount, billingThreshold),
71
72
  items,
72
73
  }),
73
74
  ];
@@ -11,7 +11,7 @@ import { checkPassportForPricingTable } from '../integrations/blocklet/passport'
11
11
  import { createListParamSchema } from '../libs/api';
12
12
  import logger from '../libs/logger';
13
13
  import { authenticate } from '../libs/security';
14
- import { getBillingThreshold, isLineItemCurrencyAligned } from '../libs/session';
14
+ import { getBillingThreshold, getMinStakeAmount, isLineItemCurrencyAligned } from '../libs/session';
15
15
  import { getDaysUntilCancel, getDaysUntilDue } from '../libs/subscription';
16
16
  import { getDataObjectFromQuery } from '../libs/util';
17
17
  import { CheckoutSession } from '../store/models/checkout-session';
@@ -224,6 +224,7 @@ router.post('/:id/checkout/:priceId', async (req, res) => {
224
224
  ]),
225
225
  subscription_data: merge(price.subscription_data || {}, getDataObjectFromQuery(req.query, 'subscription_data'), {
226
226
  billing_threshold_amount: getBillingThreshold(price.subscription_data),
227
+ min_stake_amount: getMinStakeAmount(price.subscription_data),
227
228
  }),
228
229
  metadata: {
229
230
  ...doc.metadata,
@@ -66,6 +66,7 @@ export class Subscription extends Model<InferAttributes<Subscription>, InferCrea
66
66
  declare billing_cycle_anchor: number;
67
67
  declare billing_thresholds?: {
68
68
  amount_gte: number;
69
+ stake_gte: number;
69
70
  reset_billing_cycle_anchor: boolean;
70
71
  };
71
72
 
@@ -363,6 +363,7 @@ export type SubscriptionData = {
363
363
  description: string;
364
364
  trial_period_days: number;
365
365
  billing_threshold_amount?: number;
366
+ min_stake_amount?: number;
366
367
  metadata?: Record<string, any>;
367
368
  };
368
369
 
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.3
17
+ version: 1.14.5
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.14.3",
3
+ "version": "1.14.5",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "eject": "vite eject",
@@ -52,7 +52,7 @@
52
52
  "@arcblock/validator": "^1.18.124",
53
53
  "@blocklet/js-sdk": "1.16.28",
54
54
  "@blocklet/logger": "1.16.28",
55
- "@blocklet/payment-react": "1.14.3",
55
+ "@blocklet/payment-react": "1.14.5",
56
56
  "@blocklet/sdk": "1.16.28",
57
57
  "@blocklet/ui-react": "^2.10.3",
58
58
  "@blocklet/uploader": "^0.1.20",
@@ -118,7 +118,7 @@
118
118
  "devDependencies": {
119
119
  "@abtnode/types": "1.16.28",
120
120
  "@arcblock/eslint-config-ts": "^0.3.2",
121
- "@blocklet/payment-types": "1.14.3",
121
+ "@blocklet/payment-types": "1.14.5",
122
122
  "@types/cookie-parser": "^1.4.7",
123
123
  "@types/cors": "^2.8.17",
124
124
  "@types/debug": "^4.1.12",
@@ -160,5 +160,5 @@
160
160
  "parser": "typescript"
161
161
  }
162
162
  },
163
- "gitHead": "23e4827487dc9e180191948a58074abfb47dee1d"
163
+ "gitHead": "e4715805a87b2e4e3622564f4bc26578f19211e4"
164
164
  }
@@ -5,9 +5,11 @@ import {
5
5
  api,
6
6
  formatBNStr,
7
7
  formatError,
8
+ formatPrettyMsLocale,
8
9
  formatSubscriptionProduct,
9
10
  formatTime,
10
11
  formatToDate,
12
+ formatToDatetime,
11
13
  getDidConnectQueryParams,
12
14
  getInvoiceStatusColor,
13
15
  getPrefix,
@@ -25,11 +27,13 @@ import {
25
27
  ListItem,
26
28
  ListSubheader,
27
29
  Stack,
30
+ Tooltip,
28
31
  Typography,
29
32
  } from '@mui/material';
30
33
  import { useRequest } from 'ahooks';
31
34
  import { useMemo } from 'react';
32
35
  import { joinURL, withQuery } from 'ufo';
36
+ import prettyMs from 'pretty-ms-i18n';
33
37
 
34
38
  const fetchInvoiceData = (params: Record<string, any> = {}): Promise<Paginated<TInvoiceExpanded>> => {
35
39
  const search = new URLSearchParams();
@@ -112,7 +116,33 @@ export default function SubscriptionEmbed() {
112
116
  },
113
117
  ];
114
118
 
115
- if (subscription.status === 'active' || subscription.status === 'trialing') {
119
+ if (subscription.status === 'trialing') {
120
+ const endTimestamp = subscription.current_period_end * 1000;
121
+ const remainingTime = endTimestamp - Date.now();
122
+
123
+ infoList.push({
124
+ name: t('payment.customer.subscriptions.trialLeft'),
125
+ value: (
126
+ <Typography
127
+ sx={{
128
+ color: 'success.main',
129
+ fontWeight: 'bold',
130
+ marginRight: '10px',
131
+ }}>
132
+ <Tooltip title={formatToDatetime(endTimestamp, locale)} placement="top-end" enterTouchDelay={0}>
133
+ <Typography component="span" sx={{ cursor: 'pointer' }}>
134
+ {prettyMs(remainingTime, {
135
+ locale: formatPrettyMsLocale(locale),
136
+ compact: true,
137
+ })}
138
+ </Typography>
139
+ </Tooltip>
140
+ </Typography>
141
+ ),
142
+ });
143
+ }
144
+
145
+ if (subscription.status === 'active') {
116
146
  infoList.push({
117
147
  name: t('payment.customer.subscriptions.nextInvoice'),
118
148
  value: (