MCPcopy
hub / github.com/simstudioai/sim / resetUsageForSubscription

Function resetUsageForSubscription

apps/sim/lib/billing/webhooks/invoices.ts:413–629  ·  view source on GitHub ↗
(sub: {
  plan: string | null
  referenceId: string
  periodStart?: Date | null
  periodEnd?: Date | null
})

Source from the content-addressed store, hash-verified

411}
412
413export async function resetUsageForSubscription(sub: {
414 plan: string | null
415 referenceId: string
416 periodStart?: Date | null
417 periodEnd?: Date | null
418}) {
419 const billingPeriod =
420 sub.periodStart && sub.periodEnd ? { start: sub.periodStart, end: sub.periodEnd } : null
421
422 if (await isSubscriptionOrgScoped(sub)) {
423 const ledgerUsageByUser = billingPeriod
424 ? await getBillingPeriodUsageCostByUser(
425 { type: 'organization', id: sub.referenceId },
426 billingPeriod
427 )
428 : new Map<string, number>()
429 // Copilot-family ledger per user, so last-period copilot mirrors last-period
430 // cost (baseline + usage_log) instead of capturing the baseline alone.
431 const copilotLedgerByUser = billingPeriod
432 ? await getBillingPeriodUsageCostByUser(
433 { type: 'organization', id: sub.referenceId },
434 billingPeriod,
435 COPILOT_USAGE_SOURCES
436 )
437 : new Map<string, number>()
438
439 await db.transaction(async (tx) => {
440 await tx.execute(sql.raw(`SET LOCAL lock_timeout = '${BILLING_LOCK_TIMEOUT_MS}ms'`))
441
442 const ownerRows = await tx
443 .select({ userId: member.userId })
444 .from(member)
445 .where(and(eq(member.organizationId, sub.referenceId), eq(member.role, 'owner')))
446 .for('update')
447 .limit(1)
448
449 const ownerId = ownerRows[0]?.userId
450 if (ownerId) {
451 await tx
452 .select({ userId: userStats.userId })
453 .from(userStats)
454 .where(eq(userStats.userId, ownerId))
455 .for('update')
456 .limit(1)
457 }
458
459 const membersRows = await tx
460 .select({ userId: member.userId })
461 .from(member)
462 .where(eq(member.organizationId, sub.referenceId))
463
464 const memberIds = membersRows.map((row) => row.userId)
465
466 // Lock every member's userStats before the organization row so this path
467 // follows the canonical userStats → organization order shared by the
468 // join, remove, threshold-billing, and storage-transfer paths. Locking
469 // organization first would invert against them and risk an AB-BA
470 // deadlock. The per-member UPDATE below re-locks these rows (no-op).

Callers 5

invoices.test.tsFile · 0.90
handleInvoiceFinalizedFunction · 0.85

Calls 10

isSubscriptionOrgScopedFunction · 0.90
toNumberFunction · 0.90
toDecimalFunction · 0.90
joinMethod · 0.80
executeMethod · 0.65
setMethod · 0.65
getMethod · 0.65
eqFunction · 0.50
toStringMethod · 0.45

Tested by

no test coverage detected