Skip to content

Commit 2eb2295

Browse files
authored
chore: add updateOrganizationTier and setOrganizationCredits (#5344)
1 parent 49c3416 commit 2eb2295

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

apps/frontend/components/dataprovider/oso-global-context.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ const OsoGlobalActionNames: ExtractMethodNames<OsoAppClient>[] = _.sortBy([
9292
"demoteOrganizationFromEnterprise",
9393
"addOrganizationCredits",
9494
"deductOrganizationCredits",
95+
"updateOrganizationTier",
96+
"setOrganizationCredits",
9597
]);
9698
const OsoGlobalActions: Partial<ExtractMethods<OsoAppClient>> = _.fromPairs(
9799
OsoGlobalActionNames.map((name) => [

apps/frontend/lib/clients/oso-app/oso-app.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)