import type { AppraisalStatus, Role } from "@prisma/client"; // Appraisal lifecycle (Crewing-Implementation-Spec §5.4) — mirrors the other // crewing state machines. A PM raises the appraisal directly into SUBMITTED; this // machine governs the two review advances. Rejection is orthogonal (handled in // the actions: an MPO or Manager declines → REJECTED with remarks). export type AppraisalAction = "verify" | "approve"; interface Transition { to: AppraisalStatus; allowedRoles: Role[]; } const VERIFY_ROLES: Role[] = ["MANNING", "MANAGER", "SUPERUSER"]; // verify_appraisal const APPROVE_ROLES: Role[] = ["MANAGER", "SUPERUSER"]; // approve_appraisal const TRANSITIONS: Partial>>> = { SUBMITTED: { verify: { to: "MPO_VERIFIED", allowedRoles: VERIFY_ROLES }, }, MPO_VERIFIED: { approve: { to: "MANAGER_APPROVED", allowedRoles: APPROVE_ROLES }, }, }; export function getTransition(from: AppraisalStatus, action: AppraisalAction): Transition | null { return TRANSITIONS[from]?.[action] ?? null; } export function canPerformAction(from: AppraisalStatus, action: AppraisalAction, role: Role): boolean { return getTransition(from, action)?.allowedRoles.includes(role) ?? false; } // A review may be declined while the appraisal is still in flight. const REJECTABLE_FROM: AppraisalStatus[] = ["SUBMITTED", "MPO_VERIFIED"]; export function canReject(from: AppraisalStatus): boolean { return REJECTABLE_FROM.includes(from); }