Ashutosh_Task#513 #96
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user