using BMA.EHR.Application.Repositories; using BMA.EHR.Application.Repositories.Leaves.TimeAttendants; using BMA.EHR.Domain.Common; using BMA.EHR.Domain.Models.Leave.TimeAttendants; using BMA.EHR.Domain.Shared; using BMA.EHR.Infrastructure.Persistence; using BMA.EHR.Leave.Service.DTOs.AdditionalCheck; using BMA.EHR.Leave.Service.DTOs.ChangeRound; using BMA.EHR.Leave.Service.DTOs.CheckIn; using BMA.EHR.Leave.Service.DTOs.DutyTime; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; using System.ComponentModel.DataAnnotations; using System.Security.Claims; namespace BMA.EHR.Leave.Service.Controllers { [Route("api/v{version:apiVersion}/leave")] [ApiVersion("1.0")] [ApiController] [Produces("application/json")] [Authorize] [SwaggerTag("API ระบบลงเวลาและการลา")] public class LeaveController : BaseController { #region " Fields " private readonly DutyTimeRepository _dutyTimeRepository; private readonly LeaveDbContext _context; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IWebHostEnvironment _hostingEnvironment; private readonly IConfiguration _configuration; private readonly UserProfileRepository _userProfileRepository; private readonly UserTimeStampRepository _userTimeStampRepository; private readonly MinIOService _minIOService; private readonly ProcessUserTimeStampRepository _processUserTimeStampRepository; private readonly UserDutyTimeRepository _userDutyTimeRepository; private readonly AdditionalCheckRequestRepository _additionalCheckRequestRepository; private readonly string _bucketName = "check-in"; #endregion #region " Constuctor and Destructor " public LeaveController(DutyTimeRepository dutyTimeRepository, LeaveDbContext context, IHttpContextAccessor httpContextAccessor, IWebHostEnvironment hostingEnvironment, IConfiguration configuration, UserProfileRepository userProfileRepository, UserTimeStampRepository userTimeStampRepository, MinIOService minIOService, ProcessUserTimeStampRepository processUserTimeStampRepository, UserDutyTimeRepository userDutyTimeRepository, AdditionalCheckRequestRepository additionalCheckRequestRepository) { _dutyTimeRepository = dutyTimeRepository; _context = context; _httpContextAccessor = httpContextAccessor; _hostingEnvironment = hostingEnvironment; _configuration = configuration; _userProfileRepository = userProfileRepository; _userTimeStampRepository = userTimeStampRepository; _minIOService = minIOService; _processUserTimeStampRepository = processUserTimeStampRepository; _userDutyTimeRepository = userDutyTimeRepository; _additionalCheckRequestRepository = additionalCheckRequestRepository; } #endregion #region " Properties " private string? UserId => _httpContextAccessor?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value; private string? FullName => _httpContextAccessor?.HttpContext?.User?.FindFirst("name")?.Value; private bool? PlacementAdmin => _httpContextAccessor?.HttpContext?.User?.IsInRole("placement1"); private Guid OcId { get { if (UserId != null || UserId != "") return _userProfileRepository.GetUserOCId(Guid.Parse(UserId!)); else return Guid.Empty; } } #endregion #region " Methods " #region " Duty Time รอบการทำงาน " /// /// LV1_004 - ข้อมูลทั้งหมดของรอบการปฏิบัติงาน (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("duty-time")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetAllAsync() { var data = await _dutyTimeRepository.GetAllAsync(); return Success(data); } /// /// ข้อมูลของรอบการปฏิบัติงาน (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("duty-time/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetByIdAsync(Guid id) { var data = await _dutyTimeRepository.GetByIdAsync(id); return Success(data); } /// /// LV1_001 - สร้างรอบการปฏิบัติงาน (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPost("duty-time")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> PostAsync([FromBody] CreateDutyTimeDto data) { // validate var startMorning = TimeOnly.Parse(data.StartTimeMorning); var endMorning = TimeOnly.Parse(data.EndTimeMorning); var startAfternoon = TimeOnly.Parse(data.StartTimeAfternoon); var endAfternoon = TimeOnly.Parse(data.EndTimeAfternoon); if (startMorning >= endMorning) { throw new Exception(GlobalMessages.StartTimeGreaterEnd); } if (startAfternoon >= endAfternoon) { throw new Exception(GlobalMessages.StartTimeGreaterEnd); } var oldData = await _dutyTimeRepository.GetAllAsync(); if (oldData == null || oldData.Count == 0) { var inserted = new DutyTime { Id = Guid.NewGuid(), Description = data.Description ?? "", StartTimeMorning = data.StartTimeMorning, EndTimeMorning = data.EndTimeMorning, StartTimeAfternoon = data.StartTimeAfternoon, EndTimeAfternoon = data.EndTimeAfternoon, IsActive = data.IsActive, IsDefault = true, }; var ret = await _dutyTimeRepository.AddAsync(inserted); return Success(ret); } else { if (data.IsDefault) { foreach (var d in oldData) { d.IsDefault = false; await _dutyTimeRepository.UpdateAsync(d); } } var inserted = new DutyTime { Id = Guid.NewGuid(), Description = data.Description ?? "", StartTimeMorning = data.StartTimeMorning, EndTimeMorning = data.EndTimeMorning, StartTimeAfternoon = data.StartTimeAfternoon, EndTimeAfternoon = data.EndTimeAfternoon, IsActive = data.IsActive, IsDefault = data.IsDefault, }; var ret = await _dutyTimeRepository.AddAsync(inserted); return Success(ret); } } /// /// LV1_002 - แก้ไขรอบการปฏิบัติงาน (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPut("duty-time/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> PutAsync(Guid id, [FromBody] UpdateDutyTimeDto data) { var oldData = await _dutyTimeRepository.GetByIdAsync(id); if (oldData == null) { throw new Exception(GlobalMessages.DataNotFound); } else { var oldDataList = await _dutyTimeRepository.GetAllAsync(); if (data.IsDefault) { foreach (var d in oldDataList) { d.IsDefault = false; await _dutyTimeRepository.UpdateAsync(d); } } oldData.Description = data.Description ?? ""; oldData.IsDefault = data.IsDefault; oldData.IsActive = data.IsActive; await _dutyTimeRepository.UpdateAsync(oldData); return Success(oldData); } } /// /// LV1_003 - ลบรอบการปฏิบัติงาน (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpDelete("duty-time/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> DeleteAsync(Guid id) { var oldData = await _dutyTimeRepository.GetByIdAsync(id); if (oldData == null) { throw new Exception(GlobalMessages.DataNotFound); } else { var inUseRound = await _userDutyTimeRepository.GetFirstInUseRound(oldData.Id); //if (inUseRound != null || oldData.IsActive || oldData.IsDefault) if (inUseRound != null) { throw new Exception("ไม่สามารถลบรอบการปฏิบัติงานที่ยังใช้งานอยู่ได้"); } if (oldData.IsDefault) { throw new Exception("ไม่สามารถลบรอบการปฏิบัติงานที่ตั้งค่า Default ได้"); } await _dutyTimeRepository.DeleteAsync(oldData); return Success(); } } /// /// LV1_012 - ข้อมูลทั้งหมดของรอบการปฏิบัติงานที่ active (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("round")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetAllActiveAsync() { var data = await _dutyTimeRepository.GetAllActiveAsync(); return Success(data); } #endregion #region " Check-In Check-Out ลงเวลา " /// /// LV1_006 - เช็คเวลาต้องลงเวลาเข้าหรือออกงาน (USER) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("check-time")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> CheckTimeAsync() { var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId); var data = await _userTimeStampRepository.GetLastRecord(userId); // TODO : รอดุึงรอบที่ผูกกับ user var duty = await _dutyTimeRepository.GetDefaultAsync(); CheckInResultDto ret; if (data == null) { ret = new CheckInResultDto { StartTimeMorning = duty == null ? "00:00" : duty.StartTimeMorning, EndTimeMorning = duty == null ? "00:00" : duty.EndTimeMorning, StartTimeAfternoon = duty == null ? "00:00" : duty.StartTimeAfternoon, EndTimeAfternoon = duty == null ? "00:00" : duty.EndTimeAfternoon, Description = duty == null ? "-" : duty.Description, CheckInTime = null, CheckInId = null, }; } else { if (data.CheckOut != null) { ret = new CheckInResultDto { StartTimeMorning = duty == null ? "00:00" : duty.StartTimeMorning, EndTimeMorning = duty == null ? "00:00" : duty.EndTimeMorning, StartTimeAfternoon = duty == null ? "00:00" : duty.StartTimeAfternoon, EndTimeAfternoon = duty == null ? "00:00" : duty.EndTimeAfternoon, Description = duty == null ? "-" : duty.Description, CheckInTime = null, CheckInId = null, }; } else { ret = new CheckInResultDto { StartTimeMorning = duty == null ? "00:00" : duty.StartTimeMorning, EndTimeMorning = duty == null ? "00:00" : duty.EndTimeMorning, StartTimeAfternoon = duty == null ? "00:00" : duty.StartTimeAfternoon, EndTimeAfternoon = duty == null ? "00:00" : duty.EndTimeAfternoon, Description = duty == null ? "-" : duty.Description, CheckInTime = data.CheckIn, CheckInId = data.Id, }; } } return Success(ret); } /// /// LV1_005 - ลงเวลาเข้า-ออกงาน (USER) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPost("check-in"), DisableRequestSizeLimit] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> CheckInAsync([FromForm] CheckTimeDto data) { var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId); var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId); if (profile == null) return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); if (data.Img == null) throw new Exception(GlobalMessages.NoFileToUpload); var currentDate = DateTime.Now; var fileName = $"{_bucketName}/{UserId}/{DateTime.Now.ToString("dd-MM-yyyy")}/{data.Img.FileName}"; using (var ms = new MemoryStream()) { data.Img.CopyTo(ms); await _minIOService.UploadFileAsync(fileName, ms); } var currentCheckInProcess = await _processUserTimeStampRepository.GetTimestampByDateAsync(Guid.Parse(UserId), currentDate); var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); if (defaultRound == null) { return Error("ไม่พบรอบการลงเวลาทำงาน Default", StatusCodes.Status404NotFound); } var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); // TODO : รอดุึงรอบที่ผูกกับ user var duty = userRound ?? defaultRound; // create check in object if (data.CheckInId == null) { // validate duplicate check in var currentCheckIn = await _userTimeStampRepository.GetTimestampByDateAsync(Guid.Parse(UserId), currentDate); if (currentCheckIn != null) { return Error(new Exception("ไม่สามารถลงเวลาได้ เนืองจากมีการลงเวลาในวันนี้แล้ว!"), StatusCodes.Status400BadRequest); } var checkin = new UserTimeStamp { KeycloakUserId = UserId != null ? Guid.Parse(UserId) : Guid.Empty, CheckInLat = data.Lat, CheckInLon = data.Lon, IsLocationCheckIn = data.IsLocation, CheckInLocationName = data.LocationName, CheckInPOI = data.POI, CheckInRemark = data.Remark, CheckInImageUrl = fileName, CheckIn = currentDate }; var checkInStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL"; // process - รอทำใน queue var checkin_process = new ProcessUserTimeStamp { KeycloakUserId = UserId != null ? Guid.Parse(UserId) : Guid.Empty, CheckInLat = data.Lat, CheckInLon = data.Lon, IsLocationCheckIn = data.IsLocation, CheckInLocationName = data.LocationName, CheckInPOI = data.POI, CheckInRemark = data.Remark, CheckInImageUrl = fileName, CheckIn = currentDate, CheckInStatus = checkInStatus }; await _userTimeStampRepository.AddAsync(checkin); await _processUserTimeStampRepository.AddAsync(checkin_process); } else { var checkout = await _userTimeStampRepository.GetByIdAsync(data.CheckInId.Value); var checkout_process = await _processUserTimeStampRepository.GetByIdAsync(currentCheckInProcess.Id); if (checkout != null) { checkout.CheckOutLat = data.Lat; checkout.CheckOutLon = data.Lon; checkout.IsLocationCheckOut = data.IsLocation; checkout.CheckOutLocationName = data.LocationName; checkout.CheckOutPOI = data.POI; checkout.CheckOutRemark = data.Remark; checkout.CheckOutImageUrl = fileName; checkout.CheckOut = currentDate; await _userTimeStampRepository.UpdateAsync(checkout); } else { return Error(new Exception(GlobalMessages.DataNotFound), StatusCodes.Status404NotFound); } var checkOutStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? "LATE" : DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) < DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ? "ABSENT" : "NORMAL"; if (checkout_process != null) { checkout_process.CheckOutLat = data.Lat; checkout_process.CheckOutLon = data.Lon; checkout_process.IsLocationCheckOut = data.IsLocation; checkout_process.CheckOutLocationName = data.LocationName; checkout_process.CheckOutPOI = data.POI; checkout_process.CheckOutRemark = data.Remark; checkout_process.CheckOutImageUrl = fileName; checkout_process.CheckOut = currentDate; checkout_process.CheckOutStatus = checkOutStatus; await _processUserTimeStampRepository.UpdateAsync(checkout_process); } else { return Error(new Exception(GlobalMessages.DataNotFound), StatusCodes.Status404NotFound); } } return Success(new { date = currentDate }); } /// /// LV1_007 - ประวัติการลงเวลา (USER) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("check-in/history")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> CheckInHistoryAsync(int year, int page = 1, int pageSize = 10, string keyword = "") { var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId); var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId); if (profile == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); if (defaultRound == null) { return Error("ไม่พบรอบการลงเวลาทำงาน Default", StatusCodes.Status404NotFound); } var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); // TODO : รอดุึงรอบที่ผูกกับ user var duty = userRound ?? defaultRound; var checkin_base = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}"); var checkout_base = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}"); var data = (await _processUserTimeStampRepository.GetTimeStampHistoryAsync(userId, year)) .Select(d => new CheckInHistoryDto { CheckInId = d.Id, CheckInDate = d.CheckIn.Date, CheckInTime = d.CheckIn.ToString("HH:mm:ss"), CheckInLocation = d.CheckInPOI, CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", CheckInIsLocation = d.IsLocationCheckIn, CheckInLocationName = d.CheckInLocationName, CheckOutDate = d.CheckOut == null ? null : d.CheckOut.Value.Date, CheckOutTime = d.CheckOut == null ? "" : d.CheckOut.Value.ToString("HH:mm:ss"), CheckOutLocation = d.CheckOutPOI ?? "", 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, IsEdit = _processUserTimeStampRepository.IsEditRequest(userId, d.CheckIn.Date) //IsEdit = (d.EditStatus != null && d.EditStatus != "") //EditReason = d.EditReason ?? "",ß //EditStatus = d.EditStatus ?? "" }) .ToList(); if (keyword != "") { data = data.Where(x => (x.CheckInLocation.Contains(keyword) || x.CheckOutLocation.Contains(keyword))).ToList(); } var pageData = data .Skip((page - 1) * pageSize) .Take(pageSize) .ToList(); return Success(new { data = pageData, total = data.Count }); } /// /// LV1_010 - รายการลงเวลาปฏิบัติงาน (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("log-record")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> LogRecordAsync([Required] DateTime startDate, [Required] DateTime endDate, int page = 1, int pageSize = 10, string keyword = "") { if (startDate.Date > endDate.Date) { return Error(new Exception("วันเริ่มต้นต้องมีค่าน้อยกว่าหรือเท่ากับวันสิ้นสุด"), StatusCodes.Status400BadRequest); } //var count = await _userTimeStampRepository.CountRecordAsync(); var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}"; var data = (await _userTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate)) .Select(d => new CheckInHistoryForAdminDto { Id = d.Id, FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId), CheckInDate = d.CheckIn.Date, CheckInTime = d.CheckIn.ToString("HH:mm:ss"), CheckInLocation = d.CheckInPOI, CheckInLat = d.CheckInLat, CheckInLon = d.CheckInLon, CheckInImage = $"{imgUrl}/{d.CheckInImageUrl}", // add from new specification IsLocationCheckIn = d.IsLocationCheckIn, CheckInLocationName = d.CheckInLocationName ?? "", CheckOutDate = d.CheckOut == null ? null : d.CheckOut.Value.Date, CheckOutTime = d.CheckOut == null ? "" : d.CheckOut.Value.ToString("HH:mm:ss"), CheckOutLocation = d.CheckOut == null ? "" : d.CheckOutPOI, CheckOutLat = d.CheckOut == null ? null : d.CheckOutLat, CheckOutLon = d.CheckOut == null ? null : d.CheckOutLon, CheckOutImage = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", // add from new specification IsLocationCheckOut = d.IsLocationCheckOut, CheckOutLocationName = d.CheckOutLocationName ?? "" }) .ToList(); if (keyword != "") { data = data.Where(x => x.FullName.Contains(keyword)).ToList(); } var pageData = data .Skip((page - 1) * pageSize) .Take(pageSize) .ToList(); return Success(new { data = pageData, total = data.Count }); } /// /// LV1_011 - รายละเอียดการลงเวลาปฎิบัติงานรายบุคคล Tabรายากรลงเวลาที่ประมวลผลแล้ว (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("time-record/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetTimeRecordAsync([Required] Guid id) { var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}"; var d = (await _processUserTimeStampRepository.GetTimeStampById(id)); if (d == null) { throw new Exception(GlobalMessages.DataNotFound); } else { var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(d.KeycloakUserId); if (profile == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } 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(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); var duty = userRound ?? defaultRound; var result = new CheckInDetailForAdminDto { Id = d.Id, FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId), CheckInDate = d.CheckIn.Date, CheckInTime = d.CheckIn.ToString("HH:mm"), CheckInPOI = d.CheckInPOI, CheckInLat = d.CheckInLat, CheckInLon = d.CheckInLon, CheckInImg = $"{imgUrl}/{d.CheckInImageUrl}", CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", CheckInDescription = d.CheckInRemark ?? "", CheckOutDate = d.CheckOut == null ? null : d.CheckOut.Value.Date, CheckOutTime = d.CheckOut == null ? "" : d.CheckOut.Value.ToString("HH:mm"), CheckOutPOI = d.CheckOut == null ? "" : d.CheckOutPOI, CheckOutLat = d.CheckOut == null ? null : d.CheckOutLat, CheckOutLon = d.CheckOut == null ? null : d.CheckOutLon, CheckOutImg = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", 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", CheckOutDescription = d.CheckOutRemark ?? "", }; return Success(result); } } /// /// LV1_009 - รายการลงเวลาปฏิบัติงานที่ประมวลผลแล้ว (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("time-record")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] [AllowAnonymous] public async Task> GetTimeRecordAsync([Required] DateTime startDate, [Required] DateTime endDate, int page = 1, int pageSize = 10, string status = "NORMAL", string keyword = "") { if (startDate.Date > endDate.Date) { return Error(new Exception("วันเริ่มต้นต้องมีค่าน้อยกว่าหรือเท่ากับวันสิ้นสุด"), StatusCodes.Status400BadRequest); } var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId); var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId); if (profile == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } 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(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); var duty = userRound ?? defaultRound; var checkin_base = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}"); var checkout_base = DateTime.Parse($"{DateTime.Now.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}"); //var count = await _processUserTimeStampRepository.GetTimeStampHistoryForAdminCountAsync(startDate, endDate); var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}"; var data = (await _processUserTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate)) .Select(d => new CheckInProcessHistoryForAdminDto { Id = d.Id, FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId), CheckInDate = d.CheckIn.Date, CheckInTime = d.CheckIn.ToString("HH:mm"), CheckInLocation = d.CheckInPOI, CheckInLat = d.CheckInLat, CheckInLon = d.CheckInLon, CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > 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, CheckOutTime = d.CheckOut == null ? "" : d.CheckOut.Value.ToString("HH:mm"), CheckOutLocation = d.CheckOut == null ? "" : d.CheckOutPOI, CheckOutLat = d.CheckOut == null ? null : d.CheckOutLat, CheckOutLon = d.CheckOut == null ? null : d.CheckOutLon, 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}", }) .ToList(); if (keyword != "") { data = data.Where(x => x.FullName.Contains(keyword)).ToList(); } if (status.Trim().ToUpper() != "ALL") { data = data.Where(x => x.CheckInStatus == status || x.CheckOutStatus == status).ToList(); } var pageData = data .Skip((page - 1) * pageSize) .Take(pageSize) .ToList(); return Success(new { data = pageData, total = data.Count }); } #endregion #region " เปลี่ยนรอบการทำงาน " /// /// LV1_006 - เช็คเวลาต้องลงเวลาเข้าหรือออกงาน (USER) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPost("search")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> SearchProfileAsync([FromBody] SearchProfileDto req) { var profile = await _userProfileRepository.SearchProfile(req.CitizenId, req.FirstName, req.LastName); var pagedProfile = profile.Skip((req.Page - 1) * req.PageSize).Take(req.PageSize).ToList(); var defaultRound = await _dutyTimeRepository.GetDefaultAsync(); var resultSet = new List(); foreach (var p in pagedProfile) { var roundId = p.DutyTimeId ?? Guid.Empty; var round = await _dutyTimeRepository.GetByIdAsync(roundId); var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(p.Id); var res = new SearchProfileResultDto { ProfileId = p.Id, CitizenId = p.CitizenId, FullName = $"{p.Prefix.Name}{p.FirstName} {p.LastName}", StartTimeMorning = round != null ? round.StartTimeMorning : defaultRound.StartTimeMorning, LeaveTimeAfterNoon = round != null ? round.EndTimeAfternoon : defaultRound.EndTimeAfternoon, EffectiveDate = effectiveDate == null ? null : effectiveDate.EffectiveDate.Value.Date }; resultSet.Add(res); } return Success(new { data = resultSet, total = profile.Count }); } /// /// LV1_014 - เปลี่ยนรอบการลงเวลา (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPost("round")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> CreateChangeRoundAsync([FromBody] CreateChangeRoundDto req) { var currentDate = DateTime.Now.Date; if (req.EffectiveDate.Date < currentDate) { return Error(new Exception($"วันที่มีผลต้องมากกว่าหรือเท่ากับวันที่ปัจจุบัน({currentDate.ToString("yyyy-MM-dd")})"), StatusCodes.Status400BadRequest); } var old = await _userDutyTimeRepository.GetExist(req.ProfileId, req.EffectiveDate); if (old != null) { return Error(new Exception("ไม่สามารถทำรายการได้ เนื่องจากมีการกำหนดรอบการทำงานในวันที่นี้ไว้แล้ว"), StatusCodes.Status400BadRequest); } var data = new UserDutyTime { ProfileId = req.ProfileId, DutyTimeId = req.RoundId, EffectiveDate = req.EffectiveDate, Remark = req.Remark, }; await _userDutyTimeRepository.AddAsync(data); return Success(); } /// /// LV1_015 - ประวัติการเปลี่ยนรอบการลงเวลา (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("round/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetChangeRoundHistoryByProfileIdAsync(Guid id, int page = 1, int pageSize = 10, string keyword = "") { var data = await _userDutyTimeRepository.GetListByProfileIdAsync(id); var resultSet = new List(); if (data != null) { resultSet = data .GroupBy(item => item.ProfileId) .SelectMany(group => group .OrderBy(item => item.EffectiveDate) // เรียงลำดับตาม property ที่คุณต้องการ .Select((item, index) => new ChangeRoundHistoryDto { Round = index + 1, StartTimeMorning = item.DutyTime.StartTimeMorning, LeaveTimeAfternoon = item.DutyTime.EndTimeAfternoon, EffectiveDate = item.EffectiveDate.Value, Remark = item.Remark })) .Skip((page - 1) * pageSize) .Take(pageSize) .ToList(); } return Success(new { data = resultSet, total = data.Count }); } #endregion #region " ขอลงเวลาเป็นกรณีพิเศษ " /// /// LV1_017 - เพิ่มลงเวลากรณีพิเศษ (USER) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPost("user/edit")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> CreateAdditionalCheckRequestAsync([FromBody] CreateAdditionalCheckRequestDto req) { if (req.CheckDate.Date > DateTime.Now.Date) { return Error("ไม่สามารถขอลงเวลากรณีพิเศษในวันที่มากกว่าวันที่ปัจจุบันได้", StatusCodes.Status400BadRequest); } var request = new AdditionalCheckRequest { KeycloakUserId = UserId != null ? Guid.Parse(UserId) : Guid.Empty, CheckDate = req.CheckDate, CheckInEdit = req.CheckInEdit, CheckOutEdit = req.CheckOutEdit, Description = req.Description, }; await _additionalCheckRequestRepository.AddAsync(request); return Success(); } /// /// LV1_018 - รายการลงเวลากรณีพิเศษ (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("admin/edit")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetAdditionalCheckRequestAsync([Required] int year, [Required] int month, [Required] int page = 1, [Required] int pageSize = 10, string keyword = "") { var rawData = await _additionalCheckRequestRepository.GetAdditionalCheckRequests(year, month); var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync(); if (getDefaultRound == null) { return Error("ไม่พบรอบลงเวลา Default", StatusCodes.Status404NotFound); } var result = new List(); foreach (var data in rawData) { var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(data.KeycloakUserId); if (profile == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } //var userRound = await _dutyTimeRepository.GetByIdAsync(profile.DutyTimeId ?? Guid.Empty); var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); var checkInData = await _userTimeStampRepository.GetTimestampByDateAsync(data.KeycloakUserId, data.CheckDate); var duty = userRound ?? getDefaultRound; // create result object to return var resObj = new GetAdditionalCheckRequestDto { Id = data.Id, FullName = $"{profile.Prefix.Name}{profile.FirstName} {profile.LastName}", CreatedAt = data.CreatedAt, CheckDate = data.CheckDate, CheckInEdit = data.CheckInEdit, CheckOutEdit = data.CheckOutEdit, CheckInTime = checkInData == null ? "00:00" : checkInData.CheckIn.ToString("HH:mm"), CheckOutTime = checkInData == null ? "00:00" : checkInData.CheckOut == null ? "00:00" : checkInData.CheckOut.Value.ToString("HH:mm"), CheckInStatus = checkInData == null ? null : DateTime.Parse(checkInData.CheckIn.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{checkInData.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", CheckOutStatus = checkInData == null ? null : checkInData.CheckOut == null ? null : DateTime.Parse(checkInData.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < DateTime.Parse($"{checkInData.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? "LATE" : "NORMAL", StartTimeMorning = duty.StartTimeMorning, EndTimeMorning = duty.EndTimeMorning, StartTimeAfternoon = duty.StartTimeAfternoon, EndTimeAfternoon = duty.EndTimeAfternoon, Reason = data.Comment ?? "", Status = data.Status, Description = data.Description, StatusSort = data.Status.Trim().ToLower() == "pending" ? 1 : data.Status.Trim().ToLower() == "approve" ? 2 : 3, }; result.Add(resObj); } if (keyword != "") { result = result.Where(x => x.FullName.Contains(keyword)).ToList(); } var pageResult = result.Skip((page - 1) * pageSize).Take(pageSize) .OrderBy(x => x.StatusSort) .ToList(); return Success(new { data = pageResult, total = result.Count }); } /// /// LV1_019 - อนุมัติลงเวลากรณีพิเศษ (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPut("admin/edit/approve/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> ApproveRequestAsync(Guid id, [FromBody] ApproveRequestDto req) { if (req.Reason == null || req.Reason == string.Empty) { return Error("กรุณากรอกเหตุผล", StatusCodes.Status400BadRequest); } var requestData = await _additionalCheckRequestRepository.GetByIdAsync(id); if (requestData == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } requestData.Status = "APPROVE"; requestData.Comment = req.Reason; await _additionalCheckRequestRepository.UpdateAsync(requestData); // change user timestamp var processTimeStamp = await _processUserTimeStampRepository.GetTimestampByDateAsync(requestData.KeycloakUserId, requestData.CheckDate.Date); if (processTimeStamp == null) { processTimeStamp = new ProcessUserTimeStamp { KeycloakUserId = requestData.KeycloakUserId, CheckIn = DateTime.Parse($"{requestData.CheckDate.Date.ToString("yyyy-MM-dd")} {req.CheckInTime}"), CheckOut = DateTime.Parse($"{requestData.CheckDate.Date.ToString("yyyy-MM-dd")} {req.CheckOutTime}"), CheckInRemark = req.Reason, CheckOutRemark = req.Reason, CheckInLat = 0, CheckInLon = 0, CheckOutLat = 0, CheckOutLon = 0, CheckInPOI = "ลงเวลากรณีพิเศษ", CheckOutPOI = "ลงเวลากรณีพิเศษ", CheckInStatus = req.CheckInStatus, CheckOutStatus = req.CheckOutStatus }; processTimeStamp.EditStatus = "APPROVE"; processTimeStamp.EditReason = req.Reason; await _processUserTimeStampRepository.AddAsync(processTimeStamp); } else { if (requestData.CheckInEdit) { processTimeStamp.CheckIn = DateTime.Parse($"{requestData.CheckDate.Date.ToString("yyyy-MM-dd")} {req.CheckInTime}"); processTimeStamp.CheckInRemark = req.Reason; processTimeStamp.CheckInLat = 0; processTimeStamp.CheckInLon = 0; processTimeStamp.CheckInPOI = "ลงเวลากรณีพิเศษ"; processTimeStamp.CheckInStatus = req.CheckInStatus; } if (requestData.CheckOutEdit) { processTimeStamp.CheckOut = DateTime.Parse($"{requestData.CheckDate.Date.ToString("yyyy-MM-dd")} {req.CheckOutTime}"); processTimeStamp.CheckOutRemark = req.Reason; processTimeStamp.CheckOutLat = 0; processTimeStamp.CheckOutLon = 0; processTimeStamp.CheckOutPOI = "ลงเวลากรณีพิเศษ"; processTimeStamp.CheckOutStatus = req.CheckOutStatus; } processTimeStamp.EditStatus = "APPROVE"; processTimeStamp.EditReason = req.Reason; await _processUserTimeStampRepository.UpdateAsync(processTimeStamp); } return Success(); } /// /// LV1_020 - ไม่อนุมัติลงเวลากรณีพิเศษ (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpPut("admin/edit/reject/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> RejectRequestAsync(Guid id, [FromBody] RejectRequestDto req) { if (req.Reason == null || req.Reason == string.Empty) { return Error("กรุณากรอกเหตุผล", StatusCodes.Status400BadRequest); } var requestData = await _additionalCheckRequestRepository.GetByIdAsync(id); if (requestData == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } // change user timestamp var processTimeStamp = await _processUserTimeStampRepository.GetTimestampByDateAsync(requestData.KeycloakUserId, requestData.CheckDate.Date); if (processTimeStamp != null) { processTimeStamp.EditStatus = "REJECT"; processTimeStamp.EditReason = req.Reason; await _processUserTimeStampRepository.UpdateAsync(processTimeStamp); } requestData.Status = "REJECT"; requestData.Comment = req.Reason; await _additionalCheckRequestRepository.UpdateAsync(requestData); return Success(); } /// /// LV1_021 - รายละเอียดการลงเวลาปฎิบัติงานรายบุคคล Tabรายการลงเวลา (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("log-record/{id:guid}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetLogRecordAsync([Required] Guid id) { var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}"; var d = (await _userTimeStampRepository.GetTimeStampById(id)); if (d == null) { throw new Exception(GlobalMessages.DataNotFound); } else { var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(d.KeycloakUserId); if (profile == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } 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(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); var duty = userRound ?? defaultRound; var result = new CheckInDetailForAdminDto { Id = d.Id, FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId), CheckInDate = d.CheckIn.Date, CheckInTime = d.CheckIn.ToString("HH:mm"), CheckInPOI = d.CheckInPOI, CheckInLat = d.CheckInLat, CheckInLon = d.CheckInLon, CheckInImg = $"{imgUrl}/{d.CheckInImageUrl}", CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", CheckInDescription = d.CheckInRemark ?? "", CheckOutDate = d.CheckOut == null ? null : d.CheckOut.Value.Date, CheckOutTime = d.CheckOut == null ? "" : d.CheckOut.Value.ToString("HH:mm"), CheckOutPOI = d.CheckOut == null ? "" : d.CheckOutPOI, CheckOutLat = d.CheckOut == null ? null : d.CheckOutLat, CheckOutLon = d.CheckOut == null ? null : d.CheckOutLon, CheckOutImg = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", 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" : "NORMAL", CheckOutDescription = d.CheckOutRemark ?? "", }; return Success(result); } } /// /// LV1_022 - ประวัติการยื่นขอลงเวลาพิเศษ (USER) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("edit/history")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task> GetAdditionalCheckRequestHistoryAsync([Required] int year, [Required] int month, [Required] int page = 1, [Required] int pageSize = 10, string keyword = "") { var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId); var rawData = await _additionalCheckRequestRepository.GetAdditionalCheckRequestsByUserId(userId, year, month); var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync(); if (getDefaultRound == null) { return Error("ไม่พบรอบลงเวลา Default", StatusCodes.Status404NotFound); } var result = new List(); foreach (var data in rawData) { var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(data.KeycloakUserId); if (profile == null) { return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound); } //var userRound = await _dutyTimeRepository.GetByIdAsync(profile.DutyTimeId ?? Guid.Empty); var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(profile.Id); var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty; var userRound = await _dutyTimeRepository.GetByIdAsync(roundId); var checkInData = await _userTimeStampRepository.GetTimestampByDateAsync(data.KeycloakUserId, data.CheckDate); var duty = userRound ?? getDefaultRound; DateTime? resultCheckInDate, resultCheckOutDate; string resultCheckInTime, resultCheckOutTime; if (data.CheckInEdit) { resultCheckInDate = data.CheckDate.Date; resultCheckInTime = duty.StartTimeMorning; } else { resultCheckInDate = checkInData == null ? null : checkInData.CheckIn; resultCheckInTime = checkInData == null ? "00:00" : checkInData.CheckIn.ToString("HH:mm"); } if (data.CheckOutEdit) { resultCheckOutDate = data.CheckDate.Date; resultCheckOutTime = duty.EndTimeAfternoon; } else { resultCheckOutDate = checkInData == null ? null : checkInData.CheckOut == null ? null : checkInData.CheckOut.Value.Date; resultCheckOutTime = checkInData == null ? "00:00" : checkInData.CheckOut == null ? "00:00" : checkInData.CheckOut.Value.ToString("HH:mm"); } // create result object to return var resObj = new GetAdditionalCheckRequestHistoryDto { Id = data.Id, CheckInDate = resultCheckInDate, CheckOutDate = resultCheckOutDate, CheckInTime = resultCheckInTime, CheckOutTime = resultCheckOutTime, CheckInStatus = checkInData == null ? null : DateTime.Parse(checkInData.CheckIn.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{checkInData.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", CheckOutStatus = checkInData == null ? null : checkInData.CheckOut == null ? null : DateTime.Parse(checkInData.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) < DateTime.Parse($"{checkInData.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ? "LATE" : "NORMAL", CheckInLocation = checkInData == null ? "" : checkInData.CheckInPOI, CheckOutLocation = checkInData == null ? "" : checkInData.CheckOutPOI ?? "", EditReason = data.Comment ?? "", EditStatus = data.Status, }; result.Add(resObj); } if (keyword != "") { result = result.Where(x => x.EditReason!.Contains(keyword)).ToList(); } var pageResult = result.Skip((page - 1) * pageSize).Take(pageSize) .ToList(); return Success(new { data = pageResult, total = result.Count }); } #endregion #endregion } }