Compare commits

..

7 Commits

20 changed files with 111 additions and 299 deletions

View File

@@ -8,6 +8,7 @@ public class CreateSalaryAidViewModel
public long WorkshopId { get; set; } public long WorkshopId { get; set; }
public string Amount { get; set; } public string Amount { get; set; }
public string SalaryDateTime { get; set; } public string SalaryDateTime { get; set; }
public string CalculationDateTime { get; set; }
public string NationalCode { get; set; } public string NationalCode { get; set; }
public int CalculationMonth { get; set; } public int CalculationMonth { get; set; }
public int CalculationYear { get; set; } public int CalculationYear { get; set; }

View File

@@ -8,7 +8,7 @@ public class SalaryAidGroupedByDateViewModel
public string YearFa { get; set; } public string YearFa { get; set; }
public int Month { get; set; } public int Month { get; set; }
public int Year { get; set; } public int Year { get; set; }
public List<SalaryAidGroupedByDateViewModelItems> Items { get; set; } public List<SalaryAidGroupedByDateViewModelItems> SalaryAidViewModels { get; set; }
public string TotalAmount { get; set; } public string TotalAmount { get; set; }
} }

View File

@@ -6,7 +6,7 @@ public class SalaryAidGroupedByEmployeeViewModel
{ {
public string EmployeeName { get; set; } public string EmployeeName { get; set; }
public long EmployeeId { get; set; } public long EmployeeId { get; set; }
public List<SalaryAidGroupedByEmployeeViewModelItems> Items { get; set; } public List<SalaryAidGroupedByEmployeeViewModelItems> SalaryAidViewModels { get; set; }
public string TotalAmount { get; set; } public string TotalAmount { get; set; }
} }

View File

@@ -3,15 +3,15 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.SalaryAid; namespace CompanyManagment.App.Contracts.SalaryAid;
public class SalaryAidSearchViewModel:PaginationRequest public class SalaryAidSearchViewModel
{ {
public string StartDate { get; set; } public string StartDate { get; set; }
public string EndDate { get; set; } public string EndDate { get; set; }
public long EmployeeId { get; set; } public long EmployeeId { get; set; }
public long WorkshopId { get; set; } public long WorkshopId { get; set; }
public int PageIndex { get; set; }
public bool ShowAsGrouped { get; set; } public bool ShowAsGrouped { get; set; }
} }

View File

@@ -1,6 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Security.Cryptography; using System.Security.Cryptography;
using _0_Framework.Application;
namespace CompanyManagment.App.Contracts.SalaryAid; namespace CompanyManagment.App.Contracts.SalaryAid;
@@ -8,7 +7,7 @@ public class SalaryAidsGroupedViewModel
{ {
public List<SalaryAidGroupedByEmployeeViewModel> GroupedByEmployee { get; set; } public List<SalaryAidGroupedByEmployeeViewModel> GroupedByEmployee { get; set; }
public List<SalaryAidGroupedByDateViewModel> GroupedByDate { get; set; } public List<SalaryAidGroupedByDateViewModel> GroupedByDate { get; set; }
public PagedResult<SalaryAidViewModel> List { get; set; } public List<SalaryAidViewModel> SalaryAidListViewModels { get; set; }
} }

View File

@@ -1524,7 +1524,8 @@ public class InsuranceListApplication : IInsuranceListApplication
var dateOfBirth = employeeData.DateOfBirthGr.ToFarsi(); var dateOfBirth = employeeData.DateOfBirthGr.ToFarsi();
var dateOfIssue = employeeData.DateOfIssueGr.ToFarsi(); var dateOfIssue = employeeData.DateOfIssueGr.ToFarsi();
var leftDate = employeeData.LeftWorkDateGr != null ? employeeData.LeftWorkDateGr.Value.AddDays(-1) : new DateTime(); var leftDate = employeeData.LeftWorkDateGr != null ? employeeData.LeftWorkDateGr.Value.AddDays(-1) : new DateTime();
var workingDays = Tools.GetEmployeeInsuranceWorkingDays(employeeData.StartWorkDateGr, leftDate, startDateGr, endDateGr, employeeData.EmployeeId);
var workingDays = Tools.GetEmployeeInsuranceWorkingDays(employeeData.StartWorkDateGr, leftDate, startDateGr, endDateGr, employeeData.EmployeeId);
var leftWorkFa = workingDays.hasLeftWorkInMonth ? employeeData.LeftWorkDateGr.ToFarsi() : ""; var leftWorkFa = workingDays.hasLeftWorkInMonth ? employeeData.LeftWorkDateGr.ToFarsi() : "";
var startWorkFa = employeeData.StartWorkDateGr.ToFarsi(); var startWorkFa = employeeData.StartWorkDateGr.ToFarsi();
var workshop = _workShopRepository.GetDetails(workshopId); var workshop = _workShopRepository.GetDetails(workshopId);
@@ -1606,7 +1607,7 @@ public class InsuranceListApplication : IInsuranceListApplication
MaritalStatus = employeeData.MaritalStatus, MaritalStatus = employeeData.MaritalStatus,
StartMonthCurrent = startMonthFa, StartMonthCurrent = startMonthFa,
WorkingDays = workingDays.countWorkingDays, WorkingDays = employeeData.WorkingDays,
StartWorkDate = startWorkFa, StartWorkDate = startWorkFa,
StartWorkDateGr = employeeData.StartWorkDateGr, StartWorkDateGr = employeeData.StartWorkDateGr,
LeftWorkDate = leftWorkFa, LeftWorkDate = leftWorkFa,

View File

@@ -433,7 +433,7 @@ public class SalaryAidApplication : ISalaryAidApplication
var checkouts = _checkoutRepository.GetByWorkshopIdEmployeeIdInDate( var checkouts = _checkoutRepository.GetByWorkshopIdEmployeeIdInDate(
command.WorkshopId, employeeId, calculationDateGr).GetAwaiter().GetResult(); command.WorkshopId, employeeId, calculationDateGr).GetAwaiter().GetResult();
checkouts?.SetAmountConflict(true); checkouts?.SetAmountConflict(true);
} }
} }

View File

@@ -146,7 +146,7 @@ public class SalaryAidRepository : RepositoryBase<long, SalaryAid>, ISalaryAidRe
{ {
YearFa = x.Key.YearFa, YearFa = x.Key.YearFa,
MonthFa = x.Key.MonthFa, MonthFa = x.Key.MonthFa,
Items = x.Select(s => new SalaryAidGroupedByDateViewModelItems() SalaryAidViewModels = x.Select(s => new SalaryAidGroupedByDateViewModelItems()
{ {
Amount = s.Amount, Amount = s.Amount,
EmployeeName = s.EmployeeFullName, EmployeeName = s.EmployeeFullName,
@@ -175,7 +175,7 @@ public class SalaryAidRepository : RepositoryBase<long, SalaryAid>, ISalaryAidRe
EmployeeId = x.Key, EmployeeId = x.Key,
TotalAmount = x.Sum(s => s.Amount).ToMoney(), TotalAmount = x.Sum(s => s.Amount).ToMoney(),
EmployeeName = employees.FirstOrDefault(e => e.id == x.Key).FullName, EmployeeName = employees.FirstOrDefault(e => e.id == x.Key).FullName,
Items = x.Select(s => new SalaryAidGroupedByEmployeeViewModelItems() SalaryAidViewModels = x.Select(s => new SalaryAidGroupedByEmployeeViewModelItems()
{ {
Amount = s.Amount.ToMoney(), Amount = s.Amount.ToMoney(),
Id = s.id, Id = s.id,
@@ -197,28 +197,23 @@ public class SalaryAidRepository : RepositoryBase<long, SalaryAid>, ISalaryAidRe
query = query.Where(x => x.SalaryAidDateTime >= startDate && x.SalaryAidDateTime <= endDate); query = query.Where(x => x.SalaryAidDateTime >= startDate && x.SalaryAidDateTime <= endDate);
} }
result.List = new PagedResult<SalaryAidViewModel>() result.SalaryAidListViewModels = query.OrderByDescending(x => x.SalaryAidDateTime).Skip(searchModel.PageIndex).Take(30).ToList().Select(
{ x => new SalaryAidViewModel()
TotalCount = query.Count(), {
List = query.OrderByDescending(x => x.SalaryAidDateTime).ApplyPagination(searchModel.PageIndex,searchModel.PageSize).ToList() Amount = x.Amount.ToMoney(),
.Select(x => new SalaryAidViewModel() CreationDate = x.CreationDate.ToFarsi(),
{ Id = x.id,
Amount = x.Amount.ToMoney(), EmployeeId = x.EmployeeId,
CreationDate = x.CreationDate.ToFarsi(), SalaryAidDateTimeFa = x.SalaryAidDateTime.ToFarsi(),
Id = x.id, SalaryAidDateTimeGe = x.SalaryAidDateTime,
EmployeeId = x.EmployeeId, WorkshopId = x.WorkshopId,
SalaryAidDateTimeFa = x.SalaryAidDateTime.ToFarsi(), YearFa = x.SalaryAidDateTime.ToFarsi().Substring(0, 4),
SalaryAidDateTimeGe = x.SalaryAidDateTime, MonthFa = x.SalaryAidDateTime.ToFarsi().Substring(5, 2),
WorkshopId = x.WorkshopId, PersonnelCode = personnelCodes.FirstOrDefault(p => p.EmployeeId == x.EmployeeId).PersonnelCode.ToString(),
YearFa = x.SalaryAidDateTime.ToFarsi().Substring(0, 4), EmployeeFullName = employees.FirstOrDefault(e => e.id == x.EmployeeId).FullName,
MonthFa = x.SalaryAidDateTime.ToFarsi().Substring(5, 2), AmountDouble = x.Amount,
PersonnelCode = personnelCodes.FirstOrDefault(p => p.EmployeeId == x.EmployeeId).PersonnelCode }).ToList();
.ToString(),
EmployeeFullName = employees.FirstOrDefault(e => e.id == x.EmployeeId).FullName,
AmountDouble = x.Amount,
}).ToList()
};
return result; return result;
} }

View File

@@ -1,16 +0,0 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddTaskToPhase;
/// <summary>
/// Command to add a task to an existing phase
/// </summary>
public record AddTaskToPhaseCommand(
Guid PhaseId,
string Name,
string? Description = null,
ProjectTaskPriority Priority = ProjectTaskPriority.Medium,
int OrderIndex = 0,
DateTime? DueDate = null
) : IBaseCommand;

View File

@@ -1,53 +0,0 @@
using GozareshgirProgramManager.Application._Common.Interfaces;
using GozareshgirProgramManager.Application._Common.Models;
using GozareshgirProgramManager.Domain._Common;
using GozareshgirProgramManager.Domain.ProjectAgg.Repositories;
using MediatR;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.AddTaskToPhase;
public class AddTaskToPhaseCommandHandler : IRequestHandler<AddTaskToPhaseCommand, OperationResult>
{
private readonly IProjectPhaseRepository _phaseRepository;
private readonly IUnitOfWork _unitOfWork;
public AddTaskToPhaseCommandHandler(
IProjectPhaseRepository phaseRepository,
IUnitOfWork unitOfWork)
{
_phaseRepository = phaseRepository;
_unitOfWork = unitOfWork;
}
public async Task<OperationResult> Handle(AddTaskToPhaseCommand request, CancellationToken cancellationToken)
{
try
{
// Get phase
var phase = await _phaseRepository.GetByIdAsync(request.PhaseId);
if (phase == null)
{
return OperationResult.NotFound("فاز یافت نشد");
}
// Add task
var task = phase.AddTask(request.Name, request.Description);
task.SetPriority(request.Priority);
task.SetOrderIndex(request.OrderIndex);
if (request.DueDate.HasValue)
{
task.SetDates(dueDate: request.DueDate);
}
// Save changes
await _unitOfWork.SaveChangesAsync(cancellationToken);
return OperationResult.Success();
}
catch (Exception ex)
{
return OperationResult.Failure($"خطا در افزودن تسک: {ex.Message}");
}
}
}

View File

@@ -4,4 +4,5 @@ using GozareshgirProgramManager.Domain.ProjectAgg.Enums;
namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject; namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.CreateProject;
public record CreateProjectCommand(string Name,ProjectHierarchyLevel Level, public record CreateProjectCommand(string Name,ProjectHierarchyLevel Level,
ProjectTaskPriority? Priority,
Guid? ParentId):IBaseCommand; Guid? ParentId):IBaseCommand;

View File

@@ -16,7 +16,8 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
private readonly IUnitOfWork _unitOfWork; private readonly IUnitOfWork _unitOfWork;
public CreateProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork, IProjectTaskRepository projectTaskRepository, IProjectPhaseRepository projectPhaseRepository) public CreateProjectCommandHandler(IProjectRepository projectRepository, IUnitOfWork unitOfWork,
IProjectTaskRepository projectTaskRepository, IProjectPhaseRepository projectPhaseRepository)
{ {
_projectRepository = projectRepository; _projectRepository = projectRepository;
_unitOfWork = unitOfWork; _unitOfWork = unitOfWork;
@@ -55,8 +56,8 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
{ {
if (!request.ParentId.HasValue) if (!request.ParentId.HasValue)
throw new BadRequestException("برای ایجاد فاز، شناسه پروژه الزامی است"); throw new BadRequestException("برای ایجاد فاز، شناسه پروژه الزامی است");
if(!_projectRepository.Exists(x=>x.Id == request.ParentId.Value)) if (!_projectRepository.Exists(x => x.Id == request.ParentId.Value))
{ {
throw new BadRequestException("والد پروژه یافت نشد"); throw new BadRequestException("والد پروژه یافت نشد");
} }
@@ -69,14 +70,15 @@ public class CreateProjectCommandHandler : IBaseCommandHandler<CreateProjectComm
{ {
if (!request.ParentId.HasValue) if (!request.ParentId.HasValue)
throw new BadRequestException("برای ایجاد تسک، شناسه فاز الزامی است"); throw new BadRequestException("برای ایجاد تسک، شناسه فاز الزامی است");
if(!_projectPhaseRepository.Exists(x=>x.Id == request.ParentId.Value)) if (!_projectPhaseRepository.Exists(x => x.Id == request.ParentId.Value))
{ {
throw new BadRequestException("والد پروژه یافت نشد"); throw new BadRequestException("والد پروژه یافت نشد");
} }
var projectTask = new ProjectTask(request.Name, request.ParentId.Value); var priority = request.Priority ?? ProjectTaskPriority.Low;
var projectTask = new ProjectTask(request.Name, request.ParentId.Value, priority);
await _projectTaskRepository.CreateAsync(projectTask); await _projectTaskRepository.CreateAsync(projectTask);
} }
} }

View File

@@ -10,8 +10,10 @@ public class GetProjectItemDto
public int Percentage { get; init; } public int Percentage { get; init; }
public ProjectHierarchyLevel Level { get; init; } public ProjectHierarchyLevel Level { get; init; }
public Guid? ParentId { get; init; } public Guid? ParentId { get; init; }
public int TotalHours { get; set; }
public int Minutes { get; set; } public TimeSpan TotalTime { get; init; }
public TimeSpan RemainingTime { get; init; }
public AssignmentStatus Front { get; set; } public AssignmentStatus Front { get; set; }
public AssignmentStatus Backend { get; set; } public AssignmentStatus Backend { get; set; }
public AssignmentStatus Design { get; set; } public AssignmentStatus Design { get; set; }

View File

@@ -16,7 +16,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
_context = context; _context = context;
} }
public async Task<OperationResult<GetProjectsListResponse>> Handle(GetProjectsListQuery request, CancellationToken cancellationToken) public async Task<OperationResult<GetProjectsListResponse>> Handle(GetProjectsListQuery request,
CancellationToken cancellationToken)
{ {
var projects = new List<GetProjectDto>(); var projects = new List<GetProjectDto>();
var phases = new List<GetPhaseDto>(); var phases = new List<GetPhaseDto>();
@@ -51,13 +52,14 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{ {
return new List<GetProjectDto>(); return new List<GetProjectDto>();
} }
var entities = await query var entities = await query
.OrderByDescending(p => p.CreationDate) .OrderByDescending(p => p.CreationDate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
var result = new List<GetProjectDto>(); var result = new List<GetProjectDto>();
foreach (var project in entities) foreach (var project in entities)
{ {
var (percentage, totalTime) = await CalculateProjectPercentage(project, cancellationToken); var (percentage, totalTime,remainingTime) = await CalculateProjectPercentage(project, cancellationToken);
result.Add(new GetProjectDto result.Add(new GetProjectDto
{ {
Id = project.Id, Id = project.Id,
@@ -65,10 +67,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Project, Level = ProjectHierarchyLevel.Project,
ParentId = null, ParentId = null,
Percentage = percentage, Percentage = percentage,
TotalHours = (int)totalTime.TotalHours, TotalTime = totalTime,
Minutes = totalTime.Minutes, RemainingTime = remainingTime
}); });
} }
result = result.OrderByDescending(x => x.Percentage).ToList();
return result; return result;
} }
@@ -79,13 +83,14 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{ {
query = query.Where(x => x.ProjectId == parentId); query = query.Where(x => x.ProjectId == parentId);
} }
var entities = await query var entities = await query
.OrderByDescending(p => p.CreationDate) .OrderByDescending(p => p.CreationDate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
var result = new List<GetPhaseDto>(); var result = new List<GetPhaseDto>();
foreach (var phase in entities) foreach (var phase in entities)
{ {
var (percentage, totalTime) = await CalculatePhasePercentage(phase, cancellationToken); var (percentage, totalTime,remainingTime) = await CalculatePhasePercentage(phase, cancellationToken);
result.Add(new GetPhaseDto result.Add(new GetPhaseDto
{ {
Id = phase.Id, Id = phase.Id,
@@ -93,10 +98,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Phase, Level = ProjectHierarchyLevel.Phase,
ParentId = phase.ProjectId, ParentId = phase.ProjectId,
Percentage = percentage, Percentage = percentage,
TotalHours = (int)totalTime.TotalHours, TotalTime = totalTime,
Minutes = totalTime.Minutes, RemainingTime = remainingTime
}); });
} }
result = result.OrderByDescending(x => x.Percentage).ToList();
return result; return result;
} }
@@ -107,6 +114,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
{ {
query = query.Where(x => x.PhaseId == parentId); query = query.Where(x => x.PhaseId == parentId);
} }
var entities = await query var entities = await query
.OrderByDescending(t => t.CreationDate) .OrderByDescending(t => t.CreationDate)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
@@ -118,7 +126,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
foreach (var task in entities) foreach (var task in entities)
{ {
var (percentage, totalTime) = await CalculateTaskPercentage(task, cancellationToken); var (percentage, totalTime,remainingTime) = await CalculateTaskPercentage(task, cancellationToken);
var sections = await _context.TaskSections var sections = await _context.TaskSections
.Include(s => s.Activities) .Include(s => s.Activities)
.Include(s => s.Skill) .Include(s => s.Skill)
@@ -140,13 +148,12 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// محاسبه SpentTime و RemainingTime // محاسبه SpentTime و RemainingTime
var spentTime = TimeSpan.FromTicks(sections.Sum(s => s.Activities.Sum(a => a.GetTimeSpent().Ticks))); var spentTime = TimeSpan.FromTicks(sections.Sum(s => s.Activities.Sum(a => a.GetTimeSpent().Ticks)));
var remainingTime = totalTime - spentTime;
// ساخت section DTOs برای تمام Skills // ساخت section DTOs برای تمام Skills
var sectionDtos = allSkills.Select(skill => var sectionDtos = allSkills.Select(skill =>
{ {
var section = sections.FirstOrDefault(s => s.SkillId == skill.Id); var section = sections.FirstOrDefault(s => s.SkillId == skill.Id);
if (section == null) if (section == null)
{ {
// اگر section وجود نداشت، یک DTO با وضعیت Unassigned برمی‌گردانیم // اگر section وجود نداشت، یک DTO با وضعیت Unassigned برمی‌گردانیم
@@ -184,18 +191,20 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
Level = ProjectHierarchyLevel.Task, Level = ProjectHierarchyLevel.Task,
ParentId = task.PhaseId, ParentId = task.PhaseId,
Percentage = percentage, Percentage = percentage,
TotalHours = (int)totalTime.TotalHours, TotalTime = totalTime,
Minutes = totalTime.Minutes,
SpentTime = spentTime, SpentTime = spentTime,
RemainingTime = remainingTime, RemainingTime = remainingTime,
Sections = sectionDtos, Sections = sectionDtos,
Priority = task.Priority Priority = task.Priority
}); });
} }
result = result.OrderByDescending(x => x.Percentage).ToList();
return result; return result;
} }
private async Task SetSkillFlags<TItem>(List<TItem> items, CancellationToken cancellationToken) where TItem : GetProjectItemDto private async Task SetSkillFlags<TItem>(List<TItem> items, CancellationToken cancellationToken)
where TItem : GetProjectItemDto
{ {
if (!items.Any()) if (!items.Any())
return; return;
@@ -213,7 +222,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
} }
private async Task SetSkillFlagsForProjects<TItem>(List<TItem> items, List<Guid> projectIds, CancellationToken cancellationToken) where TItem : GetProjectItemDto private async Task SetSkillFlagsForProjects<TItem>(List<TItem> items, List<Guid> projectIds,
CancellationToken cancellationToken) where TItem : GetProjectItemDto
{ {
// For projects: gather all phases, then tasks, then sections // For projects: gather all phases, then tasks, then sections
var phases = await _context.ProjectPhases var phases = await _context.ProjectPhases
@@ -243,7 +253,8 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
} }
} }
private async Task SetSkillFlagsForPhases<TItem>(List<TItem> items, List<Guid> phaseIds, CancellationToken cancellationToken) where TItem : GetProjectItemDto private async Task SetSkillFlagsForPhases<TItem>(List<TItem> items, List<Guid> phaseIds,
CancellationToken cancellationToken) where TItem : GetProjectItemDto
{ {
// For phases: gather tasks, then sections // For phases: gather tasks, then sections
var tasks = await _context.ProjectTasks var tasks = await _context.ProjectTasks
@@ -269,68 +280,81 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
} }
} }
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateProjectPercentage(Project project, CancellationToken cancellationToken) private async Task<(int Percentage, TimeSpan TotalTime,TimeSpan RemainingTime)> CalculateProjectPercentage(Project project,
CancellationToken cancellationToken)
{ {
var phases = await _context.ProjectPhases var phases = await _context.ProjectPhases
.Where(ph => ph.ProjectId == project.Id) .Where(ph => ph.ProjectId == project.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
if (!phases.Any()) if (!phases.Any())
return (0, TimeSpan.Zero); return (0, TimeSpan.Zero,TimeSpan.Zero);
var phasePercentages = new List<int>(); var phasePercentages = new List<int>();
var totalTime = TimeSpan.Zero; var totalTime = TimeSpan.Zero;
var remainingTime = TimeSpan.Zero;
foreach (var phase in phases) foreach (var phase in phases)
{ {
var (phasePercentage, phaseTime) = await CalculatePhasePercentage(phase, cancellationToken); var (phasePercentage, phaseTime,phaseRemainingTime) = await CalculatePhasePercentage(phase, cancellationToken);
phasePercentages.Add(phasePercentage); phasePercentages.Add(phasePercentage);
totalTime += phaseTime; totalTime += phaseTime;
remainingTime += phaseRemainingTime;
} }
var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0; var averagePercentage = phasePercentages.Any() ? (int)phasePercentages.Average() : 0;
return (averagePercentage, totalTime); return (averagePercentage, totalTime,remainingTime);
} }
private async Task<(int Percentage, TimeSpan TotalTime)> CalculatePhasePercentage(ProjectPhase phase, CancellationToken cancellationToken) private async Task<(int Percentage, TimeSpan TotalTime,TimeSpan RemainingTime)> CalculatePhasePercentage(ProjectPhase phase,
CancellationToken cancellationToken)
{ {
var tasks = await _context.ProjectTasks var tasks = await _context.ProjectTasks
.Where(t => t.PhaseId == phase.Id) .Where(t => t.PhaseId == phase.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
if (!tasks.Any()) if (!tasks.Any())
return (0, TimeSpan.Zero); return (0, TimeSpan.Zero,TimeSpan.Zero);
var taskPercentages = new List<int>(); var taskPercentages = new List<int>();
var totalTime = TimeSpan.Zero; var totalTime = TimeSpan.Zero;
var remainingTime = TimeSpan.Zero;
foreach (var task in tasks) foreach (var task in tasks)
{ {
var (taskPercentage, taskTime) = await CalculateTaskPercentage(task, cancellationToken); var (taskPercentage, taskTime,taskRemainingTime) = await CalculateTaskPercentage(task, cancellationToken);
taskPercentages.Add(taskPercentage); taskPercentages.Add(taskPercentage);
totalTime += taskTime; totalTime += taskTime;
remainingTime += taskRemainingTime;
} }
var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0; var averagePercentage = taskPercentages.Any() ? (int)taskPercentages.Average() : 0;
return (averagePercentage, totalTime); return (averagePercentage, totalTime,remainingTime);
} }
private async Task<(int Percentage, TimeSpan TotalTime)> CalculateTaskPercentage(ProjectTask task, CancellationToken cancellationToken) private async Task<(int Percentage, TimeSpan TotalTime, TimeSpan RemainingTime)> CalculateTaskPercentage(
ProjectTask task, CancellationToken cancellationToken)
{ {
var sections = await _context.TaskSections var sections = await _context.TaskSections
.Include(s => s.Activities) .Include(s => s.Activities)
.Include(x=>x.AdditionalTimes) .Include(x => x.AdditionalTimes)
.Where(s => s.TaskId == task.Id) .Where(s => s.TaskId == task.Id)
.ToListAsync(cancellationToken); .ToListAsync(cancellationToken);
if (!sections.Any()) if (!sections.Any())
return (0, TimeSpan.Zero); return (0, TimeSpan.Zero, TimeSpan.Zero);
var sectionPercentages = new List<int>(); var sectionPercentages = new List<int>();
var totalTime = TimeSpan.Zero; var totalTime = TimeSpan.Zero;
var spentTime = TimeSpan.Zero;
foreach (var section in sections) foreach (var section in sections)
{ {
var (sectionPercentage, sectionTime) = CalculateSectionPercentage(section); var (sectionPercentage, sectionTime) = CalculateSectionPercentage(section);
var sectionSpent = TimeSpan.FromTicks(section.Activities.Sum(x => x.GetTimeSpent().Ticks));
sectionPercentages.Add(sectionPercentage); sectionPercentages.Add(sectionPercentage);
totalTime += sectionTime; totalTime += sectionTime;
spentTime += sectionSpent;
} }
var remainingTime = totalTime - spentTime;
var averagePercentage = sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0; var averagePercentage = sectionPercentages.Any() ? (int)sectionPercentages.Average() : 0;
return (averagePercentage, totalTime); return (averagePercentage, totalTime, remainingTime);
} }
private static (int Percentage, TimeSpan TotalTime) CalculateSectionPercentage(TaskSection section) private static (int Percentage, TimeSpan TotalTime) CalculateSectionPercentage(TaskSection section)
{ {
return ((int)section.GetProgressPercentage(),section.FinalEstimatedHours); return ((int)section.GetProgressPercentage(), section.FinalEstimatedHours);
} }
private static AssignmentStatus GetAssignmentStatus(TaskSection? section) private static AssignmentStatus GetAssignmentStatus(TaskSection? section)
@@ -341,7 +365,7 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// بررسی وجود user // بررسی وجود user
bool hasUser = section.CurrentAssignedUserId > 0; bool hasUser = section.CurrentAssignedUserId > 0;
// بررسی وجود time (InitialEstimatedHours بزرگتر از صفر باشد) // بررسی وجود time (InitialEstimatedHours بزرگتر از صفر باشد)
bool hasTime = section.InitialEstimatedHours > TimeSpan.Zero; bool hasTime = section.InitialEstimatedHours > TimeSpan.Zero;
@@ -356,5 +380,4 @@ public class GetProjectsListQueryHandler : IBaseQueryHandler<GetProjectsListQuer
// تعیین تکلیف نشده: نه user دارد نه time // تعیین تکلیف نشده: نه user دارد نه time
return AssignmentStatus.Unassigned; return AssignmentStatus.Unassigned;
} }
} }

View File

@@ -9,8 +9,8 @@ public class GetTaskDto
public int Percentage { get; init; } public int Percentage { get; init; }
public ProjectHierarchyLevel Level { get; init; } public ProjectHierarchyLevel Level { get; init; }
public Guid? ParentId { get; init; } public Guid? ParentId { get; init; }
public int TotalHours { get; set; }
public int Minutes { get; set; } public TimeSpan TotalTime { get; set; }
// Task-specific fields // Task-specific fields
public TimeSpan SpentTime { get; init; } public TimeSpan SpentTime { get; init; }

View File

@@ -7,6 +7,6 @@ namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.Project
public record ProjectBoardListQuery: IBaseQuery<List<ProjectBoardListResponse>> public record ProjectBoardListQuery: IBaseQuery<List<ProjectBoardListResponse>>
{ {
public long? UserId { get; set; } public long? UserId { get; set; }
public string? SearchText { get; set; } public string? ProjectName { get; set; }
public TaskSectionStatus? Status { get; set; } public TaskSectionStatus? Status { get; set; }
} }

View File

@@ -46,11 +46,11 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
queryable = queryable.Where(x => x.CurrentAssignedUserId == request.UserId); queryable = queryable.Where(x => x.CurrentAssignedUserId == request.UserId);
} }
if (!string.IsNullOrWhiteSpace(request.SearchText)) if (!string.IsNullOrWhiteSpace(request.ProjectName))
{ {
queryable = queryable.Where(x=>x.Task.Name.Contains(request.SearchText) queryable = queryable.Where(x=>x.Task.Name.Contains(request.ProjectName)
|| x.Task.Phase.Name.Contains(request.SearchText) || x.Task.Phase.Name.Contains(request.ProjectName)
|| x.Task.Phase.Project.Name.Contains(request.SearchText)); || x.Task.Phase.Project.Name.Contains(request.ProjectName));
} }
var data = await queryable.ToListAsync(cancellationToken); var data = await queryable.ToListAsync(cancellationToken);
@@ -70,6 +70,9 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler<ProjectBoardListQu
.OrderByDescending(x => x.CurrentAssignedUserId == currentUserId) .OrderByDescending(x => x.CurrentAssignedUserId == currentUserId)
.ThenByDescending(x=>x.Task.Priority) .ThenByDescending(x=>x.Task.Priority)
.ThenBy(x => GetStatusOrder(x.Status)) .ThenBy(x => GetStatusOrder(x.Status))
.ThenBy(x=>x.Task.Phase.ProjectId)
.ThenBy(x=>x.Task.PhaseId)
.ThenBy(x=>x.TaskId)
.Select(x => .Select(x =>
{ {
// محاسبه یکبار برای هر Activity و Cache کردن نتیجه // محاسبه یکبار برای هر Activity و Cache کردن نتیجه

View File

@@ -41,15 +41,7 @@ public class ProjectPhase : ProjectHierarchyNode
public ProjectDeployStatus DeployStatus { get; set; } public ProjectDeployStatus DeployStatus { get; set; }
#region Task Management #region Task Management
public ProjectTask AddTask(string name, string? description = null)
{
var task = new ProjectTask(name, Id, description);
_tasks.Add(task);
AddDomainEvent(new TaskAddedEvent(task.Id, Id, name));
return task;
}
public void RemoveTask(Guid taskId) public void RemoveTask(Guid taskId)
{ {
var task = _tasks.FirstOrDefault(t => t.Id == taskId); var task = _tasks.FirstOrDefault(t => t.Id == taskId);

View File

@@ -16,11 +16,11 @@ public class ProjectTask : ProjectHierarchyNode
_sections = new List<TaskSection>(); _sections = new List<TaskSection>();
} }
public ProjectTask(string name, Guid phaseId, string? description = null) : base(name, description) public ProjectTask(string name, Guid phaseId,ProjectTaskPriority priority, string? description = null) : base(name, description)
{ {
PhaseId = phaseId; PhaseId = phaseId;
_sections = new List<TaskSection>(); _sections = new List<TaskSection>();
Priority = ProjectTaskPriority.Low; Priority = priority;
AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name)); AddDomainEvent(new TaskCreatedEvent(Id, phaseId, name));
} }

View File

@@ -1,138 +0,0 @@
using _0_Framework.Application;
using CompanyManagement.Infrastructure.Excel.SalaryAid;
using CompanyManagment.App.Contracts.SalaryAid;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Build.Evaluation;
using ServiceHost.BaseControllers;
namespace ServiceHost.Areas.Client.Controllers;
public class SalaryAidController:ClientBaseController
{
private readonly ISalaryAidApplication _salaryAidApplication;
private readonly long _workshopId;
private readonly SalaryAidImportExcel _salaryAidImportExcel;
public SalaryAidController(ISalaryAidApplication salaryAidApplication,IAuthHelper authHelper, SalaryAidImportExcel salaryAidImportExcel)
{
_salaryAidApplication = salaryAidApplication;
_salaryAidImportExcel = salaryAidImportExcel;
_workshopId = authHelper.GetWorkshopId();
}
[HttpGet]
public ActionResult<SalaryAidsGroupedViewModel> GetList([FromQuery]SalaryAidSearchViewModel searchModel)
{
searchModel.WorkshopId = _workshopId;
var result = _salaryAidApplication.GetSearchListAsGrouped(searchModel);
return Ok(result);
}
[HttpPost]
public ActionResult<OperationResult> Create([FromBody]CreateSalaryAidRequest request)
{
var command = new CreateSalaryAidViewModel()
{
Amount = request.Amount.ToMoney(),
CalculationMonth = request.CalculationMonth,
CalculationYear = request.CalculationYear,
EmployeeIds = request.EmployeeIds,
WorkshopId = _workshopId,
SalaryDateTime = request.SalaryDateTime,
};
var result = _salaryAidApplication.Create(command);
return result;
}
[HttpPut]
public ActionResult<OperationResult> Edit([FromBody]EditSalaryAidRequest request)
{
var command = new EditSalaryAidViewModel()
{
Id = request.Id,
Amount = request.Amount.ToMoney(),
CalculationMonth = request.CalculationMonth,
CalculationYear = request.CalculationYear,
SalaryDateTime = request.SalaryDateTime,
WorkshopId = _workshopId,
};
var result = _salaryAidApplication.Edit(command);
return result;
}
[HttpGet("{id}")]
public ActionResult<EditSalaryAidRequest> EditDetails(long id)
{
var data = _salaryAidApplication.GetDetails(id);
var res = new EditSalaryAidRequest()
{
Id = data.Id,
Amount = data.Amount.MoneyToDouble(),
CalculationMonth = data.CalculationMonth,
CalculationYear = data.CalculationYear,
SalaryDateTime = data.SalaryDateTime,
};
return res;
}
[HttpDelete("{id:long}")]
public ActionResult<OperationResult> Delete(long id)
{
var result = _salaryAidApplication.Remove(id);
return result;
}
[HttpPost("validate-excel")]
public ActionResult<ExcelValidation<SalaryAidImportData>> ValidateExcel([FromForm]ValidateExcelRequest request)
{
var validation = _salaryAidImportExcel.ReadAndValidateExcel(request.Excel, _workshopId);
return validation;
}
[HttpPost("create-from-excel")]
public async Task<ActionResult<OperationResult>> OnPostCreateFromExcelData(List<SalaryAidImportData> data)
{
var commands = data.Select(x => new CreateSalaryAidViewModel()
{
WorkshopId = x.WorkshopId,
Amount = x.Amount.ToMoney(),
EmployeeIds = [x.EmployeeId],
SalaryDateTime = x.SalaryAidDateTime,
NationalCode = x.NationalCode,
CalculationMonth = x.calculationMonth,
CalculationYear = x.calculationYear
}).ToList();
OperationResult result = await _salaryAidApplication.CreateRangeAsync(commands);
return new JsonResult(new
{
result.IsSuccedded,
result.Message
});
}
}
public class ValidateExcelRequest
{
public IFormFile Excel { get; set; }
}
public class EditSalaryAidRequest
{
public long Id { get; set; }
public long EmployeeId { get; set; }
public double Amount { get; set; }
public string SalaryDateTime { get; set; }
public int CalculationMonth { get; set; }
public int CalculationYear { get; set; }
}
public class CreateSalaryAidRequest
{
public List<long> EmployeeIds { get; set; }
public double Amount { get; set; }
public string SalaryDateTime { get; set; }
public int CalculationMonth { get; set; }
public int CalculationYear { get; set; }
}