diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AutoUpdateDeployStatus/AutoUpdateDeployStatusCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AutoUpdateDeployStatus/AutoUpdateDeployStatusCommand.cs new file mode 100644 index 00000000..66fce572 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/AutoUpdateDeployStatus/AutoUpdateDeployStatusCommand.cs @@ -0,0 +1,52 @@ +using System.Linq; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoUpdateDeployStatus; + +public record AutoUpdateDeployStatusCommand : IBaseCommand; + +public class AutoUpdateDeployStatusCommandHandler : IBaseCommandHandler +{ + private readonly IProgramManagerDbContext _dbContext; + + public AutoUpdateDeployStatusCommandHandler(IProgramManagerDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task Handle(AutoUpdateDeployStatusCommand request, + CancellationToken cancellationToken) + { + // Fetch all sections whose phase is still marked as not completed + var sections = await _dbContext.TaskSections + .Include(ts => ts.Task) + .ThenInclude(t => t.Phase) + .Where(ts => ts.Task.Phase.DeployStatus == ProjectDeployStatus.NotCompleted) + .ToListAsync(cancellationToken); + + if (sections.Count == 0) + return OperationResult.Success(); + + var phasesToUpdate = sections + .GroupBy(ts => ts.Task.PhaseId) + .Where(g => g.All(s => s.Status == TaskSectionStatus.Completed)) + .Select(g => g.First().Task.Phase) + .Distinct() + .ToList(); + + if (phasesToUpdate.Count == 0) + return OperationResult.Success(); + + foreach (var phase in phasesToUpdate) + { + phase.UpdateDeployStatus(ProjectDeployStatus.PendingDevDeploy); + } + + await _dbContext.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeDeployStatusProject/ChangeDeployeStatusProjectComand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeDeployStatusProject/ChangeDeployeStatusProjectComand.cs new file mode 100644 index 00000000..06c75b4a --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeDeployStatusProject/ChangeDeployeStatusProjectComand.cs @@ -0,0 +1,44 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeDeployStatusProject; + +public record ChangeDeployStatusProjectCommand(Guid PhaseId, ProjectDeployStatus Status):IBaseCommand; + +public class ChangeDeployStatusProjectCommandHandler : IBaseCommandHandler +{ + private readonly IProjectRepository _projectRepository; + private readonly IProjectPhaseRepository _projectPhaseRepository; + private readonly IUnitOfWork _unitOfWork; + + public ChangeDeployStatusProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork, IProjectPhaseRepository projectPhaseRepository) + { + _projectRepository = projectRepository; + _unitOfWork = unitOfWork; + _projectPhaseRepository = projectPhaseRepository; + } + + public async Task Handle(ChangeDeployStatusProjectCommand request, CancellationToken cancellationToken) + { + var project = await _projectPhaseRepository.GetByIdAsync(request.PhaseId, cancellationToken); + if (project == null) + return OperationResult.NotFound("بخش مورد نظر یافت نشد"); + + if (project.DeployStatus == ProjectDeployStatus.NotCompleted) + { + return OperationResult.Failure("وضعیت استقرار نمی‌تواند از حالت 'تایید نشده' تغییر کند."); + } + + if (request.Status == ProjectDeployStatus.NotCompleted) + { + return OperationResult.Failure("وضعیت استقرار نمی‌تواند به حالت 'تایید نشده' تغییر کند."); + } + project.UpdateDeployStatus(request.Status); + + await _unitOfWork.SaveChangesAsync(cancellationToken); + return OperationResult.Success(); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs index 5a085060..69e82940 100644 --- a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectBoardList/ProjectBoardListQueryHandler.cs @@ -22,8 +22,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler x.InitialEstimatedHours > TimeSpan.Zero) + .Where(x => x.InitialEstimatedHours > TimeSpan.Zero && x.Status != TaskSectionStatus.Completed) .Include(x => x.Task) .ThenInclude(x => x.Phase) .ThenInclude(x => x.Project) diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardDetail/ProjectDeployBoardDetailsQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardDetail/ProjectDeployBoardDetailsQueryHandler.cs new file mode 100644 index 00000000..33a1caa6 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardDetail/ProjectDeployBoardDetailsQueryHandler.cs @@ -0,0 +1,113 @@ +using System.Security.AccessControl; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail; + +public record ProjectDeployBoardDetailsResponse( + ProjectDeployBoardDetailPhaseItem Phase, + List Tasks); + +public record ProjectDeployBoardDetailPhaseItem( + string Name, + TimeSpan TotalTimeSpan, + TimeSpan DoneTimeSpan); + +public record ProjectDeployBoardDetailTaskItem( + string Name, + TimeSpan TotalTimeSpan, + TimeSpan DoneTimeSpan, + List Skills) + : ProjectDeployBoardDetailPhaseItem(Name, TotalTimeSpan, DoneTimeSpan); + +public record ProjectDeployBoardDetailItemSkill(string OriginalUserFullName, string SkillName, int TimePercentage); + +public record ProjectDeployBoardDetailsQuery(Guid PhaseId) : IBaseQuery; + +public class + ProjectDeployBoardDetailsQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _dbContext; + + public ProjectDeployBoardDetailsQueryHandler(IProgramManagerDbContext dbContext) + { + _dbContext = dbContext; + } + + public async Task> Handle(ProjectDeployBoardDetailsQuery request, + CancellationToken cancellationToken) + { + var phase = await _dbContext.ProjectPhases + .Include(x => x.Tasks) + .ThenInclude(x => x.Sections) + .ThenInclude(x => x.Activities) + .Include(x => x.Tasks) + .ThenInclude(x => x.Sections) + .ThenInclude(x => x.AdditionalTimes) + .Include(x => x.Tasks) + .ThenInclude(x => x.Sections) + .ThenInclude(x => x.Skill) + .FirstOrDefaultAsync(x => x.Id == request.PhaseId, cancellationToken); + + if (phase == null) + return OperationResult.NotFound("بخش اصلی مورد نظر یافت نشد"); + + var userIds = phase.Tasks + .SelectMany(t => t.Sections) + .Select(s => s.OriginalAssignedUserId) + .Distinct() + .ToList(); + + var usersDict = await _dbContext.Users + .Where(x => userIds.Contains(x.Id)) + .ToDictionaryAsync(x => x.Id, x => x.FullName, cancellationToken); + + var tasksRes = phase.Tasks.Select(t => + { + var totalTime = t.Sections.Select(s => s.FinalEstimatedHours) + .Aggregate(TimeSpan.Zero, (sum, next) => sum.Add(next)); + + var doneTime = t.Sections.Aggregate(TimeSpan.Zero, + (sum, next) => sum.Add(next.GetTotalTimeSpent())); + var skills = t.Sections + .Select(s => + { + var originalUserFullName = usersDict.GetValueOrDefault(s.OriginalAssignedUserId, + "کاربر ناشناس"); + + var skillName = s.Skill?.Name ?? "بدون مهارت"; + + var totalTimeSpent = s.GetTotalTimeSpent(); + + var timePercentage = s.FinalEstimatedHours.Ticks > 0 + ? (int)((totalTimeSpent.Ticks / (double)s.FinalEstimatedHours.Ticks) * 100) + : 0; + + return new ProjectDeployBoardDetailItemSkill( + originalUserFullName, + skillName, + timePercentage); + }).ToList(); + + return new ProjectDeployBoardDetailTaskItem( + t.Name, + totalTime, + doneTime, + skills); + }).ToList(); + + var totalTimeSpan = tasksRes.Aggregate(TimeSpan.Zero, + (sum, next) => sum.Add(next.TotalTimeSpan)); + + var doneTimeSpan = tasksRes.Aggregate(TimeSpan.Zero, + (sum, next) => sum.Add(next.DoneTimeSpan)); + + var phaseRes = new ProjectDeployBoardDetailPhaseItem(phase.Name, totalTimeSpan, doneTimeSpan); + + var res = new ProjectDeployBoardDetailsResponse(phaseRes, tasksRes); + + return OperationResult.Success(res); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardDetail/ProjectDeployBoardDetailsQueryValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardDetail/ProjectDeployBoardDetailsQueryValidator.cs new file mode 100644 index 00000000..0cbf5cd9 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardDetail/ProjectDeployBoardDetailsQueryValidator.cs @@ -0,0 +1,11 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail; + +public class ProjectDeployBoardDetailsQueryValidator:AbstractValidator +{ + public ProjectDeployBoardDetailsQueryValidator() + { + RuleFor(x=>x.PhaseId).NotNull().WithMessage("شناسه بخش اصلی نمی‌تواند خالی باشد"); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardList/ProjectDeployBoardListQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardList/ProjectDeployBoardListQueryHandler.cs new file mode 100644 index 00000000..6a0a7cda --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectDeployBoardList/ProjectDeployBoardListQueryHandler.cs @@ -0,0 +1,74 @@ +using System.Xml.Schema; +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; +using GozareshgirProgramManager.Domain.ProjectAgg.Entities; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardList; + +public record ProjectDeployBoardListItem() +{ + public Guid Id { get; set; } + public string ProjectName { get; set; } + public string PhaseName { get; set; } + public int TotalTasks { get; set; } + public int DoneTasks { get; set; } + public TimeSpan TotalTimeSpan { get; set; } + public TimeSpan DoneTimeSpan { get; set; } + public ProjectDeployStatus DeployStatus { get; set; } +} +public record GetProjectsDeployBoardListResponse(List Items); + + +public record GetProjectDeployBoardListQuery():IBaseQuery; + +public class ProjectDeployBoardListQueryHandler:IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _dbContext; + private readonly IAuthHelper _authHelper; + + + public ProjectDeployBoardListQueryHandler(IProgramManagerDbContext dbContext, IAuthHelper authHelper) + { + _dbContext = dbContext; + _authHelper = authHelper; + } + + public async Task> Handle(GetProjectDeployBoardListQuery request, CancellationToken cancellationToken) + { + var userId = _authHelper.GetCurrentUserId(); + if (userId == null) + { + return OperationResult.NotFound("کاربر یافت نشد"); + } + + var query =await _dbContext.TaskSections + .Include(x=>x.Activities) + .Include(x=>x.Task) + .ThenInclude(x => x.Phase) + .ThenInclude(x => x.Project) + .AsNoTracking() + .Where(x => x.Status == TaskSectionStatus.Completed + || x.Status == TaskSectionStatus.PendingForCompletion + || (x.Task.Phase.DeployStatus != ProjectDeployStatus.NotCompleted + && x.InitialEstimatedHours>TimeSpan.Zero)) + .GroupBy(x=>x.Task.PhaseId).ToListAsync(cancellationToken: cancellationToken); + + var list = query.Select(g => new ProjectDeployBoardListItem + { + Id = g.Key, + ProjectName = g.First().Task.Phase.Project.Name, + PhaseName = g.First().Task.Phase.Name, + TotalTasks = g.Select(x => x.TaskId).Distinct().Count(), + DoneTasks = g.Where(x => x.Status == TaskSectionStatus.Completed) + .Select(x => x.TaskId).Distinct().Count(), + TotalTimeSpan = TimeSpan.FromTicks(g.Sum(x => x.InitialEstimatedHours.Ticks)), + DoneTimeSpan = TimeSpan.FromTicks(g.Sum(x=>x.GetTotalTimeSpent().Ticks)), + DeployStatus = g.First().Task.Phase.DeployStatus + }).ToList(); + var response = new GetProjectsDeployBoardListResponse(list); + return OperationResult.Success(response); + } +} \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs index 539ac278..3534c50f 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs @@ -23,6 +23,7 @@ public class ProjectPhase : ProjectHierarchyNode ProjectId = projectId; _tasks = new List(); _phaseSections = new List(); + DeployStatus = ProjectDeployStatus.NotCompleted; AddDomainEvent(new PhaseCreatedEvent(Id, projectId, name)); } @@ -36,6 +37,8 @@ public class ProjectPhase : ProjectHierarchyNode public DateTime? StartDate { get; private set; } public DateTime? EndDate { get; private set; } public int OrderIndex { get; private set; } + public bool IsArchived { get; set; } + public ProjectDeployStatus DeployStatus { get; set; } #region Task Management @@ -196,4 +199,30 @@ public class ProjectPhase : ProjectHierarchyNode } #endregion + + public void SetArchived() + { + IsArchived = true; + } + public void SetUnarchived() + { + IsArchived = false; + } + public void UpdateDeployStatus(ProjectDeployStatus status) + { + DeployStatus = status; + if (status == ProjectDeployStatus.Deployed) + { + IsArchived = true; + } + } +} + +public enum ProjectDeployStatus +{ + NotCompleted, + PendingDevDeploy, + DevDeployed, + PendingDeploy, + Deployed } diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs index d5208bfb..5c5a019e 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Enums/TaskSectionStatus.cs @@ -6,5 +6,6 @@ public enum TaskSectionStatus ReadyToStart = 1, // آماده شروع InProgress = 2, // درحال انجام Incomplete = 3, // ناتمام شده - Completed = 4 // تکمیل شده + PendingForCompletion = 4, // در انتظار تکمیل + Completed = 5 // تکمیل شده } \ No newline at end of file diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs index fb6ca424..155fec66 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Events/ProjectEvents.cs @@ -8,171 +8,171 @@ namespace GozareshgirProgramManager.Domain.ProjectAgg.Events; // Project Events public record ProjectCreatedEvent(Guid ProjectId, string Name) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectStatusUpdatedEvent(Guid ProjectId, ProjectStatus Status) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectAssignedEvent(Guid ProjectId, long UserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectUnassignedEvent(Guid ProjectId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } // Phase Events public record PhaseCreatedEvent(Guid PhaseId, Guid ProjectId, string Name) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record PhaseAddedEvent(Guid PhaseId, Guid ProjectId, string Name) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record PhaseRemovedEvent(Guid PhaseId, Guid ProjectId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record PhaseStatusUpdatedEvent(Guid PhaseId, PhaseStatus Status) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record PhaseAssignedEvent(Guid PhaseId, long UserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record PhaseUnassignedEvent(Guid PhaseId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } // Task Events public record TaskCreatedEvent(Guid TaskId, Guid PhaseId, string Name) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskAddedEvent(Guid TaskId, Guid PhaseId, string Name) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskRemovedEvent(Guid TaskId, Guid PhaseId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskStatusUpdatedEvent(Guid TaskId, TaskStatus Status) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskPriorityUpdatedEvent(Guid TaskId, TaskPriority Priority) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskAssignedEvent(Guid TaskId, long UserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskUnassignedEvent(Guid TaskId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskSectionAddedEvent(Guid TaskId, Guid SectionId, Guid SkillId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskSectionRemovedEvent(Guid TaskId, Guid SectionId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } // TaskSection Events public record TaskSectionStatusChangedEvent(Guid SectionId, TaskSectionStatus OldStatus, TaskSectionStatus NewStatus,long UserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskSectionAssignedEvent(Guid SectionId, long UserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record TaskSectionTransferredEvent(Guid SectionId, long FromUserId, long ToUserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } // Section Events (Legacy - keeping for backward compatibility) public record ProjectPhaseAddedEvent(Guid ProjectId, Guid PhaseId, string PhaseName) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectTaskStatusChangedEvent(Guid SectionId, TaskStatus OldStatus, TaskStatus NewStatus) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectSectionAddedEvent(Guid SectionId, Guid TaskId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectSectionAssignedEvent(Guid SectionId, long UserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectSectionTransferredEvent(Guid SectionId, long FromUserId, long ToUserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record WorkStartedEvent(Guid SectionId, long UserId, DateTime StartTime, string? Notes) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record WorkStoppedEvent(Guid SectionId, long UserId, DateTime StartTime, DateTime EndTime, TimeSpan Duration, string? Notes) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record ProjectSectionCompletedEvent(Guid ProjectId, long UserId, TimeSpan TotalTimeSpent, string? Notes) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record AdditionalTimeAddedEvent(Guid ProjectId, Guid AdditionalTimeId, TimeSpan Hours, string? Reason, long? AddedByUserId) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record AdditionalTimeRemovedEvent(Guid ProjectId, Guid AdditionalTimeId, TimeSpan RemovedHours) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } public record InitialEstimatedTimeUpdatedEvent(Guid ProjectId, TimeSpan OldEstimate, TimeSpan NewEstimate) : IDomainEvent { - public DateTime OccurredOn { get; init; } = DateTime.UtcNow; + public DateTime OccurredOn { get; init; } = DateTime.Now; } diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs index d20ef6e0..55eff1be 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionActivityRepository.cs @@ -5,7 +5,6 @@ namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories; public interface ITaskSectionActivityRepository:IRepository { - Task GetByIdAsync(Guid id); Task> GetBySectionIdAsync(Guid sectionId); Task> GetByUserIdAsync(long userId); Task> GetActiveByUserAsync(long userId); diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs index cd8a9dcc..053ba51b 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/_Common/IRepository.cs @@ -5,7 +5,7 @@ namespace GozareshgirProgramManager.Domain._Common; public interface IRepository where T:class { T Get(TKey id); - Task GetByIdAsync(TKey id); + Task GetByIdAsync(TKey id, CancellationToken cancellationToken = default); List Get(); IQueryable GetQueryable(); void Create(T entity); diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251227094008_add phase deploy status and is archived.Designer.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251227094008_add phase deploy status and is archived.Designer.cs new file mode 100644 index 00000000..74452d75 --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251227094008_add phase deploy status and is archived.Designer.cs @@ -0,0 +1,865 @@ +// +using System; +using GozareshgirProgramManager.Infrastructure.Persistence.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + [DbContext(typeof(ProgramManagerDbContext))] + [Migration("20251227094008_add phase deploy status and is archived")] + partial class addphasedeploystatusandisarchived + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CheckoutAgg.Entities.Checkout", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CheckoutEndDate") + .HasColumnType("datetime2"); + + b.Property("CheckoutStartDate") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DeductionFromSalary") + .HasColumnType("float"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("MandatoryHours") + .HasColumnType("int"); + + b.Property("Month") + .HasColumnType("int"); + + b.Property("MonthlySalaryDefined") + .HasColumnType("float"); + + b.Property("MonthlySalaryPay") + .HasColumnType("float"); + + b.Property("RemainingHours") + .HasColumnType("int"); + + b.Property("TotalDaysWorked") + .HasColumnType("int"); + + b.Property("TotalHoursWorked") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.Property("Year") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Checkouts", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Customers", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.HasIndex("SkillId"); + + b.ToTable("PhaseSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("PlannedEndDate") + .HasColumnType("datetime2"); + + b.Property("PlannedStartDate") + .HasColumnType("datetime2"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Projects", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("DeployStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("IsArchived") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.ToTable("ProjectPhases", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ProjectId") + .HasColumnType("uniqueidentifier"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ProjectId"); + + b.HasIndex("SkillId"); + + b.ToTable("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AllocatedTime") + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("DueDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("HasAssignmentOverride") + .HasColumnType("bit"); + + b.Property("HasTimeOverride") + .HasColumnType("bit"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.Property("OrderIndex") + .HasColumnType("int"); + + b.Property("PhaseId") + .HasColumnType("uniqueidentifier"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("PhaseId"); + + b.ToTable("ProjectTasks", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("CurrentAssignedUserId") + .HasColumnType("bigint"); + + b.Property("InitialDescription") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("InitialEstimatedHours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("OriginalAssignedUserId") + .HasColumnType("bigint"); + + b.Property("SkillId") + .HasColumnType("uniqueidentifier"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("TaskId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("SkillId"); + + b.HasIndex("TaskId"); + + b.ToTable("TaskSections", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndDate") + .HasColumnType("datetime2"); + + b.Property("EndNotes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("SectionId") + .HasColumnType("uniqueidentifier"); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("SectionId"); + + b.ToTable("TaskSectionActivities", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("AddedAt") + .HasColumnType("datetime2"); + + b.Property("AddedByUserId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Hours") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("TaskSectionId") + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("TaskSectionId"); + + b.ToTable("TaskSectionAdditionalTimes", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("GozareshgirRoleId") + .HasColumnType("bigint"); + + b.Property("RoleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.ToTable("PmRoles", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("EndSettingDate") + .HasColumnType("datetime2"); + + b.Property("HolidayWorking") + .HasColumnType("bit"); + + b.Property("MonthlySalary") + .HasColumnType("float"); + + b.Property("StartSettingDate") + .HasColumnType("datetime2"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("SalaryPaymentSetting", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("nvarchar(200)"); + + b.HasKey("Id"); + + b.ToTable("Skills", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Email") + .HasMaxLength(150) + .HasColumnType("nvarchar(150)"); + + b.Property("FullName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("IsActive") + .HasColumnType("bit"); + + b.Property("Mobile") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Password") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("ProfilePhotoPath") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("VerifyCode") + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.HasKey("Id"); + + b.ToTable("Users", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("RevokedAt") + .HasColumnType("datetime2"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserAgent") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("UserId") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.HasIndex("ExpiresAt"); + + b.HasIndex("Token") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("UserRefreshTokens", (string)null); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.PhaseSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("PhaseSections") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Phase"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("Phases") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Project"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", "Project") + .WithMany("ProjectSections") + .HasForeignKey("ProjectId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany() + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Project"); + + b.Navigation("Skill"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", "Phase") + .WithMany("Tasks") + .HasForeignKey("PhaseId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Phase"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.HasOne("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", "Skill") + .WithMany("Sections") + .HasForeignKey("SkillId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", "Task") + .WithMany("Sections") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Skill"); + + b.Navigation("Task"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionActivity", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", "Section") + .WithMany("Activities") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b => + { + b.HasOne("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", null) + .WithMany("AdditionalTimes") + .HasForeignKey("TaskSectionId"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.PermissionAgg.Entities.Permission", "Permissions", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("Code") + .HasColumnType("int"); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("RoleId"); + + b1.ToTable("PmRolePermissions", (string)null); + + b1.WithOwner("Role") + .HasForeignKey("RoleId"); + + b1.Navigation("Role"); + }); + + b.Navigation("Permissions"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.SalaryPaymentSetting", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.SalaryPaymentSettingAgg.Entities.WorkingHours", "WorkingHoursList", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("EndShiftOne") + .HasColumnType("time(0)"); + + b1.Property("EndShiftTwo") + .HasColumnType("time(0)"); + + b1.Property("HasRestTime") + .HasColumnType("bit"); + + b1.Property("HasShiftOne") + .HasColumnType("bit"); + + b1.Property("HasShiftTow") + .HasColumnType("bit"); + + b1.Property("IsActiveDay") + .HasColumnType("bit"); + + b1.Property("PersianDayOfWeek") + .HasColumnType("int"); + + b1.Property("RestTime") + .HasColumnType("time(0)"); + + b1.Property("SalaryPaymentSettingId") + .HasColumnType("bigint"); + + b1.Property("ShiftDurationInMinutes") + .HasColumnType("int"); + + b1.Property("StartShiftOne") + .HasColumnType("time(0)"); + + b1.Property("StartShiftTwo") + .HasColumnType("time(0)"); + + b1.HasKey("Id"); + + b1.HasIndex("SalaryPaymentSettingId"); + + b1.ToTable("WorkingHours", (string)null); + + b1.WithOwner("SalaryPaymentSetting") + .HasForeignKey("SalaryPaymentSettingId"); + + b1.Navigation("SalaryPaymentSetting"); + }); + + b.Navigation("WorkingHoursList"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.OwnsMany("GozareshgirProgramManager.Domain.RoleUserAgg.RoleUser", "RoleUser", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property("Id")); + + b1.Property("RoleId") + .HasColumnType("bigint"); + + b1.Property("UserId") + .HasColumnType("bigint"); + + b1.HasKey("Id"); + + b1.HasIndex("UserId"); + + b1.ToTable("RoleUsers", (string)null); + + b1.WithOwner("User") + .HasForeignKey("UserId"); + + b1.Navigation("User"); + }); + + b.Navigation("RoleUser"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b => + { + b.HasOne("GozareshgirProgramManager.Domain.UserAgg.Entities.User", "User") + .WithMany("RefreshTokens") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => + { + b.Navigation("Phases"); + + b.Navigation("ProjectSections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectPhase", b => + { + b.Navigation("PhaseSections"); + + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSection", b => + { + b.Navigation("Activities"); + + b.Navigation("AdditionalTimes"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.User", b => + { + b.Navigation("RefreshTokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251227094008_add phase deploy status and is archived.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251227094008_add phase deploy status and is archived.cs new file mode 100644 index 00000000..7dce42cd --- /dev/null +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/20251227094008_add phase deploy status and is archived.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GozareshgirProgramManager.Infrastructure.Migrations +{ + /// + public partial class addphasedeploystatusandisarchived : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DeployStatus", + table: "ProjectPhases", + type: "nvarchar(30)", + maxLength: 30, + nullable: false, + defaultValue: ""); + + migrationBuilder.AddColumn( + name: "IsArchived", + table: "ProjectPhases", + type: "bit", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DeployStatus", + table: "ProjectPhases"); + + migrationBuilder.DropColumn( + name: "IsArchived", + table: "ProjectPhases"); + } + } +} diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs index 25e60639..4382f61b 100644 --- a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Migrations/AppDbContextModelSnapshot.cs @@ -126,7 +126,7 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations b.HasIndex("SkillId"); - b.ToTable("PhaseSections", (string)null); + b.ToTable("PhaseSections"); }); modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.Project", b => @@ -179,6 +179,11 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations b.Property("CreationDate") .HasColumnType("datetime2"); + b.Property("DeployStatus") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("nvarchar(30)"); + b.Property("Description") .HasMaxLength(1000) .HasColumnType("nvarchar(1000)"); @@ -189,6 +194,9 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations b.Property("HasAssignmentOverride") .HasColumnType("bit"); + b.Property("IsArchived") + .HasColumnType("bit"); + b.Property("Name") .IsRequired() .HasMaxLength(200) @@ -238,7 +246,7 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations b.HasIndex("SkillId"); - b.ToTable("ProjectSections", (string)null); + b.ToTable("ProjectSections"); }); modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.ProjectTask", b => diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs index 838b7f0e..01a43077 100644 --- a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Mappings/ProjectPhaseMapping.cs @@ -48,6 +48,9 @@ public class ProjectPhaseMapping : IEntityTypeConfiguration builder.Property(ph => ph.HasAssignmentOverride) .IsRequired(); + builder.Property(x => x.DeployStatus) + .HasConversion().HasMaxLength(30); + // Relationship with Project builder.HasOne(ph => ph.Project) .WithMany(p => p.Phases) diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs index def0cf17..3a016ae8 100644 --- a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/_Common/RepositoryBase.cs @@ -43,9 +43,9 @@ public class RepositoryBase : IRepository where T : class return _context.Find(id); } - public async Task GetByIdAsync(TKey id) + public async Task GetByIdAsync(TKey id, CancellationToken cancellationToken = default) { - return await _context.Set().FindAsync(id); + return await _context.Set().FindAsync([id], cancellationToken); } public List Get() diff --git a/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs b/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs index 225a1e9b..e13bcc97 100644 --- a/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs +++ b/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs @@ -2,6 +2,8 @@ using GozareshgirProgramManager.Application._Common.Models; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoStopOverTimeTaskSections; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoUpdateDeployStatus; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeDeployStatusProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.ChangeStatusSection; using GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.DeleteProject; @@ -12,6 +14,8 @@ using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectA using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectsList; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardDetail; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoardList; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardList; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; using MediatR; using Microsoft.AspNetCore.Mvc; @@ -22,70 +26,75 @@ namespace ServiceHost.Areas.Admin.Controllers.ProgramManager; public class ProjectController : ProgramManagerBaseController { private readonly IMediator _mediator; - + public ProjectController(IMediator mediator) { _mediator = mediator; } [HttpGet] - public async Task>> Get([FromQuery]GetProjectsListQuery query) + public async Task>> Get( + [FromQuery] GetProjectsListQuery query) { - var res=await _mediator.Send(query); + var res = await _mediator.Send(query); return res; } - + [HttpPost] public async Task> Create([FromBody] CreateProjectCommand command) { - var res=await _mediator.Send(command); + var res = await _mediator.Send(command); return res; } - + [HttpPut] public async Task> Edit([FromBody] EditProjectCommand command) { - var res=await _mediator.Send(command); + var res = await _mediator.Send(command); return res; } - + [HttpDelete] public async Task> Delete([FromQuery] DeleteProjectCommand command) { - var res=await _mediator.Send(command); + var res = await _mediator.Send(command); return res; } - + [HttpGet("assign")] - public async Task>> GetAssignableProjects(GetProjectAssignDetailsQuery query) + public async Task>> GetAssignableProjects( + GetProjectAssignDetailsQuery query) { - var res=await _mediator.Send(query); + var res = await _mediator.Send(query); return res; } - + [HttpPost("assign")] public async Task> Assign(AssignProjectCommand command) { - var res=await _mediator.Send(command); + var res = await _mediator.Send(command); return res; } + [HttpGet("set-time")] - public async Task>> GetSetTimeProjectDetails(ProjectSetTimeDetailsQuery query) + public async Task>> GetSetTimeProjectDetails( + ProjectSetTimeDetailsQuery query) { - var res=await _mediator.Send(query); + var res = await _mediator.Send(query); return res; } + [HttpPost("set-time")] public async Task> SetTimeProject(SetTimeProjectCommand command) { - var res=await _mediator.Send(command); + var res = await _mediator.Send(command); return res; } [HttpPost("change-status")] public async Task> ChangeStatus(ChangeStatusSectionCommand command) { - var res = await _mediator.Send(command); + var res = await _mediator.Send(command); return res; } @@ -97,14 +106,16 @@ public class ProjectController : ProgramManagerBaseController } [HttpGet("board")] - public async Task>>> GetProjectBoard([FromQuery] ProjectBoardListQuery query) + public async Task>>> GetProjectBoard( + [FromQuery] ProjectBoardListQuery query) { // اجرای Command برای متوقف کردن تسک‌های overtime قبل از نمایش await _mediator.Send(new AutoStopOverTimeTaskSectionsCommand()); - + var res = await _mediator.Send(query); return res; } + [HttpGet("board/details")] public async Task>> GetProjectBoardDetails(Guid id) { @@ -112,4 +123,28 @@ public class ProjectController : ProgramManagerBaseController var res = await _mediator.Send(query); return res; } + + [HttpGet("deploy-board")] + public async Task>> GetProjectDeployBoard() + { + // قبل از دریافت دیتا، وضعیت دیپلوی را بر اساس تکمیل شدن تمام سکشن‌ها به‌روزرسانی می‌کنیم + await _mediator.Send(new AutoUpdateDeployStatusCommand()); + var request = new GetProjectDeployBoardListQuery(); + return await _mediator.Send(request); + } + + [HttpGet("deploy-board/details")] + public async Task>> GetProjectDeployBoardDetails(Guid id) + { + var query = new ProjectDeployBoardDetailsQuery(id); + var res = await _mediator.Send(query); + return res; + } + + [HttpPost("deploy-board/change-status")] + public async Task> ChangeDeployStatus(ChangeDeployStatusProjectCommand command) + { + var res = await _mediator.Send(command); + return res; + } } \ No newline at end of file