Added the name of the project name in view model

This commit is contained in:
ashutosh.nehete 2025-10-08 12:16:25 +05:30
parent 629c4541d6
commit b1af96b923
2 changed files with 98 additions and 87 deletions

View File

@ -10,6 +10,7 @@ namespace Marco.Pms.Model.ViewModels.AttendanceVM
public string? LastName { get; set; }
public string? EmployeeAvatar { get; set; }
public string? OrganizationName { get; set; }
public string? ProjectName { get; set; }
public DateTime? CheckInTime { get; set; }
public DateTime? CheckOutTime { get; set; }
public string? JobRoleName { get; set; }

View File

@ -4,7 +4,6 @@ using Marco.Pms.Model.Dtos.Attendance;
using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Entitlements;
using Marco.Pms.Model.Mapper;
using Marco.Pms.Model.Projects;
using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.AttendanceVM;
using Marco.Pms.Services.Hubs;
@ -146,18 +145,11 @@ namespace MarcoBMS.Services.Controllers
[HttpGet("project/log")]
public async Task<IActionResult> EmployeeAttendanceByDateRange([FromQuery] Guid projectId, [FromQuery] Guid? organizationId, [FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null)
public async Task<IActionResult> EmployeeAttendanceByDateRange([FromQuery] Guid? projectId, [FromQuery] Guid? organizationId, [FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null)
{
Guid tenantId = GetTenantId();
var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var project = await _context.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
if (project == null)
{
_logger.LogWarning("Project {ProjectId} not found in database", projectId);
return NotFound(ApiResponse<object>.ErrorResponse("Project not found."));
}
var hasTeamAttendancePermission = await _permission.HasPermission(PermissionsMaster.TeamAttendance, LoggedInEmployee.Id);
var hasSelfAttendancePermission = await _permission.HasPermission(PermissionsMaster.SelfAttendance, LoggedInEmployee.Id);
@ -175,35 +167,41 @@ namespace MarcoBMS.Services.Controllers
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
}
if (projectId == Guid.Empty)
{
_logger.LogWarning("The project Id sent by user is less than or equal to zero");
return BadRequest(ApiResponse<object>.ErrorResponse("Project ID is required and must be greater than zero.", "Project ID is required and must be greater than zero.", 400));
}
var result = new List<EmployeeAttendanceVM>();
//Attendance? attendance = null;
if (dateFrom == null) fromDate = DateTime.UtcNow.Date;
if (dateTo == null && dateFrom != null) toDate = fromDate.AddDays(-1);
if (hasTeamAttendancePermission)
{
List<Attendance> lstAttendance = await _context.Attendes
var lstAttendanceQuery = _context.Attendes
.Include(a => a.Employee)
.ThenInclude(e => e!.Organization)
.Include(a => a.Employee)
.ThenInclude(e => e!.JobRole)
.Where(a => a.ProjectID == projectId &&
a.AttendanceDate.Date >= fromDate.Date &&
a.AttendanceDate.Date <= toDate.Date &&
a.TenantId == tenantId &&
a.Employee != null &&
a.Employee.Organization != null &&
a.Employee.JobRole != null
).ToListAsync();
.Where(a =>
a.AttendanceDate.Date >= fromDate.Date &&
a.AttendanceDate.Date <= toDate.Date &&
a.TenantId == tenantId &&
a.Employee != null &&
a.Employee.Organization != null &&
a.Employee.JobRole != null);
if (organizationId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.Employee != null && a.Employee.OrganizationId == organizationId);
}
if (projectId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.ProjectID == projectId);
}
if (hasTeamAttendancePermission)
{
List<Attendance> lstAttendance = await lstAttendanceQuery.ToListAsync();
var projectIds = lstAttendance.Select(a => a.ProjectID).ToList();
var projects = await _context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).ToListAsync();
var jobRole = await _context.JobRoles.ToListAsync();
foreach (Attendance? attendance in lstAttendance)
{
var result1 = new EmployeeAttendanceVM()
@ -216,6 +214,7 @@ namespace MarcoBMS.Services.Controllers
FirstName = attendance.Employee?.FirstName,
LastName = attendance.Employee?.LastName,
JobRoleName = attendance.Employee?.JobRole?.Name,
ProjectName = projects.Where(p => p.Id == attendance.ProjectID).Select(p => p.Name).FirstOrDefault(),
OrganizationName = attendance.Employee?.Organization?.Name
};
@ -224,26 +223,12 @@ namespace MarcoBMS.Services.Controllers
}
else if (hasSelfAttendancePermission)
{
var lstAttendanceQuery = _context.Attendes
.Include(a => a.Employee)
.ThenInclude(e => e!.Organization)
.Include(a => a.Employee)
.ThenInclude(e => e!.JobRole)
.Where(a => a.ProjectID == projectId &&
a.EmployeeId == LoggedInEmployee.Id &&
a.AttendanceDate.Date >= fromDate.Date &&
a.AttendanceDate.Date <= toDate.Date &&
a.TenantId == tenantId &&
a.Employee != null &&
a.Employee.Organization != null &&
a.Employee.JobRole != null);
if (organizationId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.Employee != null && a.Employee.OrganizationId == organizationId);
}
var lstAttendances = await lstAttendanceQuery.Where(a => a.EmployeeId == LoggedInEmployee.Id).ToListAsync();
var projectIds = lstAttendances.Select(a => a.ProjectID).ToList();
var projects = await _context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).ToListAsync();
var lstAttendances = await lstAttendanceQuery.ToListAsync();
foreach (var attendance in lstAttendances)
{
@ -255,6 +240,7 @@ namespace MarcoBMS.Services.Controllers
FirstName = attendance.Employee?.FirstName,
LastName = attendance.Employee?.LastName,
JobRoleName = attendance.Employee?.JobRole?.Name,
ProjectName = projects.Where(p => p.Id == attendance.ProjectID).Select(p => p.Name).FirstOrDefault(),
OrganizationName = attendance.Employee?.Organization?.Name,
CheckInTime = attendance.InTime,
CheckOutTime = attendance.OutTime,
@ -278,13 +264,13 @@ namespace MarcoBMS.Services.Controllers
/// <param name="includeInactive">Optional. Includes inactive employees in the team list if true.</param>
/// <param name="date">Optional. The date for which to fetch attendance, in "yyyy-MM-dd" format. Defaults to the current UTC date.</param>
/// <returns>An IActionResult containing a list of employee attendance records or an error response.</returns>
public async Task<IActionResult> EmployeeAttendanceByProjectAsync([FromQuery] Guid projectId, [FromQuery] Guid? organizationId, [FromQuery] bool includeInactive, [FromQuery] string? date = null)
public async Task<IActionResult> EmployeeAttendanceByProjectAsync([FromQuery] Guid? projectId, [FromQuery] Guid? organizationId, [FromQuery] bool includeInactive, [FromQuery] string? date = null)
{
var tenantId = GetTenantId();
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
// --- 1. Initial Validation and Permission Checks ---
_logger.LogInfo("Fetching attendance for ProjectId: {ProjectId}, TenantId: {TenantId}", projectId, tenantId);
_logger.LogInfo("Fetching attendance for ProjectId: {ProjectId}, TenantId: {TenantId}", projectId ?? Guid.Empty, tenantId);
// Validate date format
if (!DateTime.TryParse(date, out var forDate))
@ -292,14 +278,6 @@ namespace MarcoBMS.Services.Controllers
forDate = DateTime.UtcNow.Date; // Default to today's date
}
// Check if the project exists and if the employee has access
var project = await _context.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == projectId && p.TenantId == tenantId);
if (project == null)
{
_logger.LogWarning("Project {ProjectId} not found in database", projectId);
return NotFound(ApiResponse<object>.ErrorResponse("Project not found."));
}
// --- 2. Delegate to Specific Logic Based on Permissions ---
try
{
@ -326,50 +304,63 @@ namespace MarcoBMS.Services.Controllers
return StatusCode(403, ApiResponse<object>.ErrorResponse("You do not have permission to view attendance.", new { }, 403));
}
_logger.LogInfo("Successfully fetched {Count} attendance records for ProjectId: {ProjectId}", result.Count, projectId);
_logger.LogInfo("Successfully fetched {Count} attendance records for ProjectId: {ProjectId}", result.Count, projectId ?? Guid.Empty);
return Ok(ApiResponse<object>.SuccessResponse(result, $"{result.Count} attendance records fetched successfully."));
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred while fetching attendance for ProjectId: {ProjectId}", projectId);
_logger.LogError(ex, "An error occurred while fetching attendance for ProjectId: {ProjectId}", projectId ?? Guid.Empty);
return StatusCode(500, ApiResponse<object>.ErrorResponse("An internal server error occurred."));
}
}
[HttpGet("regularize")]
public async Task<IActionResult> GetRequestRegularizeAttendance([FromQuery] Guid projectId, [FromQuery] Guid? organizationId, [FromQuery] bool IncludeInActive)
public async Task<IActionResult> GetRequestRegularizeAttendance([FromQuery] Guid? projectId, [FromQuery] Guid? organizationId, [FromQuery] bool IncludeInActive)
{
Guid TenantId = GetTenantId();
Employee LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var result = new List<EmployeeAttendanceVM>();
List<Attendance> lstAttendance = await _context.Attendes.Where(c => c.ProjectID == projectId && c.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE && c.TenantId == TenantId).ToListAsync();
var lstAttendanceQuery = _context.Attendes
.Include(a => a.Employee)
.ThenInclude(e => e!.Organization)
.Include(a => a.Employee)
.ThenInclude(e => e!.JobRole)
.Where(c => c.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE && c.Employee != null && c.Employee.JobRole != null && c.TenantId == TenantId);
List<ProjectAllocation> projectteam = await _projectServices.GetTeamByProject(TenantId, projectId, organizationId, true);
var idList = projectteam.Select(p => p.EmployeeId).ToList();
var jobRole = await _context.JobRoles.ToListAsync();
if (organizationId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.Employee != null && a.Employee.OrganizationId == organizationId);
}
if (projectId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.ProjectID == projectId);
}
List<Attendance> lstAttendance = await lstAttendanceQuery.ToListAsync();
var projectIds = lstAttendance.Select(a => a.ProjectID).ToList();
var projects = await _context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == TenantId).ToListAsync();
foreach (Attendance attende in lstAttendance)
{
var teamMember = projectteam.Find(m => m.EmployeeId == attende.EmployeeId);
if (teamMember != null && teamMember.Employee != null && teamMember.Employee.JobRole != null)
var result1 = new EmployeeAttendanceVM()
{
var result1 = new EmployeeAttendanceVM()
{
Id = attende.Id,
CheckInTime = attende.InTime,
CheckOutTime = attende.OutTime,
Activity = attende.Activity,
EmployeeAvatar = null,
EmployeeId = attende.EmployeeId,
FirstName = teamMember.Employee.FirstName,
LastName = teamMember.Employee.LastName,
JobRoleName = teamMember.Employee.JobRole.Name,
OrganizationName = teamMember.Employee.Organization?.Name
};
result.Add(result1);
}
Id = attende.Id,
CheckInTime = attende.InTime,
CheckOutTime = attende.OutTime,
Activity = attende.Activity,
EmployeeAvatar = null,
EmployeeId = attende.EmployeeId,
FirstName = attende.Employee?.FirstName,
ProjectName = projects.Where(p => p.Id == attende.ProjectID).Select(p => p.Name).FirstOrDefault(),
LastName = attende.Employee?.LastName,
JobRoleName = attende.Employee?.JobRole?.Name,
OrganizationName = attende.Employee?.Organization?.Name
};
result.Add(result1);
}
@ -793,7 +784,7 @@ namespace MarcoBMS.Services.Controllers
/// <summary>
/// Fetches attendance for an entire project team using a single, optimized database query.
/// </summary>
private async Task<List<EmployeeAttendanceVM>> GetTeamAttendanceAsync(Guid tenantId, Guid projectId, Guid organizationId, DateTime forDate, bool includeInactive)
private async Task<List<EmployeeAttendanceVM>> GetTeamAttendanceAsync(Guid tenantId, Guid? projectId, Guid organizationId, DateTime forDate, bool includeInactive)
{
// This single query joins ProjectAllocations with Employees and performs a LEFT JOIN with Attendances.
// This is far more efficient than fetching collections and joining them in memory.
@ -803,12 +794,22 @@ namespace MarcoBMS.Services.Controllers
.Where(e => e.OrganizationId == organizationId && e.Organization != null && e.JobRole != null && e.IsActive);
List<Attendance> lstAttendance = await _context.Attendes.Where(c => c.ProjectID == projectId && c.AttendanceDate.Date == forDate && c.TenantId == tenantId).ToListAsync();
var lstAttendanceQuery = _context.Attendes.Where(c => c.AttendanceDate.Date == forDate && c.TenantId == tenantId);
if (projectId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.ProjectID == projectId);
}
List<Attendance> lstAttendance = await lstAttendanceQuery.ToListAsync();
var employees = await query
.AsNoTracking()
.ToListAsync();
var projectIds = lstAttendance.Select(a => a.ProjectID).ToList();
var projects = await _context.Projects.Where(p => projectIds.Contains(p.Id) && p.TenantId == tenantId).ToListAsync();
var response = employees
.Select(employee =>
{
@ -822,9 +823,6 @@ namespace MarcoBMS.Services.Controllers
JobRoleName = employee.JobRole!.Name,
};
//var member = emp.Where(e => e.Id == teamMember.EmployeeId);
var attendance = lstAttendance.Find(x => x.EmployeeId == employee.Id) ?? new Attendance();
if (attendance != null)
{
@ -832,6 +830,7 @@ namespace MarcoBMS.Services.Controllers
result1.CheckInTime = attendance.InTime;
result1.CheckOutTime = attendance.OutTime;
result1.Activity = attendance.Activity;
result1.ProjectName = projects.Where(p => p.Id == attendance.ProjectID).Select(p => p.Name).FirstOrDefault();
}
return result1;
})
@ -844,13 +843,23 @@ namespace MarcoBMS.Services.Controllers
/// <summary>
/// Fetches a single attendance record for the logged-in employee.
/// </summary>
private async Task<List<EmployeeAttendanceVM>> GetSelfAttendanceAsync(Guid tenantId, Guid projectId, Guid employeeId, DateTime forDate)
private async Task<List<EmployeeAttendanceVM>> GetSelfAttendanceAsync(Guid tenantId, Guid? projectId, Guid employeeId, DateTime forDate)
{
List<EmployeeAttendanceVM> result = new List<EmployeeAttendanceVM>();
// This query fetches the employee's project allocation and their attendance in a single trip.
Attendance lstAttendance = await _context.Attendes
.FirstOrDefaultAsync(c => c.ProjectID == projectId && c.EmployeeId == employeeId && c.AttendanceDate.Date == forDate && c.TenantId == tenantId) ?? new Attendance();
var lstAttendanceQuery = _context.Attendes
.Where(c => c.EmployeeId == employeeId && c.AttendanceDate.Date == forDate && c.TenantId == tenantId);
if (projectId.HasValue)
{
lstAttendanceQuery = lstAttendanceQuery.Where(a => a.ProjectID == projectId);
}
Attendance lstAttendance = await lstAttendanceQuery.FirstOrDefaultAsync() ?? new Attendance();
var project = await _context.Projects.FirstOrDefaultAsync(p => p.Id == lstAttendance.ProjectID && p.TenantId == tenantId);
var employee = await _context.Employees
.Include(e => e.Organization)
@ -866,6 +875,7 @@ namespace MarcoBMS.Services.Controllers
EmployeeId = employee.Id,
FirstName = employee.FirstName,
OrganizationName = employee.Organization.Name,
ProjectName = project?.Name,
LastName = employee.LastName,
JobRoleName = employee.JobRole.Name,
CheckInTime = lstAttendance.InTime,