diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs index 9d184312..dc510b13 100644 --- a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectsList/GetProjectsListQueryHandler.cs @@ -228,28 +228,30 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler projectIds.Contains(ph.ProjectId)) - .Select(ph => ph.Id) + .Select(ph => new { ph.Id, ph.ProjectId }) .ToListAsync(cancellationToken); + var phaseIds = phases.Select(ph => ph.Id).ToList(); var tasks = await _context.ProjectTasks - .Where(t => phases.Contains(t.PhaseId)) - .Select(t => t.Id) + .Where(t => phaseIds.Contains(t.PhaseId)) + .Select(t => new { t.Id, t.PhaseId }) .ToListAsync(cancellationToken); + var taskIds = tasks.Select(t => t.Id).ToList(); var sections = await _context.TaskSections .Include(s => s.Skill) - .Where(s => tasks.Contains(s.TaskId)) + .Where(s => taskIds.Contains(s.TaskId)) .ToListAsync(cancellationToken); + // Convert to tuple list for AggregatePhaseStatuses + var tasksList = tasks.Select(t => (t.Id, t.PhaseId)).ToList(); + foreach (var item in items) { - var relatedPhases = phases; // used for filtering tasks by project - var relatedTasks = await _context.ProjectTasks - .Where(t => t.PhaseId != Guid.Empty && relatedPhases.Contains(t.PhaseId)) - .Select(t => t.Id) - .ToListAsync(cancellationToken); - var itemSections = sections.Where(s => relatedTasks.Contains(s.TaskId)); - item.Backend = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Backend")); - item.Front = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Frontend")); - item.Design = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "UI/UX Design")); + var projectPhaseIds = phases.Where(ph => ph.ProjectId == item.Id).Select(ph => ph.Id).ToList(); + + // برای هر Skill، وضعیت‌های تمام Phases را تجمیع کنیم + item.Backend = AggregatePhaseStatuses(projectPhaseIds, tasksList, sections, "Backend"); + item.Front = AggregatePhaseStatuses(projectPhaseIds, tasksList, sections, "Frontend"); + item.Design = AggregatePhaseStatuses(projectPhaseIds, tasksList, sections, "UI/UX Design"); } } @@ -259,24 +261,22 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler phaseIds.Contains(t.PhaseId)) - .Select(t => t.Id) + .Select(t => new { t.Id, t.PhaseId }) .ToListAsync(cancellationToken); + var taskIds = tasks.Select(t => t.Id).ToList(); var sections = await _context.TaskSections .Include(s => s.Skill) - .Where(s => tasks.Contains(s.TaskId)) + .Where(s => taskIds.Contains(s.TaskId)) .ToListAsync(cancellationToken); foreach (var item in items) { - // Filter tasks for this phase - var phaseTaskIds = await _context.ProjectTasks - .Where(t => t.PhaseId == item.Id) - .Select(t => t.Id) - .ToListAsync(cancellationToken); + var phaseTaskIds = tasks.Where(t => t.PhaseId == item.Id).Select(t => t.Id).ToList(); var itemSections = sections.Where(s => phaseTaskIds.Contains(s.TaskId)); - item.Backend = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Backend")); - item.Front = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "Frontend")); - item.Design = GetAssignmentStatus(itemSections.FirstOrDefault(x => x.Skill?.Name == "UI/UX Design")); + + item.Backend = AggregateAssignmentStatus(itemSections.Where(x => x.Skill?.Name == "Backend")); + item.Front = AggregateAssignmentStatus(itemSections.Where(x => x.Skill?.Name == "Frontend")); + item.Design = AggregateAssignmentStatus(itemSections.Where(x => x.Skill?.Name == "UI/UX Design")); } } @@ -380,4 +380,57 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler phaseIds, + List<(Guid Id, Guid PhaseId)> tasks, + List sections, + string skillName) + { + var phaseStatuses = new List(); + + foreach (var phaseId in phaseIds) + { + var phaseTaskIds = tasks.Where(t => t.PhaseId == phaseId).Select(t => t.Id).ToList(); + var phaseSections = sections.Where(s => phaseTaskIds.Contains(s.TaskId) && s.Skill?.Name == skillName); + var phaseStatus = AggregateAssignmentStatus(phaseSections); + phaseStatuses.Add(phaseStatus); + } + + // الآن تجمیع وضعیت‌های Phases + if (!phaseStatuses.Any()) + return AssignmentStatus.Unassigned; + + // اگر هر یکی Unassigned باشد → Unassigned + if (phaseStatuses.Any(s => s == AssignmentStatus.Unassigned)) + return AssignmentStatus.Unassigned; + + // اگر Unassigned نیست و هر یکی UserOnly باشد → UserOnly + if (phaseStatuses.Any(s => s == AssignmentStatus.UserOnly)) + return AssignmentStatus.UserOnly; + + // فقط اگر همه Assigned باشند → Assigned + return AssignmentStatus.Assigned; + } + + private static AssignmentStatus AggregateAssignmentStatus(IEnumerable sections) + { + var sectionList = sections.ToList(); + if (!sectionList.Any()) + return AssignmentStatus.Unassigned; + + var statuses = sectionList.Select(GetAssignmentStatus).ToList(); + + // اگر هر یکی Unassigned باشد → Unassigned (بدترین وضعیت) + if (statuses.Any(s => s == AssignmentStatus.Unassigned)) + return AssignmentStatus.Unassigned; + + // اگر Unassigned نیست و هر یکی UserOnly باشد → UserOnly (وضعیت متوسط) + if (statuses.Any(s => s == AssignmentStatus.UserOnly)) + return AssignmentStatus.UserOnly; + + // فقط اگر همه Assigned باشند → Assigned (بهترین وضعیت) + return AssignmentStatus.Assigned; + } +} +