diff --git a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs index 726391dd..8831c397 100644 --- a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs +++ b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs @@ -439,6 +439,35 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests 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() diff --git a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveTypeRepository.cs b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveTypeRepository.cs index 0fd361ac..f55e8fb4 100644 --- a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveTypeRepository.cs +++ b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveTypeRepository.cs @@ -2,6 +2,7 @@ using BMA.EHR.Application.Messaging; using BMA.EHR.Domain.Models.Leave.Commons; using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests @@ -52,5 +53,12 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests } #endregion + + + public async Task GetLeaveTypeByCodeAsync(string code) + { + return await _dbContext.Set().FirstOrDefaultAsync(x => x.Code == code); + } + } } diff --git a/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/ProcessUserTimeStampRepository.cs b/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/ProcessUserTimeStampRepository.cs index dd0a0f70..9d0119c5 100644 --- a/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/ProcessUserTimeStampRepository.cs +++ b/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/ProcessUserTimeStampRepository.cs @@ -155,6 +155,17 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants return data.Count; } + public async Task> GetTimeStampHistoryByRangeForUserAsync(Guid userId, DateTime startDate, DateTime endDate) + { + var data = await _dbContext.Set() + .Where(x => x.KeycloakUserId == userId) + .Where(u => u.CheckIn.Date >= startDate.Date && u.CheckIn.Date <= endDate.Date) + .ToListAsync(); + + + return data; + } + public async Task> GetTimeStampHistoryForAdminAsync(DateTime startDate, DateTime endDate) { var data = await _dbContext.Set() diff --git a/BMA.EHR.Application/Repositories/UserProfileRepository.cs b/BMA.EHR.Application/Repositories/UserProfileRepository.cs index a130d13f..b179bf33 100644 --- a/BMA.EHR.Application/Repositories/UserProfileRepository.cs +++ b/BMA.EHR.Application/Repositories/UserProfileRepository.cs @@ -1,4 +1,5 @@ -using BMA.EHR.Application.Common.Interfaces; +using System.Security.Cryptography.X509Certificates; +using BMA.EHR.Application.Common.Interfaces; using BMA.EHR.Domain.Models.HR; using BMA.EHR.Domain.Models.Organizations; using BMA.EHR.Domain.Shared; @@ -83,7 +84,38 @@ namespace BMA.EHR.Application.Repositories { try { - var data = _dbContext.Set().AsQueryable(); + var data = _dbContext.Set().AsQueryable() + .Where(x => x.ProfileType == "officer"); + + + if (citizenId != null) + data = data.Where(x => x.CitizenId!.Contains(citizenId)); + + if (firstName != null) + data = data.Where(x => x.FirstName!.Contains(firstName)); + + if (lastName != null) + data = data.Where(x => x.LastName!.Contains(lastName)); + + data = data.Include(x => x.Prefix) + .Include(x => x.Position) + .Include(x => x.PositionLevel) + .Include(x => x.PosNo); + + return await data.ToListAsync(); + } + catch + { + throw; + } + } + + public async Task> SearchProfileEmployee(string? citizenId, string? firstName, string? lastName) + { + try + { + var data = _dbContext.Set().AsQueryable() + .Where(x => x.ProfileType == "employee"); if (citizenId != null) @@ -96,6 +128,8 @@ namespace BMA.EHR.Application.Repositories data = data.Where(x => x.LastName!.Contains(lastName)); data = data.Include(x => x.Prefix); + //.Include(x => x.PosNoEmployee); + return await data.ToListAsync(); } diff --git a/BMA.EHR.Leave.Service/Controllers/LeaveController.cs b/BMA.EHR.Leave.Service/Controllers/LeaveController.cs index 4e4fab39..9b8b2cd1 100644 --- a/BMA.EHR.Leave.Service/Controllers/LeaveController.cs +++ b/BMA.EHR.Leave.Service/Controllers/LeaveController.cs @@ -722,7 +722,10 @@ namespace BMA.EHR.Leave.Service.Controllers DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? "LATE" : - "NORMAL", + DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? + "ABSENT" : + "NORMAL", CheckOutDescription = d.CheckOutRemark ?? "", }; @@ -793,6 +796,8 @@ namespace BMA.EHR.Leave.Service.Controllers DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", + CheckInIsLocation = d.IsLocationCheckIn, + CheckInLocationName = d.CheckInLocationName, //CheckInImageUrl = $"{imgUrl}/{d.CheckInImageUrl}", CheckOutDate = d.CheckOut == null ? null : d.CheckOut.Value.Date, @@ -803,7 +808,12 @@ namespace BMA.EHR.Leave.Service.Controllers CheckOutStatus = d.CheckOut == null ? null : DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? "LATE" : + DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? + "ABSENT" : "NORMAL", + CheckOutIsLocation = d.IsLocationCheckOut, + CheckOutLocationName = d.CheckOutLocationName //CheckOutImageUrl = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", }) diff --git a/BMA.EHR.Leave.Service/Controllers/LeaveReportController.cs b/BMA.EHR.Leave.Service/Controllers/LeaveReportController.cs index 7cd19252..e3912d1e 100644 --- a/BMA.EHR.Leave.Service/Controllers/LeaveReportController.cs +++ b/BMA.EHR.Leave.Service/Controllers/LeaveReportController.cs @@ -2,11 +2,14 @@ using System.IO.Pipelines; using BMA.EHR.Application.Repositories; using BMA.EHR.Application.Repositories.Commands; using BMA.EHR.Application.Repositories.Leaves.LeaveRequests; +using BMA.EHR.Application.Repositories.Leaves.TimeAttendants; using BMA.EHR.Domain.Common; using BMA.EHR.Domain.Extensions; using BMA.EHR.Domain.Models.Leave.Requests; +using BMA.EHR.Domain.Models.Leave.TimeAttendants; using BMA.EHR.Domain.Shared; using BMA.EHR.Infrastructure.Persistence; +using BMA.EHR.Leave.Service.DTOs.Reports; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; @@ -25,7 +28,10 @@ namespace BMA.EHR.Leave.Service.Controllers private readonly LeaveRequestRepository _leaveRequestRepository; private readonly UserProfileRepository _userProfileRepository; private readonly CommandRepository _commandRepository; - + private readonly LeaveTypeRepository _leaveTypeRepository; + private readonly ProcessUserTimeStampRepository _processUserTimeStampRepository; + private readonly DutyTimeRepository _dutyTimeRepository; + private readonly UserDutyTimeRepository _userDutyTimeRepository; #endregion @@ -33,11 +39,19 @@ namespace BMA.EHR.Leave.Service.Controllers public LeaveReportController(LeaveRequestRepository leaveRequestRepository, UserProfileRepository userProfileRepository, - CommandRepository commandRepository) + CommandRepository commandRepository, + LeaveTypeRepository leaveTypeRepository, + ProcessUserTimeStampRepository processUserTimeStampRepository, + DutyTimeRepository dutyTimeRepository, + UserDutyTimeRepository userDutyTimeRepository) { _leaveRequestRepository = leaveRequestRepository; _userProfileRepository = userProfileRepository; _commandRepository = commandRepository; + _leaveTypeRepository = leaveTypeRepository; + _processUserTimeStampRepository = processUserTimeStampRepository; + _dutyTimeRepository = dutyTimeRepository; + _userDutyTimeRepository = userDutyTimeRepository; } #endregion @@ -513,7 +527,20 @@ namespace BMA.EHR.Leave.Service.Controllers #endregion + /// + /// LV2_033 - รายงานการลา + /// + /// รหัสของรายการขอลา + /// เป็นการแสดงรายงานการขอลาไปพิธีอัจย์หรือไม่? + /// + /// + /// เมื่อทำรายการสำเร็จ + /// ไม่ได้ Login เข้าระบบ + /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("{id:guid}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetReport(Guid id, [FromQuery] bool hajj = false) { try @@ -584,7 +611,19 @@ namespace BMA.EHR.Leave.Service.Controllers } } + /// + /// LV2_034 - รายงานการยกเลิกการลา + /// + /// รหัสของรายการขอลา + /// + /// + /// เมื่อทำรายการสำเร็จ + /// ไม่ได้ Login เข้าระบบ + /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("reject/{id:guid}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetCancelReport(Guid id) { try @@ -631,6 +670,489 @@ namespace BMA.EHR.Leave.Service.Controllers } } + + /// + /// LV2_035 - รายงานบัญชีแสดงวันลา ขรก + /// + /// + /// + /// เมื่อทำรายการสำเร็จ + /// ไม่ได้ Login เข้าระบบ + /// เมื่อเกิดข้อผิดพลาดในการทำงาน + [HttpPost("leaveday/officer")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task> GetOfficerLeaveDayReport([FromBody] GetLeaveReportDto req) + { + try + { + var profile = await _userProfileRepository.SearchProfile(null, null, null); + var count = 1; + var employees = new List(); + + + + foreach (var p in profile) + { + var sickType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-001"); + if (sickType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var sickDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + sickType.Id, + req.StartDate, + req.EndDate); + + var personalType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-002"); + if (personalType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var personalDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + personalType.Id, + req.StartDate, + req.EndDate); + + var maternityType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-003"); + if (maternityType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var maternityDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + maternityType.Id, + req.StartDate, + req.EndDate); + + var wifeType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-004"); + if (wifeType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var wifeDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + wifeType.Id, + req.StartDate, + req.EndDate); + + var restType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-005"); + if (restType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var restDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + restType.Id, + req.StartDate, + req.EndDate); + + var ordainType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-006"); + if (ordainType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var ordainDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + ordainType.Id, + req.StartDate, + req.EndDate); + + var absentType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-007"); + if (absentType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var absentDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + absentType.Id, + req.StartDate, + req.EndDate); + + var studyType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-008"); + if (studyType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var studyDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + studyType.Id, + req.StartDate, + req.EndDate); + + var agencyType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-009"); + if (agencyType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var agencyDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + agencyType.Id, + req.StartDate, + req.EndDate); + + var coupleType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-010"); + if (coupleType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var coupleDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + coupleType.Id, + req.StartDate, + req.EndDate); + + var therapyType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-011"); + if (therapyType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var therapyDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + therapyType.Id, + req.StartDate, + req.EndDate); + + var timeStamps = await _processUserTimeStampRepository.GetTimeStampHistoryByRangeForUserAsync(p.KeycloakId ?? Guid.Empty, + req.StartDate, + req.EndDate); + + + var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); + if (defaultRound == null) + { + return Error("ไม่พบรอบการลงเวลา Default", StatusCodes.Status404NotFound); + } + + //var userRound = await _dutyTimeRepository.GetByIdAsync(profile.DutyTimeId ?? Guid.Empty); + var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(p.Id); + var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; + var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); + + var duty = userRound ?? defaultRound; + + var processTimeStamps = timeStamps + .Select(d => new + { + d.Id, + CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? + "LATE" : + "NORMAL", + CheckOutStatus = d.CheckOut == null ? "" : + DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? + "LATE" : + DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? + "ABSENT" : + "NORMAL", + }); + + var absentCount = processTimeStamps.Count(x => x.CheckOutStatus == "ABSENT"); + var lateCount = processTimeStamps.Count(x => x.CheckInStatus == "LATE"); + + + + var emp = new + { + no = count, + fullName = _userProfileRepository.GetUserFullName(p.KeycloakId ?? Guid.Empty), + position = p.Position == null ? "" : p.Position.Name, + positionLevel = p.PositionLevel == null ? "" : p.PositionLevel.Name, + posNo = p.PosNo == null ? "" : p.PosNo.Name, + reason = "", + + sickDayCount = sickDayCount, + maternityDayCount = maternityDayCount, + wifeDayCount = wifeDayCount, + personalDayCount = personalDayCount, + restDayCount = restDayCount, + ordainDayCount = ordainDayCount, + absentDayCount = absentDayCount, + studyDayCount = studyDayCount, + agencyDayCount = agencyDayCount, + coupleDayCount = coupleDayCount, + therapyDayCount = therapyDayCount, + absentTotal = absentCount, + lateTotal = lateCount, + + leaveTotal = sickDayCount + + maternityDayCount + + wifeDayCount + + personalDayCount + + restDayCount + + ordainDayCount + + absentDayCount + + studyDayCount + + agencyDayCount + + coupleDayCount + + therapyDayCount + }; + + employees.Add(emp); + count++; + } + + var result = new + { + template = "LeaveHalfYear-ขรก", + reportName = "LeaveHalfYear-Officer", + data = new + { + leaveDateStart = req.StartDate.Date.ToThaiShortDate(), + leaveDateEnd = req.EndDate.Date.ToThaiShortDate(), + organizationName = profile.First().Oc ?? "", + leaveTitleType = req.Type == "FULL" ? "หนึ่งปี" : "ครึ่งปี", + employees = employees + } + }; + + + return Success(result); + } + catch (Exception ex) + { + return Error(ex); + } + } + + /// + /// LV2_036 - รายงานบัญชีแสดงวันลา ลูกจ้าง + /// + /// + /// + /// เมื่อทำรายการสำเร็จ + /// ไม่ได้ Login เข้าระบบ + /// เมื่อเกิดข้อผิดพลาดในการทำงาน + [HttpPost("leaveday/employee")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task> GetEmployeeLeaveDayReport([FromBody] GetLeaveReportDto req) + { + try + { + var profile = await _userProfileRepository.SearchProfileEmployee(null, null, null); + var count = 1; + var employees = new List(); + + + + foreach (var p in profile) + { + var sickType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-001"); + if (sickType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var sickDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + sickType.Id, + req.StartDate, + req.EndDate); + var sickCount = await _leaveRequestRepository.GetCountApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + sickType.Id, + req.StartDate, + req.EndDate); + + var personalType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-002"); + if (personalType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var personalDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + personalType.Id, + req.StartDate, + req.EndDate); + + var personalCount = await _leaveRequestRepository.GetCountApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + personalType.Id, + req.StartDate, + req.EndDate); + + var maternityType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-003"); + if (maternityType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var maternityDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + maternityType.Id, + req.StartDate, + req.EndDate); + + var wifeType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-004"); + if (wifeType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var wifeDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + wifeType.Id, + req.StartDate, + req.EndDate); + + var restType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-005"); + if (restType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var restDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + restType.Id, + req.StartDate, + req.EndDate); + + var ordainType = await _leaveTypeRepository.GetLeaveTypeByCodeAsync("LV-006"); + if (ordainType == null) + return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); + var ordainDayCount = await _leaveRequestRepository.GetSumApproveLeaveByTypeAndRangeForUser(p.KeycloakId ?? Guid.Empty, + ordainType.Id, + req.StartDate, + req.EndDate); + + var timeStamps = await _processUserTimeStampRepository.GetTimeStampHistoryByRangeForUserAsync(p.KeycloakId ?? Guid.Empty, + req.StartDate, + req.EndDate); + + var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); + if (defaultRound == null) + { + return Error("ไม่พบรอบการลงเวลา Default", StatusCodes.Status404NotFound); + } + + //var userRound = await _dutyTimeRepository.GetByIdAsync(profile.DutyTimeId ?? Guid.Empty); + var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(p.Id); + var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; + var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); + + var duty = userRound ?? defaultRound; + + var processTimeStamps = timeStamps + .Select(d => new + { + d.Id, + CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? + "LATE" : + "NORMAL", + CheckOutStatus = d.CheckOut == null ? "" : + DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? + "LATE" : + DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < + DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? + "ABSENT" : + "NORMAL", + }); + + var absentCount = processTimeStamps.Count(x => x.CheckOutStatus == "ABSENT"); + var lateCount = processTimeStamps.Count(x => x.CheckInStatus == "LATE"); + + + + var emp = new + { + no = count, + fullName = _userProfileRepository.GetUserFullName(p.KeycloakId ?? Guid.Empty), + posNo = p.PosNoEmployee ?? "", + reason = "", + + sickDay = sickDayCount, + sickDayCount = sickCount, + personalDay = personalDayCount, + personalDayCount = personalCount, + leaveDay = sickDayCount + personalDayCount, + leaveTotal = sickCount + personalCount, //*รวมจำนวนครั้งลาป่วยและลากิจ(13) + maternityDay = maternityDayCount, + wifeDay = wifeDayCount, + ordainDay = ordainDayCount, + absentTotal = absentCount, + lateTotal = lateCount, + }; + + employees.Add(emp); + count++; + } + + var result = new + { + template = "LeaveHalfYear-ลูกจ้าง", + reportName = "LeaveHalfYear-Employee", + data = new + { + leaveDateStart = req.StartDate.Date.ToThaiShortDate(), + leaveDateEnd = req.EndDate.Date.ToThaiShortDate(), + organizationName = profile.First().Oc ?? "", + leaveTitleType = req.Type == "FULL" ? "หนึ่งปี" : "ครึ่งปี", + employees = employees + } + }; + + + return Success(result); + } + catch (Exception ex) + { + return Error(ex); + } + } + + + /// + /// LV2_037 - รายงานการลงเวลาประจำวัน + /// + /// + /// + /// เมื่อทำรายการสำเร็จ + /// ไม่ได้ Login เข้าระบบ + /// เมื่อเกิดข้อผิดพลาดในการทำงาน + [HttpPost("time-records/officer")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task> GetTimeRecordsOfficerReport([FromBody] GetLeaveDetailReportDto req) + { + try + { + var profile = await _userProfileRepository.SearchProfile(null, null, null); + + var data = new List(); + + for (DateTime date = req.StartDate.Date; date.Date <= req.EndDate.Date; date = date.AddDays(1)) + { + var employees = new List(); + var count = 1; + foreach (var p in profile) + { + var timeStamps = await _processUserTimeStampRepository.GetTimestampByDateAsync(p.KeycloakId ?? Guid.Empty, date); + + var fullName = _userProfileRepository.GetUserFullName(p.KeycloakId ?? Guid.Empty); + + + var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); + if (defaultRound == null) + { + return Error("ไม่พบรอบการลงเวลา Default", StatusCodes.Status404NotFound); + } + + //var userRound = await _dutyTimeRepository.GetByIdAsync(profile.DutyTimeId ?? Guid.Empty); + var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(p.Id); + var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; + var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); + + var duty = userRound ?? defaultRound; + + var emp = new + { + no = count, + fullName = fullName, + dutyTimeName = $"{duty.StartTimeMorning} น.", + checkInLocation = timeStamps == null ? "" : timeStamps.CheckInLocationName, + checkInTime = timeStamps == null ? "" : $"{timeStamps.CheckIn.Date.ToString("HH:mm")} น.", + + checkOutLocation = timeStamps == null ? "" : timeStamps.CheckOutLocationName ?? "", + checkOutTime = timeStamps == null ? "" : + timeStamps.CheckOut != null ? + $"{timeStamps.CheckOut.Value.Date.ToString("HH:mm")} น." : + "", + + remark = "" + }; + + employees.Add(emp); + count++; + + } + + var item = new + { + DateTimeStamp = date.Date.ToThaiFullDate(), + officerTotal = profile.Count, + workTotal = count - 1, + restTotal = 0, + sickTotal = 0, + lateTotal = 0, + wfhTotal = 0, + studyTotal = 0, + employees = employees + }; + + data.Add(item); + } + + var result = new + { + template = "TimeStamp", + reportName = "TimeStamp", + data = data + }; + + return Success(result); + } + catch (Exception ex) + { + return Error(ex); + } + } + #endregion } } \ No newline at end of file diff --git a/BMA.EHR.Leave.Service/Controllers/LeaveRequestController.cs b/BMA.EHR.Leave.Service/Controllers/LeaveRequestController.cs index 922db369..b1fb31be 100644 --- a/BMA.EHR.Leave.Service/Controllers/LeaveRequestController.cs +++ b/BMA.EHR.Leave.Service/Controllers/LeaveRequestController.cs @@ -639,9 +639,19 @@ namespace BMA.EHR.Leave.Service.Controllers data.LeaveStatus = "DELETE"; data.CancelLeaveWrote = req.LeaveWrote ?? ""; - // add cancel status to new - data.LeaveCancelStatus = "NEW"; - data.LeaveCancelComment = req.Reason ?? ""; + + // ถ้าผู้มีอำนาจอนุมัติแล้ว ต้องมีการรอ + if (data.ApproveStep == "st4") + { + // add cancel status to new + data.LeaveCancelStatus = "NEW"; + data.LeaveCancelComment = req.Reason ?? ""; + + } + else + { + await _leaveRequestRepository.ApproveCancelLeaveRequestAsync(data.Id, "อนุมัติการขอยกเลิกการลา โดยระบบ"); + } // upload leave cancel document if (req.Doc != null) @@ -656,8 +666,6 @@ namespace BMA.EHR.Leave.Service.Controllers // save to database await _leaveRequestRepository.UpdateAsync(data); - // await _leaveRequestRepository.AddAsync(data); - return Success(); } diff --git a/BMA.EHR.Leave.Service/DTOs/CheckIn/CheckInProcessHistoryForAdminDto.cs b/BMA.EHR.Leave.Service/DTOs/CheckIn/CheckInProcessHistoryForAdminDto.cs index 812df71e..b284f587 100644 --- a/BMA.EHR.Leave.Service/DTOs/CheckIn/CheckInProcessHistoryForAdminDto.cs +++ b/BMA.EHR.Leave.Service/DTOs/CheckIn/CheckInProcessHistoryForAdminDto.cs @@ -29,5 +29,13 @@ public double? CheckOutLon { get; set; } = 0; public string? CheckOutStatus { get; set; } = string.Empty; + + public bool CheckInIsLocation { get; set; } = false; + + public string? CheckInLocationName { get; set; } = string.Empty; + + public bool CheckOutIsLocation { get; set; } = false; + + public string? CheckOutLocationName { get; set; } = string.Empty; } } diff --git a/BMA.EHR.Leave.Service/DTOs/Reports/GetLeaveDetailReportDto.cs b/BMA.EHR.Leave.Service/DTOs/Reports/GetLeaveDetailReportDto.cs new file mode 100644 index 00000000..4a12851a --- /dev/null +++ b/BMA.EHR.Leave.Service/DTOs/Reports/GetLeaveDetailReportDto.cs @@ -0,0 +1,10 @@ +namespace BMA.EHR.Leave.Service.DTOs.Reports +{ + public class GetLeaveDetailReportDto + { + public DateTime StartDate { get; set; } = DateTime.MinValue; + + public DateTime EndDate { get; set; } = DateTime.MinValue; + + } +} \ No newline at end of file diff --git a/BMA.EHR.Leave.Service/DTOs/Reports/GetLeaveReportDto.cs b/BMA.EHR.Leave.Service/DTOs/Reports/GetLeaveReportDto.cs new file mode 100644 index 00000000..88288832 --- /dev/null +++ b/BMA.EHR.Leave.Service/DTOs/Reports/GetLeaveReportDto.cs @@ -0,0 +1,12 @@ +namespace BMA.EHR.Leave.Service.DTOs.Reports +{ + public class GetLeaveReportDto + { + public string? Type { get; set; } = "FULL"; + + public DateTime StartDate { get; set; } = DateTime.MinValue; + + public DateTime EndDate { get; set; } = DateTime.MinValue; + + } +} \ No newline at end of file