Checking the client and status when creating service projects

This commit is contained in:
ashutosh.nehete 2025-11-11 17:53:39 +05:30
parent 4825f24694
commit 8be9b05695
6 changed files with 100 additions and 84 deletions

View File

@ -1,22 +1,20 @@
using Marco.Pms.Model.Master; using Marco.Pms.Model.ViewModels.Master;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System.ComponentModel.DataAnnotations.Schema;
namespace Marco.Pms.Model.Dtos.ServiceProject namespace Marco.Pms.Model.Dtos.ServiceProject
{ {
public class ServiceProjectDto public class ServiceProjectDto
{ {
public string Name { get; set; } = string.Empty; public required string Name { get; set; }
public string ShortName { get; set; } = string.Empty; public required string ShortName { get; set; }
public Guid ClientId { get; set; } public required Guid ClientId { get; set; }
public required List<Guid> ServiceIds { get; set; } public required List<BasicServiceMasterDto> Services { get; set; }
public string Address { get; set; } = string.Empty; public required string Address { get; set; }
public DateTime AssignedDate { get; set; } public required DateTime AssignedDate { get; set; }
public Guid StatusId { get; set; } public required Guid StatusId { get; set; }
public string ContactName { get; set; } = string.Empty; public required string ContactName { get; set; }
public string ContactPhone { get; set; } = string.Empty; public required string ContactPhone { get; set; }
public string ContactEmail { get; set; } = string.Empty; public required string ContactEmail { get; set; }
} }
} }

View File

@ -0,0 +1,8 @@
namespace Marco.Pms.Model.ViewModels.Master
{
public class BasicServiceMasterDto
{
public Guid ServiceId { get; set; }
public bool IsActive { get; set; }
}
}

View File

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

View File

@ -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 Marco.Pms.Model.ViewModels.Master;
using System; using Marco.Pms.Model.ViewModels.Organization;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Marco.Pms.Model.ViewModels.ServiceProject namespace Marco.Pms.Model.ViewModels.ServiceProject
{ {
public class ServiceProjectVm public class ServiceProjectVM
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
public string ShortName { get; set; } = string.Empty; public string ShortName { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty; public string Address { get; set; } = string.Empty;
public DateTime AssignedDate { get; set; } public DateTime AssignedDate { get; set; }
public Guid StatusId { get; set; } public StatusMaster? Status { get; set; }
public BasicOrganizationVm? Client { get; set; }
public List<ServiceMasterVM>? Services { get; set; } public List<ServiceMasterVM>? Services { get; set; }
public BasicEmployeeVM? CreatedBy { get; set; } public BasicEmployeeVM? CreatedBy { get; set; }
public BasicEmployeeVM? UpdatedBy { get; set; } public BasicEmployeeVM? UpdatedBy { get; set; }

View File

@ -194,8 +194,7 @@ namespace Marco.Pms.Services.MappingProfiles
CreateMap<ServiceProjectDto, ServiceProject>(); CreateMap<ServiceProjectDto, ServiceProject>();
CreateMap<ServiceProject,ServiceProjectVm>(); CreateMap<ServiceProject, ServiceProjectVM>();
CreateMap<ServiceProject, ServiceProjectList>();
#endregion #endregion
#region ======================================================= Employee ======================================================= #region ======================================================= Employee =======================================================

View File

@ -2,13 +2,11 @@
using Marco.Pms.DataAccess.Data; using Marco.Pms.DataAccess.Data;
using Marco.Pms.Model.Dtos.ServiceProject; using Marco.Pms.Model.Dtos.ServiceProject;
using Marco.Pms.Model.Employees; using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.ServiceProject; using Marco.Pms.Model.ServiceProject;
using Marco.Pms.Model.Utilities; using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.Activities; using Marco.Pms.Model.ViewModels.Activities;
using Marco.Pms.Model.ViewModels.Expanses;
using Marco.Pms.Model.ViewModels.Master; 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.Model.ViewModels.ServiceProject;
using Marco.Pms.Services.Helpers; using Marco.Pms.Services.Helpers;
using Marco.Pms.Services.Service.ServiceInterfaces; using Marco.Pms.Services.Service.ServiceInterfaces;
@ -27,7 +25,12 @@ namespace Marco.Pms.Services.Service
private readonly CacheUpdateHelper _cache; private readonly CacheUpdateHelper _cache;
private readonly IMapper _mapper; private readonly IMapper _mapper;
public ServiceProjectService(IDbContextFactory<ApplicationDbContext> dbContextFactory,IServiceScopeFactory serviceScopeFactory, ApplicationDbContext context, ILoggingService logger, CacheUpdateHelper cache, IMapper mapper) public ServiceProjectService(IDbContextFactory<ApplicationDbContext> dbContextFactory,
IServiceScopeFactory serviceScopeFactory,
ApplicationDbContext context,
ILoggingService logger,
CacheUpdateHelper cache,
IMapper mapper)
{ {
_serviceScopeFactory = serviceScopeFactory; _serviceScopeFactory = serviceScopeFactory;
_context = context; _context = context;
@ -40,16 +43,36 @@ namespace Marco.Pms.Services.Service
public async Task<ApiResponse<object>> CreateServiceProject(ServiceProjectDto model, Guid tenantId, Employee loggedInEmployee) public async Task<ApiResponse<object>> CreateServiceProject(ServiceProjectDto model, Guid tenantId, Employee loggedInEmployee)
{ {
using var scope = _serviceScopeFactory.CreateScope(); var serviceIds = model.Services.Where(s => s.IsActive).Select(s => s.ServiceId).ToList();
var _firebase = scope.ServiceProvider.GetService<IFirebaseService>(); var clientTask = Task.Run(async () =>
var tenant = await _context.Tenants.FirstOrDefaultAsync(t => t.Id == tenantId && t.OrganizationId == loggedInEmployee.OrganizationId);
if (tenant == null)
{ {
_logger.LogWarning("Access DENIED (OrgId:{OrgId}) by Employee {EmployeeId} for tenantId={TenantId}.", await using var context = await _dbContextFactory.CreateDbContextAsync();
loggedInEmployee.OrganizationId, loggedInEmployee.Id, tenantId); return await context.Organizations.FirstOrDefaultAsync(o => o.Id == model.ClientId && o.IsActive);
return ApiResponse<object>.ErrorResponse("Access Denied", "You do not have permission to create a service project for this tenant.", 403); });
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<object>.ErrorResponse("Client not found", "Client not found", 404);
}
if (status == null)
{
return ApiResponse<object>.ErrorResponse("Project Status not found", "Project Status not found", 404);
} }
var serviceProject = _mapper.Map<ServiceProject>(model); var serviceProject = _mapper.Map<ServiceProject>(model);
@ -59,12 +82,12 @@ namespace Marco.Pms.Services.Service
serviceProject.TenantId = tenantId; serviceProject.TenantId = tenantId;
serviceProject.IsActive = true; 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, ProjectId = serviceProject.Id,
TenantId = tenantId TenantId = tenantId
}); }).ToList();
try try
{ {
_context.ServiceProjects.Add(serviceProject); _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}.", _logger.LogInfo("Service Project {ProjectId} created successfully for TenantId={TenantId}, by Employee {EmployeeId}.",
serviceProject.Id, tenantId, loggedInEmployee); serviceProject.Id, tenantId, loggedInEmployee);
var serviceProjectVm = _mapper.Map<ServiceProjectVm>(serviceProject); var serviceProjectVM = _mapper.Map<ServiceProjectVM>(serviceProject);
var services = await _context.ServiceMasters.Where(t => model.ServiceIds.Contains(t.Id) && t.TenantId == tenantId && t.IsActive).ToListAsync(); serviceProjectVM.Client = _mapper.Map<BasicOrganizationVm>(client);
serviceProjectVM.Status = status;
serviceProjectVM.Services = services.Where(s => serviceIds.Contains(s.Id)).Select(s => _mapper.Map<ServiceMasterVM>(s)).ToList();
serviceProjectVm.Services = _mapper.Map<List<ServiceMasterVM>>(services); serviceProjectVM.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee);
serviceProjectVM.CreatedAt = DateTime.UtcNow;
serviceProjectVm.CreatedBy = _mapper.Map<BasicEmployeeVM>(loggedInEmployee); return ApiResponse<object>.SuccessResponse(serviceProjectVM, "An Successfullly occurred while saving the project.", 201);
serviceProjectVm.CreatedAt = DateTime.UtcNow;
return ApiResponse<object>.SuccessResponse(serviceProjectVm, "An Successfullly occurred while saving the project.", 201);
} }
catch (Exception ex) catch (Exception ex)
@ -97,10 +120,29 @@ namespace Marco.Pms.Services.Service
try try
{ {
var serviceProjects = await _context.ServiceProjects.Include(sp=>sp.CreatedBy).Where(sp=>sp.TenantId == tenantId && sp.IsActive).ToListAsync(); var serviceProjects = await _context.ServiceProjects
List<ServiceProjectList> serviceProjectLists = _mapper.Map<List<ServiceProjectList>>(serviceProjects); .Include(sp => sp.Client)
_logger.LogInfo("Successfully retrieved a total of {ProjectCount} projects.", serviceProjectLists.Count); .Include(sp => sp.Status)
return ApiResponse<object>.SuccessResponse(serviceProjectLists, "Projects retrieved successfully.", 200); .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<ServiceProjectVM>(sp);
result.Services = _mapper.Map<List<ServiceMasterVM>>(services);
return result;
}).ToList();
_logger.LogInfo("Successfully retrieved a total of {ProjectCount} projects.", serviceProjectVMs.Count);
return ApiResponse<object>.SuccessResponse(serviceProjectVMs, "Projects retrieved successfully.", 200);
} }
catch (Exception ex) catch (Exception ex)
@ -120,7 +162,7 @@ namespace Marco.Pms.Services.Service
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); _logger.LogWarning("Attempt to update non-existent Service project with ID {ProjectId} by user {UserId}.", id, loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Project not found.", $"No project found with ID {id}.", 404); return ApiResponse<object>.ErrorResponse("Project not found.", $"No project found with ID {id}.", 404);
@ -136,12 +178,12 @@ namespace Marco.Pms.Services.Service
await _context.SaveChangesAsync(); 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(); 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<ServiceProjectVm>(serviceProject); ServiceProjectVM serviceProjectVm = _mapper.Map<ServiceProjectVM>(serviceProject);
serviceProjectVm.Services = _mapper.Map<List<ServiceMasterVM>>(services); serviceProjectVm.Services = _mapper.Map<List<ServiceMasterVM>>(services);