866 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			866 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System.Globalization;
 | 
						|
using Marco.Pms.DataAccess.Data;
 | 
						|
using Marco.Pms.Model.AttendanceModule;
 | 
						|
using Marco.Pms.Model.Dtos.Attendance;
 | 
						|
using Marco.Pms.Model.Employees;
 | 
						|
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;
 | 
						|
using Marco.Pms.Services.Service;
 | 
						|
using MarcoBMS.Services.Helpers;
 | 
						|
using MarcoBMS.Services.Service;
 | 
						|
using Microsoft.AspNetCore.Authorization;
 | 
						|
using Microsoft.AspNetCore.Mvc;
 | 
						|
using Microsoft.AspNetCore.SignalR;
 | 
						|
using Microsoft.CodeAnalysis;
 | 
						|
using Microsoft.EntityFrameworkCore;
 | 
						|
using Document = Marco.Pms.Model.DocumentManager.Document;
 | 
						|
 | 
						|
namespace MarcoBMS.Services.Controllers
 | 
						|
{
 | 
						|
    [Authorize]
 | 
						|
    [ApiController]
 | 
						|
    [Route("api/[controller]")]
 | 
						|
    public class AttendanceController : ControllerBase
 | 
						|
    {
 | 
						|
        private readonly ApplicationDbContext _context;
 | 
						|
        private readonly EmployeeHelper _employeeHelper;
 | 
						|
        private readonly ProjectsHelper _projectsHelper;
 | 
						|
        private readonly UserHelper _userHelper;
 | 
						|
        private readonly S3UploadService _s3Service;
 | 
						|
        private readonly PermissionServices _permission;
 | 
						|
        private readonly ILoggingService _logger;
 | 
						|
        private readonly IHubContext<MarcoHub> _signalR;
 | 
						|
 | 
						|
 | 
						|
        public AttendanceController(
 | 
						|
             ApplicationDbContext context, EmployeeHelper employeeHelper, ProjectsHelper projectsHelper, UserHelper userHelper, S3UploadService s3Service, ILoggingService logger, PermissionServices permission, IHubContext<MarcoHub> signalR)
 | 
						|
        {
 | 
						|
            _context = context;
 | 
						|
            _employeeHelper = employeeHelper;
 | 
						|
            _projectsHelper = projectsHelper;
 | 
						|
            _userHelper = userHelper;
 | 
						|
            _s3Service = s3Service;
 | 
						|
            _logger = logger;
 | 
						|
            _permission = permission;
 | 
						|
            _signalR = signalR;
 | 
						|
        }
 | 
						|
 | 
						|
        private Guid GetTenantId()
 | 
						|
        {
 | 
						|
            return _userHelper.GetTenantId();
 | 
						|
            //var tenant = User.FindFirst("TenantId")?.Value;
 | 
						|
            //return (tenant != null ? Convert.ToInt32(tenant) : 1);
 | 
						|
        }
 | 
						|
 | 
						|
        [HttpGet("log/attendance/{attendanceid}")]
 | 
						|
 | 
						|
        public async Task<IActionResult> GetAttendanceLogById(Guid attendanceid)
 | 
						|
        {
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
 | 
						|
            List<AttendanceLog> lstAttendance = await _context.AttendanceLogs.Include(a => a.Document).Include(a => a.Employee).Include(a => a.UpdatedByEmployee).Where(c => c.AttendanceId == attendanceid && c.TenantId == TenantId).ToListAsync();
 | 
						|
            List<AttendanceLogVM> attendanceLogVMs = new List<AttendanceLogVM>();
 | 
						|
            foreach (var attendanceLog in lstAttendance)
 | 
						|
            {
 | 
						|
                string objectKey = attendanceLog.Document != null ? attendanceLog.Document.S3Key : string.Empty;
 | 
						|
                string preSignedUrl = string.IsNullOrEmpty(objectKey) ? string.Empty : _s3Service.GeneratePreSignedUrlAsync(objectKey);
 | 
						|
                attendanceLogVMs.Add(attendanceLog.ToAttendanceLogVMFromAttendanceLog(preSignedUrl, preSignedUrl));
 | 
						|
            }
 | 
						|
            _logger.LogInfo("{count} Attendance records fetched successfully", lstAttendance.Count);
 | 
						|
            return Ok(ApiResponse<object>.SuccessResponse(attendanceLogVMs, System.String.Format("{0} Attendance records fetched successfully", lstAttendance.Count), 200));
 | 
						|
 | 
						|
        }
 | 
						|
        [HttpGet("log/employee/{employeeId}")]
 | 
						|
 | 
						|
        public async Task<IActionResult> GetAttendanceLogByEmployeeId(Guid employeeId, [FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null)
 | 
						|
        {
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
            DateTime fromDate = new DateTime();
 | 
						|
            DateTime toDate = new DateTime();
 | 
						|
 | 
						|
            if (dateFrom != null && DateTime.TryParse(dateFrom, out fromDate) == false)
 | 
						|
            {
 | 
						|
                _logger.LogError("User sent Invalid from Date while featching attendance logs");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
 | 
						|
            }
 | 
						|
            if (dateTo != null && DateTime.TryParse(dateTo, out toDate) == false)
 | 
						|
            {
 | 
						|
                _logger.LogError("User sent Invalid to Date while featching attendance logs");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
 | 
						|
            }
 | 
						|
 | 
						|
            if (employeeId == Guid.Empty)
 | 
						|
            {
 | 
						|
                _logger.LogError("The employee Id sent by user is empty");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Employee ID is required and must not be Empty.", "Employee ID is required and must not be empty.", 400));
 | 
						|
            }
 | 
						|
            List<Attendance> attendances = await _context.Attendes.Where(c => c.EmployeeID == employeeId && c.TenantId == TenantId && c.AttendanceDate.Date >= fromDate && c.AttendanceDate.Date <= toDate).ToListAsync();
 | 
						|
            Employee? employee = await _context.Employees.Include(e => e.JobRole).FirstOrDefaultAsync(e => e.Id == employeeId && e.TenantId == TenantId && e.IsActive);
 | 
						|
            List<EmployeeAttendanceVM> results = new List<EmployeeAttendanceVM>();
 | 
						|
 | 
						|
            if (employee != null)
 | 
						|
            {
 | 
						|
                foreach (var attendance in attendances)
 | 
						|
                {
 | 
						|
                    EmployeeAttendanceVM result = new EmployeeAttendanceVM
 | 
						|
                    {
 | 
						|
                        Id = attendance.Id,
 | 
						|
                        EmployeeId = employee.Id,
 | 
						|
                        FirstName = employee.FirstName,
 | 
						|
                        LastName = employee.LastName,
 | 
						|
                        CheckInTime = attendance.InTime,
 | 
						|
                        CheckOutTime = attendance.OutTime,
 | 
						|
                        JobRoleName = employee.JobRole != null ? employee.JobRole.Name : "",
 | 
						|
                        Activity = attendance.Activity,
 | 
						|
                        EmployeeAvatar = null
 | 
						|
                    };
 | 
						|
                    results.Add(result);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            _logger.LogInfo("{count} Attendance records fetched successfully", results.Count);
 | 
						|
            return Ok(ApiResponse<object>.SuccessResponse(results, System.String.Format("{0} Attendance records fetched successfully", results.Count), 200));
 | 
						|
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="projectId">ProjectID</param>
 | 
						|
        /// <param name="date">YYYY-MM-dd</param>
 | 
						|
        /// <returns></returns>
 | 
						|
        [HttpGet("project/log")]
 | 
						|
 | 
						|
        public async Task<IActionResult> EmployeeAttendanceByDateRange([FromQuery] Guid projectId, [FromQuery] string? dateFrom = null, [FromQuery] string? dateTo = null)
 | 
						|
        {
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
            var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
 | 
						|
            var hasTeamAttendancePermission = await _permission.HasPermission(new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), LoggedInEmployee.Id);
 | 
						|
            var hasSelfAttendancePermission = await _permission.HasPermission(new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), LoggedInEmployee.Id);
 | 
						|
            var hasProjectPermission = await _permission.HasProjectPermission(LoggedInEmployee, projectId.ToString());
 | 
						|
 | 
						|
            if (!hasProjectPermission)
 | 
						|
            {
 | 
						|
                _logger.LogWarning("Employee {EmployeeId} tries to access attendance of project {ProjectId}, but don't have access", LoggedInEmployee.Id, projectId);
 | 
						|
                return Unauthorized(ApiResponse<object>.ErrorResponse("Unauthorized access", "Unauthorized access", 404));
 | 
						|
            }
 | 
						|
 | 
						|
            DateTime fromDate = new DateTime();
 | 
						|
            DateTime toDate = new DateTime();
 | 
						|
 | 
						|
            if (dateFrom != null && DateTime.TryParse(dateFrom, out fromDate) == false)
 | 
						|
            {
 | 
						|
                _logger.LogError("User sent Invalid fromDate while featching attendance logs");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
 | 
						|
            }
 | 
						|
            if (dateTo != null && DateTime.TryParse(dateTo, out toDate) == false)
 | 
						|
            {
 | 
						|
                _logger.LogError("User sent Invalid toDate while featching attendance logs");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
 | 
						|
            }
 | 
						|
 | 
						|
            if (projectId == Guid.Empty)
 | 
						|
            {
 | 
						|
                _logger.LogError("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;
 | 
						|
            ProjectAllocation? teamMember = 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.Where(c => c.ProjectID == projectId && c.AttendanceDate.Date >= fromDate.Date && c.AttendanceDate.Date <= toDate.Date && c.TenantId == TenantId).ToListAsync();
 | 
						|
 | 
						|
 | 
						|
                List<ProjectAllocation> projectteam = await _projectsHelper.GetTeamByProject(TenantId, projectId, true);
 | 
						|
                var jobRole = await _context.JobRoles.ToListAsync();
 | 
						|
                foreach (Attendance? attendance in lstAttendance)
 | 
						|
                {
 | 
						|
                    var result1 = new EmployeeAttendanceVM()
 | 
						|
                    {
 | 
						|
                        Id = attendance.Id,
 | 
						|
                        CheckInTime = attendance.InTime,
 | 
						|
                        CheckOutTime = attendance.OutTime,
 | 
						|
                        Activity = attendance.Activity
 | 
						|
                    };
 | 
						|
                    teamMember = projectteam.Find(x => x.EmployeeId == attendance.EmployeeID);
 | 
						|
                    if (teamMember != null)
 | 
						|
                    {
 | 
						|
                        result1.EmployeeAvatar = null;
 | 
						|
                        result1.EmployeeId = teamMember.EmployeeId;
 | 
						|
                        if (teamMember.Employee != null)
 | 
						|
                        {
 | 
						|
                            result1.FirstName = teamMember.Employee.FirstName;
 | 
						|
                            result1.LastName = teamMember.Employee.LastName;
 | 
						|
                            result1.JobRoleName = teamMember.Employee.JobRole != null ? teamMember.Employee.JobRole.Name : null;
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            result1.FirstName = null;
 | 
						|
                            result1.LastName = null;
 | 
						|
                            result1.JobRoleName = null;
 | 
						|
                        }
 | 
						|
 | 
						|
                        result.Add(result1);
 | 
						|
                    }
 | 
						|
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else if (hasSelfAttendancePermission)
 | 
						|
            {
 | 
						|
                List<Attendance> lstAttendances = await _context.Attendes.Where(c => c.ProjectID == projectId && c.EmployeeID == LoggedInEmployee.Id && c.AttendanceDate.Date >= fromDate.Date && c.AttendanceDate.Date <= toDate.Date && c.TenantId == TenantId).ToListAsync();
 | 
						|
                ProjectAllocation? projectAllocation = await _context.ProjectAllocations.Include(pa => pa.Employee).FirstOrDefaultAsync(pa => pa.ProjectId == projectId && pa.EmployeeId == LoggedInEmployee.Id && pa.TenantId == TenantId && pa.IsActive);
 | 
						|
                foreach (var attendance in lstAttendances)
 | 
						|
                {
 | 
						|
                    if (projectAllocation != null)
 | 
						|
                    {
 | 
						|
                        EmployeeAttendanceVM result1 = new EmployeeAttendanceVM
 | 
						|
                        {
 | 
						|
                            Id = attendance.Id,
 | 
						|
                            EmployeeAvatar = null,
 | 
						|
                            EmployeeId = projectAllocation.EmployeeId,
 | 
						|
                            FirstName = projectAllocation.Employee?.FirstName,
 | 
						|
                            LastName = projectAllocation.Employee?.LastName,
 | 
						|
                            JobRoleName = projectAllocation.Employee?.JobRole?.Name,
 | 
						|
                            CheckInTime = attendance.InTime,
 | 
						|
                            CheckOutTime = attendance.OutTime,
 | 
						|
                            Activity = attendance.Activity
 | 
						|
                        };
 | 
						|
                        result.Add(result1);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            _logger.LogInfo("{count} Attendance records fetched successfully", result.Count);
 | 
						|
            return Ok(ApiResponse<object>.SuccessResponse(result, System.String.Format("{0} Attendance records fetched successfully", result.Count), 200));
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// 
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="projectId">ProjectID</param>
 | 
						|
        /// <param name="date">YYYY-MM-dd</param>
 | 
						|
        /// <returns></returns>
 | 
						|
        [HttpGet("project/team")]
 | 
						|
 | 
						|
        public async Task<IActionResult> EmployeeAttendanceByProject([FromQuery] Guid projectId, [FromQuery] bool IncludeInActive, [FromQuery] string? date = null)
 | 
						|
        {
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
            var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
 | 
						|
            var hasTeamAttendancePermission = await _permission.HasPermission(new Guid("915e6bff-65f6-4e3f-aea8-3fd217d3ea9e"), LoggedInEmployee.Id);
 | 
						|
            var hasSelfAttendancePermission = await _permission.HasPermission(new Guid("ccb0589f-712b-43de-92ed-5b6088e7dc4e"), LoggedInEmployee.Id);
 | 
						|
            var hasProjectPermission = await _permission.HasProjectPermission(LoggedInEmployee, projectId.ToString());
 | 
						|
 | 
						|
            if (!hasProjectPermission)
 | 
						|
            {
 | 
						|
                _logger.LogWarning("Employee {EmployeeId} tries to access attendance of project {ProjectId}, but don't have access", LoggedInEmployee.Id, projectId);
 | 
						|
                return Unauthorized(ApiResponse<object>.ErrorResponse("Unauthorized access", "Unauthorized access", 404));
 | 
						|
            }
 | 
						|
 | 
						|
            DateTime forDate = new DateTime();
 | 
						|
 | 
						|
            if (date != null && DateTime.TryParse(date, out forDate) == false)
 | 
						|
            {
 | 
						|
                _logger.LogError("User sent Invalid Date while featching attendance logs");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Date", "Invalid Date", 400));
 | 
						|
 | 
						|
            }
 | 
						|
            if (projectId == Guid.Empty)
 | 
						|
            {
 | 
						|
                _logger.LogError("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 (date == null) forDate = DateTime.UtcNow.Date;
 | 
						|
            if (hasTeamAttendancePermission)
 | 
						|
            {
 | 
						|
                List<Attendance> lstAttendance = await _context.Attendes.Where(c => c.ProjectID == projectId && c.AttendanceDate.Date == forDate && c.TenantId == TenantId).ToListAsync();
 | 
						|
 | 
						|
 | 
						|
                List<ProjectAllocation> projectteam = await _projectsHelper.GetTeamByProject(TenantId, projectId, IncludeInActive);
 | 
						|
                var idList = projectteam.Select(p => p.EmployeeId).ToList();
 | 
						|
                //var emp = await _context.Employees.Where(e => idList.Contains(e.Id)).Include(e => e.JobRole).ToListAsync();
 | 
						|
                var jobRole = await _context.JobRoles.ToListAsync();
 | 
						|
 | 
						|
                foreach (ProjectAllocation teamMember in projectteam)
 | 
						|
                {
 | 
						|
                    if (teamMember.Employee != null && teamMember.Employee.JobRole != null)
 | 
						|
                    {
 | 
						|
                        var result1 = new EmployeeAttendanceVM()
 | 
						|
                        {
 | 
						|
                            EmployeeAvatar = null,
 | 
						|
                            EmployeeId = teamMember.EmployeeId,
 | 
						|
                            FirstName = teamMember.Employee.FirstName,
 | 
						|
                            LastName = teamMember.Employee.LastName,
 | 
						|
                            JobRoleName = teamMember.Employee.JobRole.Name,
 | 
						|
                        };
 | 
						|
 | 
						|
                        //var member = emp.Where(e => e.Id == teamMember.EmployeeId);
 | 
						|
 | 
						|
 | 
						|
                        attendance = lstAttendance.Find(x => x.EmployeeID == teamMember.EmployeeId) ?? new Attendance();
 | 
						|
                        if (attendance != null)
 | 
						|
                        {
 | 
						|
                            result1.Id = attendance.Id;
 | 
						|
                            result1.CheckInTime = attendance.InTime;
 | 
						|
                            result1.CheckOutTime = attendance.OutTime;
 | 
						|
                            result1.Activity = attendance.Activity;
 | 
						|
                        }
 | 
						|
 | 
						|
                        result.Add(result1);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                result.Sort(delegate (EmployeeAttendanceVM x, EmployeeAttendanceVM y)
 | 
						|
                {
 | 
						|
                    //return x.FirstName.CompareTo(y.FirstName);
 | 
						|
                    return string.Compare(x.FirstName, y.FirstName, StringComparison.Ordinal);
 | 
						|
                });
 | 
						|
            }
 | 
						|
            else if (hasSelfAttendancePermission)
 | 
						|
            {
 | 
						|
                Attendance lstAttendance = await _context.Attendes.FirstOrDefaultAsync(c => c.ProjectID == projectId && c.EmployeeID == LoggedInEmployee.Id && c.AttendanceDate.Date == forDate && c.TenantId == TenantId) ?? new Attendance();
 | 
						|
                ProjectAllocation? projectAllocation = await _context.ProjectAllocations.Include(pa => pa.Employee).FirstOrDefaultAsync(pa => pa.ProjectId == projectId && pa.EmployeeId == LoggedInEmployee.Id && pa.TenantId == TenantId && pa.IsActive);
 | 
						|
                if (projectAllocation != null)
 | 
						|
                {
 | 
						|
                    EmployeeAttendanceVM result1 = new EmployeeAttendanceVM
 | 
						|
                    {
 | 
						|
                        Id = lstAttendance.Id,
 | 
						|
                        EmployeeAvatar = null,
 | 
						|
                        EmployeeId = projectAllocation.EmployeeId,
 | 
						|
                        FirstName = projectAllocation.Employee?.FirstName,
 | 
						|
                        LastName = projectAllocation.Employee?.LastName,
 | 
						|
                        JobRoleName = projectAllocation.Employee?.JobRole?.Name,
 | 
						|
                        CheckInTime = lstAttendance.InTime,
 | 
						|
                        CheckOutTime = lstAttendance.OutTime,
 | 
						|
                        Activity = lstAttendance.Activity
 | 
						|
                    };
 | 
						|
                    result.Add(result1);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            _logger.LogInfo("{count} Attendance records fetched successfully", result.Count);
 | 
						|
 | 
						|
            return Ok(ApiResponse<object>.SuccessResponse(result, System.String.Format("{0} Attendance records fetched successfully", result.Count), 200));
 | 
						|
        }
 | 
						|
 | 
						|
        [HttpGet("regularize")]
 | 
						|
 | 
						|
        public async Task<IActionResult> GetRequestRegularizeAttendance([FromQuery] Guid projectId, [FromQuery] bool IncludeInActive)
 | 
						|
        {
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
            Employee LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
 | 
						|
            var result = new List<EmployeeAttendanceVM>();
 | 
						|
            var hasProjectPermission = await _permission.HasProjectPermission(LoggedInEmployee, projectId.ToString());
 | 
						|
 | 
						|
            if (!hasProjectPermission)
 | 
						|
            {
 | 
						|
                _logger.LogWarning("Employee {EmployeeId} tries to access attendance of project {ProjectId}, but don't have access", LoggedInEmployee.Id, projectId);
 | 
						|
                return Unauthorized(ApiResponse<object>.ErrorResponse("Unauthorized access", "Unauthorized access", 404));
 | 
						|
            }
 | 
						|
 | 
						|
            List<Attendance> lstAttendance = await _context.Attendes.Where(c => c.ProjectID == projectId && c.Activity == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE && c.TenantId == TenantId).ToListAsync();
 | 
						|
 | 
						|
 | 
						|
            List<ProjectAllocation> projectteam = await _projectsHelper.GetTeamByProject(TenantId, projectId, true);
 | 
						|
            var idList = projectteam.Select(p => p.EmployeeId).ToList();
 | 
						|
            var jobRole = await _context.JobRoles.ToListAsync();
 | 
						|
 | 
						|
            foreach (Attendance attende in lstAttendance)
 | 
						|
            {
 | 
						|
                var result1 = new EmployeeAttendanceVM()
 | 
						|
                {
 | 
						|
                    Id = attende.Id,
 | 
						|
                    CheckInTime = attende.InTime,
 | 
						|
                    CheckOutTime = attende.OutTime,
 | 
						|
                    Activity = attende.Activity,
 | 
						|
                    EmployeeAvatar = null,
 | 
						|
                    EmployeeId = attende.EmployeeID,
 | 
						|
 | 
						|
                };
 | 
						|
 | 
						|
                var teamMember = projectteam.Find(m => m.EmployeeId == attende.EmployeeID);
 | 
						|
                if (teamMember != null && teamMember.Employee != null && teamMember.Employee.JobRole != null)
 | 
						|
                {
 | 
						|
                    result1.FirstName = teamMember.Employee.FirstName;
 | 
						|
                    result1.LastName = teamMember.Employee.LastName;
 | 
						|
                    result1.JobRoleName = teamMember.Employee.JobRole.Name;
 | 
						|
                }
 | 
						|
 | 
						|
                result.Add(result1);
 | 
						|
            }
 | 
						|
 | 
						|
            result.Sort(delegate (EmployeeAttendanceVM x, EmployeeAttendanceVM y)
 | 
						|
            {
 | 
						|
                return string.Compare(x.FirstName, y.FirstName, StringComparison.Ordinal);
 | 
						|
            });
 | 
						|
            _logger.LogInfo("{count} Attendance records fetched successfully", result.Count);
 | 
						|
            return Ok(ApiResponse<object>.SuccessResponse(result, System.String.Format("{0} Attendance records fetched successfully", result.Count), 200));
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        [HttpPost]
 | 
						|
        [Route("record")]
 | 
						|
        public async Task<IActionResult> RecordAttendance([FromBody] RecordAttendanceDot recordAttendanceDot)
 | 
						|
        {
 | 
						|
            if (!ModelState.IsValid)
 | 
						|
            {
 | 
						|
                var errors = ModelState.Values
 | 
						|
                    .SelectMany(v => v.Errors)
 | 
						|
                    .Select(e => e.ErrorMessage)
 | 
						|
                    .ToList();
 | 
						|
                _logger.LogError("User sent Invalid Date while marking attendance");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
 | 
						|
            }
 | 
						|
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
            var currentEmployee = await _userHelper.GetCurrentEmployeeAsync();
 | 
						|
 | 
						|
            using var transaction = await _context.Database.BeginTransactionAsync();
 | 
						|
            try
 | 
						|
            {
 | 
						|
                Attendance? attendance = await _context.Attendes.FirstOrDefaultAsync(a => a.Id == recordAttendanceDot.Id && a.TenantId == TenantId); ;
 | 
						|
 | 
						|
                if (recordAttendanceDot.MarkTime == null)
 | 
						|
                {
 | 
						|
                    _logger.LogError("User sent Invalid Mark Time while marking attendance");
 | 
						|
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Mark Time", "Invalid Mark Time", 400));
 | 
						|
                }
 | 
						|
 | 
						|
                DateTime finalDateTime = GetDateFromTimeStamp(recordAttendanceDot.Date, recordAttendanceDot.MarkTime);
 | 
						|
                if (recordAttendanceDot.Comment == null)
 | 
						|
                {
 | 
						|
                    _logger.LogError("User sent Invalid comment while marking attendance");
 | 
						|
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Comment", "Invalid Comment", 400));
 | 
						|
                }
 | 
						|
 | 
						|
                if (attendance != null)
 | 
						|
                {
 | 
						|
                    attendance.Comment = recordAttendanceDot.Comment;
 | 
						|
                    if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.CHECK_IN)
 | 
						|
                    {
 | 
						|
                        attendance.InTime = finalDateTime;
 | 
						|
                        attendance.OutTime = null;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.CHECK_OUT;
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.CHECK_OUT)
 | 
						|
                    {
 | 
						|
                        attendance.IsApproved = true;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE;
 | 
						|
 | 
						|
 | 
						|
                        //string timeString = "10:30 PM"; // Format: "hh:mm tt"
 | 
						|
 | 
						|
                        attendance.OutTime = finalDateTime;
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)
 | 
						|
                    {
 | 
						|
                        DateTime date = attendance.AttendanceDate;
 | 
						|
                        finalDateTime = GetDateFromTimeStamp(date.Date, recordAttendanceDot.MarkTime);
 | 
						|
                        if (attendance.InTime < finalDateTime)
 | 
						|
                        {
 | 
						|
                            attendance.OutTime = finalDateTime;
 | 
						|
                            attendance.Activity = ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE;
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            _logger.LogError("Employee {EmployeeId} sent regularization request but it check-out time is earlier than check-out");
 | 
						|
                            return BadRequest(ApiResponse<object>.ErrorResponse("Check-out time must be later than check-in time", "Check-out time must be later than check-in time", 400));
 | 
						|
                        }
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.REGULARIZE)
 | 
						|
                    {
 | 
						|
                        attendance.IsApproved = true;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE;
 | 
						|
                        attendance.ApprovedBy = currentEmployee.Id;
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT)
 | 
						|
                    {
 | 
						|
                        attendance.IsApproved = false;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT;
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                    attendance.Date = DateTime.UtcNow;
 | 
						|
 | 
						|
                    // update code
 | 
						|
                    _context.Attendes.Update(attendance);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    attendance = new Attendance();
 | 
						|
                    attendance.TenantId = TenantId;
 | 
						|
                    attendance.AttendanceDate = recordAttendanceDot.Date;
 | 
						|
                    // attendance.Activity = recordAttendanceDot.Action;
 | 
						|
                    attendance.Comment = recordAttendanceDot.Comment;
 | 
						|
                    attendance.EmployeeID = recordAttendanceDot.EmployeeID;
 | 
						|
                    attendance.ProjectID = recordAttendanceDot.ProjectID;
 | 
						|
                    attendance.Date = DateTime.UtcNow;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
                    attendance.InTime = finalDateTime;
 | 
						|
                    attendance.OutTime = null;
 | 
						|
                    attendance.Activity = ATTENDANCE_MARK_TYPE.CHECK_OUT;
 | 
						|
 | 
						|
                    _context.Attendes.Add(attendance);
 | 
						|
                }
 | 
						|
 | 
						|
                await _context.SaveChangesAsync();
 | 
						|
 | 
						|
 | 
						|
                // Step 3: Always insert a new log entry
 | 
						|
                var attendanceLog = new AttendanceLog
 | 
						|
                {
 | 
						|
                    AttendanceId = attendance.Id, // Use existing or new AttendanceId
 | 
						|
                    Activity = attendance.Activity,
 | 
						|
 | 
						|
                    ActivityTime = finalDateTime,
 | 
						|
                    Comment = recordAttendanceDot.Comment,
 | 
						|
                    EmployeeID = recordAttendanceDot.EmployeeID,
 | 
						|
                    Latitude = recordAttendanceDot.Latitude,
 | 
						|
                    Longitude = recordAttendanceDot.Longitude,
 | 
						|
 | 
						|
                    TenantId = TenantId,
 | 
						|
                    UpdatedBy = currentEmployee.Id,
 | 
						|
                    UpdatedOn = recordAttendanceDot.Date
 | 
						|
                };
 | 
						|
                //if (recordAttendanceDot.Image != null && recordAttendanceDot.Image.Count > 0)
 | 
						|
                //{
 | 
						|
                //    attendanceLog.Photo = recordAttendanceDot.Image[0].Base64Data;
 | 
						|
                //}
 | 
						|
 | 
						|
 | 
						|
                _context.AttendanceLogs.Add(attendanceLog);
 | 
						|
                await _context.SaveChangesAsync();
 | 
						|
 | 
						|
                await transaction.CommitAsync(); // Commit transaction
 | 
						|
 | 
						|
                Employee employee = await _employeeHelper.GetEmployeeByID(recordAttendanceDot.EmployeeID);
 | 
						|
                if (employee.JobRole != null)
 | 
						|
                {
 | 
						|
                    EmployeeAttendanceVM vm = new EmployeeAttendanceVM()
 | 
						|
                    {
 | 
						|
                        CheckInTime = attendance.InTime,
 | 
						|
                        CheckOutTime = attendance.OutTime,
 | 
						|
                        EmployeeAvatar = null,
 | 
						|
                        EmployeeId = recordAttendanceDot.EmployeeID,
 | 
						|
                        FirstName = employee.FirstName,
 | 
						|
                        LastName = employee.LastName,
 | 
						|
                        Id = attendance.Id,
 | 
						|
                        Activity = attendance.Activity,
 | 
						|
                        JobRoleName = employee.JobRole.Name
 | 
						|
                    };
 | 
						|
                    var sendActivity = 0;
 | 
						|
                    if (recordAttendanceDot.Id == Guid.Empty)
 | 
						|
                    {
 | 
						|
                        sendActivity = 1;
 | 
						|
                    }
 | 
						|
                    var notification = new { LoggedInUserId = currentEmployee.Id, Keyword = "Attendance", Activity = sendActivity, ProjectId = attendance.ProjectID, Response = vm };
 | 
						|
                    await _signalR.Clients.All.SendAsync("NotificationEventHandler", notification);
 | 
						|
                    _logger.LogInfo("Attendance for employee {FirstName} {LastName} has been marked", employee.FirstName ?? string.Empty, employee.LastName ?? string.Empty);
 | 
						|
                    return Ok(ApiResponse<object>.SuccessResponse(vm, "Attendance marked successfully.", 200));
 | 
						|
                }
 | 
						|
                _logger.LogInfo("Attendance for employee {FirstName} {LastName} has been marked", employee.FirstName ?? string.Empty, employee.LastName ?? string.Empty);
 | 
						|
                return Ok(ApiResponse<object>.SuccessResponse(new EmployeeAttendanceVM(), "Attendance marked successfully.", 200));
 | 
						|
 | 
						|
            }
 | 
						|
            catch (Exception ex)
 | 
						|
            {
 | 
						|
                await transaction.RollbackAsync(); // Rollback on failure
 | 
						|
                _logger.LogError("{Error} while marking attendance", ex.Message);
 | 
						|
                var response = new
 | 
						|
                {
 | 
						|
                    message = ex.Message,
 | 
						|
                    detail = ex.StackTrace,
 | 
						|
                    statusCode = StatusCodes.Status500InternalServerError
 | 
						|
                };
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, response, 400));
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        [HttpPost]
 | 
						|
        [Route("record-image")]
 | 
						|
        public async Task<IActionResult> RecordAttendanceWithImage([FromBody] RecordAttendanceDot recordAttendanceDot)
 | 
						|
        {
 | 
						|
            if (!ModelState.IsValid)
 | 
						|
            {
 | 
						|
                var errors = ModelState.Values
 | 
						|
                    .SelectMany(v => v.Errors)
 | 
						|
                    .Select(e => e.ErrorMessage)
 | 
						|
                    .ToList();
 | 
						|
                _logger.LogError("User sent Invalid Date while marking attendance");
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
 | 
						|
            }
 | 
						|
 | 
						|
            Guid TenantId = GetTenantId();
 | 
						|
 | 
						|
            using var transaction = await _context.Database.BeginTransactionAsync();
 | 
						|
            try
 | 
						|
            {
 | 
						|
                Attendance? attendance = await _context.Attendes.FirstOrDefaultAsync(a => a.Id == recordAttendanceDot.Id && a.TenantId == TenantId); ;
 | 
						|
 | 
						|
                if (recordAttendanceDot.MarkTime == null)
 | 
						|
                {
 | 
						|
                    _logger.LogError("User sent Invalid Mark Time while marking attendance");
 | 
						|
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Mark Time", "Invalid Mark Time", 400));
 | 
						|
                }
 | 
						|
 | 
						|
                DateTime finalDateTime = GetDateFromTimeStamp(recordAttendanceDot.Date, recordAttendanceDot.MarkTime);
 | 
						|
                if (recordAttendanceDot.Comment == null)
 | 
						|
                {
 | 
						|
                    _logger.LogError("User sent Invalid comment while marking attendance");
 | 
						|
                    return BadRequest(ApiResponse<object>.ErrorResponse("Invalid Comment", "Invalid Comment", 400));
 | 
						|
                }
 | 
						|
 | 
						|
                if (attendance != null)
 | 
						|
                {
 | 
						|
                    attendance.Comment = recordAttendanceDot.Comment;
 | 
						|
                    if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.CHECK_IN)
 | 
						|
                    {
 | 
						|
                        attendance.InTime = finalDateTime;
 | 
						|
                        attendance.OutTime = null;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.CHECK_OUT;
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.CHECK_OUT)
 | 
						|
                    {
 | 
						|
                        attendance.IsApproved = true;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE;
 | 
						|
 | 
						|
 | 
						|
                        //string timeString = "10:30 PM"; // Format: "hh:mm tt"
 | 
						|
 | 
						|
                        attendance.OutTime = finalDateTime;
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE)
 | 
						|
                    {
 | 
						|
                        DateTime date = attendance.AttendanceDate;
 | 
						|
                        finalDateTime = GetDateFromTimeStamp(date.Date, recordAttendanceDot.MarkTime);
 | 
						|
                        if (attendance.InTime < finalDateTime)
 | 
						|
                        {
 | 
						|
                            attendance.OutTime = finalDateTime;
 | 
						|
                            attendance.Activity = ATTENDANCE_MARK_TYPE.REQUEST_REGULARIZE;
 | 
						|
                        }
 | 
						|
                        else
 | 
						|
                        {
 | 
						|
                            _logger.LogError("Employee {EmployeeId} sent regularization request but it check-out time is earlier than check-out");
 | 
						|
                            return BadRequest(ApiResponse<object>.ErrorResponse("Check-out time must be later than check-in time", "Check-out time must be later than check-in time", 400));
 | 
						|
                        }
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.REGULARIZE)
 | 
						|
                    {
 | 
						|
                        attendance.IsApproved = true;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE;
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                    else if (recordAttendanceDot.Action == ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT)
 | 
						|
                    {
 | 
						|
                        attendance.IsApproved = false;
 | 
						|
                        attendance.Activity = ATTENDANCE_MARK_TYPE.REGULARIZE_REJECT;
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                    attendance.Date = DateTime.UtcNow;
 | 
						|
 | 
						|
                    // update code
 | 
						|
                    _context.Attendes.Update(attendance);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    attendance = new Attendance();
 | 
						|
                    attendance.TenantId = TenantId;
 | 
						|
                    attendance.AttendanceDate = recordAttendanceDot.Date;
 | 
						|
                    // attendance.Activity = recordAttendanceDot.Action;
 | 
						|
                    attendance.Comment = recordAttendanceDot.Comment;
 | 
						|
                    attendance.EmployeeID = recordAttendanceDot.EmployeeID;
 | 
						|
                    attendance.ProjectID = recordAttendanceDot.ProjectID;
 | 
						|
                    attendance.Date = DateTime.UtcNow;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
                    attendance.InTime = finalDateTime;
 | 
						|
                    attendance.OutTime = null;
 | 
						|
                    attendance.Activity = ATTENDANCE_MARK_TYPE.CHECK_OUT;
 | 
						|
 | 
						|
                    _context.Attendes.Add(attendance);
 | 
						|
 | 
						|
                }
 | 
						|
                Document? document = null;
 | 
						|
                var Image = recordAttendanceDot.Image;
 | 
						|
                var preSignedUrl = string.Empty;
 | 
						|
 | 
						|
                if (Image != null && Image.ContentType != null)
 | 
						|
                {
 | 
						|
 | 
						|
                    if (string.IsNullOrEmpty(Image.Base64Data))
 | 
						|
                        return BadRequest(ApiResponse<object>.ErrorResponse("Base64 data is missing", "Base64 data is missing", 400));
 | 
						|
 | 
						|
                    //If base64 has a data URI prefix, strip it
 | 
						|
                    var base64 = Image.Base64Data.Contains(",")
 | 
						|
                        ? Image.Base64Data.Substring(Image.Base64Data.IndexOf(",") + 1)
 | 
						|
                        : Image.Base64Data;
 | 
						|
 | 
						|
                    string fileType = _s3Service.GetContentTypeFromBase64(base64);
 | 
						|
                    string fileName = _s3Service.GenerateFileName(fileType, TenantId, "attendance");
 | 
						|
 | 
						|
                    string objectKey = $"tenant-{TenantId}/Employee/{recordAttendanceDot.EmployeeID}/Attendance/{fileName}";
 | 
						|
                    await _s3Service.UploadFileAsync(base64, fileType, objectKey);
 | 
						|
                    preSignedUrl = _s3Service.GeneratePreSignedUrlAsync(objectKey);
 | 
						|
 | 
						|
                    document = new Document
 | 
						|
                    {
 | 
						|
                        FileName = Image.FileName ?? "",
 | 
						|
                        ContentType = Image.ContentType,
 | 
						|
                        S3Key = objectKey,
 | 
						|
                        Base64Data = Image.Base64Data,
 | 
						|
                        FileSize = Image.FileSize,
 | 
						|
                        UploadedAt = recordAttendanceDot.Date,
 | 
						|
                        TenantId = TenantId
 | 
						|
                    };
 | 
						|
                    _context.Documents.Add(document);
 | 
						|
 | 
						|
 | 
						|
                    await _context.SaveChangesAsync();
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
                // Step 3: Always insert a new log entry
 | 
						|
                if (document != null)
 | 
						|
                {
 | 
						|
                    var attendanceLog = new AttendanceLog
 | 
						|
                    {
 | 
						|
                        AttendanceId = attendance.Id, // Use existing or new AttendanceId
 | 
						|
                        Activity = attendance.Activity,
 | 
						|
 | 
						|
                        ActivityTime = finalDateTime,
 | 
						|
                        Comment = recordAttendanceDot.Comment,
 | 
						|
                        EmployeeID = recordAttendanceDot.EmployeeID,
 | 
						|
                        Latitude = recordAttendanceDot.Latitude,
 | 
						|
                        Longitude = recordAttendanceDot.Longitude,
 | 
						|
                        DocumentId = document.Id,
 | 
						|
                        TenantId = TenantId,
 | 
						|
                        UpdatedBy = recordAttendanceDot.EmployeeID,
 | 
						|
                        UpdatedOn = recordAttendanceDot.Date
 | 
						|
                    };
 | 
						|
                    _context.AttendanceLogs.Add(attendanceLog);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    var attendanceLog = new AttendanceLog
 | 
						|
                    {
 | 
						|
                        AttendanceId = attendance.Id, // Use existing or new AttendanceId
 | 
						|
                        Activity = attendance.Activity,
 | 
						|
 | 
						|
                        ActivityTime = finalDateTime,
 | 
						|
                        Comment = recordAttendanceDot.Comment,
 | 
						|
                        EmployeeID = recordAttendanceDot.EmployeeID,
 | 
						|
                        Latitude = recordAttendanceDot.Latitude,
 | 
						|
                        Longitude = recordAttendanceDot.Longitude,
 | 
						|
                        DocumentId = document != null ? document.Id : null,
 | 
						|
                        TenantId = TenantId,
 | 
						|
                        UpdatedBy = recordAttendanceDot.EmployeeID,
 | 
						|
                        UpdatedOn = recordAttendanceDot.Date
 | 
						|
                    };
 | 
						|
                    _context.AttendanceLogs.Add(attendanceLog);
 | 
						|
                }
 | 
						|
 | 
						|
                //if (recordAttendanceDot.Image != null && recordAttendanceDot.Image.Count > 0)
 | 
						|
                //{
 | 
						|
                //    attendanceLog.Photo = recordAttendanceDot.Image[0].Base64Data;
 | 
						|
                //}
 | 
						|
                await _context.SaveChangesAsync();
 | 
						|
 | 
						|
                await transaction.CommitAsync(); // Commit transaction
 | 
						|
 | 
						|
                Employee employee = await _employeeHelper.GetEmployeeByID(recordAttendanceDot.EmployeeID);
 | 
						|
                if (employee.JobRole != null)
 | 
						|
                {
 | 
						|
                    EmployeeAttendanceVM vm = new EmployeeAttendanceVM();
 | 
						|
                    if (document != null)
 | 
						|
                    {
 | 
						|
                        vm = new EmployeeAttendanceVM()
 | 
						|
                        {
 | 
						|
                            CheckInTime = attendance.InTime,
 | 
						|
                            CheckOutTime = attendance.OutTime,
 | 
						|
                            EmployeeAvatar = null,
 | 
						|
                            EmployeeId = recordAttendanceDot.EmployeeID,
 | 
						|
                            FirstName = employee.FirstName,
 | 
						|
                            LastName = employee.LastName,
 | 
						|
                            Id = attendance.Id,
 | 
						|
                            Activity = attendance.Activity,
 | 
						|
                            JobRoleName = employee.JobRole.Name,
 | 
						|
                            DocumentId = document.Id,
 | 
						|
                            ThumbPreSignedUrl = preSignedUrl,
 | 
						|
                            PreSignedUrl = preSignedUrl
 | 
						|
                        };
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        vm = new EmployeeAttendanceVM()
 | 
						|
                        {
 | 
						|
                            CheckInTime = attendance.InTime,
 | 
						|
                            CheckOutTime = attendance.OutTime,
 | 
						|
                            EmployeeAvatar = null,
 | 
						|
                            EmployeeId = recordAttendanceDot.EmployeeID,
 | 
						|
                            FirstName = employee.FirstName,
 | 
						|
                            LastName = employee.LastName,
 | 
						|
                            Id = attendance.Id,
 | 
						|
                            Activity = attendance.Activity,
 | 
						|
                            JobRoleName = employee.JobRole.Name,
 | 
						|
                            DocumentId = Guid.Empty,
 | 
						|
                            ThumbPreSignedUrl = string.Empty,
 | 
						|
                            PreSignedUrl = string.Empty
 | 
						|
                        };
 | 
						|
                    }
 | 
						|
 | 
						|
                    _logger.LogInfo("Attendance for employee {FirstName} {LastName} has been marked", employee.FirstName ?? string.Empty, employee.LastName ?? string.Empty);
 | 
						|
                    return Ok(ApiResponse<object>.SuccessResponse(vm, "Attendance marked successfully.", 200));
 | 
						|
                }
 | 
						|
                _logger.LogInfo("Attendance for employee {FirstName} {LastName} has been marked", employee.FirstName ?? string.Empty, employee.LastName ?? string.Empty);
 | 
						|
                return Ok(ApiResponse<object>.SuccessResponse(new EmployeeAttendanceVM(), "Attendance marked successfully.", 200));
 | 
						|
 | 
						|
            }
 | 
						|
            catch (Exception ex)
 | 
						|
            {
 | 
						|
                await transaction.RollbackAsync(); // Rollback on failure
 | 
						|
                _logger.LogError("{Error} while marking attendance", ex.Message);
 | 
						|
                var response = new
 | 
						|
                {
 | 
						|
                    message = ex.Message,
 | 
						|
                    detail = ex.StackTrace,
 | 
						|
                    statusCode = StatusCodes.Status500InternalServerError
 | 
						|
                };
 | 
						|
                return BadRequest(ApiResponse<object>.ErrorResponse(ex.Message, response, 400));
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
        private static DateTime GetDateFromTimeStamp(DateTime date, string timeString)
 | 
						|
        {
 | 
						|
            //DateTime date = recordAttendanceDot.Date;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
            // Parse time string to TimeSpan
 | 
						|
            DateTime parsedTime = DateTime.ParseExact(timeString, "hh:mm tt", CultureInfo.InvariantCulture);
 | 
						|
 | 
						|
            // Combine date with time
 | 
						|
            DateTime finalDateTime = new DateTime(date.Year, date.Month, date.Day, parsedTime.Hour, parsedTime.Minute, 0);
 | 
						|
            return finalDateTime;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |