Exclude client targets for soft-deleted clients

findAll and findById filter on client.deletedAt = null so targets
belonging to a soft-deleted client are invisible. The create guard
also rejects soft-deleted clients. The raw SQL balance query now
excludes soft-deleted time entries and projects from tracked totals.
This commit is contained in:
simon.franken
2026-02-23 15:24:58 +01:00
parent 1a7d13d5b9
commit 159022ef38

View File

@@ -68,7 +68,7 @@ export interface ClientTargetWithBalance {
export class ClientTargetService { export class ClientTargetService {
async findAll(userId: string): Promise<ClientTargetWithBalance[]> { async findAll(userId: string): Promise<ClientTargetWithBalance[]> {
const targets = await prisma.clientTarget.findMany({ const targets = await prisma.clientTarget.findMany({
where: { userId }, where: { userId, client: { deletedAt: null } },
include: { include: {
client: { select: { id: true, name: true } }, client: { select: { id: true, name: true } },
corrections: { orderBy: { date: 'asc' } }, corrections: { orderBy: { date: 'asc' } },
@@ -81,7 +81,7 @@ export class ClientTargetService {
async findById(id: string, userId: string) { async findById(id: string, userId: string) {
return prisma.clientTarget.findFirst({ return prisma.clientTarget.findFirst({
where: { id, userId }, where: { id, userId, client: { deletedAt: null } },
include: { include: {
client: { select: { id: true, name: true } }, client: { select: { id: true, name: true } },
corrections: { orderBy: { date: 'asc' } }, corrections: { orderBy: { date: 'asc' } },
@@ -97,8 +97,8 @@ export class ClientTargetService {
throw new BadRequestError('startDate must be a Monday'); throw new BadRequestError('startDate must be a Monday');
} }
// Ensure the client belongs to this user // Ensure the client belongs to this user and is not soft-deleted
const client = await prisma.client.findFirst({ where: { id: data.clientId, userId } }); const client = await prisma.client.findFirst({ where: { id: data.clientId, userId, deletedAt: null } });
if (!client) { if (!client) {
throw new NotFoundError('Client not found'); throw new NotFoundError('Client not found');
} }
@@ -229,6 +229,8 @@ export class ClientTargetService {
AND p.client_id = ${target.clientId} AND p.client_id = ${target.clientId}
AND te.start_time >= ${periodStart} AND te.start_time >= ${periodStart}
AND te.start_time <= ${periodEnd} AND te.start_time <= ${periodEnd}
AND te.deleted_at IS NULL
AND p.deleted_at IS NULL
GROUP BY DATE_TRUNC('week', te.start_time AT TIME ZONE 'UTC') GROUP BY DATE_TRUNC('week', te.start_time AT TIME ZONE 'UTC')
`); `);