From c215dc58641b853d234dc8fa8ab2c59d25da9167 Mon Sep 17 00:00:00 2001 From: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Date: Tue, 24 Jun 2025 09:18:14 +0200 Subject: [PATCH] fix: credit balance issues (#21904) * fix creating user balance * fix org check if teamId is given * adjust hasAvailableCredits function * improve comments * fix creditBalance.create * adjust test --------- Co-authored-by: CarinaWolli --- apps/web/pages/api/twilio/webhook.ts | 2 +- packages/features/ee/billing/credit-service.test.ts | 1 + packages/features/ee/billing/credit-service.ts | 11 ++++++++++- packages/lib/server/repository/credits.ts | 11 ++++++++++- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/apps/web/pages/api/twilio/webhook.ts b/apps/web/pages/api/twilio/webhook.ts index 5b669f3a88..18f909ae0b 100644 --- a/apps/web/pages/api/twilio/webhook.ts +++ b/apps/web/pages/api/twilio/webhook.ts @@ -121,7 +121,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { if (!orgId) { orgId = await getOrgIdFromMemberOrTeamId({ - memberId: parsedUserId, + ...(!parsedTeamId ? { memberId: parsedUserId } : {}), teamId: parsedTeamId, }); } diff --git a/packages/features/ee/billing/credit-service.test.ts b/packages/features/ee/billing/credit-service.test.ts index 3e79225250..a11ad985ac 100644 --- a/packages/features/ee/billing/credit-service.test.ts +++ b/packages/features/ee/billing/credit-service.test.ts @@ -191,6 +191,7 @@ describe("CreditService", () => { teamId: 1, availableCredits: 0, creditType: CreditType.ADDITIONAL, + limitReached: true, }); }); }); diff --git a/packages/features/ee/billing/credit-service.ts b/packages/features/ee/billing/credit-service.ts index 9c181c3d11..9166e49ae5 100644 --- a/packages/features/ee/billing/credit-service.ts +++ b/packages/features/ee/billing/credit-service.ts @@ -130,6 +130,9 @@ export class CreditService { }); } + /* + also returns true if team has no available credits but limitReachedAt is not yet set + */ async hasAvailableCredits({ userId, teamId }: { userId?: number | null; teamId?: number | null }) { return await prisma.$transaction(async (tx) => { if (!IS_SMS_CREDITS_ENABLED) return true; @@ -160,12 +163,14 @@ export class CreditService { ); return true; } + // limtReachedAt is set and still no available credits + return false; } if (userId) { const teamWithAvailableCredits = await this._getTeamWithAvailableCredits({ userId, tx }); - if (teamWithAvailableCredits && teamWithAvailableCredits?.availableCredits > 0) return true; + if (teamWithAvailableCredits && !teamWithAvailableCredits.limitReached) return true; const userCredits = await this._getAllCredits({ userId, tx }); @@ -182,6 +187,9 @@ export class CreditService { }); } + /* + If user has memberships, it always returns a team, even if all have limit reached. In that case, limitReached: true is returned + */ protected async _getTeamWithAvailableCredits({ userId, tx }: { userId: number; tx: PrismaTransaction }) { const memberships = await MembershipRepository.findAllAcceptedMemberships(userId, tx); @@ -226,6 +234,7 @@ export class CreditService { teamId: memberships[0].teamId, availableCredits: 0, creditType: CreditType.ADDITIONAL, + limitReached: true, }; } diff --git a/packages/lib/server/repository/credits.ts b/packages/lib/server/repository/credits.ts index 59883a2f4c..603ec50b66 100644 --- a/packages/lib/server/repository/credits.ts +++ b/packages/lib/server/repository/credits.ts @@ -180,8 +180,17 @@ export class CreditsRepository { } static async createCreditBalance(data: Prisma.CreditBalanceUncheckedCreateInput, tx?: PrismaTransaction) { + const { teamId, userId } = data; + + if (!teamId && !userId) { + throw new Error("Team or user ID is required"); + } + return (tx ?? prisma).creditBalance.create({ - data, + data: { + ...data, + ...(!teamId ? { userId } : {}), + }, }); }