100 lines
2.9 KiB
TypeScript
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;
|
|
}
|