import type { Prisma } from "@capakraken/db"; import { VacationStatus } from "@capakraken/db"; import type { UpdateVacationStatusInput } from "@capakraken/shared"; import { TRPCError } from "@trpc/server"; type VacationApprovalWriteData = Record; export const approvableVacationStatuses: readonly VacationStatus[] = [ VacationStatus.PENDING, VacationStatus.CANCELLED, VacationStatus.REJECTED, ]; export function assertVacationApprovable(status: VacationStatus): void { if (!approvableVacationStatuses.includes(status)) { throw new TRPCError({ code: "BAD_REQUEST", message: "Only PENDING, CANCELLED, or REJECTED vacations can be approved", }); } } export function assertVacationRejectable(status: VacationStatus): void { if (status !== VacationStatus.PENDING) { throw new TRPCError({ code: "BAD_REQUEST", message: "Only PENDING vacations can be rejected", }); } } export function assertVacationCancelable(status: VacationStatus): void { if (status === VacationStatus.CANCELLED) { throw new TRPCError({ code: "BAD_REQUEST", message: "Already cancelled", }); } } export function isVacationManagerRole(role: string | null | undefined): boolean { return role === "ADMIN" || role === "MANAGER"; } export function canActorCancelVacation(input: { actorId: string; actorRole: string | null | undefined; requestedById: string | null | undefined; resourceUserId: string | null | undefined; }): boolean { if (isVacationManagerRole(input.actorRole)) { return true; } return input.requestedById === input.actorId || input.resourceUserId === input.actorId; } export function buildApprovedVacationUpdateData(input: { deductionSnapshotWriteData: VacationApprovalWriteData; approvedById?: string | undefined; approvedAt: Date; }): Prisma.VacationUncheckedUpdateInput { return { status: VacationStatus.APPROVED, rejectionReason: null, ...input.deductionSnapshotWriteData, ...(input.approvedById ? { approvedById: input.approvedById } : {}), approvedAt: input.approvedAt, }; } export function buildRejectedVacationUpdateData(input: { rejectionReason?: string | undefined; }): Prisma.VacationUncheckedUpdateInput { return { status: VacationStatus.REJECTED, ...(input.rejectionReason !== undefined ? { rejectionReason: input.rejectionReason } : {}), }; } export function buildVacationStatusUpdateData(input: { status: UpdateVacationStatusInput["status"]; note?: string | undefined; approvedById: string; approvedAt: Date; }): Prisma.VacationUncheckedUpdateInput { const data: Prisma.VacationUncheckedUpdateInput = { status: input.status }; if (input.status === VacationStatus.APPROVED) { data.approvedById = input.approvedById; data.approvedAt = input.approvedAt; data.rejectionReason = null; } if (input.note !== undefined) { data.note = input.note; } return data; }