['SOW Approval'], 'SOW Approval' => ['Estimation', 'Pre-sales'], 'Estimation' => ['Estimate Approved', 'SOW Approval'], 'Estimate Approved' => ['Resource Allocation', 'Estimate Rework'], 'Resource Allocation' => ['Sprint 0', 'Estimate Approved'], 'Sprint 0' => ['In Progress', 'Resource Allocation'], 'In Progress' => ['UAT', 'Sprint 0', 'On Hold'], 'UAT' => ['Handover / Sign-off', 'In Progress', 'On Hold'], 'Handover / Sign-off' => ['Closed', 'UAT'], 'Estimate Rework' => ['Estimation'], 'On Hold' => ['In Progress', 'Cancelled'], 'Cancelled' => [], 'Closed' => [], ]; /** * Return the valid target statuses for the provided current status. */ public function getValidTransitions(string $currentStatus): array { return $this->statusTransitions[$currentStatus] ?? []; } /** * Determine if a transition from the current status to the target is allowed. */ public function canTransition(string $currentStatus, string $targetStatus): bool { return in_array($targetStatus, $this->getValidTransitions($currentStatus), true); } /** * Return statuses that do not allow further transitions. */ public function getTerminalStatuses(): array { return array_keys(array_filter($this->statusTransitions, static fn (array $targets): bool => $targets === [])); } /** * Determine if a status requires an approved estimate before entering. */ public function requiresEstimate(string $statusName): bool { return $statusName === 'Estimate Approved'; } }