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>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
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 };
|
||||
}
|
||||
Reference in New Issue
Block a user