Files
calendar/packages/lib/server/repository/credits.ts
T
ef114d7727 feat: add email and phone number to credit expense log (#22846)
* feat: add email and phone number to credit expense log

* feat: fix test cases

* Update downloadExpenseLog.handler.ts

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
2025-09-04 09:25:19 +05:30

243 lines
5.3 KiB
TypeScript

import dayjs from "@calcom/dayjs";
import prisma, { type PrismaTransaction } from "@calcom/prisma";
import { Prisma } from "@calcom/prisma/client";
import type { CreditType } from "@calcom/prisma/enums";
export class CreditsRepository {
static async findCreditBalance(
{ teamId, userId }: { teamId?: number; userId?: number },
tx?: PrismaTransaction
) {
const prismaClient = tx ?? prisma;
const select = {
id: true,
additionalCredits: true,
limitReachedAt: true,
warningSentAt: true,
};
if (teamId) {
return await prismaClient.creditBalance.findUnique({
where: {
teamId,
},
select,
});
}
if (userId) {
return await prismaClient.creditBalance.findUnique({
where: { userId },
select,
});
}
}
static async findCreditExpenseLogByExternalRef(externalRef: string, tx?: PrismaTransaction) {
const prismaClient = tx ?? prisma;
return await prismaClient.creditExpenseLog.findUnique({
where: { externalRef },
select: {
id: true,
credits: true,
creditType: true,
date: true,
bookingUid: true,
},
});
}
static async findCreditBalanceWithTeamOrUser(
{
teamId,
userId,
}: {
teamId?: number | null;
userId?: number | null;
},
tx?: PrismaTransaction
) {
const prismaClient = tx ?? prisma;
const select = {
id: true,
additionalCredits: true,
limitReachedAt: true,
warningSentAt: true,
team: {
select: {
id: true,
name: true,
members: {
select: {
user: {
select: {
id: true,
name: true,
email: true,
locale: true,
},
},
},
},
},
},
user: {
select: {
id: true,
name: true,
email: true,
locale: true,
},
},
};
if (teamId) {
return await prismaClient.creditBalance.findUnique({
where: {
teamId,
},
select,
});
}
if (userId) {
return await prismaClient.creditBalance.findUnique({
where: { userId },
select,
});
}
}
static async findCreditBalanceWithExpenseLogs(
{
teamId,
userId,
startDate = dayjs().startOf("month").toDate(),
endDate = new Date(),
creditType,
}: { teamId?: number; userId?: number; startDate?: Date; endDate?: Date; creditType?: CreditType },
tx?: PrismaTransaction
) {
if (!teamId && !userId) return null;
const prismaClient = tx ?? prisma;
return await prismaClient.creditBalance.findUnique({
where: {
teamId,
...(!teamId ? { userId } : {}),
},
select: {
additionalCredits: true,
expenseLogs: {
where: {
date: {
gte: startDate,
lte: endDate,
},
...(creditType ? { creditType } : {}),
},
orderBy: {
date: "desc",
},
select: {
date: true,
credits: true,
creditType: true,
bookingUid: true,
smsSid: true,
smsSegments: true,
phoneNumber: true,
email: true,
callDuration: true,
externalRef: true,
},
},
},
});
}
static async updateCreditBalance(
{
id,
teamId,
userId,
data,
}: {
id?: string;
teamId?: number | null;
userId?: number | null;
data: Prisma.CreditBalanceUncheckedUpdateInput;
},
tx?: PrismaTransaction
) {
const prismaClient = tx ?? prisma;
if (id) {
return prismaClient.creditBalance.update({
where: { id },
data,
});
}
if (teamId) {
return prismaClient.creditBalance.update({
where: { teamId },
data,
});
}
if (userId) {
return prismaClient.creditBalance.update({
where: { userId },
data,
});
}
return null;
}
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,
...(!teamId ? { userId } : {}),
},
});
}
static async createCreditExpenseLog(
data: Prisma.CreditExpenseLogUncheckedCreateInput,
tx?: PrismaTransaction
) {
const prismaClient = tx ?? prisma;
try {
return await prismaClient.creditExpenseLog.create({
data,
});
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2002") {
throw new Error(`Duplicate external reference - already processed: ${data?.externalRef}`);
}
throw error;
}
}
static async createCreditPurchaseLog(data: { credits: number; creditBalanceId: string }) {
const { credits, creditBalanceId } = data;
return prisma.creditPurchaseLog.create({
data: {
credits,
creditBalanceId,
},
});
}
}