@@ -2028,6 +2028,62 @@ class OsoAppClient {
20282028 return true ;
20292029 }
20302030
2031+ /**
2032+ * Update an organization's tier (FREE or ENTERPRISE)
2033+ * @param orgName
2034+ * @param tier
2035+ * @returns Promise<boolean>
2036+ */
2037+ async updateOrganizationTier (
2038+ args : Partial < { orgName : string ; tier : "FREE" | "ENTERPRISE" } > ,
2039+ ) {
2040+ const orgName = ensure (
2041+ args . orgName ,
2042+ "orgName is required to update organization tier" ,
2043+ ) ;
2044+ const tier = ensure (
2045+ args . tier ,
2046+ "tier is required to update organization tier" ,
2047+ ) ;
2048+
2049+ if ( tier !== "FREE" && tier !== "ENTERPRISE" ) {
2050+ throw new Error ( "Invalid tier. Must be either 'FREE' or 'ENTERPRISE'" ) ;
2051+ }
2052+
2053+ const { data : org } = await this . supabaseClient
2054+ . from ( "organizations" )
2055+ . select ( "pricing_plan(plan_name)" )
2056+ . eq ( "org_name" , orgName )
2057+ . is ( "deleted_at" , null )
2058+ . single ( )
2059+ . throwOnError ( ) ;
2060+
2061+ if ( ! org ) {
2062+ throw new MissingDataError ( `Organization not found: ${ orgName } ` ) ;
2063+ }
2064+
2065+ if ( ! org . pricing_plan ) {
2066+ throw new MissingDataError (
2067+ `Pricing plan not found for organization: ${ orgName } ` ,
2068+ ) ;
2069+ }
2070+
2071+ const currentPlanName = org . pricing_plan . plan_name ;
2072+
2073+ if ( currentPlanName === tier ) {
2074+ console . log (
2075+ `Organization ${ orgName } is already on the ${ tier } tier. No changes made.` ,
2076+ ) ;
2077+ return true ;
2078+ }
2079+
2080+ if ( tier === "ENTERPRISE" ) {
2081+ return this . promoteOrganizationToEnterprise ( { orgName } ) ;
2082+ } else {
2083+ return this . demoteOrganizationFromEnterprise ( { orgName } ) ;
2084+ }
2085+ }
2086+
20312087 /**
20322088 * Manually add credits to organization balance
20332089 * @param args
@@ -2096,6 +2152,69 @@ class OsoAppClient {
20962152 return true ;
20972153 }
20982154
2155+ /**
2156+ * Manually set organization's credits to an exact amount
2157+ * @param args
2158+ * @return Promise<boolean>
2159+ */
2160+ async setOrganizationCredits (
2161+ args : Partial < {
2162+ orgName : string ;
2163+ amount : number ;
2164+ reason ?: string ;
2165+ } > ,
2166+ ) {
2167+ const orgName = ensure (
2168+ args . orgName ,
2169+ "orgName is required to set organization credits" ,
2170+ ) ;
2171+ const { amount, reason } = args ;
2172+
2173+ if ( amount === undefined || amount < 0 ) {
2174+ throw new Error ( "Amount must be a non-negative number" ) ;
2175+ }
2176+
2177+ const org = await this . getOrganizationByName ( { orgName } ) ;
2178+ const user = await this . getUser ( ) ;
2179+
2180+ const currentBalance = await this . getOrganizationCredits ( {
2181+ orgName,
2182+ } ) ;
2183+
2184+ const newBalance = amount ;
2185+
2186+ await this . supabaseClient
2187+ . from ( "organization_credits" )
2188+ . upsert (
2189+ {
2190+ org_id : org . id ,
2191+ credits_balance : newBalance ,
2192+ updated_at : new Date ( ) . toISOString ( ) ,
2193+ } ,
2194+ { onConflict : "org_id" } ,
2195+ )
2196+ . throwOnError ( ) ;
2197+
2198+ await this . supabaseClient
2199+ . from ( "organization_credit_transactions" )
2200+ . insert ( {
2201+ org_id : org . id ,
2202+ user_id : user . id ,
2203+ amount : newBalance - currentBalance ,
2204+ transaction_type : "admin_set" ,
2205+ metadata : {
2206+ reason : reason || "Manual admin credit set" ,
2207+ admin_action : true ,
2208+ previous_balance : currentBalance ,
2209+ new_balance : newBalance ,
2210+ } ,
2211+ created_at : new Date ( ) . toISOString ( ) ,
2212+ } )
2213+ . throwOnError ( ) ;
2214+
2215+ return true ;
2216+ }
2217+
20992218 /**
21002219 * Manually deduct credits from organization balance
21012220 * @param args
0 commit comments