From 8be9b05695c9c8c3b75589bad722acbf7fbab488 Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Tue, 11 Nov 2025 17:53:39 +0530 Subject: [PATCH] Checking the client and status when creating service projects --- .../Dtos/ServiceProject/ServiceProjectDto.cs | 24 ++-- .../Master/BasicServiceMasterDto.cs | 8 ++ .../ServiceProject/ServiceProjectList.cs | 28 ----- .../ServiceProject/ServiceProjectVm.cs | 15 +-- .../MappingProfiles/MappingProfile.cs | 3 +- .../Service/ServiceProjectService.cs | 106 ++++++++++++------ 6 files changed, 100 insertions(+), 84 deletions(-) create mode 100644 Marco.Pms.Model/ViewModels/Master/BasicServiceMasterDto.cs delete mode 100644 Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectList.cs diff --git a/Marco.Pms.Model/Dtos/ServiceProject/ServiceProjectDto.cs b/Marco.Pms.Model/Dtos/ServiceProject/ServiceProjectDto.cs index db8322c..b5c7e1e 100644 --- a/Marco.Pms.Model/Dtos/ServiceProject/ServiceProjectDto.cs +++ b/Marco.Pms.Model/Dtos/ServiceProject/ServiceProjectDto.cs @@ -1,22 +1,20 @@ -using Marco.Pms.Model.Master; -using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; -using System.ComponentModel.DataAnnotations.Schema; +using Marco.Pms.Model.ViewModels.Master; namespace Marco.Pms.Model.Dtos.ServiceProject { public class ServiceProjectDto { - public string Name { get; set; } = string.Empty; - public string ShortName { get; set; } = string.Empty; - public Guid ClientId { get; set; } - public required List ServiceIds { get; set; } - public string Address { get; set; } = string.Empty; - public DateTime AssignedDate { get; set; } - public Guid StatusId { get; set; } + public required string Name { get; set; } + public required string ShortName { get; set; } + public required Guid ClientId { get; set; } + public required List Services { get; set; } + public required string Address { get; set; } + public required DateTime AssignedDate { get; set; } + public required Guid StatusId { get; set; } - public string ContactName { get; set; } = string.Empty; - public string ContactPhone { get; set; } = string.Empty; - public string ContactEmail { get; set; } = string.Empty; + public required string ContactName { get; set; } + public required string ContactPhone { get; set; } + public required string ContactEmail { get; set; } } } diff --git a/Marco.Pms.Model/ViewModels/Master/BasicServiceMasterDto.cs b/Marco.Pms.Model/ViewModels/Master/BasicServiceMasterDto.cs new file mode 100644 index 0000000..5a058ff --- /dev/null +++ b/Marco.Pms.Model/ViewModels/Master/BasicServiceMasterDto.cs @@ -0,0 +1,8 @@ +namespace Marco.Pms.Model.ViewModels.Master +{ + public class BasicServiceMasterDto + { + public Guid ServiceId { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectList.cs b/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectList.cs deleted file mode 100644 index 0f0bcde..0000000 --- a/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectList.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Marco.Pms.Model.ViewModels.Activities; -using Marco.Pms.Model.ViewModels.Master; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Marco.Pms.Model.ViewModels.ServiceProject -{ - public class ServiceProjectList - { - - public Guid Id { get; set; } - public string Name { get; set; } = string.Empty; - public string ShortName { get; set; } = string.Empty; - public string Address { get; set; } = string.Empty; - public DateTime AssignedDate { get; set; } - public Guid StatusId { get; set; } - - public BasicEmployeeVM? CreatedBy { get; set; } - public BasicEmployeeVM? UpdatedBy { get; set; } - public DateTime? UpdatedAt { get; set; } - - public DateTime CreatedAt { get; set; } - - } -} diff --git a/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectVm.cs b/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectVm.cs index b032a42..e86d7fd 100644 --- a/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectVm.cs +++ b/Marco.Pms.Model/ViewModels/ServiceProject/ServiceProjectVm.cs @@ -1,22 +1,19 @@ -using Marco.Pms.Model.ViewModels.Activities; +using Marco.Pms.Model.Master; +using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Master; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Marco.Pms.Model.ViewModels.Organization; namespace Marco.Pms.Model.ViewModels.ServiceProject { - public class ServiceProjectVm + public class ServiceProjectVM { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public string ShortName { get; set; } = string.Empty; public string Address { get; set; } = string.Empty; public DateTime AssignedDate { get; set; } - public Guid StatusId { get; set; } - + public StatusMaster? Status { get; set; } + public BasicOrganizationVm? Client { get; set; } public List? Services { get; set; } public BasicEmployeeVM? CreatedBy { get; set; } public BasicEmployeeVM? UpdatedBy { get; set; } diff --git a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs index 2428eea..ef95d37 100644 --- a/Marco.Pms.Services/MappingProfiles/MappingProfile.cs +++ b/Marco.Pms.Services/MappingProfiles/MappingProfile.cs @@ -194,8 +194,7 @@ namespace Marco.Pms.Services.MappingProfiles CreateMap(); - CreateMap(); - CreateMap(); + CreateMap(); #endregion #region ======================================================= Employee ======================================================= diff --git a/Marco.Pms.Services/Service/ServiceProjectService.cs b/Marco.Pms.Services/Service/ServiceProjectService.cs index 08837bd..d2a74ce 100644 --- a/Marco.Pms.Services/Service/ServiceProjectService.cs +++ b/Marco.Pms.Services/Service/ServiceProjectService.cs @@ -2,13 +2,11 @@ using Marco.Pms.DataAccess.Data; using Marco.Pms.Model.Dtos.ServiceProject; using Marco.Pms.Model.Employees; -using Marco.Pms.Model.Entitlements; using Marco.Pms.Model.ServiceProject; using Marco.Pms.Model.Utilities; using Marco.Pms.Model.ViewModels.Activities; -using Marco.Pms.Model.ViewModels.Expanses; using Marco.Pms.Model.ViewModels.Master; -using Marco.Pms.Model.ViewModels.Projects; +using Marco.Pms.Model.ViewModels.Organization; using Marco.Pms.Model.ViewModels.ServiceProject; using Marco.Pms.Services.Helpers; using Marco.Pms.Services.Service.ServiceInterfaces; @@ -27,7 +25,12 @@ namespace Marco.Pms.Services.Service private readonly CacheUpdateHelper _cache; private readonly IMapper _mapper; - public ServiceProjectService(IDbContextFactory dbContextFactory,IServiceScopeFactory serviceScopeFactory, ApplicationDbContext context, ILoggingService logger, CacheUpdateHelper cache, IMapper mapper) + public ServiceProjectService(IDbContextFactory dbContextFactory, + IServiceScopeFactory serviceScopeFactory, + ApplicationDbContext context, + ILoggingService logger, + CacheUpdateHelper cache, + IMapper mapper) { _serviceScopeFactory = serviceScopeFactory; _context = context; @@ -40,16 +43,36 @@ namespace Marco.Pms.Services.Service public async Task> CreateServiceProject(ServiceProjectDto model, Guid tenantId, Employee loggedInEmployee) { - using var scope = _serviceScopeFactory.CreateScope(); - var _firebase = scope.ServiceProvider.GetService(); - - var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.Id == tenantId && t.OrganizationId == loggedInEmployee.OrganizationId); - - if (tenant == null) + var serviceIds = model.Services.Where(s => s.IsActive).Select(s => s.ServiceId).ToList(); + var clientTask = Task.Run(async () => { - _logger.LogWarning("Access DENIED (OrgId:{OrgId}) by Employee {EmployeeId} for tenantId={TenantId}.", - loggedInEmployee.OrganizationId, loggedInEmployee.Id, tenantId); - return ApiResponse.ErrorResponse("Access Denied", "You do not have permission to create a service project for this tenant.", 403); + await using var context = await _dbContextFactory.CreateDbContextAsync(); + return await context.Organizations.FirstOrDefaultAsync(o => o.Id == model.ClientId && o.IsActive); + }); + var serviceTask = Task.Run(async () => + { + await using var context = await _dbContextFactory.CreateDbContextAsync(); + return await context.ServiceMasters.Where(s => serviceIds.Contains(s.Id) && s.TenantId == tenantId && s.IsActive).ToListAsync(); + }); + var statusTask = Task.Run(async () => + { + await using var context = await _dbContextFactory.CreateDbContextAsync(); + return await context.StatusMasters.FirstOrDefaultAsync(s => s.Id == model.StatusId); + }); + + await Task.WhenAll(clientTask, serviceTask, statusTask); + + var client = clientTask.Result; + var services = serviceTask.Result; + var status = statusTask.Result; + + if (client == null) + { + return ApiResponse.ErrorResponse("Client not found", "Client not found", 404); + } + if (status == null) + { + return ApiResponse.ErrorResponse("Project Status not found", "Project Status not found", 404); } var serviceProject = _mapper.Map(model); @@ -59,12 +82,12 @@ namespace Marco.Pms.Services.Service serviceProject.TenantId = tenantId; serviceProject.IsActive = true; - var projectServiceMapping = model.ServiceIds.Select(serviceId => new ServiceProjectServiceMapping + var projectServiceMapping = model.Services.Where(sdto => services.Any(s => s.Id == sdto.ServiceId)).Select(sdto => new ServiceProjectServiceMapping { - ServiceId = serviceId, + ServiceId = sdto.ServiceId, ProjectId = serviceProject.Id, TenantId = tenantId - }); + }).ToList(); try { _context.ServiceProjects.Add(serviceProject); @@ -73,14 +96,14 @@ namespace Marco.Pms.Services.Service _logger.LogInfo("Service Project {ProjectId} created successfully for TenantId={TenantId}, by Employee {EmployeeId}.", serviceProject.Id, tenantId, loggedInEmployee); - var serviceProjectVm = _mapper.Map(serviceProject); - var services = await _context.ServiceMasters.Where(t => model.ServiceIds.Contains(t.Id) && t.TenantId == tenantId && t.IsActive).ToListAsync(); + var serviceProjectVM = _mapper.Map(serviceProject); + serviceProjectVM.Client = _mapper.Map(client); + serviceProjectVM.Status = status; + serviceProjectVM.Services = services.Where(s => serviceIds.Contains(s.Id)).Select(s => _mapper.Map(s)).ToList(); - serviceProjectVm.Services = _mapper.Map>(services); - - serviceProjectVm.CreatedBy = _mapper.Map(loggedInEmployee); - serviceProjectVm.CreatedAt = DateTime.UtcNow; - return ApiResponse.SuccessResponse(serviceProjectVm, "An Successfullly occurred while saving the project.", 201); + serviceProjectVM.CreatedBy = _mapper.Map(loggedInEmployee); + serviceProjectVM.CreatedAt = DateTime.UtcNow; + return ApiResponse.SuccessResponse(serviceProjectVM, "An Successfullly occurred while saving the project.", 201); } catch (Exception ex) @@ -97,10 +120,29 @@ namespace Marco.Pms.Services.Service try { - var serviceProjects = await _context.ServiceProjects.Include(sp=>sp.CreatedBy).Where(sp=>sp.TenantId == tenantId && sp.IsActive).ToListAsync(); - List serviceProjectLists = _mapper.Map>(serviceProjects); - _logger.LogInfo("Successfully retrieved a total of {ProjectCount} projects.", serviceProjectLists.Count); - return ApiResponse.SuccessResponse(serviceProjectLists, "Projects retrieved successfully.", 200); + var serviceProjects = await _context.ServiceProjects + .Include(sp => sp.Client) + .Include(sp => sp.Status) + .Include(sp => sp.CreatedBy).ThenInclude(e => e!.JobRole) + .Include(sp => sp.UpdatedBy).ThenInclude(e => e!.JobRole) + .Where(sp => sp.TenantId == tenantId && sp.IsActive).ToListAsync(); + + var serviceProjectIds = serviceProjects.Select(sp => sp.Id).ToList(); + var serviceProjectServiceMappings = await _context.ServiceProjectServiceMapping + .Include(sps => sps.Service) + .Where(sps => serviceProjectIds.Contains(sps.Id) && sps.Service != null && sps.TenantId == tenantId) + .ToListAsync(); + + var serviceProjectVMs = serviceProjects.Select(sp => + { + var services = serviceProjectServiceMappings.Where(sps => sps.ProjectId == sp.Id).Select(sps => sps.Service!).ToList(); + var result = _mapper.Map(sp); + result.Services = _mapper.Map>(services); + return result; + }).ToList(); + + _logger.LogInfo("Successfully retrieved a total of {ProjectCount} projects.", serviceProjectVMs.Count); + return ApiResponse.SuccessResponse(serviceProjectVMs, "Projects retrieved successfully.", 200); } catch (Exception ex) @@ -118,9 +160,9 @@ namespace Marco.Pms.Services.Service try { - var serviceProject = await _context.ServiceProjects.Where(sp => sp.Id == id && sp.TenantId == tenantId).FirstOrDefaultAsync(); + var serviceProject = await _context.ServiceProjects.Where(sp => sp.Id == id && sp.TenantId == tenantId).FirstOrDefaultAsync(); - if(serviceProject == null) + if (serviceProject == null) { _logger.LogWarning("Attempt to update non-existent Service project with ID {ProjectId} by user {UserId}.", id, loggedInEmployee.Id); return ApiResponse.ErrorResponse("Project not found.", $"No project found with ID {id}.", 404); @@ -135,13 +177,13 @@ namespace Marco.Pms.Services.Service serviceProject.UpdatedById = loggedInEmployee.Id; await _context.SaveChangesAsync(); - - serviceProject = await _context.ServiceProjects.Include(sp => sp.UpdatedBy).Where(sp => sp.Id == id && sp.TenantId == tenantId).FirstOrDefaultAsync(); + + serviceProject = await _context.ServiceProjects.Include(sp => sp.UpdatedBy).Where(sp => sp.Id == id && sp.TenantId == tenantId).FirstOrDefaultAsync(); var services = await _context.ServiceProjectServiceMapping.Include(t => t.Service).Where(t => t.ProjectId == serviceProject!.Id && t.Service != null && t.TenantId == tenantId).Select(t => t.Service!).ToListAsync(); - ServiceProjectVm serviceProjectVm = _mapper.Map(serviceProject); + ServiceProjectVM serviceProjectVm = _mapper.Map(serviceProject); serviceProjectVm.Services = _mapper.Map>(services);