diff --git a/Marco.Pms.Services/Controllers/ProjectController.cs b/Marco.Pms.Services/Controllers/ProjectController.cs index deadf09..df23a29 100644 --- a/Marco.Pms.Services/Controllers/ProjectController.cs +++ b/Marco.Pms.Services/Controllers/ProjectController.cs @@ -319,6 +319,14 @@ namespace MarcoBMS.Services.Controllers return StatusCode(response.StatusCode, response); } + [HttpGet("get/task/team/{projectId}")] + public async Task GetProjectTeamByServiceAndOrganization(Guid projectId, [FromQuery] Guid? serviceId, [FromQuery] Guid? organizationId) + { + Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _projectServices.GetProjectTeamByServiceAndOrganizationAsync(projectId, serviceId, organizationId, tenantId, loggedInEmployee); + return StatusCode(response.StatusCode, response); + } + #endregion #region =================================================================== Project InfraStructure Get APIs =================================================================== diff --git a/Marco.Pms.Services/Service/ProjectServices.cs b/Marco.Pms.Services/Service/ProjectServices.cs index 9e2a1b0..f96dabf 100644 --- a/Marco.Pms.Services/Service/ProjectServices.cs +++ b/Marco.Pms.Services/Service/ProjectServices.cs @@ -1166,6 +1166,190 @@ namespace Marco.Pms.Services.Service 500); } } + public async Task> GetProjectTeamByServiceAndOrganization(Guid projectId, Guid? serviceId, Guid? organizationId, Guid tenantId, Employee loggedInEmployee) + { + using var scope = _serviceScopeFactory.CreateScope(); + var _permission = scope.ServiceProvider.GetRequiredService(); + + 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 ApiResponse.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) + { + _logger.LogWarning("User {EmployeeId} attempts to get employees for project {ProjectId} without permission", loggedInEmployee.Id, projectId); + return ApiResponse.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); + } + + var projectAllocationQuery = _context.ProjectAllocations + .Include(pa => pa.Employee) + .ThenInclude(e => e!.JobRole) + .Where(pa => pa.ProjectId == projectId && pa.Employee != null && organizationIds.Contains(pa.Employee.OrganizationId)); + + if (serviceId.HasValue) + { + projectAllocationQuery = projectAllocationQuery.Where(pa => pa.ServiceId == serviceId); + } + if (organizationId.HasValue) + { + projectAllocationQuery = projectAllocationQuery.Where(pa => pa.Employee != null && pa.Employee.OrganizationId == organizationId); + } + + var projectAllocations = await projectAllocationQuery + .ToListAsync(); + + var result = projectAllocations.Select(pa => _mapper.Map(pa.Employee)).Distinct().ToList(); + + return ApiResponse.SuccessResponse(result, "Employee list fetched successfully", 200); + } + + public async Task> GetProjectTeamByServiceAndOrganizationAsync( + Guid projectId, Guid? serviceId, Guid? organizationId, Guid tenantId, Employee loggedInEmployee) + { + _logger.LogDebug("Started fetching project team. ProjectId: {ProjectId}, ServiceId: {ServiceId}, OrganizationId: {OrganizationId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}", + projectId, serviceId ?? Guid.Empty, organizationId ?? Guid.Empty, tenantId, loggedInEmployee.Id); + + try + { + // Use a single DbContext instance + using var scope = _serviceScopeFactory.CreateScope(); + var _permission = scope.ServiceProvider.GetRequiredService(); + + // Fetch project and tenant entities in parallel + 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 = await projectTask; + var tenant = await tenantTask; + + if (project == null || tenant == null) + { + _logger.LogWarning("Project {ProjectId} or Tenant {TenantId} not found in the database.", projectId, tenantId); + return ApiResponse.ErrorResponse("Project or tenant not found", "Project or tenant record not found", 404); + } + + // Check permission to view project team + var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId); + if (!hasProjectPermission) + { + _logger.LogWarning("Access denied: User {EmployeeId} tried to get team for Project {ProjectId}", loggedInEmployee.Id, projectId); + return ApiResponse.ErrorResponse("Access denied", "User does not have permission to view this project team", 403); + } + + // Query ProjectOrgMappings for associated organizations + var organizationQuery = _context.ProjectOrgMappings + .Include(po => po.ProjectService) + .Where(po => po.ProjectService != null && po.ProjectService.ProjectId == projectId); + + // Restrict organizations for non-PMC/Promoter users + 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).Distinct().ToListAsync(); + + // Add PMC, Promoter, Tenant organizations for privileged users + 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); + } + + organizationIds = organizationIds.Distinct().ToList(); + + // Build ProjectAllocation query for employees by service/organization if specified + var allocationQuery = _context.ProjectAllocations + .Include(pa => pa.Employee) + .ThenInclude(e => e!.JobRole) + .Where(pa => pa.ProjectId == projectId + && pa.Employee != null + && organizationIds.Contains(pa.Employee.OrganizationId)); + + if (serviceId.HasValue) + { + allocationQuery = allocationQuery.Where(pa => pa.ServiceId == serviceId); + } + if (organizationId.HasValue) + { + allocationQuery = allocationQuery.Where(pa => pa.Employee != null && pa.Employee.OrganizationId == organizationId); + } + + var projectAllocations = await allocationQuery.ToListAsync(); + + // Map to distinct EmployeeVM results + var employeeList = projectAllocations + .Select(pa => _mapper.Map(pa.Employee)) + .Distinct() + .ToList(); + + _logger.LogInfo("Fetched {EmployeeCount} employees for Project {ProjectId}.", employeeList.Count, projectId); + + return ApiResponse.SuccessResponse(employeeList, "Employee list fetched successfully", 200); + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occurred while fetching project team for ProjectId: {ProjectId}", projectId); + return ApiResponse.ErrorResponse("Internal error", "An error occurred while fetching the project team", 500); + } + } #endregion diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs index 5c3158c..7151187 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IProjectServices.cs @@ -23,6 +23,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> GetProjectsByEmployeeAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee); Task>> AssigneProjectsToEmployeeAsync(List projectAllocationDtos, Guid employeeId, Guid tenantId, Employee loggedInEmployee); Task> GetProjectByEmployeeBasicAsync(Guid employeeId, Guid tenantId, Employee loggedInEmployee); + Task> GetProjectTeamByServiceAndOrganizationAsync(Guid projectId, Guid? serviceId, Guid? organizationId, Guid tenantId, Employee loggedInEmployee); Task> GetInfraDetailsAsync(Guid projectId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee); Task> GetWorkItemsAsync(Guid workAreaId, Guid? serviceId, Guid tenantId, Employee loggedInEmployee);