startOfMonth(); $allocated = (float) Allocation::where('project_id', $projectId) ->where('team_member_id', $teamMemberId) ->where('month', $monthDate) ->sum('allocated_hours'); $actual = (float) Actual::where('project_id', $projectId) ->where('team_member_id', $teamMemberId) ->where('month', $monthDate) ->sum('hours_logged'); if ($allocated <= 0) { $variancePercentage = $actual == 0 ? 0.0 : 100.0; } else { $variancePercentage = (($actual - $allocated) / $allocated) * 100; } return [ 'allocated' => $allocated, 'actual' => $actual, 'variance_percentage' => $variancePercentage, 'indicator' => $this->getIndicator($variancePercentage), ]; } public function getInactiveProjectStatuses(): array { return ['Done', 'Cancelled', 'Closed']; } public function canLogToInactiveProjects(): bool { return (bool) config('actuals.allow_actuals_on_inactive_projects', false); } private function getIndicator(float $variancePercentage): string { $absolute = abs($variancePercentage); if ($absolute <= 5) { return 'green'; } if ($absolute <= 20) { return 'yellow'; } return 'red'; } }