Merge pull request 'Added the service Id in Query parameter to get infra details API' (#139) from Ashutosh_Enhancement_#1355 into Organization_Management
Reviewed-on: #139
This commit is contained in:
commit
4c6070fee5
@ -32,7 +32,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
public class EmployeeController : ControllerBase
|
public class EmployeeController : ControllerBase
|
||||||
{
|
{
|
||||||
|
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
||||||
private readonly ApplicationDbContext _context;
|
private readonly ApplicationDbContext _context;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly UserManager<ApplicationUser> _userManager;
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
@ -50,7 +50,8 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
private readonly Guid organizationId;
|
private readonly Guid organizationId;
|
||||||
|
|
||||||
|
|
||||||
public EmployeeController(IServiceScopeFactory serviceScopeFactory,
|
public EmployeeController(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
||||||
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
IEmailSender emailSender,
|
IEmailSender emailSender,
|
||||||
ApplicationDbContext context,
|
ApplicationDbContext context,
|
||||||
@ -64,6 +65,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
IMapper mapper,
|
IMapper mapper,
|
||||||
GeneralHelper generalHelper)
|
GeneralHelper generalHelper)
|
||||||
{
|
{
|
||||||
|
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
_context = context;
|
_context = context;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
@ -120,7 +122,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("list/project/{projectId}")]
|
[HttpGet("list/organizations/{projectId}")]
|
||||||
public async Task<IActionResult> GetEmployeesByProjectAsync(Guid projectId, [FromQuery] string searchString)
|
public async Task<IActionResult> GetEmployeesByProjectAsync(Guid projectId, [FromQuery] string searchString)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -128,6 +130,28 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
// Get the currently logged-in employee information
|
// Get the currently logged-in employee information
|
||||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
|
|
||||||
|
var projectTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Projects.FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
|
||||||
|
});
|
||||||
|
|
||||||
|
var tenantTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await context.Tenants.FirstOrDefaultAsync(t => t.Id == tenantId);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.WhenAll(projectTask, tenantTask);
|
||||||
|
|
||||||
|
var project = projectTask.Result;
|
||||||
|
var tenant = tenantTask.Result;
|
||||||
|
|
||||||
|
if (project == null || tenant == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Project {ProjectId} not found in database for tenant {TenantId}", projectId, tenantId);
|
||||||
|
return NotFound(ApiResponse<object>.ErrorResponse("Project not found", "Project not found", 404));
|
||||||
|
}
|
||||||
// Check if the logged-in employee has permission for the requested project
|
// Check if the logged-in employee has permission for the requested project
|
||||||
var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId);
|
var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId);
|
||||||
if (!hasProjectPermission)
|
if (!hasProjectPermission)
|
||||||
@ -136,20 +160,36 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access denied", "User does not have access to view the employees for this project", 403));
|
return StatusCode(403, ApiResponse<object>.ErrorResponse("Access denied", "User does not have access to view the employees for this project", 403));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var organizationQuery = _context.ProjectOrgMappings
|
||||||
|
.Include(po => po.ProjectService)
|
||||||
|
.Where(po => po.ProjectService != null && po.ProjectService.ProjectId == projectId);
|
||||||
|
|
||||||
|
if (loggedInEmployee.OrganizationId != project.PMCId && loggedInEmployee.OrganizationId != project.PromoterId && loggedInEmployee.OrganizationId != tenant.OrganizationId)
|
||||||
|
{
|
||||||
|
organizationQuery = organizationQuery.Where(po => po.ParentOrganizationId == loggedInEmployee.OrganizationId || po.OrganizationId == loggedInEmployee.OrganizationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
var organizationIds = await organizationQuery.Select(po => po.OrganizationId).ToListAsync();
|
||||||
|
|
||||||
|
if (loggedInEmployee.OrganizationId == project.PMCId || loggedInEmployee.OrganizationId == project.PromoterId || loggedInEmployee.OrganizationId == tenant.OrganizationId)
|
||||||
|
{
|
||||||
|
organizationIds.Add(project.PMCId);
|
||||||
|
organizationIds.Add(project.PromoterId);
|
||||||
|
organizationIds.Add(tenant.OrganizationId);
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch employees allocated to the project matching the search criteria
|
// Fetch employees allocated to the project matching the search criteria
|
||||||
var employees = await _context.ProjectAllocations
|
var employees = await _context.Employees
|
||||||
.AsNoTracking() // Improves performance by disabling change tracking for read-only query
|
.AsNoTracking() // Improves performance by disabling change tracking for read-only query
|
||||||
.Include(pa => pa.Employee)
|
.Include(e => e.JobRole)
|
||||||
.ThenInclude(e => e!.JobRole)
|
.Where(e => (e.FirstName + " " + e.LastName).Contains(searchString) && organizationIds.Contains(e.OrganizationId))
|
||||||
.Where(pa => pa.ProjectId == projectId && pa.Employee != null &&
|
|
||||||
(pa.Employee.FirstName + " " + pa.Employee.LastName).Contains(searchString))
|
|
||||||
.Select(pa => pa.Employee!)
|
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
var result = employees.Select(e => _mapper.Map<EmployeeVM>(e)).Distinct().ToList();
|
||||||
_logger.LogInfo("Employees fetched for project {ProjectId} by user {EmployeeId}. Count: {Count}", projectId, loggedInEmployee.Id, employees.Count);
|
_logger.LogInfo("Employees fetched for project {ProjectId} by user {EmployeeId}. Count: {Count}", projectId, loggedInEmployee.Id, employees.Count);
|
||||||
|
|
||||||
// Return the employee list wrapped in a successful API response
|
// Return the employee list wrapped in a successful API response
|
||||||
return Ok(ApiResponse<object>.SuccessResponse(employees, "Employee list fetched successfully", 200));
|
return Ok(ApiResponse<object>.SuccessResponse(result, "Employee list fetched successfully", 200));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -324,7 +324,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
#region =================================================================== Project InfraStructure Get APIs ===================================================================
|
#region =================================================================== Project InfraStructure Get APIs ===================================================================
|
||||||
|
|
||||||
[HttpGet("infra-details/{projectId}")]
|
[HttpGet("infra-details/{projectId}")]
|
||||||
public async Task<IActionResult> GetInfraDetails(Guid projectId)
|
public async Task<IActionResult> GetInfraDetails(Guid projectId, [FromQuery] Guid? serviceId)
|
||||||
{
|
{
|
||||||
// --- Step 1: Input Validation ---
|
// --- Step 1: Input Validation ---
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
@ -336,7 +336,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
|
|
||||||
// --- Step 2: Prepare data without I/O ---
|
// --- Step 2: Prepare data without I/O ---
|
||||||
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||||
var response = await _projectServices.GetInfraDetailsAsync(projectId, tenantId, loggedInEmployee);
|
var response = await _projectServices.GetInfraDetailsAsync(projectId, serviceId, tenantId, loggedInEmployee);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -357,6 +357,7 @@ namespace MarcoBMS.Services.Controllers
|
|||||||
var response = await _projectServices.GetWorkItemsAsync(workAreaId, serviceId, tenantId, loggedInEmployee);
|
var response = await _projectServices.GetWorkItemsAsync(workAreaId, serviceId, tenantId, loggedInEmployee);
|
||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("tasks-employee/{employeeId}")]
|
[HttpGet("tasks-employee/{employeeId}")]
|
||||||
public async Task<IActionResult> GetTasksByEmployee(Guid employeeId, [FromQuery] DateTime? fromDate, DateTime? toDate)
|
public async Task<IActionResult> GetTasksByEmployee(Guid employeeId, [FromQuery] DateTime? fromDate, DateTime? toDate)
|
||||||
{
|
{
|
||||||
|
@ -177,7 +177,10 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
|
|
||||||
#region ======================================================= Employee =======================================================
|
#region ======================================================= Employee =======================================================
|
||||||
|
|
||||||
CreateMap<Employee, EmployeeVM>();
|
CreateMap<Employee, EmployeeVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.JobRole,
|
||||||
|
opt => opt.MapFrom(src => src.JobRole != null ? src.JobRole.Name : ""));
|
||||||
CreateMap<CreateUserDto, Employee>();
|
CreateMap<CreateUserDto, Employee>();
|
||||||
CreateMap<MobileUserManageDto, Employee>();
|
CreateMap<MobileUserManageDto, Employee>();
|
||||||
|
|
||||||
|
@ -1176,7 +1176,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
/// Retrieves the full infrastructure hierarchy (Buildings, Floors, Work Areas) for a project,
|
/// Retrieves the full infrastructure hierarchy (Buildings, Floors, Work Areas) for a project,
|
||||||
/// including aggregated work summaries.
|
/// including aggregated work summaries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee)
|
public async Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee)
|
||||||
{
|
{
|
||||||
_logger.LogInfo("GetInfraDetails called for ProjectId: {ProjectId}", projectId);
|
_logger.LogInfo("GetInfraDetails called for ProjectId: {ProjectId}", projectId);
|
||||||
|
|
||||||
@ -1223,19 +1223,74 @@ namespace Marco.Pms.Services.Service
|
|||||||
if (cachedResult != null)
|
if (cachedResult != null)
|
||||||
{
|
{
|
||||||
_logger.LogInfo("Cache HIT for infra details for ProjectId: {ProjectId}", projectId);
|
_logger.LogInfo("Cache HIT for infra details for ProjectId: {ProjectId}", projectId);
|
||||||
return ApiResponse<object>.SuccessResponse(cachedResult, "Infra details fetched successfully from cache.", 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInfo("Cache MISS for infra details for ProjectId: {ProjectId}. Fetching from database.", projectId);
|
_logger.LogInfo("Cache MISS for infra details for ProjectId: {ProjectId}. Fetching from database.", projectId);
|
||||||
|
|
||||||
// --- Step 3: Fetch all required data from the database ---
|
// --- Step 3: Fetch all required data from the database ---
|
||||||
|
if (cachedResult == null)
|
||||||
var buildingMongoList = await _generalHelper.GetProjectInfraFromDB(projectId);
|
{
|
||||||
|
cachedResult = await _generalHelper.GetProjectInfraFromDB(projectId);
|
||||||
|
}
|
||||||
// --- Step 5: Proactively update the cache ---
|
// --- Step 5: Proactively update the cache ---
|
||||||
//await _cache.SetBuildingInfra(projectId, buildingMongoList);
|
//await _cache.SetBuildingInfra(projectId, buildingMongoList);
|
||||||
|
|
||||||
_logger.LogInfo("Infra details fetched successfully for ProjectId: {ProjectId}, Buildings: {Count}", projectId, buildingMongoList.Count);
|
if (serviceId.HasValue)
|
||||||
return ApiResponse<object>.SuccessResponse(buildingMongoList, "Infra details fetched successfully", 200);
|
{
|
||||||
|
var workAreaIds = cachedResult
|
||||||
|
.SelectMany(b => b.Floors)
|
||||||
|
.SelectMany(f => f.WorkAreas)
|
||||||
|
.Select(w => Guid.Parse(w.Id))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var workItems = await _context.WorkItems.Where(wi => workAreaIds.Contains(wi.WorkAreaId)
|
||||||
|
&& wi.ActivityMaster != null
|
||||||
|
&& wi.ActivityMaster.ActivityGroup != null
|
||||||
|
&& wi.ActivityMaster.ActivityGroup.ServiceId == serviceId)
|
||||||
|
.GroupBy(wi => wi.WorkAreaId)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
WorkAreaId = g.Key,
|
||||||
|
PlannedWork = g.Sum(wi => wi.PlannedWork),
|
||||||
|
CompletedWork = g.Sum(wi => wi.CompletedWork)
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
cachedResult = cachedResult.Select(b =>
|
||||||
|
{
|
||||||
|
double buildingPlanned = 0, buildingCompleted = 0;
|
||||||
|
var floors = b.Floors.Select(f =>
|
||||||
|
{
|
||||||
|
double floorPlanned = 0, floorCompleted = 0;
|
||||||
|
var workArea = f.WorkAreas.Select(wa =>
|
||||||
|
{
|
||||||
|
var workItem = workItems.FirstOrDefault(wi => wi.WorkAreaId == Guid.Parse(wa.Id));
|
||||||
|
wa.PlannedWork = workItem?.PlannedWork ?? 0;
|
||||||
|
wa.CompletedWork = workItem?.CompletedWork ?? 0;
|
||||||
|
|
||||||
|
floorPlanned += workItem?.PlannedWork ?? 0;
|
||||||
|
floorCompleted += workItem?.CompletedWork ?? 0;
|
||||||
|
|
||||||
|
return wa;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
f.PlannedWork = floorPlanned;
|
||||||
|
f.CompletedWork = floorCompleted;
|
||||||
|
|
||||||
|
buildingPlanned += floorPlanned;
|
||||||
|
buildingCompleted += floorCompleted;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}).ToList();
|
||||||
|
b.PlannedWork = buildingPlanned;
|
||||||
|
b.CompletedWork = buildingCompleted;
|
||||||
|
return b;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInfo("Infra details fetched successfully for ProjectId: {ProjectId}, Buildings: {Count}", projectId, cachedResult.Count);
|
||||||
|
return ApiResponse<object>.SuccessResponse(cachedResult, "Infra details fetched successfully", 200);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
Task<ApiResponse<List<ProjectAllocationVM>>> AssigneProjectsToEmployeeAsync(List<ProjectsAllocationDto> projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<List<ProjectAllocationVM>>> AssigneProjectsToEmployeeAsync(List<ProjectsAllocationDto> projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
|
||||||
Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ApiResponse<object>> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee);
|
Task<ApiResponse<object>> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee);
|
||||||
Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee);
|
Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user