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.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 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) { _dutyTimeRepository = dutyTimeRepository; _context = context; _httpContextAccessor = httpContextAccessor; _hostingEnvironment = hostingEnvironment; _configuration = configuration; _userProfileRepository = userProfileRepository; _userTimeStampRepository = userTimeStampRepository; _minIOService = minIOService; _processUserTimeStampRepository = processUserTimeStampRepository; } #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 = true, 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 = true, 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 { if (oldData.IsActive || oldData.IsDefault) { throw new Exception("ไม่สามารถลบรอบการปฏิบัติงานที่ยังใช้งานอยู่ได้"); } 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 { 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.CheckOut == null ? data.Id : null, }; } 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) { 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); // 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("ไม่สามารถลงเวลาได้ เนืองจากมีการลงเวลาในวันนี้แล้ว!"), (int)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 }; // 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 }; 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), (int)StatusCodes.Status404NotFound); } 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; await _processUserTimeStampRepository.UpdateAsync(checkout_process); } else { return Error(new Exception(GlobalMessages.DataNotFound), (int)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); // TODO : รอดุึงรอบที่ผูกกับ user var duty = await _dutyTimeRepository.GetDefaultAsync(); if (duty == null) { return Error(new Exception(GlobalMessages.DataNotFound), (int)StatusCodes.Status404NotFound); } 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 _userTimeStampRepository.GetTimeStampHistoryAsync(userId, year, page, pageSize, keyword)) .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", 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" : "NORMAL", }) .ToList(); return Success(data); } /// /// 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("วันเริ่มต้นต้องมีค่าน้อยกว่าหรือเท่ากับวันสิ้นสุด"), (int)StatusCodes.Status400BadRequest); } var count = await _userTimeStampRepository.CountRecordAsync(); var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}"; var data = (await _userTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate, page, pageSize, keyword)) .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, //CheckInImageUrl = $"{imgUrl}/{d.CheckInImageUrl}", 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, //CheckOutImageUrl = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", }) .ToList(); return Success(new { data = data, total = count }); } /// /// LV1_011 - รายละเอียดการลงเวลาปฎิบัติงานรายบุคคล /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ 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 _userTimeStampRepository.GetTimeStampById(id)); if (d == null) { throw new Exception(GlobalMessages.DataNotFound); } else { var result = new CheckInDetailForAdminDto { 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, CheckInImg = $"{imgUrl}/{d.CheckInImageUrl}", 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, CheckOutImg = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", }; return Success(result); } } /// /// LV1_009 - รายการลงเวลาปฏิบัติงานที่ประมวลผลแล้ว (ADMIN) /// /// /// /// เมื่อทำรายการสำเร็จ /// ไม่ได้ Login เข้าระบบ /// เมื่อเกิดข้อผิดพลาดในการทำงาน [HttpGet("time-record")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] 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("วันเริ่มต้นต้องมีค่าน้อยกว่าหรือเท่ากับวันสิ้นสุด"), (int)StatusCodes.Status400BadRequest); } var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId); // TODO : รอดุึงรอบที่ผูกกับ user var duty = await _dutyTimeRepository.GetDefaultAsync(); if (duty == null) { return Error(new Exception(GlobalMessages.DataNotFound), (int)StatusCodes.Status404NotFound); } 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.CountRecordAsync(); var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}"; var data = (await _processUserTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate, page, pageSize, keyword)) .Select(d => new CheckInProcessHistoryForAdminDto { 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, CheckInStatus = DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) > DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ? "LATE" : "NORMAL", //CheckInImageUrl = $"{imgUrl}/{d.CheckInImageUrl}", 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, 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", //CheckOutImageUrl = d.CheckOut == null ? "" : $"{imgUrl}/{d.CheckOutImageUrl}", }) .Where(x => x.CheckInStatus == status || x.CheckOutStatus == status) .ToList(); return Success(new { data = data, total = count }); } #endregion #endregion } }