feat: skip updating subscription if unlimited seats

This commit is contained in:
Henry
2025-09-07 22:44:59 +01:00
parent 10d04838bd
commit c6a4c60807
2 changed files with 37 additions and 24 deletions

View File

@@ -2,8 +2,10 @@ import { TRPCError } from "@trpc/server";
import { z } from "zod"; import { z } from "zod";
import * as memberRepo from "@kan/db/repository/member.repo"; import * as memberRepo from "@kan/db/repository/member.repo";
import * as subscriptionRepo from "@kan/db/repository/subscription.repo";
import * as userRepo from "@kan/db/repository/user.repo"; import * as userRepo from "@kan/db/repository/user.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo"; import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { getSubscriptionByPlan, hasUnlimitedSeats } from "@kan/shared/utils";
import { updateSubscriptionSeats } from "@kan/stripe"; import { updateSubscriptionSeats } from "@kan/stripe";
import { createTRPCRouter, protectedProcedure } from "../trpc"; import { createTRPCRouter, protectedProcedure } from "../trpc";
@@ -62,29 +64,34 @@ export const memberRouter = createTRPCRouter({
} }
if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") { if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") {
const subscriptions = await ctx.auth.api.listActiveSubscriptions({ const subscriptions = await subscriptionRepo.getByReferenceId(
workspacePublicId: workspace.publicId, ctx.db,
}); workspace.publicId,
// get the active subscription
const activeSubscription = subscriptions.find(
(sub) =>
sub.status === "active" ||
(sub.status === "trialing" && sub.plan === "team"),
); );
if (!activeSubscription) { // get the active subscriptions
const activeTeamSubscription = getSubscriptionByPlan(
subscriptions,
"team",
);
const activeProSubscription = getSubscriptionByPlan(
subscriptions,
"pro",
);
const unlimitedSeats = hasUnlimitedSeats(subscriptions);
if (!activeTeamSubscription && !activeProSubscription) {
throw new TRPCError({ throw new TRPCError({
message: `Workspace with public ID ${workspace.publicId} does not have an active subscription`, message: `Workspace with public ID ${workspace.publicId} does not have an active subscription`,
code: "NOT_FOUND", code: "NOT_FOUND",
}); });
} }
// Update the Stripe subscription to add a seat with immediate proration // Update the Stripe subscription
if (activeSubscription.stripeSubscriptionId) { if (activeTeamSubscription?.stripeSubscriptionId && !unlimitedSeats) {
try { try {
await updateSubscriptionSeats( await updateSubscriptionSeats(
activeSubscription.stripeSubscriptionId, activeTeamSubscription.stripeSubscriptionId,
1, 1,
); );
} catch (error) { } catch (error) {
@@ -204,22 +211,23 @@ export const memberRouter = createTRPCRouter({
// Handle subscription seat decrement for cloud environment // Handle subscription seat decrement for cloud environment
if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") { if (process.env.NEXT_PUBLIC_KAN_ENV === "cloud") {
const subscriptions = await ctx.auth.api.listActiveSubscriptions({ const subscriptions = await subscriptionRepo.getByReferenceId(
workspacePublicId: workspace.publicId, ctx.db,
}); workspace.publicId,
// get the active subscription
const activeSubscription = subscriptions.find(
(sub) =>
sub.status === "active" ||
(sub.status === "trialing" && sub.plan === "team"),
); );
// get the active subscriptions
const activeTeamSubscription = getSubscriptionByPlan(
subscriptions,
"team",
);
const unlimitedSeats = hasUnlimitedSeats(subscriptions);
// Only decrease seats if there's an active subscription and stripeSubscriptionId // Only decrease seats if there's an active subscription and stripeSubscriptionId
if (activeSubscription?.stripeSubscriptionId) { if (activeTeamSubscription?.stripeSubscriptionId && !unlimitedSeats) {
try { try {
await updateSubscriptionSeats( await updateSubscriptionSeats(
activeSubscription.stripeSubscriptionId, activeTeamSubscription.stripeSubscriptionId,
-1, -1,
); );
} catch (error) { } catch (error) {

View File

@@ -14,6 +14,11 @@ export interface Subscription {
unlimitedSeats: boolean; unlimitedSeats: boolean;
periodStart: Date | null; periodStart: Date | null;
periodEnd: Date | null; periodEnd: Date | null;
referenceId: string;
stripeSubscriptionId: string | null;
stripeCustomerId: string | null;
createdAt: Date;
updatedAt: Date;
} }
export const getActiveSubscriptions = ( export const getActiveSubscriptions = (