44 * billing-events API is stubbed.
55 */
66import { db } from '@sim/db'
7- import { usageLog , user , userStats } from '@sim/db/schema'
7+ import { organization , usageLog , user , userStats } from '@sim/db/schema'
88import { generateId } from '@sim/utils/id'
99import { eq , inArray } from 'drizzle-orm'
1010import { afterAll , afterEach , beforeEach , describe , expect , it , vi } from 'vitest'
1111import { type FalAICostSettlementPayload , settleFalAICost } from '@/lib/tools/falai-settlement'
1212
1313const HOSTED_KEY_ENV_VAR = 'FALAI_API_KEY_1'
1414const userIds : string [ ] = [ ]
15+ const organizationIds : string [ ] = [ ]
1516
1617async function createUser ( ) : Promise < string > {
1718 const id = `falai-settlement-user-${ generateId ( ) } `
@@ -29,8 +30,17 @@ async function createUser(): Promise<string> {
2930 return id
3031}
3132
33+ async function createOrganization ( ) : Promise < string > {
34+ const id = `falai-settlement-org-${ generateId ( ) } `
35+ await db . insert ( organization ) . values ( { id, name : 'Fal Settlement Org' , slug : id } )
36+ organizationIds . push ( id )
37+ return id
38+ }
39+
40+ /** A settlement billed to an organization payer, the snapshot shape for a run outside a workspace. */
3241function payloadFor (
3342 userId : string ,
43+ organizationId : string ,
3444 billedProviderCostDollars : number ,
3545 billingPeriod = { start : '2026-11-01T00:00:00.000Z' , end : '2026-12-01T00:00:00.000Z' }
3646) : FalAICostSettlementPayload {
@@ -45,9 +55,9 @@ function payloadFor(
4555 billingAttribution : {
4656 actorUserId : userId ,
4757 workspaceId : null ,
48- organizationId : null ,
58+ organizationId,
4959 billedAccountUserId : userId ,
50- billingEntity : { type : 'user ' , id : userId } ,
60+ billingEntity : { type : 'organization ' , id : organizationId } ,
5161 billingPeriod,
5262 payerSubscription : null ,
5363 } ,
@@ -103,12 +113,16 @@ afterAll(async () => {
103113 await db . delete ( usageLog ) . where ( inArray ( usageLog . userId , userIds ) )
104114 await db . delete ( user ) . where ( inArray ( user . id , userIds ) )
105115 }
116+ if ( organizationIds . length > 0 ) {
117+ await db . delete ( organization ) . where ( inArray ( organization . id , organizationIds ) )
118+ }
106119} )
107120
108121describe ( 'settleFalAICost' , ( ) => {
109122 it ( 'bills the shortfall once when the exact charge exceeds the estimate, however often it runs' , async ( ) => {
110123 const userId = await createUser ( )
111- const payload = payloadFor ( userId , 6.49 )
124+ const organizationId = await createOrganization ( )
125+ const payload = payloadFor ( userId , organizationId , 6.49 )
112126 stubFalBillingEvents ( { requestId : payload . requestId , costDollars : 15 } )
113127
114128 expect ( await settleFalAICost ( payload ) ) . toBe ( 'charged' )
@@ -125,8 +139,9 @@ describe('settleFalAICost', () => {
125139
126140 it ( 'bills a settlement that outlives its billing period to the payer current period' , async ( ) => {
127141 const userId = await createUser ( )
142+ const organizationId = await createOrganization ( )
128143 const endedPeriod = { start : '2026-01-01T00:00:00.000Z' , end : '2026-02-01T00:00:00.000Z' }
129- const payload = payloadFor ( userId , 6.49 , endedPeriod )
144+ const payload = payloadFor ( userId , organizationId , 6.49 , endedPeriod )
130145 stubFalBillingEvents ( { requestId : payload . requestId , costDollars : 15 } )
131146
132147 expect ( await settleFalAICost ( payload ) ) . toBe ( 'charged' )
@@ -138,19 +153,21 @@ describe('settleFalAICost', () => {
138153
139154 it ( 'bills nothing while fal has not recorded the charge' , async ( ) => {
140155 const userId = await createUser ( )
156+ const organizationId = await createOrganization ( )
141157 stubFalBillingEvents ( null )
142158
143- expect ( await settleFalAICost ( payloadFor ( userId , 0.25 ) ) ) . toBe ( 'pending' )
159+ expect ( await settleFalAICost ( payloadFor ( userId , organizationId , 0.25 ) ) ) . toBe ( 'pending' )
144160
145161 expect ( await settlementRows ( userId ) ) . toHaveLength ( 0 )
146162 } )
147163
148164 it ( 'refuses to settle when the hosted key that ran the request is not configured' , async ( ) => {
149165 const userId = await createUser ( )
166+ const organizationId = await createOrganization ( )
150167 vi . stubEnv ( HOSTED_KEY_ENV_VAR , '' )
151168 const fetchMock = stubFalBillingEvents ( null )
152169
153- await expect ( settleFalAICost ( payloadFor ( userId , 6.49 ) ) ) . rejects . toThrow (
170+ await expect ( settleFalAICost ( payloadFor ( userId , organizationId , 6.49 ) ) ) . rejects . toThrow (
154171 'Hosted fal key FALAI_API_KEY_1 is not configured'
155172 )
156173 expect ( fetchMock ) . not . toHaveBeenCalled ( )
0 commit comments