diff --git a/Marco.Pms.Model/ViewModels/DashBoard/AttendanceOverviewVM.cs b/Marco.Pms.Model/ViewModels/DashBoard/AttendanceOverviewVM.cs new file mode 100644 index 0000000..e1e626e --- /dev/null +++ b/Marco.Pms.Model/ViewModels/DashBoard/AttendanceOverviewVM.cs @@ -0,0 +1,9 @@ +namespace Marco.Pms.Model.ViewModels.DashBoard +{ + public class AttendanceOverviewVM + { + public string? Role { get; set; } + public string? Date { get; set; } + public int Present { get; set; } + } +} diff --git a/Marco.Pms.Services/Controllers/DashboardController.cs b/Marco.Pms.Services/Controllers/DashboardController.cs index c22ca18..8a51336 100644 --- a/Marco.Pms.Services/Controllers/DashboardController.cs +++ b/Marco.Pms.Services/Controllers/DashboardController.cs @@ -354,5 +354,70 @@ namespace Marco.Pms.Services.Controllers _logger.LogInfo($"Record of performed activities for project {projectId} for date {currentDate.Date} by employee {LoggedInEmployee.Id}"); return Ok(ApiResponse.SuccessResponse(report, $"Record of performed activities for project {project.Name} for date {currentDate.Date}", 200)); } + + [HttpGet("attendance-overview/{projectId}")] + public async Task GetAttendanceOverView(Guid projectId, [FromQuery] string days) + { + _logger.LogInfo("GetAttendanceOverView called for ProjectId: {ProjectId}, Days: {Days}", projectId, days); + + if (!int.TryParse(days, out int dayCount) || dayCount <= 0) + { + return BadRequest(ApiResponse.ErrorResponse("Invalid number of days", "Days must be a positive integer", 400)); + } + + DateTime today = DateTime.UtcNow.Date; + DateTime startDate = today.AddDays(-dayCount); + + // Step 1: Get project allocations and related job roles + var allocations = await _context.ProjectAllocations + .Where(pa => pa.ProjectId == projectId) + .ToListAsync(); + + var jobRoleIds = allocations.Select(pa => pa.JobRoleId).Distinct().ToList(); + var jobRoles = await _context.JobRoles + .Where(jr => jobRoleIds.Contains(jr.Id)) + .ToListAsync(); + + // Step 2: Get attendance records for the given range + var attendances = await _context.Attendes + .Where(a => a.ProjectID == projectId + && a.InTime.HasValue + && a.InTime.Value.Date >= startDate + && a.InTime.Value.Date <= today) + .ToListAsync(); + + var result = new List(); + + // Step 3: Generate report per day and job role + for (DateTime date = today; date >= startDate; date = date.AddDays(-1)) + { + foreach (var jobRole in jobRoles) + { + var employeeIds = allocations + .Where(pa => pa.JobRoleId == jobRole.Id) + .Select(pa => pa.EmployeeId) + .ToList(); + + var count = attendances + .Count(a => employeeIds.Contains(a.EmployeeID) && a.InTime!.Value.Date == date); + + result.Add(new AttendanceOverviewVM + { + Role = jobRole.Name, + Date = date.ToString("yyyy-MM-dd"), + Present = count + }); + } + } + + var ordered = result + .OrderByDescending(r => r.Date) + .ThenByDescending(r => r.Present) + .ToList(); + + _logger.LogInfo("Attendance overview fetched for ProjectId: {ProjectId}, Total Records: {Count}", projectId, ordered.Count); + + return Ok(ApiResponse.SuccessResponse(ordered, $"{ordered.Count} records fetched for attendance overview", 200)); + } } }