Files
CapaKraken/packages/application/src/use-cases/vacation/reject-vacation.ts
T
Hartmut dda049075f refactor(application): extract vacation management into application use-cases
Moves approve, reject, cancel, and request vacation business logic
out of the tRPC procedure layer into packages/application, matching
the pattern used by allocation use-cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 16:49:45 +02:00

80 lines
2.2 KiB
TypeScript

import type { Prisma, PrismaClient, VacationStatus } from "@capakraken/db";
import { TRPCError } from "@trpc/server";
type DbClient = Pick<PrismaClient, "vacation">;
export type RejectVacationDeps = {
assertVacationRejectable: (status: VacationStatus) => void;
buildRejectedVacationUpdateData: (input: {
rejectionReason?: string | undefined;
}) => Prisma.VacationUncheckedUpdateInput;
};
export type RejectVacationInput = {
id: string;
rejectionReason?: string | undefined;
};
export type RejectVacationResult = {
vacation: Awaited<ReturnType<PrismaClient["vacation"]["update"]>>;
};
export async function rejectVacation(
db: DbClient,
input: RejectVacationInput,
deps: RejectVacationDeps,
): Promise<RejectVacationResult> {
const existing = await db.vacation.findUnique({ where: { id: input.id } });
if (!existing) {
throw new TRPCError({ code: "NOT_FOUND", message: "Vacation not found" });
}
deps.assertVacationRejectable(existing.status);
const updated = await db.vacation.update({
where: { id: input.id },
data: deps.buildRejectedVacationUpdateData({
rejectionReason: input.rejectionReason,
}),
});
return { vacation: updated };
}
export type BatchRejectVacationDeps = {
buildRejectedVacationUpdateData: (input: {
rejectionReason?: string | undefined;
}) => Prisma.VacationUncheckedUpdateInput;
};
export type BatchRejectVacationInput = {
ids: string[];
rejectionReason?: string | undefined;
};
export type BatchRejectVacationResult = {
rejected: number;
vacations: Array<{ id: string; resourceId: string }>;
};
export async function batchRejectVacations(
db: DbClient,
input: BatchRejectVacationInput,
deps: BatchRejectVacationDeps,
): Promise<BatchRejectVacationResult> {
const vacations: Array<{ id: string; resourceId: string }> =
await db.vacation.findMany({
where: { id: { in: input.ids }, status: "PENDING" },
select: { id: true, resourceId: true },
});
await db.vacation.updateMany({
where: { id: { in: vacations.map((v) => v.id) } },
data: deps.buildRejectedVacationUpdateData({
rejectionReason: input.rejectionReason,
}),
});
return { rejected: vacations.length, vacations };
}