Merge pull request 'Issues_Aug_1W' (#113) from Issues_Aug_1W into main

Reviewed-on: #113
This commit is contained in:
ashutosh.nehete 2025-08-23 11:08:42 +00:00
commit 4ebd49d0c8

View File

@ -191,24 +191,88 @@ namespace MarcoBMS.Services.Controllers
var response = await employeeQuery.Take(10).Select(e => _mapper.Map<BasicEmployeeVM>(e)).ToListAsync(); var response = await employeeQuery.Take(10).Select(e => _mapper.Map<BasicEmployeeVM>(e)).ToListAsync();
return Ok(ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200)); return Ok(ApiResponse<object>.SuccessResponse(response, $"{response.Count} records of employees fetched successfully", 200));
} }
[HttpGet]
[Route("search/{name}/{projectid?}")] /// <summary>
public async Task<IActionResult> SearchEmployee(string name, Guid? projectid) /// Retrieves a paginated list of employees assigned to a specified project (if provided),
/// with optional search functionality.
/// Ensures that the logged-in user has necessary permissions before accessing project employees.
/// </summary>
/// <param name="projectId">Optional project identifier to filter employees by project.</param>
/// <param name="searchString">Optional search string to filter employees by name.</param>
/// <param name="pageNumber">Page number for pagination (default = 1).</param>
/// <returns>Paginated list of employees in BasicEmployeeVM format wrapped in ApiResponse.</returns>
[HttpGet("search")]
public async Task<IActionResult> GetEmployeesByProjectBasic(Guid? projectId, [FromQuery] string? searchString,
[FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
{ {
if (!ModelState.IsValid) // Log API entry with context
_logger.LogInfo("Fetching employees. ProjectId: {ProjectId}, SearchString: {SearchString}, PageNumber: {PageNumber}",
projectId ?? Guid.Empty, searchString ?? "", pageNumber);
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
_logger.LogDebug("Logged-in EmployeeId: {EmployeeId}", loggedInEmployee.Id);
// Initialize query scoped by tenant
var employeeQuery = _context.Employees.Where(e => e.TenantId == tenantId);
// Filter by project if projectId is supplied
if (projectId.HasValue && projectId.Value != Guid.Empty)
{ {
var errors = ModelState.Values _logger.LogDebug("Project filter applied. Checking permission for EmployeeId: {EmployeeId} on ProjectId: {ProjectId}",
.SelectMany(v => v.Errors) loggedInEmployee.Id, projectId);
.Select(e => e.ErrorMessage)
.ToList();
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
// Validate project access permission
var hasProjectPermission = await _permission.HasProjectPermission(loggedInEmployee, projectId.Value);
if (!hasProjectPermission)
{
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have permission for ProjectId: {ProjectId}",
loggedInEmployee.Id, projectId);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"Access denied",
"User does not have access to view employees for this project",
403));
}
// Employees allocated to the project
var employeeIds = await _context.ProjectAllocations
.Where(pa => pa.ProjectId == projectId && pa.IsActive && pa.TenantId == tenantId)
.Select(pa => pa.EmployeeId)
.ToListAsync();
_logger.LogDebug("Project employees retrieved. Total linked employees found: {Count}", employeeIds.Count);
// Apply project allocation filter
employeeQuery = employeeQuery.Where(e => employeeIds.Contains(e.Id));
} }
var result = await _employeeHelper.SearchEmployeeByProjectId(GetTenantId(), name.ToLower(), projectid);
return Ok(ApiResponse<object>.SuccessResponse(result, "Filter applied.", 200)); // Apply search filter if provided
if (!string.IsNullOrWhiteSpace(searchString))
{
var searchStringLower = searchString.ToLower();
_logger.LogDebug("Search filter applied. Search term: {SearchTerm}", searchStringLower);
employeeQuery = employeeQuery.Where(e =>
(e.FirstName + " " + e.LastName).ToLower().Contains(searchStringLower));
}
// Pagination and Projection (executed in DB)
var employees = await employeeQuery
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.Select(e => _mapper.Map<BasicEmployeeVM>(e))
.ToListAsync();
_logger.LogInfo("Employees fetched successfully. Records returned: {Count}", employees.Count);
return Ok(ApiResponse<object>.SuccessResponse(
employees,
$"{employees.Count} employee records fetched successfully",
200));
} }
[HttpGet] [HttpGet]
[Route("profile/get/{employeeId}")] [Route("profile/get/{employeeId}")]
public async Task<IActionResult> GetEmployeeProfileById(Guid employeeId) public async Task<IActionResult> GetEmployeeProfileById(Guid employeeId)
@ -447,86 +511,104 @@ namespace MarcoBMS.Services.Controllers
} }
[HttpDelete("{id}")] [HttpDelete("{id}")]
public async Task<IActionResult> SuspendEmployee(Guid id) public async Task<IActionResult> SuspendEmployee(Guid id, [FromQuery] bool active = false)
{ {
Guid tenantId = _userHelper.GetTenantId(); Guid tenantId = _userHelper.GetTenantId();
var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync(); var LoggedEmployee = await _userHelper.GetCurrentEmployeeAsync();
Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.IsActive && e.TenantId == tenantId); Employee? employee = await _context.Employees.FirstOrDefaultAsync(e => e.Id == id && e.TenantId == tenantId);
if (employee != null) if (employee == null)
{ {
if (employee.IsSystem) _logger.LogWarning("Employee with ID {EmploueeId} not found in database", id);
return NotFound(ApiResponse<object>.ErrorResponse("Employee Not found successfully", "Employee Not found successfully", 404));
}
if (employee.IsSystem)
{
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to suspend system-defined employee with ID {EmployeeId}", LoggedEmployee.Id, employee.Id);
return BadRequest(ApiResponse<object>.ErrorResponse("System-defined employees cannot be suspended.", "System-defined employees cannot be suspended.", 400));
}
var assignedToTasks = await _context.TaskMembers.Where(t => t.EmployeeId == employee.Id).ToListAsync();
if (assignedToTasks.Count != 0)
{
List<Guid> taskIds = assignedToTasks.Select(t => t.TaskAllocationId).ToList();
var tasks = await _context.TaskAllocations.Where(t => taskIds.Contains(t.Id)).ToListAsync();
foreach (var assignedToTask in assignedToTasks)
{ {
_logger.LogWarning("Employee with ID {LoggedEmployeeId} tries to suspend system-defined employee with ID {EmployeeId}", LoggedEmployee.Id, employee.Id); var task = tasks.Find(t => t.Id == assignedToTask.TaskAllocationId);
return BadRequest(ApiResponse<object>.ErrorResponse("System-defined employees cannot be suspended.", "System-defined employees cannot be suspended.", 400)); if (task != null && task.CompletedTask == 0)
{
_logger.LogWarning("Employee with ID {EmployeeId} is currently assigned to any incomplete task", employee.Id);
return BadRequest(ApiResponse<object>.ErrorResponse("Employee is currently assigned to any incomplete task", "Employee is currently assigned to any incomplete task", 400));
}
} }
else }
var attendance = await _context.Attendes.Where(a => a.EmployeeID == employee.Id && (a.OutTime == null || a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)).ToListAsync();
if (attendance.Count != 0)
{
_logger.LogWarning("Employee with ID {EmployeeId} have any pending check-out or regularization requests", employee.Id);
return BadRequest(ApiResponse<object>.ErrorResponse("Employee have any pending check-out or regularization requests", "Employee have any pending check-out or regularization requests", 400));
}
if (active)
{
employee.IsActive = true;
var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
if (user != null)
{ {
var assignedToTasks = await _context.TaskMembers.Where(t => t.EmployeeId == employee.Id).ToListAsync(); user.IsActive = true;
if (assignedToTasks.Count != 0) _logger.LogInfo("The application user associated with employee ID {EmployeeId} has been actived.", employee.Id);
{
List<Guid> taskIds = assignedToTasks.Select(t => t.TaskAllocationId).ToList();
var tasks = await _context.TaskAllocations.Where(t => taskIds.Contains(t.Id)).ToListAsync();
foreach (var assignedToTask in assignedToTasks)
{
var task = tasks.Find(t => t.Id == assignedToTask.TaskAllocationId);
if (task != null && task.CompletedTask == 0)
{
_logger.LogWarning("Employee with ID {EmployeeId} is currently assigned to any incomplete task", employee.Id);
return BadRequest(ApiResponse<object>.ErrorResponse("Employee is currently assigned to any incomplete task", "Employee is currently assigned to any incomplete task", 400));
}
}
}
var attendance = await _context.Attendes.Where(a => a.EmployeeID == employee.Id && (a.OutTime == null || a.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)).ToListAsync();
if (attendance.Count != 0)
{
_logger.LogWarning("Employee with ID {EmployeeId} have any pending check-out or regularization requests", employee.Id);
return BadRequest(ApiResponse<object>.ErrorResponse("Employee have any pending check-out or regularization requests", "Employee have any pending check-out or regularization requests", 400));
}
employee.IsActive = false;
var projectAllocations = await _context.ProjectAllocations.Where(a => a.EmployeeId == employee.Id).ToListAsync();
if (projectAllocations.Count != 0)
{
List<ProjectAllocation> allocations = new List<ProjectAllocation>();
foreach (var projectAllocation in projectAllocations)
{
projectAllocation.ReAllocationDate = DateTime.UtcNow;
projectAllocation.IsActive = false;
allocations.Add(projectAllocation);
}
_logger.LogInfo("Employee with ID {EmployeeId} has been removed from all assigned projects.", employee.Id);
}
var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
if (user != null)
{
user.IsActive = false;
_logger.LogInfo("The application user associated with employee ID {EmployeeId} has been suspended.", employee.Id);
var refreshTokens = await _context.RefreshTokens.AsNoTracking().Where(t => t.UserId == user.Id).ToListAsync();
if (refreshTokens.Count != 0)
{
_context.RefreshTokens.RemoveRange(refreshTokens);
_logger.LogInfo("Refresh tokens associated with employee ID {EmployeeId} has been removed.", employee.Id);
}
}
var roleMapping = await _context.EmployeeRoleMappings.AsNoTracking().Where(r => r.EmployeeId == employee.Id).ToListAsync();
if (roleMapping.Count != 0)
{
_context.EmployeeRoleMappings.RemoveRange(roleMapping);
_logger.LogInfo("Application role mapping associated with employee ID {EmployeeId} has been removed.", employee.Id);
}
await _context.SaveChangesAsync();
_logger.LogInfo("Employee with ID {EmployeId} Deleted successfully", employee.Id);
var notification = new { LoggedInUserId = LoggedEmployee.Id, Keyword = "Employee", EmployeeId = employee.Id };
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
} }
_logger.LogInfo("Employee with ID {EmployeId} Actived successfully", employee.Id);
} }
else else
{ {
_logger.LogWarning("Employee with ID {EmploueeId} not found in database", id); employee.IsActive = false;
var projectAllocations = await _context.ProjectAllocations.Where(a => a.EmployeeId == employee.Id).ToListAsync();
if (projectAllocations.Count != 0)
{
List<ProjectAllocation> allocations = new List<ProjectAllocation>();
foreach (var projectAllocation in projectAllocations)
{
projectAllocation.ReAllocationDate = DateTime.UtcNow;
projectAllocation.IsActive = false;
allocations.Add(projectAllocation);
}
_logger.LogInfo("Employee with ID {EmployeeId} has been removed from all assigned projects.", employee.Id);
}
var user = await _context.ApplicationUsers.FirstOrDefaultAsync(u => u.Id == employee.ApplicationUserId);
if (user != null)
{
user.IsActive = false;
_logger.LogInfo("The application user associated with employee ID {EmployeeId} has been suspended.", employee.Id);
var refreshTokens = await _context.RefreshTokens.AsNoTracking().Where(t => t.UserId == user.Id).ToListAsync();
if (refreshTokens.Count != 0)
{
_context.RefreshTokens.RemoveRange(refreshTokens);
_logger.LogInfo("Refresh tokens associated with employee ID {EmployeeId} has been removed.", employee.Id);
}
}
var roleMapping = await _context.EmployeeRoleMappings.AsNoTracking().Where(r => r.EmployeeId == employee.Id).ToListAsync();
if (roleMapping.Count != 0)
{
_context.EmployeeRoleMappings.RemoveRange(roleMapping);
_logger.LogInfo("Application role mapping associated with employee ID {EmployeeId} has been removed.", employee.Id);
}
_logger.LogInfo("Employee with ID {EmployeId} Deleted successfully", employee.Id);
} }
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
_logger.LogError(ex, "Exception Occured While activting/deactivting employee {EmployeeId}", employee.Id);
return StatusCode(500, ApiResponse<object>.ErrorResponse("Internal Error Occured", "Error occured while saving the entity", 500));
}
var notification = new { LoggedInUserId = LoggedEmployee.Id, Keyword = "Employee", EmployeeId = employee.Id };
await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200)); return Ok(ApiResponse<object>.SuccessResponse(new { }, "Employee Suspended successfully", 200));
} }
private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId) private static Employee GetNewEmployeeModel(CreateUserDto model, Guid TenantId, string ApplicationUserId)