using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.WebUtilities; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using MTWorkHR.Application.Identity; using MTWorkHR.Application.Mapper; using MTWorkHR.Application.Models; using MTWorkHR.Core.Global; using MTWorkHR.Core.IRepositories; using MTWorkHR.Core.UnitOfWork; using MTWorkHR.Infrastructure.Entities; using MTWorkHR.Application.Services.Interfaces; using MTWorkHR.Core.Email; using MTWorkHR.Core.Entities; using System.Linq.Dynamic.Core; using System.Linq; using Microsoft.AspNetCore.Http; using MTWorkHR.Core.Entities.Base; namespace MTWorkHR.Application.Services { public class AttendanceService : BaseService, IAttendanceService { private readonly IUnitOfWork _unitOfWork; private readonly GlobalInfo _globalInfo; private readonly IUserService _userService; public AttendanceService(IUnitOfWork unitOfWork, GlobalInfo globalInfo, IUserService userService) :base(unitOfWork) { _unitOfWork = unitOfWork; _globalInfo = globalInfo; _userService = userService; } public async Task> GetAll(AttendancePagingInputDto pagingInputDto) { // Fetch all attendances with related data var attendanceResult = await _unitOfWork.Attendance.GetAllWithChildrenAsync(); var query = attendanceResult.Item1.AsQueryable(); // Apply filters based on user type and input if (_globalInfo.UserType != UserTypeEnum.Business) { query = query.Where(m => m.UserId == _globalInfo.UserId); } if (!string.IsNullOrEmpty(pagingInputDto.Filter)) { query = query.Where(u => u.LeaveReason!.Contains(pagingInputDto.Filter) || u.UserName!.Contains(pagingInputDto.Filter)); } if (pagingInputDto.SearchDate != null) { query = query.Where(u => u.AttendanceDate.Date == pagingInputDto.SearchDate.Value.Date); } if (!string.IsNullOrEmpty(pagingInputDto.UserId)) { query = query.Where(u => u.UserId == pagingInputDto.UserId); } // Apply sorting var orderedQuery = query.OrderBy($"{pagingInputDto.OrderByField} {pagingInputDto.OrderType}"); // Apply paging var pagedQuery = orderedQuery .Skip((pagingInputDto.PageNumber - 1) * pagingInputDto.PageSize) .Take(pagingInputDto.PageSize); // Fetch total count for pagination var totalCount = await query.CountAsync(); // Map attendance data to DTOs var attendanceDtos = MapperObject.Mapper.Map>(await pagedQuery.ToListAsync()); // Fetch all company employees var employeesList = await _userService.GetAllCompanyEmployees(); // Filter employees by name if provided if (!string.IsNullOrEmpty(pagingInputDto.UserName)) { var filter = pagingInputDto.UserName; var filters = filter.Split(" "); var firstNameFilter = filters[0]; var lastNameFilter = filters.Length > 1 ? filters[1] : ""; employeesList = employeesList.Where(u => u.UserName.Contains(filter) || u.Email.Contains(filter) || u.FavoriteName.Contains(filter) || u.FirstName.Contains(filter) || u.LastName.Contains(filter) || (u.FirstName.Contains(firstNameFilter) && (string.IsNullOrEmpty(lastNameFilter) || u.LastName.Contains(lastNameFilter))) || (u.LastName.Contains(lastNameFilter) && (string.IsNullOrEmpty(firstNameFilter) || u.FirstName.Contains(firstNameFilter))) ).ToList(); } // Create a dictionary to store user data var userDataDictionary = new Dictionary(); // Fetch user data for all employees foreach (var employee in employeesList) { var user = await _userService.GetUserWithAttachmentById(employee.Id); if (user != null) { var userDto = MapperObject.Mapper.Map(user); userDto.ProfileImage = await GetProfileImageAsync(user.UserAttachments); userDataDictionary[employee.Id] = userDto; } } // Combine attendance data with user data var result = new List(); if (string.IsNullOrEmpty(pagingInputDto.UserId)) { foreach (var employee in employeesList) { var latestAttendance = attendanceDtos.LastOrDefault(a => a.UserId == employee.Id); if (latestAttendance != null) { latestAttendance.Employee = userDataDictionary[employee.Id]; } else { latestAttendance = new AttendanceDto { UserId = employee.Id, UserName = employee.UserName, Employee = userDataDictionary[employee.Id] }; } result.Add(latestAttendance); } } else { foreach (var attendance in attendanceDtos) { attendance.Employee = userDataDictionary[pagingInputDto.UserId]; } result = attendanceDtos.ToList(); } // Return the paged result return new PagingResultDto { Result = result, Total = string.IsNullOrEmpty(pagingInputDto.UserId) ? result.Count : totalCount }; } // Helper method to get profile image private async Task GetProfileImageAsync(ICollection attachments) { var profileImage = attachments?.FirstOrDefault(a => a.AttachmentTypeId == 9); if (profileImage == null) return null; using (var stream = new MemoryStream(profileImage.Content)) { var file = new FormFile(stream, 0, stream.Length, Path.GetFileNameWithoutExtension(profileImage.FileName), profileImage.FilePath) { Headers = new HeaderDictionary(), ContentType = profileImage.ContentType, ContentDisposition = new System.Net.Mime.ContentDisposition { FileName = profileImage.FileName }.ToString() }; return file; } } public override async Task Create(AttendanceDto input) { if (input.CheckInTime.HasValue) input.AttendanceDate = input.CheckInTime.Value.Date; var oldEntity = await _unitOfWork.Attendance.GetAttendanceByUserId(input.UserId, input.AttendanceDate); if (oldEntity is null) { var entitiy = MapperObject.Mapper.Map(input); if (entitiy is null) throw new AppException(ExceptionEnum.MapperIssue); var newEntity = await _unitOfWork.Attendance.AddAsync(entitiy); var Success = await _unitOfWork.CompleteAsync(); var response = Mapper.MapperObject.Mapper.Map(newEntity); return response; } else { throw new AppException(ExceptionEnum.UserAlreadyCheckedIn); var response = Mapper.MapperObject.Mapper.Map(oldEntity); return response; } } public override async Task Update(AttendanceDto input) { Attendance? entity = null; if (input.CheckInTime.HasValue) input.AttendanceDate = input.CheckInTime.Value.Date; else if (input.CheckOutTime.HasValue) input.AttendanceDate = input.CheckOutTime.Value.Date; if (input.Id > 0) entity = await _unitOfWork.Attendance.GetByIdAsync(input.Id); else entity = await _unitOfWork.Attendance.GetAttendanceByUserId(input.UserId, input.AttendanceDate); if (entity is null) throw new AppException(ExceptionEnum.RecordNotExist); entity.CheckOutTime = input.CheckOutTime; entity.LeaveType = input.LeaveType; entity.LeaveReason = input.LeaveReason; await _unitOfWork.CompleteAsync(); var response = Mapper.MapperObject.Mapper.Map(entity); return response; } public async Task GetAttendanceByUserId(string userId, DateTime attendanceDate) { var entity = await _unitOfWork.Attendance.GetAttendanceByUserId(userId, attendanceDate); if (entity is null) return null; var response = Mapper.MapperObject.Mapper.Map(entity); return response; } } }