mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-16 01:46:38 +00:00
Rename tiers and get working
This commit is contained in:
@@ -17,8 +17,8 @@ import { eq, and, ne } from "drizzle-orm";
|
||||
|
||||
export async function getOrgTierData(
|
||||
orgId: string
|
||||
): Promise<{ tier: "home_lab" | "starter" | "scale" | null; active: boolean }> {
|
||||
let tier: "home_lab" | "starter" | "scale" | null = null;
|
||||
): Promise<{ tier: "tier1" | "tier2" | "tier3" | null; active: boolean }> {
|
||||
let tier: "tier1" | "tier2" | "tier3" | null = null;
|
||||
let active = false;
|
||||
|
||||
if (build !== "saas") {
|
||||
@@ -50,9 +50,9 @@ export async function getOrgTierData(
|
||||
if (subscription) {
|
||||
// Validate that subscription.type is one of the expected tier values
|
||||
if (
|
||||
subscription.type === "home_lab" ||
|
||||
subscription.type === "starter" ||
|
||||
subscription.type === "scale"
|
||||
subscription.type === "tier1" ||
|
||||
subscription.type === "tier2" ||
|
||||
subscription.type === "tier3"
|
||||
) {
|
||||
tier = subscription.type;
|
||||
active = true;
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function isLicensedOrSubscribed(orgId: string): Promise<boolean> {
|
||||
|
||||
if (build === "saas") {
|
||||
const { tier, active } = await getOrgTierData(orgId);
|
||||
return (tier == "home_lab" || tier == "starter" || tier == "scale") && active;
|
||||
return (tier == "tier1" || tier == "tier2" || tier == "tier3") && active;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -17,7 +17,7 @@ import { getOrgTierData } from "#private/lib/billing";
|
||||
export async function isSubscribed(orgId: string): Promise<boolean> {
|
||||
if (build === "saas") {
|
||||
const { tier, active } = await getOrgTierData(orgId);
|
||||
return (tier == "home_lab" || tier == "starter" || tier == "scale") && active;
|
||||
return (tier == "tier1" || tier == "tier2" || tier == "tier3") && active;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -39,7 +39,7 @@ export async function verifyValidSubscription(
|
||||
}
|
||||
|
||||
const { tier, active } = await getOrgTierData(orgId);
|
||||
if ((tier == "home_lab" || tier == "starter" || tier == "scale") && active) {
|
||||
if ((tier == "tier1" || tier == "tier2" || tier == "tier3") && active) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
|
||||
@@ -35,7 +35,7 @@ const changeTierSchema = z.strictObject({
|
||||
});
|
||||
|
||||
const changeTierBodySchema = z.strictObject({
|
||||
tier: z.enum(["home_lab", "starter", "scale"])
|
||||
tier: z.enum(["tier1", "tier2", "tier3"])
|
||||
});
|
||||
|
||||
export async function changeTier(
|
||||
@@ -93,9 +93,9 @@ export async function changeTier(
|
||||
eq(subscriptions.customerId, customer.customerId),
|
||||
eq(subscriptions.status, "active"),
|
||||
or(
|
||||
eq(subscriptions.type, "home_lab"),
|
||||
eq(subscriptions.type, "starter"),
|
||||
eq(subscriptions.type, "scale")
|
||||
eq(subscriptions.type, "tier1"),
|
||||
eq(subscriptions.type, "tier2"),
|
||||
eq(subscriptions.type, "tier3")
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -112,11 +112,11 @@ export async function changeTier(
|
||||
|
||||
// Get the target tier's price set
|
||||
let targetPriceSet: FeaturePriceSet;
|
||||
if (tier === "home_lab") {
|
||||
if (tier === "tier1") {
|
||||
targetPriceSet = getHomeLabFeaturePriceSet();
|
||||
} else if (tier === "starter") {
|
||||
} else if (tier === "tier2") {
|
||||
targetPriceSet = getStarterFeaturePriceSet();
|
||||
} else if (tier === "scale") {
|
||||
} else if (tier === "tier3") {
|
||||
targetPriceSet = getScaleFeaturePriceSet();
|
||||
} else {
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid tier"));
|
||||
@@ -148,11 +148,11 @@ export async function changeTier(
|
||||
);
|
||||
|
||||
// Determine if we're switching between different products
|
||||
// home_lab uses HOME_LAB product, starter/scale use USERS product
|
||||
// tier1 uses TIER1 product, tier2/tier3 use USERS product
|
||||
const currentTier = subscription.type;
|
||||
const switchingProducts =
|
||||
(currentTier === "home_lab" && (tier === "starter" || tier === "scale")) ||
|
||||
((currentTier === "starter" || currentTier === "scale") && tier === "home_lab");
|
||||
(currentTier === "tier1" && (tier === "tier2" || tier === "tier3")) ||
|
||||
((currentTier === "tier2" || currentTier === "tier3") && tier === "tier1");
|
||||
|
||||
let updatedSubscription;
|
||||
|
||||
@@ -189,7 +189,7 @@ export async function changeTier(
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// Same product, different price tier (starter <-> scale)
|
||||
// Same product, different price tier (tier2 <-> tier3)
|
||||
// We can simply update the price
|
||||
logger.info(
|
||||
`Updating price from ${currentTier} to ${tier} for subscription ${subscription.subscriptionId}`
|
||||
|
||||
@@ -31,7 +31,7 @@ const createCheckoutSessionSchema = z.strictObject({
|
||||
});
|
||||
|
||||
const createCheckoutSessionBodySchema = z.strictObject({
|
||||
tier: z.enum(["home_lab", "starter", "scale"]),
|
||||
tier: z.enum(["tier1", "tier2", "tier3"]),
|
||||
});
|
||||
|
||||
export async function createCheckoutSession(
|
||||
@@ -83,11 +83,11 @@ export async function createCheckoutSession(
|
||||
}
|
||||
|
||||
let lineItems: Stripe.Checkout.SessionCreateParams.LineItem[];
|
||||
if (tier === "home_lab") {
|
||||
if (tier === "tier1") {
|
||||
lineItems = await getLineItems(getHomeLabFeaturePriceSet(), orgId);
|
||||
} else if (tier === "starter") {
|
||||
} else if (tier === "tier2") {
|
||||
lineItems = await getLineItems(getStarterFeaturePriceSet(), orgId);
|
||||
} else if (tier === "scale") {
|
||||
} else if (tier === "tier3") {
|
||||
lineItems = await getLineItems(getScaleFeaturePriceSet(), orgId);
|
||||
} else {
|
||||
return next(
|
||||
|
||||
@@ -78,16 +78,10 @@ export async function getOrgUsage(
|
||||
// Get usage for org
|
||||
const usageData = [];
|
||||
|
||||
const sites = await usageService.getUsage(
|
||||
orgId,
|
||||
FeatureId.SITES
|
||||
);
|
||||
const users = await usageService.getUsageDaily(orgId, FeatureId.USERS);
|
||||
const domains = await usageService.getUsageDaily(
|
||||
orgId,
|
||||
FeatureId.DOMAINS
|
||||
);
|
||||
const remoteExitNodes = await usageService.getUsageDaily(
|
||||
const sites = await usageService.getUsage(orgId, FeatureId.SITES);
|
||||
const users = await usageService.getUsage(orgId, FeatureId.USERS);
|
||||
const domains = await usageService.getUsage(orgId, FeatureId.DOMAINS);
|
||||
const remoteExitNodes = await usageService.getUsage(
|
||||
orgId,
|
||||
FeatureId.REMOTE_EXIT_NODES
|
||||
);
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from "@server/lib/billing/features";
|
||||
import Stripe from "stripe";
|
||||
|
||||
export type SubscriptionType = "home_lab" | "starter" | "scale" | "license";
|
||||
export type SubscriptionType = "tier1" | "tier2" | "tier3" | "license";
|
||||
|
||||
export function getSubType(fullSubscription: Stripe.Response<Stripe.Subscription>): SubscriptionType | null {
|
||||
// Determine subscription type by checking subscription items
|
||||
@@ -41,21 +41,21 @@ export function getSubType(fullSubscription: Stripe.Response<Stripe.Subscription
|
||||
// Check if price ID matches home lab tier
|
||||
const homeLabPrices = Object.values(getHomeLabFeaturePriceSet());
|
||||
if (homeLabPrices.includes(priceId)) {
|
||||
return "home_lab";
|
||||
return "tier1";
|
||||
}
|
||||
|
||||
// Check if price ID matches starter tier
|
||||
const starterPrices = Object.values(getStarterFeaturePriceSet());
|
||||
if (starterPrices.includes(priceId)) {
|
||||
return "starter";
|
||||
// Check if price ID matches tier2 tier
|
||||
const tier2Prices = Object.values(getStarterFeaturePriceSet());
|
||||
if (tier2Prices.includes(priceId)) {
|
||||
return "tier2";
|
||||
}
|
||||
|
||||
// Check if price ID matches scale tier
|
||||
const scalePrices = Object.values(getScaleFeaturePriceSet());
|
||||
if (scalePrices.includes(priceId)) {
|
||||
return "scale";
|
||||
// Check if price ID matches tier3 tier
|
||||
const tier3Prices = Object.values(getScaleFeaturePriceSet());
|
||||
if (tier3Prices.includes(priceId)) {
|
||||
return "tier3";
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ export async function handleSubscriptionCreated(
|
||||
}
|
||||
|
||||
return {
|
||||
stripeSubscriptionItemId: item.id,
|
||||
subscriptionId: subscription.id,
|
||||
planId: item.plan.id,
|
||||
priceId: item.price.id,
|
||||
@@ -132,7 +133,7 @@ export async function handleSubscriptionCreated(
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "home_lab" || type === "starter" || type === "scale") {
|
||||
if (type === "tier1" || type === "tier2" || type === "tier3") {
|
||||
logger.debug(
|
||||
`Handling SAAS subscription lifecycle for org ${customer.orgId} with type ${type}`
|
||||
);
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function handleSubscriptionDeleted(
|
||||
}
|
||||
|
||||
const type = getSubType(fullSubscription);
|
||||
if (type == "home_lab" || type == "starter" || type == "scale") {
|
||||
if (type == "tier1" || type == "tier2" || type == "tier3") {
|
||||
logger.debug(
|
||||
`Handling SaaS subscription deletion for orgId ${customer.orgId} and subscription ID ${subscription.id}`
|
||||
);
|
||||
|
||||
@@ -82,6 +82,7 @@ export async function handleSubscriptionUpdated(
|
||||
// Upsert subscription items
|
||||
if (Array.isArray(fullSubscription.items?.data)) {
|
||||
const itemsToUpsert = fullSubscription.items.data.map((item) => ({
|
||||
stripeSubscriptionItemId: item.id,
|
||||
subscriptionId: subscription.id,
|
||||
planId: item.plan.id,
|
||||
priceId: item.price.id,
|
||||
@@ -237,7 +238,7 @@ export async function handleSubscriptionUpdated(
|
||||
}
|
||||
// --- end usage update ---
|
||||
|
||||
if (type === "home_lab" || type === "starter" || type === "scale") {
|
||||
if (type === "tier1" || type === "tier2" || type === "tier3") {
|
||||
logger.debug(
|
||||
`Handling SAAS subscription lifecycle for org ${customer.orgId} with type ${type}`
|
||||
);
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
import {
|
||||
freeLimitSet,
|
||||
homeLabLimitSet,
|
||||
starterLimitSet,
|
||||
scaleLimitSet,
|
||||
tier2LimitSet,
|
||||
tier3LimitSet,
|
||||
limitsService,
|
||||
LimitSet
|
||||
} from "@server/lib/billing";
|
||||
@@ -24,16 +24,16 @@ import { SubscriptionType } from "./hooks/getSubType";
|
||||
|
||||
function getLimitSetForSubscriptionType(subType: SubscriptionType | null): LimitSet {
|
||||
switch (subType) {
|
||||
case "home_lab":
|
||||
case "tier1":
|
||||
return homeLabLimitSet;
|
||||
case "starter":
|
||||
return starterLimitSet;
|
||||
case "scale":
|
||||
return scaleLimitSet;
|
||||
case "tier2":
|
||||
return tier2LimitSet;
|
||||
case "tier3":
|
||||
return tier3LimitSet;
|
||||
case "license":
|
||||
// License subscriptions use starter limits by default
|
||||
// License subscriptions use tier2 limits by default
|
||||
// This can be adjusted based on your business logic
|
||||
return starterLimitSet;
|
||||
return tier2LimitSet;
|
||||
default:
|
||||
return freeLimitSet;
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ export async function createRemoteExitNode(
|
||||
});
|
||||
|
||||
if (numExitNodeOrgs) {
|
||||
await usageService.updateDaily(
|
||||
await usageService.updateCount(
|
||||
orgId,
|
||||
FeatureId.REMOTE_EXIT_NODES,
|
||||
numExitNodeOrgs.length
|
||||
|
||||
@@ -106,7 +106,7 @@ export async function deleteRemoteExitNode(
|
||||
});
|
||||
|
||||
if (numExitNodeOrgs) {
|
||||
await usageService.updateDaily(
|
||||
await usageService.updateCount(
|
||||
orgId,
|
||||
FeatureId.REMOTE_EXIT_NODES,
|
||||
numExitNodeOrgs.length
|
||||
|
||||
Reference in New Issue
Block a user