
How I Implemented Department-Scoped Approval Workflows for Requisitions
Direct answer (40 words): Split “what status comes next” from “who may click approve”: threshold rules move PENDING_MANAGER to APPROVED or PENDING_FINANCE by amount; who may approve uses department manager id, approver department match, and finance permission—so approvals follow org structure, not only role names.
Status machine (amount-driven)
const MANAGER_ONLY_THRESHOLD = new Decimal(5000);
/**
* Determine the next status for a requisition after an approval action.
*
* Workflow rules:
* - DRAFT -> submit -> PENDING_MANAGER
* - PENDING_MANAGER + Manager approves + amount <= 5000 -> APPROVED
* - PENDING_MANAGER + Manager approves + amount > 5000 -> PENDING_FINANCE
* - PENDING_FINANCE + Finance approves -> APPROVED
*/
export function determineNextStatus(
totalAmount: Decimal,
currentStatus: RequisitionStatus
): RequisitionStatus {
switch (currentStatus) {
case "DRAFT":
return "PENDING_MANAGER";
case "PENDING_MANAGER":
if (totalAmount.lte(MANAGER_ONLY_THRESHOLD)) {
return "APPROVED";
}
return "PENDING_FINANCE";
case "PENDING_FINANCE":
return "APPROVED";
default:
return currentStatus;
}
}
Authorization (org context)
export function canUserApprove(
userId: string,
userPermissions: Permissions | null | undefined,
userDepartmentId: string | null,
requisition: RequisitionForAuth
): boolean {
if (requisition.status === "PENDING_MANAGER") {
const isDeptManager = requisition.department.managerId === userId;
const isApproverInDept =
canApproveManager(userPermissions) &&
userDepartmentId === requisition.departmentId;
return isDeptManager || isApproverInDept;
}
if (requisition.status === "PENDING_FINANCE") {
return canApproveFinance(userPermissions);
}
return false;
}
Why this design scales
- Thresholds are easy to tune per deployment (policy, currency, or risk appetite).
- Department scoping prevents cross-department approval spoofing when multiple buyers share a role label.
- Pure functions stay testable without mocking Prisma—ideal for unit tests around edge cases.
Read the full case study: CPMS — Comprehensive Procurement Management System