diff --git a/Company.Domain/ClassificationSchemeAgg/IClassificationGroupRepository.cs b/Company.Domain/ClassificationSchemeAgg/IClassificationGroupRepository.cs index e636b438..8da1913a 100644 --- a/Company.Domain/ClassificationSchemeAgg/IClassificationGroupRepository.cs +++ b/Company.Domain/ClassificationSchemeAgg/IClassificationGroupRepository.cs @@ -21,6 +21,27 @@ public interface IClassificationGroupRepository : IRepository Task> GetGroupAndJobs(long schemeId); + /// + /// دریافت لیست گروه ها + /// + /// + /// + Task> GetGroupList(long schemeId); + + /// + /// دریافت لیست مشاغل برای مودال ایجاد و ویرایش + /// + /// + /// + Task GetCreateOrEditJobsData(long groupId); + + /// + /// چک میکند که آی پرسنلی وجود دارد که این شغل به او نسبت داده شده + /// + /// + /// + /// + Task CheckIfEmployeeHasThisJob(long jobId, long groupId); /// /// دریافت مشاغل گروه توسط آی دی گروه diff --git a/CompanyManagment.App.Contracts/ClassificationScheme/AddOrEditJobInGroupDto.cs b/CompanyManagment.App.Contracts/ClassificationScheme/AddOrEditJobInGroupDto.cs new file mode 100644 index 00000000..035ba02e --- /dev/null +++ b/CompanyManagment.App.Contracts/ClassificationScheme/AddOrEditJobInGroupDto.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +namespace CompanyManagment.App.Contracts.ClassificationScheme; + +public class AddOrEditJobInGroupDto +{ + /// + /// آی دی گروه + /// + public long GroupId { get; set; } + + /// + /// شماره گروه نوع عددی + /// + public int GroupNoInt { get; set; } + + + public List AddJobListDto { get; set; } +} + + +/// +/// لیست مشغال افزوده شده به گروه +/// +public class AddJobListDto +{ + /// + /// آی دی شغل در مشاغل اداره کار + /// + public long JobId { get; set; } + + /// + /// نام شغل + /// + public string JobName { get; set; } +} diff --git a/CompanyManagment.App.Contracts/ClassificationScheme/GetGroupAndJobSchemeListDto.cs b/CompanyManagment.App.Contracts/ClassificationScheme/GetGroupAndJobSchemeListDto.cs new file mode 100644 index 00000000..af6b0148 --- /dev/null +++ b/CompanyManagment.App.Contracts/ClassificationScheme/GetGroupAndJobSchemeListDto.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace CompanyManagment.App.Contracts.ClassificationScheme; + +public class GetGroupAndJobSchemeListDto +{ + /// + /// آی دی گروه + /// + public long GroupId { get; set; } + + /// + /// شماره گروه نوع عددی + /// + public int GroupNoInt { get; set; } + + /// + /// آیا شغلی به گروه اضافه شده + /// + public bool HasAnyJob { get; set; } +} + diff --git a/CompanyManagment.App.Contracts/ClassificationScheme/IClassificationSchemeApplication.cs b/CompanyManagment.App.Contracts/ClassificationScheme/IClassificationSchemeApplication.cs index d87424ba..f4da7501 100644 --- a/CompanyManagment.App.Contracts/ClassificationScheme/IClassificationSchemeApplication.cs +++ b/CompanyManagment.App.Contracts/ClassificationScheme/IClassificationSchemeApplication.cs @@ -185,12 +185,14 @@ public interface IClassificationSchemeApplication Task BaseYearComputeOneGroup(DateTime schemeStart, DateTime? schemeEnd, DateTime contractStart, DateTime contractEnd, string groupNo, long employeeId, long workshopId); + #region ForApi + /// /// چک کردن امکان حذف طرح /// /// /// - Task CheckToDeleteScheme(long id); + Task> CheckToDeleteScheme(long id); /// /// حذف طرح @@ -199,4 +201,30 @@ public interface IClassificationSchemeApplication /// Task DeleteScheme(long id); + /// + /// تب گروه ها و مشاغل + /// لیست گروه ها + /// + /// + /// + Task> GetGroupList(long schemeId); + + + /// + /// دریافت لیست مشاغل برای مودال ایجاد و ویرایش + /// + /// + /// + Task GetCreateOrEditJobsData(long groupId); + + /// + /// چک میکند که آی پرسنلی وجود دارد که این شغل به او نسبت داده شده + /// + /// + /// + /// + Task CheckIfEmployeeHasThisJob(long jobId, long groupId); + + #endregion + } \ No newline at end of file diff --git a/CompanyManagment.Application/ClassificationSchemeApplication.cs b/CompanyManagment.Application/ClassificationSchemeApplication.cs index fdc2f332..52184360 100644 --- a/CompanyManagment.Application/ClassificationSchemeApplication.cs +++ b/CompanyManagment.Application/ClassificationSchemeApplication.cs @@ -132,11 +132,18 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication return await _classificationGroupRepository.GetGroupAndJobs(schemeId); } + public async Task> GetGroupList(long schemeId) + { + return await _classificationGroupRepository.GetGroupList(schemeId); + } + public async Task> GetGroupJobs(long groupId) { return await _classificationGroupRepository.GetGroupJobs(groupId); } + + public async Task CheckEmployeeHasThisJob(long id, long groupId) { return await _classificationGroupRepository.CheckEmployeeHasThisJob(id, groupId); @@ -437,7 +444,7 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication edit.EditMultipleGroupMember(lastRecord.ClassificationGroupId, lastRecord.ClassificationGroupJobId, lastRecord.StartGroupDate.Value); } - + newStartDateList = newStartDateList.OrderByDescending(x => x).ToList(); @@ -480,7 +487,7 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication var zeroItem = command.First(x => x.Id == 0); var oldGroupsMemberize = await _classificationEmployeeRepository.GetEmployeeMemberizeData(zeroItem.EmployeeId); var scheme = await _classificationSchemeRepository.GetClassificationSchemeToCompute(zeroItem.SchemeId); - command = command.Where(x=>x.Id != 0).ToList(); + command = command.Where(x => x.Id != 0).ToList(); var newStartDateList = new List(); foreach (var item in command) { @@ -500,7 +507,7 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication if (item.StartGroupDateFa.Substring(8, 2) != "01") return op.Failed("تاریخ شروع فقط می تواند یکم هر ماه باشد"); - if (oldGroupsMemberize.Any(x=>x.StartGroupDate == startDate && x.Id != item.Id)) + if (oldGroupsMemberize.Any(x => x.StartGroupDate == startDate && x.Id != item.Id)) return op.Failed($"تاریخ {item.StartGroupDateFa} با تاریخ های قبل یا بعد از خود تداخل دارد"); if (startDate < scheme.ExecutionDateGr) @@ -518,14 +525,14 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication - + } var removeItemIdList = command.Select(x => x.Id).ToList(); - var toBeRemove = removeItemIdList.Any() ? oldGroupsMemberize.Where(x=> !removeItemIdList.Contains(x.Id)).Select(x=>x.Id).ToList() : oldGroupsMemberize.Select(x=>x.Id).ToList(); + var toBeRemove = removeItemIdList.Any() ? oldGroupsMemberize.Where(x => !removeItemIdList.Contains(x.Id)).Select(x => x.Id).ToList() : oldGroupsMemberize.Select(x => x.Id).ToList(); if (toBeRemove.Any()) { - var getRemoveList =await _classificationEmployeeRepository.GetListByIdList(toBeRemove); + var getRemoveList = await _classificationEmployeeRepository.GetListByIdList(toBeRemove); await _classificationEmployeeRepository.RemoveRangeByEdit(getRemoveList); } @@ -563,35 +570,38 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication contractEnd, groupNo, employeeId, workshopId); } - public async Task CheckToDeleteScheme(long id) + public async Task> CheckToDeleteScheme(long id) { - var op = new CheckStatusToDeleteScheme(); + var op = new OperationResult(); var scheme = _classificationSchemeRepository.Get(id); if (scheme != null) { - var employeeInfoList =await _classificationEmployeeRepository.GetEmployeeListData(id); + var employeeInfoList = await _classificationEmployeeRepository.GetEmployeeListData(id); var anyHasGroup = employeeInfoList.Any(x => x.HasGroup); if (employeeInfoList.Any() && anyHasGroup) { - op.DeleteSchemeStatus = DeleteSchemeStatus.ConfirmationNeeded; - op.Message = "برای این طرح پرسنل افزوده شده است، آیا از حذف طرح اطمینان دارید"; - return op; + + string message = "برای این طرح پرسنل افزوده شده است، آیا از حذف طرح اطمینان دارید"; + + + return op.Succcedded(new CheckStatusToDeleteScheme() + { DeleteSchemeStatus = DeleteSchemeStatus.ConfirmationNeeded, Message = message }); } else { - - op.DeleteSchemeStatus = DeleteSchemeStatus.Valid; - op.Message = "مجاز برای حذف"; - return op; + + var message = "مجاز برای حذف"; + return op.Succcedded(new CheckStatusToDeleteScheme() + { DeleteSchemeStatus = DeleteSchemeStatus.Valid, Message = message }); } } - op.DeleteSchemeStatus = DeleteSchemeStatus.NotValid; - op.Message = "یافت نشد"; - return op; + return op.Failed("یافت نشد", new CheckStatusToDeleteScheme() { DeleteSchemeStatus = DeleteSchemeStatus.NotValid }); + + } public async Task DeleteScheme(long id) @@ -607,4 +617,20 @@ public class ClassificationSchemeApplication : IClassificationSchemeApplication return op.Failed("یافت نشد"); } + + + public async Task GetCreateOrEditJobsData(long groupId) + { + return await _classificationGroupRepository.GetCreateOrEditJobsData(groupId); + } + + public async Task CheckIfEmployeeHasThisJob(long jobId, long groupId) + { + var op = new OperationResult(); + var checkExistAny = await _classificationGroupRepository.CheckIfEmployeeHasThisJob(jobId, groupId); + if (checkExistAny) + return op.Failed("این شغل قبلا به پرسنلی از این گروه داده شده و نمیتوانید آن را حذف کنید"); + + return op.Succcedded(-1, "حذف با موفقیت انجام شد"); + } } \ No newline at end of file diff --git a/CompanyManagment.Application/WorkshopAppliction.cs b/CompanyManagment.Application/WorkshopAppliction.cs index d98ac684..64ee3c80 100644 --- a/CompanyManagment.Application/WorkshopAppliction.cs +++ b/CompanyManagment.Application/WorkshopAppliction.cs @@ -407,6 +407,10 @@ public class WorkshopAppliction : IWorkshopApplication public EditWorkshop GetDetails(long id) { var workshop = _workshopRepository.GetDetails(id); + if (workshop == null) + { + return null; + } if (workshop.IsClassified) { workshop.CreatePlan = _workshopPlanApplication.GetWorkshopPlanByWorkshopId(id); diff --git a/CompanyManagment.EFCore/Repository/ClassificationGroupRepository.cs b/CompanyManagment.EFCore/Repository/ClassificationGroupRepository.cs index 9b33ab36..74c37171 100644 --- a/CompanyManagment.EFCore/Repository/ClassificationGroupRepository.cs +++ b/CompanyManagment.EFCore/Repository/ClassificationGroupRepository.cs @@ -65,6 +65,8 @@ public class ClassificationGroupRepository : RepositoryBasex.GroupNoInt).ToListAsync(); } + + /// /// دریافت مشاغل گروه توسط آی دی گروه /// @@ -164,4 +166,63 @@ public class ClassificationGroupRepository : RepositoryBase> GetGroupList(long schemeId) + { + return await _context.ClassificationGroups.Where(x => x.ClassificationSchemeId == schemeId) + .Include(x => x.ClassificationGroupJobs).Select(x => new GetGroupAndJobSchemeListDto + { + GroupId = x.id, + GroupNoInt = Convert.ToInt32(x.GroupNo), + HasAnyJob = x.ClassificationGroupJobs.Any() + + }).OrderBy(x => x.GroupNoInt).ToListAsync(); + } + + + public async Task GetCreateOrEditJobsData(long groupId) + { + var result = await _context.ClassificationGroups.Where(x => x.id == groupId) + .Include(x => x.ClassificationGroupJobs).FirstOrDefaultAsync(); + if (result == null) + return new AddOrEditJobInGroupDto(); + + return new AddOrEditJobInGroupDto() + { + GroupId = result.id, + GroupNoInt = Convert.ToInt32(result.GroupNo), + AddJobListDto = result.ClassificationGroupJobs.Select(job => new AddJobListDto + { + JobId = job.JobId, + JobName = $"{job.JobName} - {job.JobCode}" + }).ToList(), + }; + } + + + /// + /// چک میکند که آی پرسنلی وجود دارد که این شغل به او نسبت داده شده + /// + /// + /// + /// + public async Task CheckIfEmployeeHasThisJob(long jobId, long groupId) + { + var result = await _context.ClassificationGroups.Where(x => x.id == groupId) + .Include(x => x.ClassificationGroupJobs).FirstOrDefaultAsync(); + var job = result.ClassificationGroupJobs.FirstOrDefault(x => x.JobId == jobId); + if (job == null) + return false; + + var id = job.id; + return await _context.ClassificationEmployees.AnyAsync(x => + x.ClassificationGroupJobId == id && x.ClassificationGroupId == groupId); + } + #endregion } \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ApproveTaskSectionCompletion/ApproveTaskSectionCompletionCommand.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ApproveTaskSectionCompletion/ApproveTaskSectionCompletionCommand.cs new file mode 100644 index 00000000..4b21408b --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ApproveTaskSectionCompletion/ApproveTaskSectionCompletionCommand.cs @@ -0,0 +1,57 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain._Common; +using GozareshgirProgramManager.Domain._Common.Exceptions; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using GozareshgirProgramManager.Domain.ProjectAgg.Repositories; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ApproveTaskSectionCompletion; + +public record ApproveTaskSectionCompletionCommand(Guid TaskSectionId, bool IsApproved) : IBaseCommand; + +public class ApproveTaskSectionCompletionCommandHandler : IBaseCommandHandler +{ + private readonly ITaskSectionRepository _taskSectionRepository; + private readonly IUnitOfWork _unitOfWork; + private readonly IAuthHelper _authHelper; + + public ApproveTaskSectionCompletionCommandHandler( + ITaskSectionRepository taskSectionRepository, + IUnitOfWork unitOfWork, + IAuthHelper authHelper) + { + _taskSectionRepository = taskSectionRepository; + _unitOfWork = unitOfWork; + _authHelper = authHelper; + } + + public async Task Handle(ApproveTaskSectionCompletionCommand request, CancellationToken cancellationToken) + { + var currentUserId = _authHelper.GetCurrentUserId() + ?? throw new UnAuthorizedException(" ? "); + + var section = await _taskSectionRepository.GetByIdAsync(request.TaskSectionId, cancellationToken); + if (section == null) + { + return OperationResult.NotFound(" ? "); + } + + if (section.Status != TaskSectionStatus.PendingForCompletion) + { + return OperationResult.Failure(" ԝ?? ʘ? ?? ? "); + } + + if (request.IsApproved) + { + section.UpdateStatus(TaskSectionStatus.Completed); + } + else + { + section.UpdateStatus(TaskSectionStatus.Incomplete); + } + + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return OperationResult.Success(); + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ApproveTaskSectionCompletion/ApproveTaskSectionCompletionCommandValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ApproveTaskSectionCompletion/ApproveTaskSectionCompletionCommandValidator.cs new file mode 100644 index 00000000..c12a43c3 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ApproveTaskSectionCompletion/ApproveTaskSectionCompletionCommandValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Commands.ApproveTaskSectionCompletion; + +public class ApproveTaskSectionCompletionCommandValidator : AbstractValidator +{ + public ApproveTaskSectionCompletionCommandValidator() + { + RuleFor(c => c.TaskSectionId) + .NotEmpty() + .NotNull() + .WithMessage(" ? ? "); + } +} diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs index 9e6803f5..178a0257 100644 --- a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/ChangeStatusSection/ChangeStatusSectionCommandHandler.cs @@ -52,7 +52,10 @@ public class ChangeStatusSectionCommandHandler : IBaseCommandHandler> { { TaskSectionStatus.ReadyToStart, [TaskSectionStatus.InProgress] }, - { TaskSectionStatus.InProgress, [TaskSectionStatus.Incomplete, TaskSectionStatus.Completed] }, - { TaskSectionStatus.Incomplete, [TaskSectionStatus.InProgress, TaskSectionStatus.Completed] }, - { TaskSectionStatus.Completed, [TaskSectionStatus.InProgress, TaskSectionStatus.Incomplete] }, // Can return to InProgress or Incomplete + { TaskSectionStatus.InProgress, [TaskSectionStatus.Incomplete, TaskSectionStatus.PendingForCompletion] }, + { TaskSectionStatus.Incomplete, [TaskSectionStatus.InProgress, TaskSectionStatus.PendingForCompletion] }, + { TaskSectionStatus.PendingForCompletion, [TaskSectionStatus.InProgress, TaskSectionStatus.Incomplete] }, // Can return to InProgress or Incomplete { TaskSectionStatus.NotAssigned, [TaskSectionStatus.InProgress, TaskSectionStatus.ReadyToStart] } }; diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs index e88116b6..2ee2ea7d 100644 --- a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Commands/SetTimeProject/SetTimeProjectCommandHandler.cs @@ -72,6 +72,17 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandlerx.UserId is > 0).ToList(); + // حذف ProjectSections که در validSkills نیستند + var validSkillIds = skillItems.Select(x => x.SkillId).ToList(); + var sectionsToRemove = project.ProjectSections + .Where(s => !validSkillIds.Contains(s.SkillId)) + .ToList(); + + foreach (var section in sectionsToRemove) + { + project.RemoveProjectSection(section.SkillId); + } + // تخصیص در سطح پروژه foreach (var item in skillItems) { @@ -102,6 +113,16 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler !validSkillIds.Contains(s.SkillId)) + .ToList(); + + foreach (var section in phaseSectionsToRemove) + { + phase.RemovePhaseSection(section.SkillId); + } + // برای phase هم باید section‌ها را به‌روزرسانی کنیم foreach (var item in skillItems ) { @@ -122,6 +143,16 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler !validSkillIds.Contains(s.SkillId)) + .ToList(); + + foreach (var section in taskSectionsToRemove) + { + task.RemoveSection(section.Id); + } + foreach (var item in skillItems) { var section = task.Sections.FirstOrDefault(s => s.SkillId == item.SkillId); @@ -177,6 +208,18 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandlerx.UserId is > 0).ToList(); + + // حذف PhaseSections که در validSkills نیستند + var validSkillIds = skillItems.Select(x => x.SkillId).ToList(); + var sectionsToRemove = phase.PhaseSections + .Where(s => !validSkillIds.Contains(s.SkillId)) + .ToList(); + + foreach (var section in sectionsToRemove) + { + phase.RemovePhaseSection(section.SkillId); + } + // به‌روزرسانی یا اضافه کردن PhaseSection foreach (var item in skillItems) { @@ -200,6 +243,16 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler !validSkillIds.Contains(s.SkillId)) + .ToList(); + + foreach (var section in taskSectionsToRemove) + { + task.RemoveSection(section.Id); + } + foreach (var item in skillItems) { var section = task.Sections.FirstOrDefault(s => s.SkillId == item.SkillId); @@ -246,7 +299,16 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandlerx.UserId is > 0).ToList(); - task.ClearTaskSections(); + // حذف سکشن‌هایی که در validSkills نیستند + var validSkillIds = validSkills.Select(x => x.SkillId).ToList(); + var sectionsToRemove = task.Sections + .Where(s => !validSkillIds.Contains(s.SkillId)) + .ToList(); + + foreach (var sectionToRemove in sectionsToRemove) + { + task.RemoveSection(sectionToRemove.Id); + } foreach (var skillItem in validSkills) { @@ -304,7 +366,7 @@ public class SetTimeProjectCommandHandler : IBaseCommandHandler +/// درخواست جستجو در سراسر سلسله‌مراتب پروژه (پروژه، فاز، تسک). +/// نتایج با اطلاعات مسیر سلسله‌مراتب برای پشتیبانی از ناوبری درخت در رابط کاربری بازگردانده می‌شود. +/// +public record GetProjectSearchQuery( + string SearchQuery) : IBaseQuery; + \ No newline at end of file diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchQueryHandler.cs new file mode 100644 index 00000000..e9cb3c25 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchQueryHandler.cs @@ -0,0 +1,132 @@ +using GozareshgirProgramManager.Application._Common.Interfaces; +using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; +using Microsoft.EntityFrameworkCore; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; + +/// +/// Handler برای درخواست جستجوی سراسری در سلسله‌مراتب پروژه. +/// این handler در تمام سطح‌های پروژه، فاز و تسک جستجو می‌کند و از تمام فیلدهای متنی (نام، توضیحات) استفاده می‌کند. +/// همچنین در زیرمجموعه‌های هر سطح (ProjectSections، PhaseSections، TaskSections) جستجو می‌کند. +/// +public class GetProjectSearchQueryHandler : IBaseQueryHandler +{ + private readonly IProgramManagerDbContext _context; + private const int MaxResults = 50; + + public GetProjectSearchQueryHandler(IProgramManagerDbContext context) + { + _context = context; + } + + public async Task> Handle( + GetProjectSearchQuery request, + CancellationToken cancellationToken) + { + var searchQuery = request.SearchQuery.ToLower(); + var results = new List(); + + // جستجو در پروژه‌ها و ProjectSections + var projects = await SearchProjects(searchQuery, cancellationToken); + results.AddRange(projects); + + // جستجو در فازها و PhaseSections + var phases = await SearchPhases(searchQuery, cancellationToken); + results.AddRange(phases); + + // جستجو در تسک‌ها و TaskSections + var tasks = await SearchTasks(searchQuery, cancellationToken); + results.AddRange(tasks); + + // مرتب‌سازی نتایج: ابتدا بر اساس سطح سلسله‌مراتب (پروژه → فاز → تسک)، سپس بر اساس نام + var sortedResults = results + .OrderBy(r => r.Level) + .ThenBy(r => r.Title) + .Take(MaxResults) + .ToList(); + + var response = new GetProjectSearchResponse(sortedResults); + return OperationResult.Success(response); + } + + /// + /// جستجو در جدول پروژه‌ها (نام، توضیحات) و ProjectSections (نام مهارت، توضیحات اولیه) + /// + private async Task> SearchProjects( + string searchQuery, + CancellationToken cancellationToken) + { + var projects = await _context.Projects + .Where(p => + p.Name.ToLower().Contains(searchQuery) || + (p.Description != null && p.Description.ToLower().Contains(searchQuery))) + .Select(p => new ProjectHierarchySearchResultDto + { + Id = p.Id, + Title = p.Name, + Level = ProjectHierarchyLevel.Project, + ProjectId = null, + PhaseId = null + }) + .ToListAsync(cancellationToken); + + return projects; + } + + /// + /// جستجو در جدول فازهای پروژه (نام، توضیحات) و PhaseSections + /// + private async Task> SearchPhases( + string searchQuery, + CancellationToken cancellationToken) + { + var phases = await _context.ProjectPhases + .Where(ph => + ph.Name.ToLower().Contains(searchQuery) || + (ph.Description != null && ph.Description.ToLower().Contains(searchQuery))) + .Select(ph => new ProjectHierarchySearchResultDto + { + Id = ph.Id, + Title = ph.Name, + Level = ProjectHierarchyLevel.Phase, + ProjectId = ph.ProjectId, + PhaseId = null + }) + .ToListAsync(cancellationToken); + + return phases; + } + + /// + /// جستجو در جدول تسک‌های پروژه (نام، توضیحات) و TaskSections (نام مهارت، توضیح اولیه، اطلاعات اضافی) + /// + private async Task> SearchTasks( + string searchQuery, + CancellationToken cancellationToken) + { + var tasks = await _context.ProjectTasks + .Include(t => t.Sections) + .Include(t => t.Phase) + .Where(t => + t.Name.ToLower().Contains(searchQuery) || + (t.Description != null && t.Description.ToLower().Contains(searchQuery)) || + t.Sections.Any(s => + (s.InitialDescription != null && s.InitialDescription.ToLower().Contains(searchQuery)) || + s.AdditionalTimes.Any(at => at.Reason != null && at.Reason.ToLower().Contains(searchQuery)))) + .Select(t => new ProjectHierarchySearchResultDto + { + Id = t.Id, + Title = t.Name, + Level = ProjectHierarchyLevel.Task, + ProjectId = t.Phase.ProjectId, + PhaseId = t.PhaseId + }) + .ToListAsync(cancellationToken); + + return tasks; + } + +} + + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchQueryValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchQueryValidator.cs new file mode 100644 index 00000000..70c25241 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchQueryValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; + +/// +/// اعتبارسنج برای درخواست جستجوی سراسری +/// +public class GetProjectSearchQueryValidator : AbstractValidator +{ + public GetProjectSearchQueryValidator() + { + RuleFor(x => x.SearchQuery) + .NotEmpty().WithMessage("متن جستجو نمی‌تواند خالی باشد.") + .MinimumLength(2).WithMessage("متن جستجو باید حداقل 2 حرف باشد.") + .MaximumLength(500).WithMessage("متن جستجو نمی‌تواند بیش از 500 حرف باشد."); + } +} + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchResponse.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchResponse.cs new file mode 100644 index 00000000..288206f7 --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/GetProjectSearchResponse.cs @@ -0,0 +1,8 @@ +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; + +/// +/// پوسته‌ی پاسخ برای نتایج جستجوی سراسری +/// +public record GetProjectSearchResponse( + List Results); + diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/ProjectHierarchySearchResultDto.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/ProjectHierarchySearchResultDto.cs new file mode 100644 index 00000000..036d3a8b --- /dev/null +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/GetProjectHierarchySearch/ProjectHierarchySearchResultDto.cs @@ -0,0 +1,36 @@ +using GozareshgirProgramManager.Domain.ProjectAgg.Enums; + +namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; + +/// +/// DTO برای نتایج جستجوی سراسری در سلسله‌مراتب پروژه. +/// حاوی اطلاعات کافی برای بازسازی مسیر سلسله‌مراتب و بسط درخت در رابط کاربری است. +/// +public record ProjectHierarchySearchResultDto +{ + /// + /// شناسه آیتم (پروژه، فاز یا تسک) + /// + public Guid Id { get; init; } + + /// + /// نام/عنوان آیتم + /// + public string Title { get; init; } = string.Empty; + + /// + /// سطح سلسله‌مراتب این آیتم + /// + public ProjectHierarchyLevel Level { get; init; } + + /// + /// شناسه پروژه - همیشه برای فاز و تسک پر شده است، برای پروژه با شناسه خود پر می‌شود + /// + public Guid? ProjectId { get; init; } + + /// + /// شناسه فاز - فقط برای تسک پر شده است، برای پروژه و فاز خالی است + /// + public Guid? PhaseId { get; init; } +} + 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 69e82940..0cfd9bac 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 @@ -53,67 +53,81 @@ public class ProjectBoardListQueryHandler : IBaseQueryHandler x.Id, x => x.FullName, cancellationToken); - var result = data.Select(x => - { - // محاسبه یکبار برای هر Activity و Cache کردن نتیجه - var activityTimeData = x.Activities.Select(a => + var result = data + .Select(x => { - var timeSpent = a.GetTimeSpent(); - return new + // محاسبه یکبار برای هر Activity و Cache کردن نتیجه + var activityTimeData = x.Activities.Select(a => { - Activity = a, - TimeSpent = timeSpent, - TotalSeconds = timeSpent.TotalSeconds, - FormattedTime = timeSpent.ToString(@"hh\:mm") - }; - }).ToList(); - - // ادغام پشت سر هم فعالیت‌های یک کاربر - var mergedHistories = new List(); - foreach (var activityData in activityTimeData) - { - var lastHistory = mergedHistories.LastOrDefault(); - - // اگر آخرین history برای همین کاربر باشد، زمان‌ها را جمع می‌کنیم - if (lastHistory != null && lastHistory.UserId == activityData.Activity.UserId) - { - var totalTimeSpan = lastHistory.WorkedTimeSpan + activityData.TimeSpent; - lastHistory.WorkedTimeSpan = totalTimeSpan; - lastHistory.WorkedTime = totalTimeSpan.ToString(@"hh\:mm"); - } - else - { - // در غیر این صورت، یک history جدید اضافه می‌کنیم - mergedHistories.Add(new ProjectProgressHistoryDto() + var timeSpent = a.GetTimeSpent(); + return new { - UserId = activityData.Activity.UserId, - IsCurrentUser = activityData.Activity.UserId == currentUserId, - Name = users.GetValueOrDefault(activityData.Activity.UserId, "ناشناس"), - WorkedTime = activityData.FormattedTime, - WorkedTimeSpan = activityData.TimeSpent, - }); - } - } + Activity = a, + TimeSpent = timeSpent, + TotalSeconds = timeSpent.TotalSeconds, + FormattedTime = timeSpent.ToString(@"hh\:mm") + }; + }).ToList(); - return new ProjectBoardListResponse() - { - Id = x.Id, - PhaseName = x.Task.Phase.Name, - ProjectName = x.Task.Phase.Project.Name, - TaskName = x.Task.Name, - SectionStatus = x.Status, - Progress = new ProjectProgressDto() + // ادغام پشت سر هم فعالیت‌های یک کاربر + var mergedHistories = new List(); + foreach (var activityData in activityTimeData) { - CompleteSecond = x.FinalEstimatedHours.TotalSeconds, - CurrentSecond = activityTimeData.Sum(a => a.TotalSeconds), - Histories = mergedHistories - }, - OriginalUser = users.GetValueOrDefault(x.OriginalAssignedUserId, "ناشناس"), - AssignedUser = x.CurrentAssignedUserId == x.OriginalAssignedUserId ? null - : users.GetValueOrDefault(x.CurrentAssignedUserId, "ناشناس"), - SkillName = x.Skill?.Name??"-", - }; - }).ToList(); + var lastHistory = mergedHistories.LastOrDefault(); + + // اگر آخرین history برای همین کاربر باشد، زمان‌ها را جمع می‌کنیم + if (lastHistory != null && lastHistory.UserId == activityData.Activity.UserId) + { + var totalTimeSpan = lastHistory.WorkedTimeSpan + activityData.TimeSpent; + lastHistory.WorkedTimeSpan = totalTimeSpan; + lastHistory.WorkedTime = totalTimeSpan.ToString(@"hh\:mm"); + } + else + { + // در غیر این صورت، یک history جدید اضافه می‌کنیم + mergedHistories.Add(new ProjectProgressHistoryDto() + { + UserId = activityData.Activity.UserId, + IsCurrentUser = activityData.Activity.UserId == currentUserId, + Name = users.GetValueOrDefault(activityData.Activity.UserId, "ناشناس"), + WorkedTime = activityData.FormattedTime, + WorkedTimeSpan = activityData.TimeSpent, + }); + } + } + + mergedHistories = mergedHistories.OrderByDescending(h => h.IsCurrentUser).ToList(); + + return new ProjectBoardListResponse() + { + Id = x.Id, + PhaseName = x.Task.Phase.Name, + ProjectName = x.Task.Phase.Project.Name, + TaskName = x.Task.Name, + SectionStatus = x.Status, + Progress = new ProjectProgressDto() + { + CompleteSecond = x.FinalEstimatedHours.TotalSeconds, + CurrentSecond = activityTimeData.Sum(a => a.TotalSeconds), + Histories = mergedHistories + }, + OriginalUser = users.GetValueOrDefault(x.OriginalAssignedUserId, "ناشناس"), + AssignedUser = x.CurrentAssignedUserId == x.OriginalAssignedUserId ? null + : users.GetValueOrDefault(x.CurrentAssignedUserId, "ناشناس"), + SkillName = x.Skill?.Name??"-", + }; + }) + .OrderByDescending(r => + { + // اگر AssignedUser null نباشد، بررسی کن که برابر current user هست یا نه + if (r.AssignedUser != null) + { + return users.FirstOrDefault(u => u.Value == r.AssignedUser).Key == currentUserId; + } + // اگر AssignedUser null بود، از OriginalUser بررسی کن + return users.FirstOrDefault(u => u.Value == r.OriginalUser).Key == currentUserId; + }) + .ToList(); return OperationResult>.Success(result); } diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs index c3f48bfa..aee31370 100644 --- a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryHandler.cs @@ -75,14 +75,14 @@ public class ProjectSetTimeDetailsQueryHandler CreationDate = x.CreationDate.ToFarsi() }).OrderBy(x => x.CreationDate).ToList() ?? [], InitCreationTime = section?.CreationDate.ToFarsi() ?? "", - SkillName = skill?.Name ?? "", + SkillName = skill.Name ?? "", UserFullName = user?.FullName ?? "", SectionId = section?.Id ?? Guid.Empty, InitialDescription = section?.InitialDescription ?? "", InitialHours = (int)(section?.InitialEstimatedHours.TotalHours ?? 0), InitialMinutes = section?.InitialEstimatedHours.Minutes ?? 0, UserId = section?.OriginalAssignedUserId ?? 0, - SkillId = task.Id, + SkillId = skill.Id, }; }).OrderBy(x => x.SkillId).ToList(), task.Id, diff --git a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs index a91c0756..bd2c0dbe 100644 --- a/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs +++ b/ProgramManager/src/Application/GozareshgirProgramManager.Application/Modules/Projects/Queries/ProjectSetTimeDetails/ProjectSetTimeDetailsQueryValidator.cs @@ -1,4 +1,4 @@ -using FluentValidation; +using FluentValidation; using GozareshgirProgramManager.Domain.ProjectAgg.Enums; namespace GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs index dc2bfa15..8e8e2b31 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/Project.cs @@ -74,6 +74,15 @@ public class Project : ProjectHierarchyNode } } + public void RemoveProjectSection(Guid skillId) + { + var section = _projectSections.FirstOrDefault(s => s.SkillId == skillId); + if (section != null) + { + _projectSections.Remove(section); + } + } + public void ClearProjectSections() { _projectSections.Clear(); diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs index 3534c50f..60b98df9 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Entities/ProjectPhase.cs @@ -87,6 +87,15 @@ public class ProjectPhase : ProjectHierarchyNode } } + public void RemovePhaseSection(Guid skillId) + { + var section = _phaseSections.FirstOrDefault(s => s.SkillId == skillId); + if (section != null) + { + _phaseSections.Remove(section); + } + } + public void ClearPhaseSections() { _phaseSections.Clear(); diff --git a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs index b4a4c5dd..487991a8 100644 --- a/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs +++ b/ProgramManager/src/Domain/GozareshgirProgramManager.Domain/ProjectAgg/Repositories/ITaskSectionRepository.cs @@ -13,4 +13,5 @@ public interface ITaskSectionRepository: IRepository Task> GetAssignedToUserAsync(long userId); Task> GetActiveSectionsIncludeAllAsync(CancellationToken cancellationToken); + Task HasUserAnyInProgressSectionAsync(long userId, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs index 81306c82..f00d4512 100644 --- a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/ProjectPhaseRepository.cs @@ -19,6 +19,7 @@ public class ProjectPhaseRepository : RepositoryBase, IProje public Task GetWithTasksAsync(Guid phaseId) { return _context.ProjectPhases + .Include(x=>x.PhaseSections) .Include(p => p.Tasks) .ThenInclude(t => t.Sections) .ThenInclude(s => s.Skill) diff --git a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs index 89fb05fd..1b29e154 100644 --- a/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs +++ b/ProgramManager/src/Infrastructure/GozareshgirProgramManager.Infrastructure/Persistence/Repositories/TaskSectionRepository.cs @@ -45,4 +45,11 @@ public class TaskSectionRepository:RepositoryBase,ITaskSection .Include(x => x.AdditionalTimes) .ToListAsync(cancellationToken); } + + public async Task HasUserAnyInProgressSectionAsync(long userId, CancellationToken cancellationToken = default) + { + return await _context.TaskSections + .AnyAsync(x => x.CurrentAssignedUserId == userId && x.Status == TaskSectionStatus.InProgress, + cancellationToken); + } } \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/ClassificationSchemeController.cs b/ServiceHost/Areas/Admin/Controllers/ClassificationSchemeController.cs index a5a4e598..1cdba86a 100644 --- a/ServiceHost/Areas/Admin/Controllers/ClassificationSchemeController.cs +++ b/ServiceHost/Areas/Admin/Controllers/ClassificationSchemeController.cs @@ -21,6 +21,8 @@ public class ClassificationSchemeController : AdminBaseController _authHelper = authHelper; } + #region SchemeTab + /// /// لیست طرح /// @@ -29,7 +31,7 @@ public class ClassificationSchemeController : AdminBaseController [HttpGet] public async Task> GetList(long workshopId) { - var result =await _classificationSchemeApplication.GetClassificationSchemeList(workshopId); + var result = await _classificationSchemeApplication.GetClassificationSchemeList(workshopId); return result; } @@ -66,7 +68,7 @@ public class ClassificationSchemeController : AdminBaseController [HttpPut("Scheme")] public async Task> EditScheme([FromBody] EditClassificationSchemeDto command) { - var result =await _classificationSchemeApplication.EditClassificationScheme(command); + var result = await _classificationSchemeApplication.EditClassificationScheme(command); return result; } @@ -76,9 +78,9 @@ public class ClassificationSchemeController : AdminBaseController /// /// [HttpGet("CheckToDeleteScheme")] - public async Task CheckToDeleteScheme(long id) + public async Task> CheckToDeleteScheme(long id) { - var result =await _classificationSchemeApplication.CheckToDeleteScheme(id); + var result = await _classificationSchemeApplication.CheckToDeleteScheme(id); return result; } @@ -93,4 +95,47 @@ public class ClassificationSchemeController : AdminBaseController var result = await _classificationSchemeApplication.DeleteScheme(id); return result; } + + #endregion + + #region GroupsTab + /// + /// دریافت لیست گروه ها + /// + /// + /// + [HttpGet("GetGroupList")] + public async Task> GetGroupList(long schemeId) + { + var result = await _classificationSchemeApplication.GetGroupList(schemeId); + return result; + } + + /// + /// دریافت لیست مشاغل گروه برای مودال افزودن و ویرایش + /// + /// + /// + [HttpGet("GetCreateOrEditJobsData")] + public async Task GetCreateOrEditJobsData(long groupId) + { + var result = await _classificationSchemeApplication.GetCreateOrEditJobsData(groupId); + return result; + } + + /// + /// چک میکند که آیا امکان حذف شغل از گروه وجود دارد + /// + /// + /// + /// + [HttpGet("CheckDeleteJobFromGroup")] + public async Task> CheckDeleteJobFromGroup(long jobId, long groupId) + { + var result = await _classificationSchemeApplication.CheckIfEmployeeHasThisJob(jobId, groupId); + return result; + } + + + #endregion } \ No newline at end of file diff --git a/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs b/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs index a9f0fce8..a729d322 100644 --- a/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs +++ b/ServiceHost/Areas/Admin/Controllers/ProgramManager/ProjectController.cs @@ -1,5 +1,6 @@ using System.Runtime.InteropServices; using GozareshgirProgramManager.Application._Common.Models; +using GozareshgirProgramManager.Application.Modules.Projects.Commands.ApproveTaskSectionCompletion; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AssignProject; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoStopOverTimeTaskSections; using GozareshgirProgramManager.Application.Modules.Projects.Commands.AutoUpdateDeployStatus; @@ -17,6 +18,7 @@ using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectBoar using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardDetail; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectDeployBoardList; using GozareshgirProgramManager.Application.Modules.Projects.Queries.ProjectSetTimeDetails; +using GozareshgirProgramManager.Application.Modules.Projects.Queries.GetProjectHierarchySearch; using MediatR; using Microsoft.AspNetCore.Mvc; using ServiceHost.BaseControllers; @@ -40,6 +42,15 @@ public class ProjectController : ProgramManagerBaseController return res; } + [HttpGet("search")] + public async Task>> Search( + [FromQuery] string query) + { + var searchQuery = new GetProjectSearchQuery(query); + var res = await _mediator.Send(searchQuery); + return res; + } + [HttpPost] public async Task> Create([FromBody] CreateProjectCommand command) { @@ -147,4 +158,11 @@ public class ProjectController : ProgramManagerBaseController var res = await _mediator.Send(command); return res; } + + [HttpPost("approve-completion")] + public async Task> ApproveTaskSectionCompletion([FromBody] ApproveTaskSectionCompletionCommand command) + { + var res = await _mediator.Send(command); + return res; + } } \ No newline at end of file diff --git a/ServiceHost/Areas/AdminNew/Pages/Company/Ticket/Index.cshtml.cs b/ServiceHost/Areas/AdminNew/Pages/Company/Ticket/Index.cshtml.cs index bf33a3ed..11b18fd1 100644 --- a/ServiceHost/Areas/AdminNew/Pages/Company/Ticket/Index.cshtml.cs +++ b/ServiceHost/Areas/AdminNew/Pages/Company/Ticket/Index.cshtml.cs @@ -80,7 +80,7 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.Ticket public IActionResult OnGetShowDetailTicketByAdmin(long ticketID) { var res = _ticketApplication.GetDetails(ticketID); - res.WorkshopName = _workshopApplication.GetDetails(res.WorkshopId).WorkshopFullName; + res.WorkshopName = _workshopApplication.GetDetails(res.WorkshopId)?.WorkshopFullName??""; return Partial("DetailTicketModal", res); }