Compare commits

...

15 Commits

Author SHA1 Message Date
aa37ca4b28 add: enhance deployment status validation in ChangeDeployStatusProject command and include Activities in ProjectDeployBoardList query 2025-12-30 17:19:59 +03:30
45615684ed add: enhance skill calculation in ProjectDeployBoardDetailsQueryHandler and refine query conditions in ProjectDeployBoardListQueryHandler 2025-12-30 15:55:57 +03:30
94955ea1b4 add: update GetProjectDeployBoardDetails method to use ProjectDeployBoardDetailsQuery 2025-12-30 12:54:53 +03:30
656bb49fab add: remove GetByIdAsync method and add Id property to ProjectDeployBoardListItem 2025-12-30 12:30:06 +03:30
fb5b98bf25 add: update UpdateDeployStatus method to archive project phase upon deployment 2025-12-30 11:54:56 +03:30
1e733f3f20 add: implement ChangeDeployStatusProject command and handler for updating project deployment status 2025-12-30 11:10:40 +03:30
d855684cd7 add: implement AutoUpdateDeployStatusCommand for automatic deployment status updates 2025-12-29 12:16:51 +03:30
9e5e8d8e5d refactor: improve code formatting and structure in ProjectController 2025-12-29 11:45:32 +03:30
9eefdd8fd1 add: implement GetProjectDeployBoardDetails endpoint for retrieving project board details 2025-12-29 10:27:23 +03:30
2159901614 add: implement ProjectDeployBoardDetailsQuery and its handler with validation for project phase details 2025-12-27 19:42:13 +03:30
7ce7854091 add: include DeployStatus in ProjectDeployBoardListItem for deployment status tracking 2025-12-27 16:26:07 +03:30
4c638cbdae add: implement DeployStatus and IsArchived properties in ProjectPhase, and create ProjectDeployBoardListQueryHandler for project deployment management 2025-12-27 13:59:37 +03:30
39a5918a11 add: implement ProjectDeployBoardListQueryHandler and initialize GetProjectsListQueryHandler structure 2025-12-24 18:55:01 +03:30
b9e271de1a fix: update OccurredOn property to use DateTime.Now instead of DateTime.UtcNow in event records 2025-12-23 15:00:18 +03:30
e661bc2dcb add: enhance ProjectBoardListQueryHandler and ProjectPhase to manage task section statuses and deployment states 2025-12-23 14:52:41 +03:30
17 changed files with 1337 additions and 61 deletions

View File

@@ -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<AutoUpdateDeployStatusCommand>
{
private readonly IProgramManagerDbContext _dbContext;
public AutoUpdateDeployStatusCommandHandler(IProgramManagerDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<OperationResult> 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();
}
}

View File

@@ -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<ChangeDeployStatusProjectCommand>
{
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<OperationResult> 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();
}
}

View File

@@ -22,8 +22,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
CancellationToken cancellationToken)
{
var currentUserId = _authHelper.GetCurrentUserId();
var queryable = _programManagerDbContext.TaskSections.AsNoTracking()
.Where(x => 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)

View File

@@ -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<ProjectDeployBoardDetailTaskItem> Tasks);
public record ProjectDeployBoardDetailPhaseItem(
string Name,
TimeSpan TotalTimeSpan,
TimeSpan DoneTimeSpan);
public record ProjectDeployBoardDetailTaskItem(
string Name,
TimeSpan TotalTimeSpan,
TimeSpan DoneTimeSpan,
List<ProjectDeployBoardDetailItemSkill> Skills)
: ProjectDeployBoardDetailPhaseItem(Name, TotalTimeSpan, DoneTimeSpan);
public record ProjectDeployBoardDetailItemSkill(string OriginalUserFullName, string SkillName, int TimePercentage);
public record ProjectDeployBoardDetailsQuery(Guid PhaseId) : IBaseQuery<ProjectDeployBoardDetailsResponse>;
public class
ProjectDeployBoardDetailsQueryHandler : IBaseQueryHandler<ProjectDeployBoardDetailsQuery,
ProjectDeployBoardDetailsResponse>
{
private readonly IProgramManagerDbContext _dbContext;
public ProjectDeployBoardDetailsQueryHandler(IProgramManagerDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<OperationResult<ProjectDeployBoardDetailsResponse>> 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<ProjectDeployBoardDetailsResponse>.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<ProjectDeployBoardDetailsResponse>.Success(res);
}
}

View File

@@ -0,0 +1,11 @@
using FluentValidation;
namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail;
public class ProjectDeployBoardDetailsQueryValidator:AbstractValidator<ProjectDeployBoardDetailsQuery>
{
public ProjectDeployBoardDetailsQueryValidator()
{
RuleFor(x=>x.PhaseId).NotNull().WithMessage("شناسه بخش اصلی نمی‌تواند خالی باشد");
}
}

View File

@@ -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<ProjectDeployBoardListItem> Items);
public record GetProjectDeployBoardListQuery():IBaseQuery<GetProjectsDeployBoardListResponse>;
public class ProjectDeployBoardListQueryHandler:IBaseQueryHandler<GetProjectDeployBoardListQuery, GetProjectsDeployBoardListResponse>
{
private readonly IProgramManagerDbContext _dbContext;
private readonly IAuthHelper _authHelper;
public ProjectDeployBoardListQueryHandler(IProgramManagerDbContext dbContext, IAuthHelper authHelper)
{
_dbContext = dbContext;
_authHelper = authHelper;
}
public async Task<OperationResult<GetProjectsDeployBoardListResponse>> Handle(GetProjectDeployBoardListQuery request, CancellationToken cancellationToken)
{
var userId = _authHelper.GetCurrentUserId();
if (userId == null)
{
return OperationResult<GetProjectsDeployBoardListResponse>.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<GetProjectsDeployBoardListResponse>.Success(response);
}
}

View File

@@ -23,6 +23,7 @@ public class ProjectPhase : ProjectHierarchyNode
ProjectId = projectId;
_tasks = new List<ProjectTask>();
_phaseSections = new List<PhaseSection>();
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
}

View File

@@ -6,5 +6,6 @@ public enum TaskSectionStatus
ReadyToStart = 1, // آماده شروع
InProgress = 2, // درحال انجام
Incomplete = 3, // ناتمام شده
Completed = 4 // تکمیل شده
PendingForCompletion = 4, // در انتظار تکمیل
Completed = 5 // تکمیل شده
}

View File

@@ -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;
}

View File

@@ -5,7 +5,6 @@ namespace GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
public interface ITaskSectionActivityRepository:IRepository<Guid,TaskSectionActivity>
{
Task<TaskSectionActivity?> GetByIdAsync(Guid id);
Task<List<TaskSectionActivity>> GetBySectionIdAsync(Guid sectionId);
Task<List<TaskSectionActivity>> GetByUserIdAsync(long userId);
Task<List<TaskSectionActivity>> GetActiveByUserAsync(long userId);

View File

@@ -5,7 +5,7 @@ namespace GozareshgirProgramManager.Domain._Common;
public interface IRepository<TKey, T> where T:class
{
T Get(TKey id);
Task<T?> GetByIdAsync(TKey id);
Task<T?> GetByIdAsync(TKey id, CancellationToken cancellationToken = default);
List<T> Get();
IQueryable<T> GetQueryable();
void Create(T entity);

View File

@@ -0,0 +1,865 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CheckoutEndDate")
.HasColumnType("datetime2");
b.Property<DateTime>("CheckoutStartDate")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<double>("DeductionFromSalary")
.HasColumnType("float");
b.Property<string>("FullName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<int>("MandatoryHours")
.HasColumnType("int");
b.Property<int>("Month")
.HasColumnType("int");
b.Property<double>("MonthlySalaryDefined")
.HasColumnType("float");
b.Property<double>("MonthlySalaryPay")
.HasColumnType("float");
b.Property<int>("RemainingHours")
.HasColumnType("int");
b.Property<int>("TotalDaysWorked")
.HasColumnType("int");
b.Property<int>("TotalHoursWorked")
.HasColumnType("int");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.Property<int>("Year")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Checkouts", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.CustomerAgg.Customer", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime2");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Email")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<string>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<Guid>("PhaseId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("SkillId")
.HasColumnType("uniqueidentifier");
b.Property<long>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<DateTime?>("PlannedEndDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("PlannedStartDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime2");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("DeployStatus")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<bool>("IsArchived")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("OrderIndex")
.HasColumnType("int");
b.Property<Guid>("ProjectId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime2");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<Guid>("ProjectId")
.HasColumnType("uniqueidentifier");
b.Property<Guid>("SkillId")
.HasColumnType("uniqueidentifier");
b.Property<long>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("AllocatedTime")
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<DateTime?>("DueDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<bool>("HasTimeOverride")
.HasColumnType("bit");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200)
.HasColumnType("nvarchar(200)");
b.Property<int>("OrderIndex")
.HasColumnType("int");
b.Property<Guid>("PhaseId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Priority")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime?>("StartDate")
.HasColumnType("datetime2");
b.Property<string>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<long>("CurrentAssignedUserId")
.HasColumnType("bigint");
b.Property<string>("InitialDescription")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("InitialEstimatedHours")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<long>("OriginalAssignedUserId")
.HasColumnType("bigint");
b.Property<Guid>("SkillId")
.HasColumnType("uniqueidentifier");
b.Property<string>("Status")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<Guid>("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<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("EndDate")
.HasColumnType("datetime2");
b.Property<string>("EndNotes")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<string>("Notes")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<Guid>("SectionId")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("StartDate")
.HasColumnType("datetime2");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.HasIndex("SectionId");
b.ToTable("TaskSectionActivities", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.ProjectAgg.Entities.TaskSectionAdditionalTime", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("AddedAt")
.HasColumnType("datetime2");
b.Property<long?>("AddedByUserId")
.HasColumnType("bigint");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Hours")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<string>("Reason")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<Guid?>("TaskSectionId")
.HasColumnType("uniqueidentifier");
b.HasKey("Id");
b.HasIndex("TaskSectionId");
b.ToTable("TaskSectionAdditionalTimes", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.RoleAgg.Entities.Role", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<long?>("GozareshgirRoleId")
.HasColumnType("bigint");
b.Property<string>("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<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<DateTime?>("EndSettingDate")
.HasColumnType("datetime2");
b.Property<bool>("HolidayWorking")
.HasColumnType("bit");
b.Property<double>("MonthlySalary")
.HasColumnType("float");
b.Property<DateTime?>("StartSettingDate")
.HasColumnType("datetime2");
b.Property<long>("UserId")
.HasColumnType("bigint");
b.HasKey("Id");
b.ToTable("SalaryPaymentSetting", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.SkillAgg.Entities.Skill", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("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<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
b.Property<long?>("AccountId")
.HasColumnType("bigint");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("Email")
.HasMaxLength(150)
.HasColumnType("nvarchar(150)");
b.Property<string>("FullName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<bool>("IsActive")
.HasColumnType("bit");
b.Property<string>("Mobile")
.IsRequired()
.HasMaxLength(20)
.HasColumnType("nvarchar(20)");
b.Property<string>("Password")
.IsRequired()
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
b.Property<string>("ProfilePhotoPath")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("UserName")
.IsRequired()
.HasMaxLength(100)
.HasColumnType("nvarchar(100)");
b.Property<string>("VerifyCode")
.HasMaxLength(10)
.HasColumnType("nvarchar(10)");
b.HasKey("Id");
b.ToTable("Users", (string)null);
});
modelBuilder.Entity("GozareshgirProgramManager.Domain.UserAgg.Entities.UserRefreshToken", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("datetime2");
b.Property<string>("IpAddress")
.HasMaxLength(50)
.HasColumnType("nvarchar(50)");
b.Property<DateTime?>("RevokedAt")
.HasColumnType("datetime2");
b.Property<string>("Token")
.IsRequired()
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<string>("UserAgent")
.HasMaxLength(500)
.HasColumnType("nvarchar(500)");
b.Property<long>("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<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property<long>("Id"));
b1.Property<int>("Code")
.HasColumnType("int");
b1.Property<long>("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<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property<long>("Id"));
b1.Property<TimeSpan>("EndShiftOne")
.HasColumnType("time(0)");
b1.Property<TimeSpan>("EndShiftTwo")
.HasColumnType("time(0)");
b1.Property<bool>("HasRestTime")
.HasColumnType("bit");
b1.Property<bool>("HasShiftOne")
.HasColumnType("bit");
b1.Property<bool>("HasShiftTow")
.HasColumnType("bit");
b1.Property<bool>("IsActiveDay")
.HasColumnType("bit");
b1.Property<int>("PersianDayOfWeek")
.HasColumnType("int");
b1.Property<TimeSpan>("RestTime")
.HasColumnType("time(0)");
b1.Property<long>("SalaryPaymentSettingId")
.HasColumnType("bigint");
b1.Property<int>("ShiftDurationInMinutes")
.HasColumnType("int");
b1.Property<TimeSpan>("StartShiftOne")
.HasColumnType("time(0)");
b1.Property<TimeSpan>("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<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b1.Property<long>("Id"));
b1.Property<long>("RoleId")
.HasColumnType("bigint");
b1.Property<long>("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
}
}
}

View File

@@ -0,0 +1,41 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace GozareshgirProgramManager.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class addphasedeploystatusandisarchived : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "DeployStatus",
table: "ProjectPhases",
type: "nvarchar(30)",
maxLength: 30,
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<bool>(
name: "IsArchived",
table: "ProjectPhases",
type: "bit",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DeployStatus",
table: "ProjectPhases");
migrationBuilder.DropColumn(
name: "IsArchived",
table: "ProjectPhases");
}
}
}

View File

@@ -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<DateTime>("CreationDate")
.HasColumnType("datetime2");
b.Property<string>("DeployStatus")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("nvarchar(30)");
b.Property<string>("Description")
.HasMaxLength(1000)
.HasColumnType("nvarchar(1000)");
@@ -189,6 +194,9 @@ namespace GozareshgirProgramManager.Infrastructure.Migrations
b.Property<bool>("HasAssignmentOverride")
.HasColumnType("bit");
b.Property<bool>("IsArchived")
.HasColumnType("bit");
b.Property<string>("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 =>

View File

@@ -48,6 +48,9 @@ public class ProjectPhaseMapping : IEntityTypeConfiguration<ProjectPhase>
builder.Property(ph => ph.HasAssignmentOverride)
.IsRequired();
builder.Property(x => x.DeployStatus)
.HasConversion<string>().HasMaxLength(30);
// Relationship with Project
builder.HasOne(ph => ph.Project)
.WithMany(p => p.Phases)

View File

@@ -43,9 +43,9 @@ public class RepositoryBase<TKey, T> : IRepository<TKey, T> where T : class
return _context.Find<T>(id);
}
public async Task<T?> GetByIdAsync(TKey id)
public async Task<T?> GetByIdAsync(TKey id, CancellationToken cancellationToken = default)
{
return await _context.Set<T>().FindAsync(id);
return await _context.Set<T>().FindAsync([id], cancellationToken);
}
public List<T> Get()

View File

@@ -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<ActionResult<OperationResult<GetProjectsListResponse>>> Get([FromQuery]GetProjectsListQuery query)
public async Task<ActionResult<OperationResult<GetProjectsListResponse>>> Get(
[FromQuery] GetProjectsListQuery query)
{
var res=await _mediator.Send(query);
var res = await _mediator.Send(query);
return res;
}
[HttpPost]
public async Task<ActionResult<OperationResult>> Create([FromBody] CreateProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpPut]
public async Task<ActionResult<OperationResult>> Edit([FromBody] EditProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpDelete]
public async Task<ActionResult<OperationResult>> Delete([FromQuery] DeleteProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpGet("assign")]
public async Task<ActionResult<OperationResult<GetProjectAssignDetailsResponse>>> GetAssignableProjects(GetProjectAssignDetailsQuery query)
public async Task<ActionResult<OperationResult<GetProjectAssignDetailsResponse>>> GetAssignableProjects(
GetProjectAssignDetailsQuery query)
{
var res=await _mediator.Send(query);
var res = await _mediator.Send(query);
return res;
}
[HttpPost("assign")]
public async Task<ActionResult<OperationResult>> Assign(AssignProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpGet("set-time")]
public async Task<ActionResult<OperationResult<ProjectSetTimeResponse>>> GetSetTimeProjectDetails(ProjectSetTimeDetailsQuery query)
public async Task<ActionResult<OperationResult<ProjectSetTimeResponse>>> GetSetTimeProjectDetails(
ProjectSetTimeDetailsQuery query)
{
var res=await _mediator.Send(query);
var res = await _mediator.Send(query);
return res;
}
[HttpPost("set-time")]
public async Task<ActionResult<OperationResult>> SetTimeProject(SetTimeProjectCommand command)
{
var res=await _mediator.Send(command);
var res = await _mediator.Send(command);
return res;
}
[HttpPost("change-status")]
public async Task<ActionResult<OperationResult>> 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<ActionResult<OperationResult<List<ProjectBoardListResponse>>>> GetProjectBoard([FromQuery] ProjectBoardListQuery query)
public async Task<ActionResult<OperationResult<List<ProjectBoardListResponse>>>> 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<ActionResult<OperationResult<ProjectBoardDetailResponse>>> 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<ActionResult<OperationResult<GetProjectsDeployBoardListResponse>>> GetProjectDeployBoard()
{
// قبل از دریافت دیتا، وضعیت دیپلوی را بر اساس تکمیل شدن تمام سکشن‌ها به‌روزرسانی می‌کنیم
await _mediator.Send(new AutoUpdateDeployStatusCommand());
var request = new GetProjectDeployBoardListQuery();
return await _mediator.Send(request);
}
[HttpGet("deploy-board/details")]
public async Task<ActionResult<OperationResult<ProjectDeployBoardDetailsResponse>>> GetProjectDeployBoardDetails(Guid id)
{
var query = new ProjectDeployBoardDetailsQuery(id);
var res = await _mediator.Send(query);
return res;
}
[HttpPost("deploy-board/change-status")]
public async Task<ActionResult<OperationResult>> ChangeDeployStatus(ChangeDeployStatusProjectCommand command)
{
var res = await _mediator.Send(command);
return res;
}
}