fix(server): separate active subscriptions (#13077)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved accuracy of subscription management by ensuring only active
or trialing subscriptions are considered in all relevant user,
workspace, and license actions.
* Enhanced consistency in subscription retrieval for workspace member
updates and subscription-related operations.

* **Refactor**
* Updated internal subscription retrieval methods to distinguish between
general and active subscriptions for more precise handling across the
app.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Yii
2025-07-08 11:02:08 +08:00
committed by GitHub
parent b9b336f728
commit 61da63a4a0
7 changed files with 40 additions and 8 deletions
@@ -84,9 +84,14 @@ export abstract class SubscriptionManager {
subscription: KnownStripeSubscription
): Promise<void>;
abstract getActiveSubscription(
identity: z.infer<typeof SubscriptionIdentity>
): Promise<Subscription | null>;
abstract getSubscription(
identity: z.infer<typeof SubscriptionIdentity>
): Promise<Subscription | null>;
abstract cancelSubscription(
subscription: Subscription
): Promise<Subscription>;
@@ -186,6 +186,14 @@ export class SelfhostTeamSubscriptionManager extends SubscriptionManager {
}
getSubscription(identity: z.infer<typeof SelfhostTeamSubscriptionIdentity>) {
return this.db.subscription.findFirst({
where: { targetId: identity.key },
});
}
getActiveSubscription(
identity: z.infer<typeof SelfhostTeamSubscriptionIdentity>
) {
return this.db.subscription.findFirst({
where: {
targetId: identity.key,
@@ -198,6 +198,15 @@ export class UserSubscriptionManager extends SubscriptionManager {
}
async getSubscription(args: z.infer<typeof UserSubscriptionIdentity>) {
return this.db.subscription.findFirst({
where: {
targetId: args.userId,
plan: args.plan,
},
});
}
async getActiveSubscription(args: z.infer<typeof UserSubscriptionIdentity>) {
return this.db.subscription.findFirst({
where: {
targetId: args.userId,
@@ -202,6 +202,16 @@ export class WorkspaceSubscriptionManager extends SubscriptionManager {
}
getSubscription(identity: z.infer<typeof WorkspaceSubscriptionIdentity>) {
return this.db.subscription.findFirst({
where: {
targetId: identity.workspaceId,
},
});
}
getActiveSubscription(
identity: z.infer<typeof WorkspaceSubscriptionIdentity>
) {
return this.db.subscription.findFirst({
where: {
targetId: identity.workspaceId,
@@ -277,7 +287,7 @@ export class WorkspaceSubscriptionManager extends SubscriptionManager {
@OnEvent('workspace.members.updated')
async onMembersUpdated({ workspaceId }: Events['workspace.members.updated']) {
const count = await this.models.workspaceUser.chargedCount(workspaceId);
const subscription = await this.getSubscription({
const subscription = await this.getActiveSubscription({
plan: SubscriptionPlan.Team,
workspaceId,
});