Added project validation in attendance Overview API

This commit is contained in:
ashutosh.nehete 2025-06-20 13:09:13 +05:30
parent b78c5c07c5
commit 82ebd07d61

View File

@ -5,6 +5,7 @@ using Marco.Pms.Model.Employees;
using Marco.Pms.Model.Projects; using Marco.Pms.Model.Projects;
using Marco.Pms.Model.Utilities; using Marco.Pms.Model.Utilities;
using Marco.Pms.Model.ViewModels.DashBoard; using Marco.Pms.Model.ViewModels.DashBoard;
using Marco.Pms.Services.Service;
using MarcoBMS.Services.Helpers; using MarcoBMS.Services.Helpers;
using MarcoBMS.Services.Service; using MarcoBMS.Services.Service;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -21,11 +22,13 @@ namespace Marco.Pms.Services.Controllers
private readonly ApplicationDbContext _context; private readonly ApplicationDbContext _context;
private readonly UserHelper _userHelper; private readonly UserHelper _userHelper;
private readonly ILoggingService _logger; private readonly ILoggingService _logger;
public DashboardController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger) private readonly PermissionServices _permissionServices;
public DashboardController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, PermissionServices permissionServices)
{ {
_context = context; _context = context;
_userHelper = userHelper; _userHelper = userHelper;
_logger = logger; _logger = logger;
_permissionServices = permissionServices;
} }
[HttpGet("progression")] [HttpGet("progression")]
public async Task<IActionResult> GetGraph([FromQuery] double days, [FromQuery] string FromDate, [FromQuery] Guid? projectId) public async Task<IActionResult> GetGraph([FromQuery] double days, [FromQuery] string FromDate, [FromQuery] Guid? projectId)
@ -360,36 +363,67 @@ namespace Marco.Pms.Services.Controllers
{ {
_logger.LogInfo("GetAttendanceOverView called for ProjectId: {ProjectId}, Days: {Days}", projectId, days); _logger.LogInfo("GetAttendanceOverView called for ProjectId: {ProjectId}, Days: {Days}", projectId, days);
// Step 1: Validate project existence
var project = await _context.Projects.AsNoTracking().FirstOrDefaultAsync(p => p.Id == projectId);
if (project == null)
{
_logger.LogWarning("Project not found for ProjectId: {ProjectId}", projectId);
return BadRequest(ApiResponse<object>.ErrorResponse("Project not found", "Project not found", 400));
}
// Step 2: Permission check
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
bool hasAssigned = await _permissionServices.HasProjectPermission(loggedInEmployee, projectId.ToString());
if (!hasAssigned)
{
_logger.LogWarning("Unauthorized access attempt. EmployeeId: {EmployeeId}, ProjectId: {ProjectId}", loggedInEmployee.Id, projectId);
return StatusCode(403, ApiResponse<object>.ErrorResponse(
"You don't have permission to access this feature",
"You don't have permission to access this feature", 403));
}
// Step 3: Validate and parse days input
if (!int.TryParse(days, out int dayCount) || dayCount <= 0) if (!int.TryParse(days, out int dayCount) || dayCount <= 0)
{ {
_logger.LogWarning("Invalid days input received: {Days}", days);
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid number of days", "Days must be a positive integer", 400)); return BadRequest(ApiResponse<object>.ErrorResponse("Invalid number of days", "Days must be a positive integer", 400));
} }
// Step 4: Define date range
DateTime today = DateTime.UtcNow.Date; DateTime today = DateTime.UtcNow.Date;
DateTime startDate = today.AddDays(-dayCount); DateTime startDate = today.AddDays(-dayCount);
// Step 1: Get project allocations and related job roles // Step 5: Load project allocations and related job roles
var allocations = await _context.ProjectAllocations var allocations = await _context.ProjectAllocations
.Where(pa => pa.ProjectId == projectId) .Where(pa => pa.ProjectId == projectId)
.ToListAsync(); .ToListAsync();
if (!allocations.Any())
{
_logger.LogInfo("No employee allocations found for project: {ProjectId}", projectId);
return Ok(ApiResponse<object>.SuccessResponse(new List<AttendanceOverviewVM>(), "No allocations found", 200));
}
var jobRoleIds = allocations.Select(pa => pa.JobRoleId).Distinct().ToList(); var jobRoleIds = allocations.Select(pa => pa.JobRoleId).Distinct().ToList();
var jobRoles = await _context.JobRoles var jobRoles = await _context.JobRoles
.Where(jr => jobRoleIds.Contains(jr.Id)) .Where(jr => jobRoleIds.Contains(jr.Id))
.ToListAsync(); .ToListAsync();
// Step 2: Get attendance records for the given range // Step 6: Load attendance records for given date range
var attendances = await _context.Attendes var attendances = await _context.Attendes
.Where(a => a.ProjectID == projectId .Where(a =>
&& a.InTime.HasValue a.ProjectID == projectId &&
&& a.InTime.Value.Date >= startDate a.InTime.HasValue &&
&& a.InTime.Value.Date <= today) a.InTime.Value.Date >= startDate &&
a.InTime.Value.Date <= today)
.ToListAsync(); .ToListAsync();
var result = new List<AttendanceOverviewVM>(); var overviewList = new List<AttendanceOverviewVM>();
// Step 3: Generate report per day and job role // Step 7: Process attendance per date per role
for (DateTime date = today; date >= startDate; date = date.AddDays(-1)) for (DateTime date = today; date > startDate; date = date.AddDays(-1))
{ {
foreach (var jobRole in jobRoles) foreach (var jobRole in jobRoles)
{ {
@ -398,26 +432,27 @@ namespace Marco.Pms.Services.Controllers
.Select(pa => pa.EmployeeId) .Select(pa => pa.EmployeeId)
.ToList(); .ToList();
var count = attendances int presentCount = attendances
.Count(a => employeeIds.Contains(a.EmployeeID) && a.InTime!.Value.Date == date); .Count(a => employeeIds.Contains(a.EmployeeID) && a.InTime!.Value.Date == date);
result.Add(new AttendanceOverviewVM overviewList.Add(new AttendanceOverviewVM
{ {
Role = jobRole.Name, Role = jobRole.Name,
Date = date.ToString("yyyy-MM-dd"), Date = date.ToString("yyyy-MM-dd"),
Present = count Present = presentCount
}); });
} }
} }
var ordered = result // Step 8: Order result for consistent presentation
var sortedResult = overviewList
.OrderByDescending(r => r.Date) .OrderByDescending(r => r.Date)
.ThenByDescending(r => r.Present) .ThenByDescending(r => r.Present)
.ToList(); .ToList();
_logger.LogInfo("Attendance overview fetched for ProjectId: {ProjectId}, Total Records: {Count}", projectId, ordered.Count); _logger.LogInfo("Attendance overview fetched. ProjectId: {ProjectId}, Records: {Count}", projectId, sortedResult.Count);
return Ok(ApiResponse<object>.SuccessResponse(ordered, $"{ordered.Count} records fetched for attendance overview", 200)); return Ok(ApiResponse<object>.SuccessResponse(sortedResult, $"{sortedResult.Count} records fetched for attendance overview", 200));
} }
} }
} }