payment-kit 1.19.8 → 1.19.10

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.
@@ -13,14 +13,14 @@ import { encodeApproveItx } from '../../integrations/ethereum/token';
13
13
  import { blocklet, ethWallet, wallet } from '../../libs/auth';
14
14
  import logger from '../../libs/logger';
15
15
  import { getGasPayerExtra, getTokenLimitsForDelegation } from '../../libs/payment';
16
- import {
17
- getCheckoutAmount,
18
- getCheckoutSessionSubscriptionIds,
19
- getFastCheckoutAmount,
20
- getStatementDescriptor,
21
- getSubscriptionCreateSetup,
16
+ import {
17
+ getCheckoutAmount,
18
+ getCheckoutSessionSubscriptionIds,
19
+ getFastCheckoutAmount,
20
+ getStatementDescriptor,
21
+ getSubscriptionCreateSetup,
22
22
  isDonationCheckoutSession,
23
- getSubscriptionLineItems
23
+ getSubscriptionLineItems,
24
24
  } from '../../libs/session';
25
25
  import {
26
26
  expandSubscriptionItems,
@@ -68,7 +68,11 @@ export async function ensureCheckoutSession(checkoutSessionId: string) {
68
68
  return checkoutSession;
69
69
  }
70
70
 
71
- export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: string, skipCustomer?: boolean): Promise<Result> {
71
+ export async function ensurePaymentIntent(
72
+ checkoutSessionId: string,
73
+ userDid?: string,
74
+ skipCustomer?: boolean
75
+ ): Promise<Result> {
72
76
  const checkoutSession = await ensureCheckoutSession(checkoutSessionId);
73
77
 
74
78
  let paymentCurrencyId;
@@ -100,11 +104,8 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
100
104
  let primarySubscription: Subscription | null = null;
101
105
  if (subscriptionIds.length > 0) {
102
106
  // @ts-ignore
103
- subscriptions = await Promise.all(
104
- subscriptionIds.filter(Boolean)
105
- .map(id => Subscription.findByPk(id))
106
- );
107
-
107
+ subscriptions = await Promise.all(subscriptionIds.filter(Boolean).map((id) => Subscription.findByPk(id)));
108
+
108
109
  subscriptions = subscriptions.filter(Boolean);
109
110
  for (const subscription of subscriptions) {
110
111
  if (subscription && subscription.status !== 'incomplete') {
@@ -119,81 +120,69 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
119
120
  }
120
121
  }
121
122
  let customer = null;
122
-
123
+
123
124
  if (!skipCustomer) {
124
- // 检查是否为打赏场景
125
- const isDonation = isDonationCheckoutSession(checkoutSession);
126
-
127
- // if donation, create customer if not exists
128
- if (isDonation && !checkoutSession.customer_id && userDid) {
129
- customer = await Customer.findByPkOrDid(userDid);
130
- if (!customer) {
131
- const { user } = await blocklet.getUser(userDid);
132
- if (user) {
133
- customer = await Customer.create({
134
- did: userDid,
135
- email: user.email,
136
- name: user.fullName || userDid,
137
- description: user.remark,
138
- metadata: { fromDonation: true },
139
- livemode: checkoutSession.livemode,
140
- phone: user.phone,
141
- address: Customer.formatAddressFromUser(user),
142
- delinquent: false,
143
- balance: '0',
144
- next_invoice_sequence: 1,
145
- invoice_prefix: Customer.getInvoicePrefix(),
146
- });
147
- logger.info('Customer created for donation', { userDid, customerId: customer.id });
148
- } else {
149
- customer = await Customer.create({
150
- did: userDid,
151
- email: '',
152
- name: 'anonymous',
153
- description: 'Anonymous customer',
154
- metadata: { fromDonation: true, anonymous: true },
155
- livemode: checkoutSession.livemode,
156
- phone:'',
157
- delinquent: false,
158
- balance: '0',
159
- next_invoice_sequence: 1,
160
- invoice_prefix: Customer.getInvoicePrefix(),
161
- });
125
+ // 检查是否为打赏场景
126
+ const isDonation = isDonationCheckoutSession(checkoutSession);
127
+
128
+ // if donation, create customer if not exists
129
+ if (isDonation && !checkoutSession.customer_id && userDid) {
130
+ customer = await Customer.findByPkOrDid(userDid);
131
+ if (!customer) {
132
+ const { user } = await blocklet.getUser(userDid);
133
+ if (user) {
134
+ customer = await Customer.create({
135
+ did: userDid,
136
+ email: user.email,
137
+ name: user.fullName || userDid,
138
+ description: user.remark,
139
+ metadata: { fromDonation: true },
140
+ livemode: checkoutSession.livemode,
141
+ phone: user.phone,
142
+ address: Customer.formatAddressFromUser(user),
143
+ delinquent: false,
144
+ balance: '0',
145
+ next_invoice_sequence: 1,
146
+ invoice_prefix: Customer.getInvoicePrefix(),
147
+ });
148
+ logger.info('Customer created for donation', { userDid, customerId: customer.id });
149
+ } else {
150
+ customer = await Customer.create({
151
+ did: userDid,
152
+ email: '',
153
+ name: 'anonymous',
154
+ description: 'Anonymous customer',
155
+ metadata: { fromDonation: true, anonymous: true },
156
+ livemode: checkoutSession.livemode,
157
+ phone: '',
158
+ delinquent: false,
159
+ balance: '0',
160
+ next_invoice_sequence: 1,
161
+ invoice_prefix: Customer.getInvoicePrefix(),
162
+ });
163
+ }
162
164
  }
163
- }
164
-
165
- if (customer) {
166
- await checkoutSession.update({ customer_id: customer.id, customer_did: customer.did });
167
- if (paymentIntent) {
168
- await paymentIntent.update({ customer_id: customer.id });
165
+
166
+ if (customer) {
167
+ await checkoutSession.update({ customer_id: customer.id, customer_did: customer.did });
168
+ if (paymentIntent) {
169
+ await paymentIntent.update({ customer_id: customer.id });
170
+ }
171
+ logger.info('Customer associated with donation', {
172
+ userDid,
173
+ customerId: customer.id,
174
+ checkoutSessionId: checkoutSession.id,
175
+ paymentIntentId: paymentIntent?.id,
176
+ });
169
177
  }
170
- logger.info('Customer associated with donation', {
171
- userDid,
172
- customerId: customer.id,
173
- checkoutSessionId: checkoutSession.id,
174
- paymentIntentId: paymentIntent?.id
175
- });
176
- }
177
- } else {
178
- // 非打赏场景或已有客户ID的情况
179
- customer = await Customer.findByPk(checkoutSession.customer_id);
180
- }
181
- if (!customer) {
182
- throw new Error('Customer not found');
183
- }
184
-
185
- if (userDid && !isDonation) {
186
- const { user } = await blocklet.getUser(userDid, { enableConnectedAccount: true });
187
- if (!user) {
188
- throw new Error('Seems you have not connected to this app before');
178
+ } else {
179
+ // 非打赏场景或已有客户ID的情况
180
+ customer = await Customer.findByPk(checkoutSession.customer_id);
189
181
  }
190
-
191
- if (customer.did !== user.did) {
192
- throw new Error('This is not your payment intent');
182
+ if (!customer) {
183
+ throw new Error('Customer not found');
193
184
  }
194
185
  }
195
- }
196
-
197
186
 
198
187
  const [paymentMethod, paymentCurrency] = await Promise.all([
199
188
  PaymentMethod.findByPk(paymentMethodId),
@@ -223,7 +212,7 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
223
212
  };
224
213
  }
225
214
 
226
- export async function ensureSetupIntent(checkoutSessionId: string, userDid?: string) {
215
+ export async function ensureSetupIntent(checkoutSessionId: string) {
227
216
  const checkoutSession = await ensureCheckoutSession(checkoutSessionId);
228
217
 
229
218
  if (!checkoutSession.setup_intent_id) {
@@ -256,16 +245,6 @@ export async function ensureSetupIntent(checkoutSessionId: string, userDid?: str
256
245
  if (!customer) {
257
246
  throw new Error('Customer not found for checkoutSession');
258
247
  }
259
- if (userDid) {
260
- const { user } = await blocklet.getUser(userDid, { enableConnectedAccount: true });
261
- if (!user) {
262
- throw new Error('Seems you have not connected to this app before');
263
- }
264
-
265
- if (customer.did !== user.did) {
266
- throw new Error('This is not your setupIntent');
267
- }
268
- }
269
248
 
270
249
  const [paymentMethod, paymentCurrency] = await Promise.all([
271
250
  PaymentMethod.findByPk(subscription.default_payment_method_id),
@@ -344,8 +323,13 @@ export async function ensureSetupIntent(checkoutSessionId: string, userDid?: str
344
323
  export async function ensureSubscriptionDelegation(subscriptionId: string) {
345
324
  const subscription = (await Subscription.findOne({
346
325
  where: { id: subscriptionId },
347
- include: [{ model: PaymentCurrency, as: 'paymentCurrency' }, { model: PaymentMethod, as: 'paymentMethod' }],
348
- })) as (Subscription & { paymentCurrency: PaymentCurrency; paymentMethod: PaymentMethod; items?: TLineItemExpanded[] }) | null;
326
+ include: [
327
+ { model: PaymentCurrency, as: 'paymentCurrency' },
328
+ { model: PaymentMethod, as: 'paymentMethod' },
329
+ ],
330
+ })) as
331
+ | (Subscription & { paymentCurrency: PaymentCurrency; paymentMethod: PaymentMethod; items?: TLineItemExpanded[] })
332
+ | null;
349
333
  if (!subscription) {
350
334
  throw new Error('Subscription not found');
351
335
  }
@@ -380,7 +364,6 @@ export async function ensureInvoiceForCheckout({
380
364
  subscriptions,
381
365
  lineItems,
382
366
  }: Args): Promise<{ invoice: Invoice | null; items: InvoiceItem[] }> {
383
-
384
367
  const isGroupInvoice = subscriptions && subscriptions.length > 1;
385
368
  // invoices are optional when checkout session is in payment mode
386
369
  if (checkoutSession.mode === 'payment' && !checkoutSession.invoice_creation?.enabled) {
@@ -426,9 +409,7 @@ export async function ensureInvoiceForCheckout({
426
409
  client.invoices
427
410
  .voidInvoice(invoice.metadata.stripe_id)
428
411
  .then(() => {
429
- logger.info(
430
- `Invoice marked void on stripe for checkout session ${checkoutSession.id}: ${existingInvoice}`
431
- );
412
+ logger.info(`Invoice marked void on stripe for checkout session ${checkoutSession.id}: ${existingInvoice}`);
432
413
  })
433
414
  .catch((err) => {
434
415
  logger.error(
@@ -441,16 +422,16 @@ export async function ensureInvoiceForCheckout({
441
422
  }
442
423
 
443
424
  const currency = await PaymentCurrency.findByPk(checkoutSession.currency_id);
444
-
425
+
445
426
  const metadata = {
446
427
  ...(checkoutSession.invoice_creation?.invoice_data?.metadata || {}),
447
428
  };
448
-
429
+
449
430
  if (isGroupInvoice) {
450
- metadata.subscription_ids = subscriptions.map(sub => sub.id);
431
+ metadata.subscription_ids = subscriptions.map((sub) => sub.id);
451
432
  metadata.is_group_invoice = true;
452
433
  }
453
-
434
+
454
435
  const trialInDays = Number(checkoutSession.subscription_data?.trial_period_days || 0);
455
436
  const trialEnd = Number(checkoutSession.subscription_data?.trial_end || 0);
456
437
  const now = dayjs().unix();
@@ -507,14 +488,13 @@ export async function ensureInvoiceForCheckout({
507
488
  return { invoice, items };
508
489
  }
509
490
 
510
-
511
491
  export async function ensureInvoicesForSubscriptions({
512
492
  checkoutSession,
513
493
  customer,
514
494
  subscriptions,
515
495
  invoiceProps,
516
- }: Omit<Args, 'subscription'> & { subscriptions: Subscription[]; invoiceProps?: Partial<TInvoice> }): Promise<{
517
- invoices: Invoice[];
496
+ }: Omit<Args, 'subscription'> & { subscriptions: Subscription[]; invoiceProps?: Partial<TInvoice> }): Promise<{
497
+ invoices: Invoice[];
518
498
  }> {
519
499
  if (!subscriptions?.length) {
520
500
  logger.warn('No subscriptions provided for invoice creation');
@@ -523,15 +503,16 @@ export async function ensureInvoicesForSubscriptions({
523
503
 
524
504
  const lineItems = await Price.expand(checkoutSession.line_items, { product: true });
525
505
 
526
- const primarySubscription = (subscriptions.find((x) => x.metadata.is_primary_subscription) || subscriptions[0]) as Subscription;
506
+ const primarySubscription = (subscriptions.find((x) => x.metadata.is_primary_subscription) ||
507
+ subscriptions[0]) as Subscription;
527
508
  const invoices = await Promise.all(
528
509
  subscriptions.map(async (subscription) => {
529
510
  const subItems = await getSubscriptionLineItems(subscription, lineItems, primarySubscription);
530
- const { invoice } = await ensureInvoiceForCheckout({
531
- checkoutSession,
532
- customer,
533
- subscription,
534
- subscriptions,
511
+ const { invoice } = await ensureInvoiceForCheckout({
512
+ checkoutSession,
513
+ customer,
514
+ subscription,
515
+ subscriptions,
535
516
  lineItems: subItems,
536
517
  props: invoiceProps,
537
518
  });
@@ -540,10 +521,10 @@ export async function ensureInvoicesForSubscriptions({
540
521
  );
541
522
 
542
523
  const createdInvoices = invoices.filter(Boolean);
543
-
524
+
544
525
  logger.info(`Created ${createdInvoices.length} invoices for subscriptions`, {
545
526
  checkoutSessionId: checkoutSession.id,
546
- invoiceIds: createdInvoices.map(inv => inv?.id)
527
+ invoiceIds: createdInvoices.map((inv) => inv?.id),
547
528
  });
548
529
 
549
530
  return { invoices: createdInvoices as Invoice[] };
@@ -625,7 +606,7 @@ export async function ensureSubscriptionRecharge(subscriptionId: string) {
625
606
  paymentMethod: paymentMethod as PaymentMethod,
626
607
  receiverAddress,
627
608
  subscription,
628
- customer
609
+ customer,
629
610
  };
630
611
  }
631
612
 
@@ -715,7 +696,7 @@ export async function getDelegationTxClaim({
715
696
  billingThreshold,
716
697
  paymentMethod,
717
698
  paymentCurrency,
718
- requiredStake
699
+ requiredStake,
719
700
  });
720
701
  if (mode === 'delegation') {
721
702
  tokenRequirements = [];
@@ -788,7 +769,11 @@ export async function getDelegationTxClaim({
788
769
  throw new Error(`getDelegationTxClaim: Payment method ${paymentMethod.type} not supported`);
789
770
  }
790
771
 
791
- export function getStakeAmount(subscription: Subscription, paymentCurrency: PaymentCurrency, items: TLineItemExpanded[]) {
772
+ export function getStakeAmount(
773
+ subscription: Subscription,
774
+ paymentCurrency: PaymentCurrency,
775
+ items: TLineItemExpanded[]
776
+ ) {
792
777
  const billingThreshold = Number(subscription.billing_thresholds?.amount_gte || 0);
793
778
  const minStakeAmount = Number(subscription.billing_thresholds?.stake_gte || 0);
794
779
  const threshold = fromTokenToUnit(Math.max(billingThreshold, minStakeAmount), paymentCurrency.decimal);
@@ -816,29 +801,29 @@ export async function getStakeTxClaim({
816
801
  }) {
817
802
  let billingThreshold = Number(subscription.billing_thresholds?.amount_gte || 0);
818
803
  let minStakeAmount = Number(subscription.billing_thresholds?.stake_gte || 0);
819
-
804
+
820
805
  const hasGrouping = subscriptions && subscriptions.length > 1;
821
806
  if (hasGrouping) {
822
- const primarySubscription = subscriptions[0] as Subscription;
807
+ const primarySubscription = subscriptions[0] as Subscription;
823
808
  // use the settings of the primary subscription, not the scattered staking
824
809
  billingThreshold = Number(primarySubscription.billing_thresholds?.amount_gte || 0);
825
810
  minStakeAmount = Number(primarySubscription.billing_thresholds?.stake_gte || 0);
826
-
811
+
827
812
  logger.info('Using primary subscription for staking', {
828
813
  primarySubscriptionId: primarySubscription.id,
829
814
  billingThreshold,
830
815
  minStakeAmount,
831
- allSubscriptionIds: subscriptions.map(s => s.id)
816
+ allSubscriptionIds: subscriptions.map((s) => s.id),
832
817
  });
833
818
  }
834
-
819
+
835
820
  const threshold = fromTokenToUnit(Math.max(billingThreshold, minStakeAmount), paymentCurrency.decimal);
836
821
  const staking = getSubscriptionStakeSetup(items, paymentCurrency.id, threshold.toString());
837
822
  const amount = staking.licensed.add(staking.metered).toString();
838
-
823
+
839
824
  logger.info('getStakeTxClaim', {
840
825
  subscriptionId: subscription.id,
841
- allSubscriptions: subscriptions?.map(s => s.id) || [],
826
+ allSubscriptions: subscriptions?.map((s) => s.id) || [],
842
827
  billingThreshold,
843
828
  minStakeAmount,
844
829
  threshold: threshold.toString(),
@@ -849,11 +834,9 @@ export async function getStakeTxClaim({
849
834
  if (paymentMethod.type === 'arcblock') {
850
835
  // create staking data
851
836
  const client = paymentMethod.getOcapClient();
852
-
853
- const stakeId = hasGrouping
854
- ? `stake-group-${subscription.id}`
855
- : subscription.id;
856
-
837
+
838
+ const stakeId = hasGrouping ? `stake-group-${subscription.id}` : subscription.id;
839
+
857
840
  const address = await getCustomerStakeAddress(userDid, stakeId);
858
841
  const { state } = await client.getStakeState({ address });
859
842
  const data = {
@@ -862,10 +845,12 @@ export async function getStakeTxClaim({
862
845
  {
863
846
  appId: wallet.address,
864
847
  subscriptionId: subscription.id,
865
- ...(hasGrouping ? {
866
- subscriptionGroup: true,
867
- subscriptionIds: subscriptions.map(s => s.id)
868
- } : {})
848
+ ...(hasGrouping
849
+ ? {
850
+ subscriptionGroup: true,
851
+ subscriptionIds: subscriptions.map((s) => s.id),
852
+ }
853
+ : {}),
869
854
  },
870
855
  JSON.parse(state?.data?.value || '{}')
871
856
  ),
@@ -902,11 +887,13 @@ export async function getStakeTxClaim({
902
887
  meta: {
903
888
  purpose: 'staking',
904
889
  address,
905
- ...(hasGrouping ? {
906
- subscriptionGroup: true,
907
- primarySubscriptionId: subscription.id,
908
- allSubscriptionIds: subscriptions.map(s => s.id)
909
- } : {})
890
+ ...(hasGrouping
891
+ ? {
892
+ subscriptionGroup: true,
893
+ primarySubscriptionId: subscription.id,
894
+ allSubscriptionIds: subscriptions.map((s) => s.id),
895
+ }
896
+ : {}),
910
897
  },
911
898
  chainInfo: {
912
899
  host: paymentMethod.settings?.arcblock?.api_host as string,
@@ -1015,7 +1002,7 @@ export async function getTokenRequirements({
1015
1002
  paymentCurrency,
1016
1003
  trialing = false,
1017
1004
  billingThreshold = 0,
1018
- requiredStake
1005
+ requiredStake,
1019
1006
  }: TokenRequirementArgs) {
1020
1007
  const tokenRequirements = [];
1021
1008
  let amount = getFastCheckoutAmount(items, mode, paymentCurrency.id, !!trialing);
@@ -1197,7 +1184,7 @@ export async function ensureReStakeContext(subscriptionId: string) {
1197
1184
  };
1198
1185
  }
1199
1186
  export async function ensureSubscriptionForCollectBatch(
1200
- subscriptionId?: string,
1187
+ subscriptionId?: string,
1201
1188
  currencyId?: string,
1202
1189
  customerId?: string
1203
1190
  ) {
@@ -1258,13 +1245,13 @@ export async function ensureSubscriptionForOverdraftProtection(subscriptionId: s
1258
1245
  if (!subscription) {
1259
1246
  throw new Error(`Subscription ${subscriptionId} not found when prepare SubGuard`);
1260
1247
  }
1261
- // @ts-ignore
1248
+ // @ts-ignore
1262
1249
  subscription.items = await expandSubscriptionItems(subscription.id);
1263
1250
  const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
1264
1251
  if (!paymentCurrency) {
1265
1252
  throw new Error(`PaymentCurrency ${subscription.currency_id} not found when prepare SubGuard`);
1266
1253
  }
1267
-
1254
+
1268
1255
  const paymentMethod = await PaymentMethod.findByPk(paymentCurrency.payment_method_id);
1269
1256
 
1270
1257
  if (!paymentMethod) {
@@ -1288,7 +1275,6 @@ export async function ensureSubscriptionForOverdraftProtection(subscriptionId: s
1288
1275
  };
1289
1276
  }
1290
1277
 
1291
-
1292
1278
  async function executeSingleTransaction(
1293
1279
  client: any,
1294
1280
  claim: any,
@@ -1323,13 +1309,12 @@ export async function executeOcapTransactions(
1323
1309
  ) {
1324
1310
  const client = paymentMethod.getOcapClient();
1325
1311
  logger.info('start executeOcapTransactions', { userDid, claims });
1326
-
1327
- const delegation = claims.find(x => x.type === 'signature' && x.meta?.purpose === 'delegation');
1328
- const staking = claims.find(x => x.type === 'prepareTx' && x.meta?.purpose === 'staking');
1329
-
1330
- const stakingAmount = staking?.requirement?.tokens?.find(
1331
- (x: any) => x?.address === paymentCurrencyContract
1332
- )?.value || '0';
1312
+
1313
+ const delegation = claims.find((x) => x.type === 'signature' && x.meta?.purpose === 'delegation');
1314
+ const staking = claims.find((x) => x.type === 'prepareTx' && x.meta?.purpose === 'staking');
1315
+
1316
+ const stakingAmount =
1317
+ staking?.requirement?.tokens?.find((x: any) => x?.address === paymentCurrencyContract)?.value || '0';
1333
1318
 
1334
1319
  try {
1335
1320
  const getHeaders = (index: number): Record<string, string> => {
@@ -1341,17 +1326,17 @@ export async function executeOcapTransactions(
1341
1326
  const req = requestSource[headerIndex];
1342
1327
  return req ? client.pickGasPayerHeaders(req) : {};
1343
1328
  }
1344
-
1329
+
1345
1330
  if (requestSource && typeof requestSource === 'object') {
1346
1331
  return client.pickGasPayerHeaders(requestSource);
1347
1332
  }
1348
-
1333
+
1349
1334
  return {};
1350
1335
  };
1351
1336
 
1352
1337
  const transactions = [
1353
1338
  { claim: delegation, type: 'Delegate' },
1354
- { claim: staking, type: 'Stake' }
1339
+ { claim: staking, type: 'Stake' },
1355
1340
  ];
1356
1341
 
1357
1342
  const txHashes = [];
@@ -1377,7 +1362,7 @@ export async function executeOcapTransactions(
1377
1362
  type: 'delegate',
1378
1363
  staking: {
1379
1364
  tx_hash: stakingTxHash,
1380
- address: await getCustomerStakeAddress(userDid, nonce || subscriptionId || ''),
1365
+ address: await getCustomerStakeAddress(userDid, nonce || subscriptionId || ''),
1381
1366
  },
1382
1367
  stakingAmount,
1383
1368
  };
@@ -1413,7 +1398,7 @@ export async function updateStripeSubscriptionAfterChangePayment(setupIntent: Se
1413
1398
  const toMethod = await PaymentMethod.findByPk(toMethodId);
1414
1399
  if (toMethod?.type === 'stripe') {
1415
1400
  // resume stripe
1416
- const client = toMethod?.getStripeClient();
1401
+ const client = toMethod?.getStripeClient();
1417
1402
  const stripeSubscriptionId = subscription.payment_details?.stripe?.subscription_id as string;
1418
1403
  if (client && stripeSubscriptionId) {
1419
1404
  const stripeSubscription = await client.subscriptions.retrieve(stripeSubscriptionId);
@@ -1443,7 +1428,7 @@ export async function returnStakeForCanceledSubscription(subscriptionId: string)
1443
1428
  if (subscription.status !== 'canceled') {
1444
1429
  throw new Error(`Subscription ${subscriptionId} is not canceled`);
1445
1430
  }
1446
-
1431
+
1447
1432
  if (!subscription.payment_details?.arcblock?.staking?.tx_hash) {
1448
1433
  throw new Error(`No staking transaction found in subscription ${subscriptionId}`);
1449
1434
  }
@@ -1455,4 +1440,4 @@ export async function returnStakeForCanceledSubscription(subscriptionId: string)
1455
1440
  } catch (err) {
1456
1441
  logger.error('returnStakeForCanceledSubscription failed', { error: err, subscriptionId });
1457
1442
  }
1458
- }
1443
+ }
@@ -1,3 +1,4 @@
1
+ import pAll from 'p-all';
1
2
  import { broadcastEvmTransaction, executeEvmTransaction, waitForEvmTxConfirm } from '../../integrations/ethereum/tx';
2
3
  import type { CallbackArgs } from '../../libs/auth';
3
4
  import dayjs from '../../libs/dayjs';
@@ -19,13 +20,24 @@ import {
19
20
  } from './shared';
20
21
  import { ensureStakeInvoice } from '../../libs/invoice';
21
22
  import { EVM_CHAIN_TYPES } from '../../libs/constants';
23
+ import { updateDataConcurrency } from '../../libs/env';
22
24
 
23
25
  const updateInvoices = async (invoices: Invoice[], update: Partial<Invoice>) => {
24
- await Promise.all(invoices.map((invoice) => invoice.update(update)));
26
+ await pAll(
27
+ invoices.map((invoice) => async () => {
28
+ await invoice.update(update);
29
+ }),
30
+ { concurrency: updateDataConcurrency }
31
+ );
25
32
  };
26
33
 
27
34
  const updateSubscriptions = async (subscriptions: Subscription[], update: Partial<Subscription>) => {
28
- await Promise.all(subscriptions.map((subscription) => subscription.update(update)));
35
+ await pAll(
36
+ subscriptions.map((subscription) => async () => {
37
+ await subscription.update(update);
38
+ }),
39
+ { concurrency: updateDataConcurrency }
40
+ );
29
41
  };
30
42
 
31
43
  export default {
@@ -46,7 +58,6 @@ export default {
46
58
  paymentMethod,
47
59
  paymentCurrency,
48
60
  subscriptions,
49
- customer,
50
61
  subscription: primarySubscription,
51
62
  } = await ensurePaymentIntent(checkoutSessionId, connectedDid || sessionUserDid || userDid);
52
63
  if (!subscriptions || subscriptions.length === 0) {
@@ -71,7 +82,7 @@ export default {
71
82
  const delegation = await isDelegationSufficientForPayment({
72
83
  paymentMethod,
73
84
  paymentCurrency,
74
- userDid: customer.did,
85
+ userDid,
75
86
  amount: fastCheckoutAmount,
76
87
  });
77
88
 
@@ -208,8 +219,11 @@ export default {
208
219
  }
209
220
  }
210
221
 
211
- await Promise.all(
212
- subscriptions.map((subscription) => addSubscriptionJob(subscription, 'cycle', false, subscription.trial_end))
222
+ await pAll(
223
+ subscriptions.map((subscription) => async () => {
224
+ await addSubscriptionJob(subscription, 'cycle', false, subscription.trial_end);
225
+ }),
226
+ { concurrency: updateDataConcurrency }
213
227
  );
214
228
 
215
229
  logger.info('CheckoutSession updated with multiple subscriptions', {
@@ -233,6 +247,7 @@ export default {
233
247
  paymentCurrency,
234
248
  userDid,
235
249
  amount: fastCheckoutAmount,
250
+ skipUserCheck: true,
236
251
  });
237
252
 
238
253
  if (tokenBalanceCheck.sufficient === false) {
@@ -151,6 +151,7 @@ router.put('/:id', auth, async (req, res) => {
151
151
 
152
152
  const updateData: any = {
153
153
  ...pick(req.body, ['name', 'description', 'status']),
154
+ unit: req.body.unit || meter.unit,
154
155
  updated_by: req.user?.did,
155
156
  };
156
157
 
@@ -306,6 +306,8 @@ const updateCurrencySchema = Joi.object({
306
306
  name: Joi.string().empty('').max(32).optional(),
307
307
  description: Joi.string().empty('').max(255).optional(),
308
308
  logo: Joi.string().empty('').optional(),
309
+ metadata: Joi.object().optional(),
310
+ symbol: Joi.string().empty('').optional(),
309
311
  }).unknown(true);
310
312
  router.put('/:id', auth, async (req, res) => {
311
313
  const { id } = req.params;
@@ -329,11 +331,18 @@ router.put('/:id', auth, async (req, res) => {
329
331
  return res.status(400).json({ error: 'Payment method not found' });
330
332
  }
331
333
 
332
- const updatedCurrency = await currency.update({
334
+ const updates: Partial<TPaymentCurrency> = {
333
335
  name: raw.name || currency.name,
334
336
  description: raw.description || currency.description,
335
337
  logo: raw.logo || method.logo,
336
- });
338
+ metadata: raw.metadata || currency.metadata,
339
+ };
340
+
341
+ if (currency.type === 'credit') {
342
+ updates.symbol = raw.symbol || currency.symbol;
343
+ }
344
+
345
+ const updatedCurrency = await currency.update(updates);
337
346
  return res.json(updatedCurrency);
338
347
  });
339
348