where($dateField, '>=', $filters['date_from']); } if (! empty($filters['date_to'])) { $query->where($dateField, '<=', $filters['date_to']); } return $query; } public function projectStatus($filters = []) { $query = Project::query(); if (! empty($filters['status'])) { $query->where('status', $filters['status']); } if (! empty($filters['project_id'])) { $query->where('id', $filters['project_id']); } $projects = $query->get(); $grouped = $projects->groupBy('status'); return $grouped->map(fn ($items, $status) => [ 'status' => $status === 'planning' ? 'برنامه‌ریزی' : ($status === 'in_progress' ? 'در حال انجام' : ($status === 'done' ? 'تکمیل شده' : ($status === 'on_hold' ? 'متوقف' : $status))), 'count' => $items->count(), 'label' => $status, 'value' => $items->count(), ])->values(); } public function delayedTasks($filters = []) { $query = Task::with(['project:id,title', 'assignee:id,name']) ->whereDate('due_date', '<', Carbon::today()) ->where('status', '!=', 'done'); $query = $this->applyDateFilters($query, $filters, 'due_date'); if (! empty($filters['project_id'])) { $query->where('project_id', $filters['project_id']); } if (! empty($filters['user_id'])) { $query->where('assignee_id', $filters['user_id']); } if (! empty($filters['status'])) { $query->where('status', $filters['status']); } return $query->orderBy('due_date')->get()->map(fn ($t) => [ 'id' => $t->id, 'title' => $t->title, 'project' => ['title' => $t->project?->title], 'project_name' => $t->project?->title, 'assignee' => ['name' => $t->assignee?->name], 'assignee_name' => $t->assignee?->name, 'due_date' => $t->due_date?->format('Y-m-d'), 'delay_days' => abs(Carbon::today()->diffInDays($t->due_date, false)), 'days_delayed' => abs(Carbon::today()->diffInDays($t->due_date, false)), 'priority' => $t->priority, ]); } public function teamPerformance($filters = []) { $query = User::with(['tasks' => function ($q) use ($filters) { if (! empty($filters['date_from'])) { $q->where('created_at', '>=', $filters['date_from']); } if (! empty($filters['date_to'])) { $q->where('created_at', '<=', $filters['date_to']); } }]); if (! empty($filters['user_id'])) { $query->where('id', $filters['user_id']); } $users = $query->get(); return $users->map(function ($user) { $totalTasks = $user->tasks->count(); $completedTasks = $user->tasks->where('status', 'done')->count(); $delayedTasks = $user->tasks->where('due_date', '<', Carbon::now())->where('status', '!=', 'done')->count(); $inProgress = $user->tasks->whereNotIn('status', ['done', 'canceled'])->count(); return [ 'name' => $user->name, 'completed' => $completedTasks, 'in_progress' => $inProgress, 'delayed' => $delayedTasks, 'total' => $totalTasks, ]; }); } public function workload($filters = []) { $query = User::query(); if (! empty($filters['user_id'])) { $query->where('id', $filters['user_id']); } $users = $query->get(); $allActiveTasks = Task::where('status', '!=', 'done')->count(); $maxTasks = max($allActiveTasks, 1); return $users->map(function ($user) use ($maxTasks) { $activeTasks = Task::where('assignee_id', $user->id)->where('status', '!=', 'done')->count(); $loadPercent = min(round(($activeTasks / $maxTasks) * 100), 100); return [ 'user_id' => $user->id, 'name' => $user->name, 'tasks_count' => $activeTasks, 'total' => $activeTasks, 'load_percent' => $loadPercent, 'load' => $loadPercent, ]; }); } public function sprintProgress($filters = []) { $query = Sprint::with(['project:id,title', 'tasks']); if (! empty($filters['project_id'])) { $query->where('project_id', $filters['project_id']); } if (! empty($filters['status'])) { $query->where('status', $filters['status']); } $sprints = $query->get(); return $sprints->map(function ($sprint) { $totalTasks = $sprint->tasks->count(); $completedTasks = $sprint->tasks->where('status', 'done')->count(); return [ 'id' => $sprint->id, 'title' => $sprint->title, 'project' => $sprint->project?->title, 'start_date' => $sprint->start_date, 'end_date' => $sprint->end_date, 'status' => $sprint->status, 'total_tasks' => $totalTasks, 'completed_tasks' => $completedTasks, 'progress' => $totalTasks > 0 ? round(($completedTasks / $totalTasks) * 100, 2) : 0, ]; }); } public function timeEstimate($filters = []) { $query = Task::with('project'); $query = $this->applyDateFilters($query, $filters); if (! empty($filters['project_id'])) { $query->where('project_id', $filters['project_id']); } if (! empty($filters['user_id'])) { $query->where('assignee_id', $filters['user_id']); } if (! empty($filters['status'])) { $query->where('status', $filters['status']); } $tasks = $query->get(); return $tasks->map(function ($task) { $diff = ($task->estimated_time ?? 0) - ($task->actual_time ?? 0); return [ 'id' => $task->id, 'title' => $task->title, 'project' => ['title' => $task->project?->title ?? '—'], 'estimated' => $task->estimated_time, 'estimated_time' => $task->estimated_time, 'actual' => $task->actual_time, 'actual_time' => $task->actual_time, 'diff' => $diff, 'difference' => $diff, 'status' => $task->status, ]; }); } public function recentActivities($filters = []) { $query = ActivityLog::with('user'); $query = $this->applyDateFilters($query, $filters); if (! empty($filters['project_id'])) { $query->where('project_id', $filters['project_id']); } if (! empty($filters['user_id'])) { $query->where('user_id', $filters['user_id']); } if (! empty($filters['action'])) { $query->where('action', $filters['action']); } return $query->orderBy('created_at', 'desc')->limit(50)->get()->map(fn ($log) => [ 'id' => $log->id, 'description' => $log->description, 'user' => $log->user?->name ?? '?', 'user_name' => $log->user?->name ?? '?', 'created_at' => $log->created_at?->toDateTimeString(), 'time_ago' => $log->created_at?->diffForHumans(), ]); } public function riskyProjects($filters = []) { $query = Project::whereIn('risk_level', ['high', 'critical'])->where('is_archived', false); if (! empty($filters['status'])) { $query->where('status', $filters['status']); } if (! empty($filters['project_id'])) { $query->where('id', $filters['project_id']); } return $query->with('projectManager:id,name')->get()->map(fn ($p) => [ 'id' => $p->id, 'title' => $p->title, 'risk_level' => $p->risk_level, 'progress' => $p->progress, 'delayed_tasks' => Task::where('project_id', $p->id)->where('due_date', '<', Carbon::now())->where('status', '!=', 'done')->count(), ]); } }