Files
CapaKraken/packages/api/src/router/vacation-management-support.ts
T

100 lines
2.9 KiB
TypeScript

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<string, unknown>;
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;
}