Added the service Id in Query parameter to get infra details API #139
@ -32,7 +32,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
public class EmployeeController : ControllerBase
|
||||
{
|
||||
|
||||
private readonly IDbContextFactory<ApplicationDbContext> _dbContextFactory;
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
@ -50,7 +50,8 @@ namespace MarcoBMS.Services.Controllers
|
||||
private readonly Guid organizationId;
|
||||
|
||||
|
||||
public EmployeeController(IServiceScopeFactory serviceScopeFactory,
|
||||
public EmployeeController(IDbContextFactory<ApplicationDbContext> dbContextFactory,
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IEmailSender emailSender,
|
||||
ApplicationDbContext context,
|
||||
@ -64,6 +65,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
IMapper mapper,
|
||||
GeneralHelper generalHelper)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory ?? throw new ArgumentNullException(nameof(dbContextFactory));
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_context = context;
|
||||
_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)
|
||||
{
|
||||
try
|
||||
@ -128,6 +130,28 @@ namespace MarcoBMS.Services.Controllers
|
||||
// Get the currently logged-in employee information
|
||||
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
|
||||
var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId);
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
var employees = await _context.ProjectAllocations
|
||||
var employees = await _context.Employees
|
||||
.AsNoTracking() // Improves performance by disabling change tracking for read-only query
|
||||
.Include(pa => pa.Employee)
|
||||
.ThenInclude(e => e!.JobRole)
|
||||
.Where(pa => pa.ProjectId == projectId && pa.Employee != null &&
|
||||
(pa.Employee.FirstName + " " + pa.Employee.LastName).Contains(searchString))
|
||||
.Select(pa => pa.Employee!)
|
||||
.Include(e => e.JobRole)
|
||||
.Where(e => (e.FirstName + " " + e.LastName).Contains(searchString) && organizationIds.Contains(e.OrganizationId))
|
||||
.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);
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -324,7 +324,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
#region =================================================================== Project InfraStructure Get APIs ===================================================================
|
||||
|
||||
[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 ---
|
||||
if (!ModelState.IsValid)
|
||||
@ -336,7 +336,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
// --- Step 2: Prepare data without I/O ---
|
||||
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);
|
||||
|
||||
}
|
||||
@ -357,6 +357,7 @@ namespace MarcoBMS.Services.Controllers
|
||||
var response = await _projectServices.GetWorkItemsAsync(workAreaId, serviceId, tenantId, loggedInEmployee);
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
[HttpGet("tasks-employee/{employeeId}")]
|
||||
public async Task<IActionResult> GetTasksByEmployee(Guid employeeId, [FromQuery] DateTime? fromDate, DateTime? toDate)
|
||||
{
|
||||
|
@ -177,7 +177,10 @@ namespace Marco.Pms.Services.MappingProfiles
|
||||
|
||||
#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<MobileUserManageDto, Employee>();
|
||||
|
||||
|
@ -1176,7 +1176,7 @@ namespace Marco.Pms.Services.Service
|
||||
/// Retrieves the full infrastructure hierarchy (Buildings, Floors, Work Areas) for a project,
|
||||
/// including aggregated work summaries.
|
||||
/// </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);
|
||||
|
||||
@ -1223,19 +1223,74 @@ namespace Marco.Pms.Services.Service
|
||||
if (cachedResult != null)
|
||||
{
|
||||
_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);
|
||||
|
||||
// --- Step 3: Fetch all required data from the database ---
|
||||
|
||||
var buildingMongoList = await _generalHelper.GetProjectInfraFromDB(projectId);
|
||||
if (cachedResult == null)
|
||||
{
|
||||
cachedResult = await _generalHelper.GetProjectInfraFromDB(projectId);
|
||||
}
|
||||
// --- Step 5: Proactively update the cache ---
|
||||
//await _cache.SetBuildingInfra(projectId, buildingMongoList);
|
||||
|
||||
_logger.LogInfo("Infra details fetched successfully for ProjectId: {ProjectId}, Buildings: {Count}", projectId, buildingMongoList.Count);
|
||||
return ApiResponse<object>.SuccessResponse(buildingMongoList, "Infra details fetched successfully", 200);
|
||||
if (serviceId.HasValue)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -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<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>> GetTasksByEmployeeAsync(Guid employeeId, DateTime fromDate, DateTime toDate, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ServiceResponse> ManageProjectInfraAsync(List<InfraDto> infraDtos, Guid tenantId, Employee loggedInEmployee);
|
||||
|
Loading…
x
Reference in New Issue
Block a user