using System.Drawing; using BMA.EHR.Application.Common.Interfaces; using BMA.EHR.Application.Messaging; using BMA.EHR.Domain.Models.HR; using BMA.EHR.Domain.Models.Leave.Commons; using BMA.EHR.Domain.Models.Leave.Requests; using BMA.EHR.Domain.Models.Notifications; using BMA.EHR.Domain.Shared; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests { public class LeaveRequestRepository : GenericLeaveRepository { #region " Fields " private readonly ILeaveDbContext _dbContext; private readonly IHttpContextAccessor _httpContextAccessor; private readonly OrganizationCommonRepository _organizationCommonRepository; private readonly UserProfileRepository _userProfileRepository; private readonly IConfiguration _configuration; private readonly EmailSenderService _emailSenderService; private readonly IApplicationDBContext _appDbContext; #endregion #region " Constructor and Destuctor " public LeaveRequestRepository(ILeaveDbContext dbContext, IHttpContextAccessor httpContextAccessor, OrganizationCommonRepository organizationCommonRepository, UserProfileRepository userProfileRepository, IConfiguration configuration, EmailSenderService emailSenderService, IApplicationDBContext appDbContext) : base(dbContext, httpContextAccessor) { _dbContext = dbContext; _httpContextAccessor = httpContextAccessor; _organizationCommonRepository = organizationCommonRepository; _userProfileRepository = userProfileRepository; _configuration = configuration; _emailSenderService = emailSenderService; _appDbContext = appDbContext; } #endregion #region " Properties " protected Guid UserOrganizationId { get { if (UserId != null || UserId != "") return _userProfileRepository.GetUserOCId(Guid.Parse(UserId!)); else return Guid.Empty; } } #endregion #region " Methods " #region " Overrides " public override async Task GetByIdAsync(Guid id) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.LeaveDocument) .ThenInclude(x => x.Document) .Include(x => x.LeaveDraftDocument) .Include(x => x.LeaveCancelDocument) .Include(x => x.Type) .FirstOrDefaultAsync(x => x.Id == id); return data; } public override async Task AddAsync(LeaveRequest entity) { if (entity.LeaveCancelDocument != null) _dbContext.Attatch(entity.LeaveCancelDocument); if (entity.LeaveDraftDocument != null) _dbContext.Attatch(entity.LeaveDraftDocument); // if (entity.LeaveDocument != null) // _dbContext.Attatch(entity.LeaveDocument); if (entity.Type != null) _dbContext.Attatch(entity.Type); return await base.AddAsync(entity); } public override async Task UpdateAsync(LeaveRequest entity) { if (entity.LeaveCancelDocument != null) _dbContext.Attatch(entity.LeaveCancelDocument); if (entity.LeaveDraftDocument != null) _dbContext.Attatch(entity.LeaveDraftDocument); // if (entity.LeaveDocument != null) // _dbContext.Attatch(entity.LeaveDocument); if (entity.Type != null) _dbContext.Attatch(entity.Type); return await base.UpdateAsync(entity); } #endregion public async Task> GetLeaveRequestByYearAsync(int year) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.LeaveStartDate.Year == year) .Where(x => x.LeaveStatus != "REJECT" && x.LeaveStatus != "DELETE") .ToListAsync(); return data; } public async Task> GetLeaveRequestByUserIdAsync(Guid keycloakUserId, int year, Guid type, string status) { var rawData = _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId); if (year != 0) rawData = rawData.Where(x => x.LeaveStartDate.Year == year); if (type != Guid.Empty) rawData = rawData.Where(x => x.Type.Id == type); if (status.Trim().ToUpper() != "ALL") rawData = rawData.Where(x => x.LeaveStatus == status); return await rawData.ToListAsync(); } public async Task> GetLeaveRequestForAdminAsync(int year, Guid type, string status, DateTime startDate, DateTime endDate) { var rawData = _dbContext.Set() .Include(x => x.Type) .Where(x => x.LeaveStatus != "DRAFT") .AsQueryable(); if (year != 0) rawData = rawData.Where(x => x.LeaveStartDate.Year == year); if (type != Guid.Empty) rawData = rawData.Where(x => x.Type.Id == type); if (status.Trim().ToUpper() != "ALL") rawData = rawData.Where(x => x.LeaveStatus == status); if (startDate != DateTime.MinValue) rawData = rawData.Where(x => x.LeaveStartDate >= startDate); if (endDate != DateTime.MinValue) rawData = rawData.Where(x => x.LeaveEndDate <= endDate); return await rawData.ToListAsync(); } public async Task GetRestDayTotalByYearForUserAsync(Guid keycloakUserId, int year) { var leaveType = await _dbContext.Set().AsQueryable().FirstOrDefaultAsync(l => l.Code.Trim().ToUpper() == "LV-005"); if (leaveType == null) { throw new Exception("ไม่พบข้อมูลประเภทการลาพักผ่อน โปรดติดต่อผู้ดูและระบบ"); } var data = _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveType.Id) .Where(x => x.LeaveStartDate.Year == year) .Sum(x => x.LeaveTotal); return data; } public async Task GetSumLeaveByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId, int year) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Year == year) .Where(x => x.LeaveStatus != "REJECT" && x.LeaveStatus != "DELETE") .ToListAsync(); return data.Sum(x => x.LeaveTotal); } public async Task GetLeaveLastByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStatus != "REJECT" && x.LeaveStatus != "DELETE") .OrderByDescending(x => x.LeaveStartDate.Date) .Select(x => x.LeaveStartDate.Date) .FirstOrDefaultAsync(); return data; } public async Task GetLastLeaveRequestByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStatus != "REJECT" && x.LeaveStatus != "DELETE") .OrderByDescending(x => x.LeaveStartDate.Date) .FirstOrDefaultAsync(); return data; } public async Task> GetCancelLeaveRequestForAdminAsync(int year, Guid type, string status) { var rawData = _dbContext.Set() .Include(x => x.Type) .Where(x => x.LeaveStatus == "DELETE") .AsQueryable(); if (year != 0) rawData = rawData.Where(x => x.LeaveStartDate.Year == year); if (type != Guid.Empty) rawData = rawData.Where(x => x.Type.Id == type); if (status.Trim().ToUpper() != "ALL") rawData = rawData.Where(x => x.LeaveCancelStatus == status); return await rawData.ToListAsync(); } public async Task ApproveCancelLeaveRequestAsync(Guid id, string Reason) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId); if (profile == null) { throw new Exception(GlobalMessages.DataNotFound); } rawData.LeaveCancelStatus = "APPROVE"; rawData.LeaveCancelComment = Reason; await UpdateAsync(rawData); // TODO: remove วันลา // Send Noti var noti = new Notification { Body = $"การขอยกเลิกใบลาของคุณได้รับการอนุมัติ", ReceiverUserId = profile.Id, Type = "", Payload = "", }; _appDbContext.Set().Add(noti); await _appDbContext.SaveChangesAsync(); } public async Task RejectCancelLeaveRequestAsync(Guid id, string Reason) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId); if (profile == null) { throw new Exception(GlobalMessages.DataNotFound); } rawData.LeaveCancelStatus = "REJECT"; rawData.LeaveCancelComment = Reason; await UpdateAsync(rawData); // TODO: remove วันลา var leaveType = await _appDbContext.Set() .FirstOrDefaultAsync(x => x.Name == rawData.Type.Name); // insert to profile leave var profileLeave = await _appDbContext.Set() .Where(x => x.TypeLeave.Id == leaveType.Id) .Where(x => x.Profile.Id == profile.Id) .Where(x => x.DateStartLeave == rawData.LeaveStartDate && x.DateEndLeave == rawData.LeaveEndDate) .FirstOrDefaultAsync(); if (profileLeave != null) { _appDbContext.Set().Remove(profileLeave); await _appDbContext.SaveChangesAsync(); } // insert into process timestamp // Send Noti var noti = new Notification { Body = $"การขอยกเลิกใบลาของคุณไม่ได้รับการอนุมัติ \r\nเนืองจาก {Reason}", ReceiverUserId = profile.Id, Type = "", Payload = "", }; _appDbContext.Set().Add(noti); await _appDbContext.SaveChangesAsync(); } public async Task SendToOfficerAsync(Guid id) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } var isDuplicate = await CheckDuplicateLeave(rawData.KeycloakUserId, rawData.LeaveStartDate.Date, rawData.LeaveEndDate.Date, rawData.LeaveRange ?? "ALL"); if (isDuplicate) { throw new Exception("ไม่สามารถขอลาในช่วงเวลาเดียวกันได้ เนื่องจากมีการขอลาในช่วงเวลาดังกล่าวแล้ว"); } rawData.LeaveStatus = "NEW"; //rawData.ApproveStep = "st2"; await UpdateAsync(rawData); } public async Task OfficerApproveLeaveRequest(Guid id) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } rawData.LeaveStatus = "PENDING"; rawData.ApproveStep = "st2"; await UpdateAsync(rawData); } public async Task CommanderApproveLeaveRequest(Guid id, string reason) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } if (rawData.ApproveStep != "st2") { throw new Exception("คำขอนี้ยังไม่ได้รับการอนุมัติจากเจ้าหน้าที่ ไม่สามารถทำรายการได้"); } rawData.LeaveStatus = "PENDING"; rawData.LeaveComment = reason; rawData.ApproveStep = "st3"; await UpdateAsync(rawData); } public async Task ApproveLeaveRequest(Guid id, string reason) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } if (rawData.ApproveStep != "st3") { throw new Exception("คำขอนี้ยังไม่ได้รับการอนุมัติจากผู้บังคับบัญชา ไม่สามารถทำรายการได้"); } var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId); if (profile == null) { throw new Exception(GlobalMessages.DataNotFound); } rawData.LeaveStatus = "APPROVE"; rawData.LeaveDirectorComment = reason; rawData.ApproveStep = "st4"; await UpdateAsync(rawData); var leaveType = await _appDbContext.Set() .FirstOrDefaultAsync(x => x.Name == rawData.Type.Name); // insert to profile leave var profileLeave = new ProfileLeave { DateStartLeave = rawData.LeaveStartDate, DateEndLeave = rawData.LeaveEndDate, TotalLeave = rawData.LeaveTotal, Status = "approve", Reason = rawData.LeaveDetail, Profile = profile, TypeLeave = leaveType }; _appDbContext.Set().Add(profileLeave); await _appDbContext.SaveChangesAsync(); // insert to process timestamp // Send Noti var noti = new Notification { Body = $"การขอลาของคุณได้รับการอนุมัติ", ReceiverUserId = profile.Id, Type = "", Payload = "", }; _appDbContext.Set().Add(noti); await _appDbContext.SaveChangesAsync(); } public async Task RejectLeaveRequest(Guid id, string reason) { var rawData = await GetByIdAsync(id); if (rawData == null) { throw new Exception(GlobalMessages.DataNotFound); } if (rawData.ApproveStep != "st3") { throw new Exception("คำขอนี้ยังไม่ได้รับการอนุมัติจากผู้บังคับบัญชา ไม่สามารถทำรายการได้"); } var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(rawData.KeycloakUserId); if (profile == null) { throw new Exception(GlobalMessages.DataNotFound); } rawData.LeaveStatus = "REJECT"; rawData.LeaveDirectorComment = reason; rawData.ApproveStep = "st5"; await UpdateAsync(rawData); // Send Noti var noti = new Notification { Body = $"การขอลาของคุณไม่ได้รับการอนุมัติ \r\nเนื่องจาก{reason}", ReceiverUserId = profile.Id, Type = "", Payload = "", }; _appDbContext.Set().Add(noti); await _appDbContext.SaveChangesAsync(); } public async Task GetSumSendLeaveByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId, int year) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Year == year) .ToListAsync(); return data.Sum(x => x.LeaveTotal); } public async Task GetSumApproveLeaveByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId, int year) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Year == year) .Where(x => x.LeaveStatus == "APPROVE") .ToListAsync(); if (data.Count > 0) return data.Sum(x => x.LeaveTotal); else return 0.0; } public async Task GetSumApproveLeaveByRangeForUser(Guid keycloakUserId,DateTime startDate, DateTime endDate) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date) .Where(x => x.LeaveStatus == "APPROVE") .ToListAsync(); if (data.Count > 0) return data.Sum(x => x.LeaveTotal); else return 0; } public async Task GetSumApproveLeaveByTypeAndRangeForUser(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date) .Where(x => x.LeaveStatus == "APPROVE") .ToListAsync(); if (data.Count > 0) return data.Sum(x => x.LeaveTotal); else return 0; } public async Task GetCountApproveLeaveByTypeAndRangeForUser(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date) .Where(x => x.LeaveStatus == "APPROVE") .ToListAsync(); return data.Count; } public async Task GetSumRejectLeaveByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId, int year) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Year == year) .Where(x => x.LeaveStatus == "REJECT") .ToListAsync(); if (data.Count > 0) return data.Sum(x => x.LeaveTotal); else return 0; } public async Task GetSumDeleteLeaveByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId, int year) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.Type.Id == leaveTypeId) .Where(x => x.LeaveStartDate.Year == year) .Where(x => x.LeaveStatus == "DELETE") .ToListAsync(); if (data.Count > 0) return data.Sum(x => x.LeaveTotal); else return 0; } public async Task CheckDuplicateLeave(Guid keycloakUserId, DateTime startDate, DateTime endDate, string range) { var leaveStatus = new List() { "NEW", "PENDING", "APPROVE" }; if (range == "ALL") { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) //.Where(x => x.LeaveRange == "ALL") .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.LeaveStartDate.Date == startDate.Date || x.LeaveEndDate.Date == endDate.Date) .Where(x => leaveStatus.Contains(x.LeaveStatus)) .ToListAsync(); return data.Count > 0; } else { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.LeaveRange == range) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.LeaveStartDate.Date == startDate.Date || x.LeaveEndDate.Date == endDate.Date) .Where(x => leaveStatus.Contains(x.LeaveStatus)) .ToListAsync(); return data.Count > 0; } } public async Task DeleteLeaveDocumentAsync(Guid Id) { var doc = await _dbContext.Set() .Where(x => x.Id == Id) .FirstOrDefaultAsync(); if (doc != null) { _dbContext.Set().Remove(doc); await _dbContext.SaveChangesAsync(); } } public async Task GetLeavePeriodAsync(Guid keycloakUserId, DateTime date) { var data = await _dbContext.Set().AsQueryable() .Include(x => x.Type) .Where(x => x.KeycloakUserId == keycloakUserId) .Where(x => x.LeaveStatus == "APPROVE") .Where(x => x.LeaveStartDate.Date <= date.Date && x.LeaveEndDate >= date.Date) .FirstOrDefaultAsync(); return data; } #endregion } }