Added an API to get list service project allocation

This commit is contained in:
ashutosh.nehete 2025-11-14 17:25:32 +05:30
parent e7a21e9e2f
commit c61ef92f6e
3 changed files with 78 additions and 11 deletions

View File

@ -98,11 +98,11 @@ namespace Marco.Pms.Services.Controllers
#region =================================================================== Service Project Allocation Functions ===================================================================
[HttpPost("get/allocation/list")]
public async Task<IActionResult> GetServiceProjectAllocationList([FromQuery] Guid? projectId, [FromQuery] Guid? employeeId)
[HttpGet("get/allocation/list")]
public async Task<IActionResult> GetServiceProjectAllocationList([FromQuery] Guid? projectId, [FromQuery] Guid? employeeId, [FromQuery] bool isActive = true)
{
Employee loggedInEmploee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _serviceProject.GetServiceProjectAllocationListAsync(projectId, employeeId, loggedInEmploee, tenantId);
var response = await _serviceProject.GetServiceProjectAllocationListAsync(projectId, employeeId, true, loggedInEmploee, tenantId);
return StatusCode(response.StatusCode, response);
}

View File

@ -16,7 +16,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
#endregion
#region =================================================================== Service Project Allocation Functions ===================================================================
Task<ApiResponse<object>> GetServiceProjectAllocationListAsync(Guid? projectId, Guid? employeeId, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetServiceProjectAllocationListAsync(Guid? projectId, Guid? employeeId, bool isActive, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> ManageServiceProjectAllocationAsync(List<ServiceProjectAllocationDto> model, Employee loggedInEmployee, Guid tenantId);
#endregion
#region =================================================================== Job Tickets Functions ===================================================================

View File

@ -363,10 +363,74 @@ namespace Marco.Pms.Services.Service
#endregion
#region =================================================================== Service Project Allocation Functions ===================================================================
public async Task<ApiResponse<object>> GetServiceProjectAllocationListAsync(Guid? projectId, Guid? employeeId, Employee loggedInEmployee, Guid tenantId)
/// <summary>
/// Retrieves a list of service project allocations filtered by project ID or employee ID and active status within the tenant context.
/// </summary>
/// <param name="projectId">Optional project ID filter.</param>
/// <param name="employeeId">Optional employee ID filter.</param>
/// <param name="isActive">Filter for active/inactive allocations.</param>
/// <param name="loggedInEmployee">Employee making the request (for audit/logging).</param>
/// <param name="tenantId">Tenant identifier for multi-tenant data isolation.</param>
/// <returns>ApiResponse with the list of matching service project allocations or error details.</returns>
public async Task<ApiResponse<object>> GetServiceProjectAllocationListAsync(Guid? projectId, Guid? employeeId, bool isActive, Employee loggedInEmployee, Guid tenantId)
{
return ApiResponse<object>.SuccessResponse(projectId, "Service project allocation fetched successfully", 200);
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetServiceProjectAllocationListAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
if (!projectId.HasValue && !employeeId.HasValue)
{
_logger.LogInfo("GetServiceProjectAllocationListAsync missing required filters by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Bad Request", "Provide at least one of (ProjectId or EmployeeId).", 400);
}
try
{
_logger.LogInfo("Fetching service project allocations for tenant {TenantId} by employee {EmployeeId} " +
"with filters - ProjectId: {ProjectId}, EmployeeId: {EmployeeId}, IsActive: {IsActive}",
tenantId, loggedInEmployee.Id, projectId ?? Guid.Empty, employeeId ?? Guid.Empty, isActive);
// Base query with includes for related navigation properties
var allocationQuery = _context.ServiceProjectAllocations
.Include(spa => spa.Project)
.Include(spa => spa.TeamRole)
.Include(spa => spa.Employee).ThenInclude(e => e!.JobRole)
.Include(spa => spa.AssignedBy).ThenInclude(e => e!.JobRole)
.Include(spa => spa.ReAssignedBy).ThenInclude(e => e!.JobRole)
.Where(spa => spa.IsActive == isActive && spa.TenantId == tenantId);
// Apply filtering by either project or employee (mutually exclusive)
if (projectId.HasValue)
{
allocationQuery = allocationQuery.Where(spa => spa.ProjectId == projectId.Value);
}
else if (employeeId.HasValue)
{
allocationQuery = allocationQuery.Where(spa => spa.EmployeeId == employeeId.Value);
}
// Execute query and sort results by most recent assignment
var allocations = await allocationQuery
.OrderByDescending(spa => spa.AssignedAt)
.ToListAsync();
var response = _mapper.Map<List<ServiceProjectAllocationVM>>(allocations);
_logger.LogInfo("{Count} service project allocations fetched successfully for tenant {TenantId}", response.Count, tenantId);
return ApiResponse<object>.SuccessResponse(response, "Service project allocations fetched successfully", 200);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching service project allocations for tenant {TenantId} by employee {EmployeeId}", tenantId, loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Internal Server Error", "Failed to fetch service project allocations. Please try again later.", 500);
}
}
/// <summary>
/// Manages service project allocations by adding new active allocations and removing inactive ones.
/// Validates projects, employees, and team roles exist before applying changes.
@ -400,22 +464,22 @@ namespace Marco.Pms.Services.Service
var projectTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.ServiceProjects.Where(sp => projectIds.Contains(sp.Id) && sp.TenantId == tenantId && sp.IsActive).ToListAsync();
return await context.ServiceProjects.AsNoTracking().Where(sp => projectIds.Contains(sp.Id) && sp.TenantId == tenantId && sp.IsActive).ToListAsync();
});
var employeeTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.Employees.Where(e => employeeIds.Contains(e.Id) && e.IsActive).ToListAsync();
return await context.Employees.AsNoTracking().Where(e => employeeIds.Contains(e.Id) && e.IsActive).ToListAsync();
});
var teamRoleTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.TeamRoleMasters.Where(trm => teamRoleIds.Contains(trm.Id)).ToListAsync();
return await context.TeamRoleMasters.AsNoTracking().Where(trm => teamRoleIds.Contains(trm.Id)).ToListAsync();
});
var allocationTask = Task.Run(async () =>
{
await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.ServiceProjectAllocations.Where(spa => projectIds.Contains(spa.ProjectId) && spa.TenantId == tenantId && spa.IsActive).ToListAsync();
return await context.ServiceProjectAllocations.AsNoTracking().Where(spa => projectIds.Contains(spa.ProjectId) && spa.TenantId == tenantId && spa.IsActive).ToListAsync();
});
await Task.WhenAll(projectTask, employeeTask, teamRoleTask, allocationTask);
@ -463,13 +527,16 @@ namespace Marco.Pms.Services.Service
}
else if (!dto.IsActive && existingAllocation != null)
{
existingAllocation.IsActive = false;
existingAllocation.ReAssignedAt = DateTime.UtcNow;
existingAllocation.ReAssignedById = loggedInEmployee.Id;
allocationsToRemove.Add(existingAllocation);
}
}
// Batch changes for efficiency
if (newAllocations.Any()) _context.ServiceProjectAllocations.AddRange(newAllocations);
if (allocationsToRemove.Any()) _context.ServiceProjectAllocations.RemoveRange(allocationsToRemove);
if (allocationsToRemove.Any()) _context.ServiceProjectAllocations.UpdateRange(allocationsToRemove);
await _context.SaveChangesAsync();