MCPcopy Index your code
hub / github.com/simstudioai/sim / reconcileOrganizationSeats

Function reconcileOrganizationSeats

apps/sim/lib/billing/organizations/seats.ts:41–151  ·  view source on GitHub ↗
({
  organizationId,
  reason,
}: ReconcileOrganizationSeatsParams)

Source from the content-addressed store, hash-verified

39 * always correct regardless of interleaving.
40 */
41export async function reconcileOrganizationSeats({
42 organizationId,
43 reason,
44}: ReconcileOrganizationSeatsParams): Promise<ReconcileOrganizationSeatsResult> {
45 if (!isBillingEnabled) {
46 return { changed: false, reason: 'Billing is not enabled' }
47 }
48
49 type ReconcileOutcome =
50 | { kind: 'skip'; reason: string }
51 | { kind: 'noop'; seats: number }
52 | {
53 kind: 'changed'
54 previousSeats: number
55 seats: number
56 outboxEventId: string
57 sync: { id: string; plan: string; status: string | null }
58 }
59
60 const outcome = await db.transaction<ReconcileOutcome>(async (tx) => {
61 const [orgSubscription] = await tx
62 .select()
63 .from(subscription)
64 .where(
65 and(
66 eq(subscription.referenceId, organizationId),
67 inArray(subscription.status, USABLE_SUBSCRIPTION_STATUSES)
68 )
69 )
70 .for('update')
71 .limit(1)
72
73 if (!orgSubscription) {
74 return { kind: 'skip', reason: 'No active subscription found' }
75 }
76 if (!isTeam(orgSubscription.plan)) {
77 return { kind: 'skip', reason: 'Seat changes are only available for Team plans' }
78 }
79 if (!orgSubscription.stripeSubscriptionId) {
80 return { kind: 'skip', reason: 'No Stripe subscription found for this organization' }
81 }
82
83 const [memberCountRow] = await tx
84 .select({ value: count() })
85 .from(member)
86 .where(eq(member.organizationId, organizationId))
87
88 const targetSeats = Math.max(1, memberCountRow?.value ?? 1)
89 const currentSeats = orgSubscription.seats ?? 1
90
91 if (targetSeats === currentSeats) {
92 return { kind: 'noop', seats: currentSeats }
93 }
94
95 await tx
96 .update(subscription)
97 .set({ seats: targetSeats })
98 .where(eq(subscription.id, orgSubscription.id))

Callers 5

acceptInvitationFunction · 0.90
reconcileTeamSeatDriftFunction · 0.90
seats.test.tsFile · 0.90
route.tsFile · 0.90
route.tsFile · 0.90

Calls 6

isTeamFunction · 0.90
enqueueOutboxEventFunction · 0.90
infoMethod · 0.80
setMethod · 0.65
eqFunction · 0.50

Tested by

no test coverage detected