hrms-api-backend/BMA.EHR.Leave/Controllers/LeaveController.cs

3299 lines
162 KiB
C#

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.Application.Repositories.MessageQueue;
using BMA.EHR.Application.Responses.Profiles;
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.Calendar;
using BMA.EHR.Leave.Service.DTOs.ChangeRound;
using BMA.EHR.Leave.Service.DTOs.CheckIn;
using BMA.EHR.Leave.Service.DTOs.DutyTime;
using BMA.EHR.Leave.Service.DTOs.LeaveRequest;
using iTextSharp.text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.ObjectPool;
using Nest;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Swashbuckle.AspNetCore.Annotations;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using SearchProfileResultDto = BMA.EHR.Leave.Service.DTOs.ChangeRound.SearchProfileResultDto;
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 LeaveRequestRepository _leaveRequestRepository;
private readonly UserCalendarRepository _userCalendarRepository;
private readonly PermissionRepository _permission;
private readonly CommandRepository _commandRepository;
private readonly NotificationRepository _notificationRepository;
private readonly string _bucketName = "check-in";
private readonly ObjectPool<IModel> _objectPool;
private readonly string _fakeCheckInQueue = "fake-bma-checkin-queue";
private readonly string _realCheckInQueue = "bma-checkin-queue";
private readonly HttpClient _httpClient;
#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,
UserCalendarRepository userCalendarRepository,
CommandRepository commandRepository,
LeaveRequestRepository leaveRequestRepository,
ObjectPool<IModel> objectPool,
PermissionRepository permission,
NotificationRepository notificationRepository,
HttpClient httpClient)
{
_dutyTimeRepository = dutyTimeRepository;
_context = context;
_httpContextAccessor = httpContextAccessor;
_hostingEnvironment = hostingEnvironment;
_configuration = configuration;
_userProfileRepository = userProfileRepository;
_userTimeStampRepository = userTimeStampRepository;
_minIOService = minIOService;
_processUserTimeStampRepository = processUserTimeStampRepository;
_userDutyTimeRepository = userDutyTimeRepository;
_additionalCheckRequestRepository = additionalCheckRequestRepository;
_userCalendarRepository = userCalendarRepository;
_commandRepository = commandRepository;
_leaveRequestRepository = leaveRequestRepository;
_notificationRepository = notificationRepository;
_objectPool = objectPool;
_permission = permission;
_httpClient = httpClient;
var authString = $"{_configuration["Rabbit:User"] ?? ""}:{_configuration["Rabbit:Password"] ?? ""}";
var authToken = Convert.ToBase64String(Encoding.ASCII.GetBytes(authString));
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authToken);
}
#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 string? AccessToken => _httpContextAccessor?.HttpContext?.Request.Headers["Authorization"];
private Guid OcId
{
get
{
if (UserId != null || UserId != "")
return _userProfileRepository.GetUserOCId(Guid.Parse(UserId!), AccessToken);
else
return Guid.Empty;
}
}
#endregion
#region " Methods "
#region " Duty Time รอบการทำงาน "
/// <summary>
/// LV1_004 - ข้อมูลทั้งหมดของรอบการปฏิบัติงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("duty-time")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetAllAsync()
{
var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_WORK_ROUND");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
var data = await _dutyTimeRepository.GetAllAsync();
return Success(data);
}
/// <summary>
/// ข้อมูลของรอบการปฏิบัติงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("duty-time/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetByIdAsync(Guid id)
{
var data = await _dutyTimeRepository.GetByIdAsync(id);
return Success(data);
}
/// <summary>
/// LV1_001 - สร้างรอบการปฏิบัติงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("duty-time")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> PostAsync([FromBody] CreateDutyTimeDto data)
{
var getPermission = await _permission.GetPermissionAPIAsync("CREATE", "SYS_WORK_ROUND");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
// 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);
}
}
/// <summary>
/// LV1_002 - แก้ไขรอบการปฏิบัติงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("duty-time/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> PutAsync(Guid id, [FromBody] UpdateDutyTimeDto data)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_WORK_ROUND");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
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;
if (!data.IsActive)
{
// ลบรายการที่เคยผูกไว้ทั้งหมด
var userDutyTimes = await _context.UserDutyTimes.Where(x => x.DutyTimeId == oldData.Id).ToListAsync();
_context.UserDutyTimes.RemoveRange(userDutyTimes);
await _context.SaveChangesAsync();
}
await _dutyTimeRepository.UpdateAsync(oldData);
return Success(oldData);
}
}
/// <summary>
/// LV1_003 - ลบรอบการปฏิบัติงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpDelete("duty-time/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> DeleteAsync(Guid id)
{
var getPermission = await _permission.GetPermissionAPIAsync("DELETE", "SYS_WORK_ROUND");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
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();
}
}
/// <summary>
/// LV1_012 - ข้อมูลทั้งหมดของรอบการปฏิบัติงานที่ active (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("round")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetAllActiveAsync()
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
var data = await _dutyTimeRepository.GetAllActiveAsync();
return Success(data);
}
#endregion
#region " Check-In Check-Out ลงเวลา "
/// <summary>
/// LV1_006 - เช็คเวลาต้องลงเวลาเข้าหรือออกงาน (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("check-time")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CheckTimeAsync()
{
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var data = await _userTimeStampRepository.GetLastRecord(userId);
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
if (profile == null)
{
throw new Exception(GlobalMessages.DataNotFound);
}
var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync();
if (getDefaultRound == 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);
var duty = userRound ?? getDefaultRound;
// 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)
{
// fix issue SIT ระบบบันทึกเวลาปฏิบัติงาน>>ลงเวลาเข้า-ออกงาน (กรณีลงเวลาออกอีกวัน) #921
var cur_date = DateTime.Now.Date;
// ถ้า check-in + check-out ไปแล้ว
if (data.CheckIn.Date == cur_date && data.CheckOut.Value.Date == cur_date)
{
return Error("คุณได้ทำการลงเวลาเข้าและออกเรียบร้อยแล้ว คุณจะสามารถลงเวลาได้อีกครั้งในวันถัดไป");
}
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 = 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);
}
/// <summary>
/// LV1_005 - ลงเวลาเข้า-ออกงาน (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("check-in"), DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CheckInAsync([FromForm] CheckTimeDto data)
{
// prepare data and convert request body and send to queue
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var currentDate = DateTime.Now;
var checkFileBytes = new byte[0];
// fix issue : ระบบลงเวลาปฏิบัติงาน>>รูปภาพไม่แสดงในฝั่งของ Admin #804
if (data.Img != null && data.Img.Length > 0)
{
var formFile = data.Img;
using (var memoryStream = new MemoryStream())
{
await formFile.CopyToAsync(memoryStream);
checkFileBytes = memoryStream.ToArray();
}
}
var checkData = new CheckTimeDtoRB
{
UserId = userId,
CurrentDate = currentDate,
CheckInId = data.CheckInId,
Lat = data.Lat,
Lon = data.Lon,
POI = data.POI,
IsLocation = data.IsLocation,
LocationName = data.LocationName,
Remark = data.Remark,
CheckInFileName = data.Img == null ? "no-file" : data.Img.FileName,
CheckInFileBytes = checkFileBytes,
Token = AccessToken ?? ""
};
var channel = _objectPool.Get();
try
{
var queue = _configuration["Rabbit:Queue"] ?? "basic-queue";
channel.QueueDeclare(queue: queue, durable: true, exclusive: false, autoDelete: false, arguments: null);
var serializedObject = JsonConvert.SerializeObject(checkData);
var body = Encoding.UTF8.GetBytes(serializedObject);
// add task id for check in queue
string taskId = Guid.NewGuid().ToString();
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
properties.MessageId = userId.ToString("D");// ระบบลงเวลาต้องมีการเช็คสถานะใน rabbitMQ ด้วยว่ามีการรอรันอยู่ไหม ลงเวลาเข้า/ออกงาน #894
channel.BasicPublish(exchange: "",
routingKey: queue,
basicProperties: properties,
body: body);
return Success(new { date = currentDate, taskId = taskId, keycloakId = userId });
}
finally
{
_objectPool.Return(channel);
}
}
[HttpGet("check-status")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CheckInCheckStatus()
{
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var currentDate = DateTime.Now;
var channel = _objectPool.Get();
try
{
var _url = _configuration["Rabbit:URL"] ?? "";
var _queue = _configuration["Rabbit:Queue"] ?? "basic-queue";
// Step 1: ตรวจสอบจำนวน message ทั้งหมดในคิว
string queueUrl = $"{_url}{_queue}";
var queueResponse = await _httpClient.GetAsync(queueUrl);
if (!queueResponse.IsSuccessStatusCode)
{
return Error("Error accessing RabbitMQ API", (int)queueResponse.StatusCode);
}
var queueContent = await queueResponse.Content.ReadAsStringAsync();
var queueData = JObject.Parse(queueContent);
int totalMessages = queueData["messages"]?.Value<int>() ?? 0;
// Step 2: วนลูปดึง message ทีละ 100 งาน
int batchSize = 100;
var allMessages = new List<string>();
int processedMessages = 0;
while (processedMessages < totalMessages)
{
var requestBody = new StringContent(
$"{{\"count\":{batchSize},\"requeue\":true,\"encoding\":\"auto\",\"ackmode\":\"ack_requeue_true\"}}",
Encoding.UTF8,
"application/json"
);
string getMessagesUrl = $"{_url}{_queue}/get";
var response = await _httpClient.PostAsync(getMessagesUrl, requestBody);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode, "Error retrieving messages from RabbitMQ.");
}
var content = await response.Content.ReadAsStringAsync();
var messages = JArray.Parse(content);
if (messages.Count == 0)
{
break;
}
processedMessages += messages.Count;
allMessages.AddRange(messages.Select(m => m["properties"].ToString()));
}
// Step 3: ค้นหา taskIds ที่อยู่ใน messages ทั้งหมด
var foundTasks = allMessages.FirstOrDefault(x => x.Contains(userId.ToString("D")));
return Success(new { keycloakId = userId, InQueue = foundTasks != null });
}
catch (Exception ex)
{
return Error(ex, ex.Message);
}
finally
{
_objectPool.Return(channel);
}
}
/// <summary>
/// Fake Check in
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("fake-check-in"), DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[AllowAnonymous]
public ActionResult<ResponseObject> FakeCheckIn([FromBody] FakeCheckTimeDto data)
{
var currentDate = DateTime.Now;
var channel = _objectPool.Get();
try
{
channel.QueueDeclare(queue: _fakeCheckInQueue, durable: true, exclusive: false, autoDelete: false, arguments: null);
// Create Task ID
string taskId = Guid.NewGuid().ToString();
var properties = channel.CreateBasicProperties();
properties.Persistent = true;
properties.MessageId = taskId; // แนบ Message ID เพื่อใช้ตรวจสอบ
var serializedObject = JsonConvert.SerializeObject(data);
var body = Encoding.UTF8.GetBytes(serializedObject);
channel.BasicPublish(exchange: "",
routingKey: _fakeCheckInQueue,
basicProperties: properties,
body: body);
return Success(new { date = currentDate, taskId = taskId });
}
finally
{
_objectPool.Return(channel);
}
}
[HttpGet("fake-check-status/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[AllowAnonymous]
public async Task<ActionResult<ResponseObject>> FakeCheckInCheckStatus(Guid id)
{
var currentDate = DateTime.Now;
var channel = _objectPool.Get();
try
{
var _url = _configuration["Rabbit:URL"] ?? "";
// Step 1: ตรวจสอบจำนวน message ทั้งหมดในคิว
string queueUrl = $"{_url}{_fakeCheckInQueue}";
var queueResponse = await _httpClient.GetAsync(queueUrl);
if (!queueResponse.IsSuccessStatusCode)
{
return Error("Error accessing RabbitMQ API", (int)queueResponse.StatusCode);
}
var queueContent = await queueResponse.Content.ReadAsStringAsync();
var queueData = JObject.Parse(queueContent);
int totalMessages = queueData["messages"]?.Value<int>() ?? 0;
// Step 2: วนลูปดึง message ทีละ 100 งาน
int batchSize = 100;
var allMessages = new List<string>();
int processedMessages = 0;
while (processedMessages < totalMessages)
{
var requestBody = new StringContent(
$"{{\"count\":{batchSize},\"requeue\":true,\"encoding\":\"auto\",\"ackmode\":\"ack_requeue_true\"}}",
Encoding.UTF8,
"application/json"
);
string getMessagesUrl = $"{_url}{_fakeCheckInQueue}/get";
var response = await _httpClient.PostAsync(getMessagesUrl, requestBody);
if (!response.IsSuccessStatusCode)
{
return StatusCode((int)response.StatusCode, "Error retrieving messages from RabbitMQ.");
}
var content = await response.Content.ReadAsStringAsync();
var messages = JArray.Parse(content);
if (messages.Count == 0)
{
break;
}
processedMessages += messages.Count;
allMessages.AddRange(messages.Select(m => m["properties"].ToString()));
}
// Step 3: ค้นหา taskIds ที่อยู่ใน messages ทั้งหมด
var foundTasks = allMessages.FirstOrDefault(x => x.Contains(id.ToString("D")));
return Success(new { taskId = id, InQueue = foundTasks != null });
}
catch (Exception ex)
{
return Error(ex, ex.Message);
}
finally
{
_objectPool.Return(channel);
}
}
/// <summary>
/// Check in Processing
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("process-check-in"), DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[AllowAnonymous]
public async Task<ActionResult<ResponseObject>> ProcessCheckInAsync([FromBody] CheckTimeDtoRB data)
{
var userId = data.UserId ?? Guid.Empty;
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, data.Token);
if (profile == null)
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
if (data.CheckInFileName == "no-file") throw new Exception(GlobalMessages.NoFileToUpload);
var currentDate = data.CurrentDate ?? DateTime.Now;
var check_status = data.CheckInId == null ? "check-in-picture" : "check-out-picture";
var fileName = $"{_bucketName}/{userId}/{currentDate.ToString("dd-MM-yyyy")}/{check_status}/{data.CheckInFileName}";
using (var ms = new MemoryStream(data.CheckInFileBytes ?? new byte[0]))
{
await _minIOService.UploadFileAsync(fileName, ms);
}
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(userId, currentDate);
if (currentCheckIn != null)
{
return Error(new Exception("ไม่สามารถลงเวลาได้ เนื่องจากมีการลงเวลาในวันนี้แล้ว!"), StatusCodes.Status400BadRequest);
}
var checkin = new UserTimeStamp
{
KeycloakUserId = userId,
CheckInLat = data.Lat,
CheckInLon = data.Lon,
IsLocationCheckIn = data.IsLocation,
CheckInLocationName = data.LocationName,
CheckInPOI = data.POI,
CheckInRemark = data.Remark,
CheckInImageUrl = fileName,
CheckIn = currentDate,
Prefix = profile.Prefix,
FirstName = profile.FirstName,
LastName = profile.LastName,
CitizenId = profile.CitizenId,
Root = profile.Root,
Child1 = profile.Child1,
Child2 = profile.Child2,
Child3 = profile.Child3,
Child4 = profile.Child4,
RootId = profile.RootId,
Child1Id = profile.Child1Id,
Child2Id = profile.Child2Id,
Child3Id = profile.Child3Id,
Child4Id = profile.Child4Id,
Gender = profile.Gender,
ProfileId = profile.Id,
ProfileType = profile.ProfileType,
RootDnaId = profile.RootDnaId,
Child1DnaId = profile.Child1DnaId,
Child2DnaId = profile.Child2DnaId,
Child3DnaId = profile.Child3DnaId,
Child4DnaId = profile.Child4DnaId,
};
var startTime = "";
if (!data.IsLocation && data.LocationName == "ไปประชุม/อบรม/สัมมนา/ปฏิบัติงานที่บ้านนอกสถานที่")
{
startTime = "09:30";
}
else
startTime = duty.StartTimeMorning;
var checkInStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {startTime}") ?
DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"LATE" :
"NORMAL";
// process - รอทำใน queue
var checkin_process = new ProcessUserTimeStamp
{
KeycloakUserId = userId,
CheckInLat = data.Lat,
CheckInLon = data.Lon,
IsLocationCheckIn = data.IsLocation,
CheckInLocationName = data.LocationName,
CheckInPOI = data.POI,
CheckInRemark = data.Remark,
CheckInImageUrl = fileName,
CheckIn = currentDate,
CheckInStatus = checkInStatus,
Prefix = profile.Prefix,
FirstName = profile.FirstName,
LastName = profile.LastName,
CitizenId = profile.CitizenId,
Root = profile.Root,
Child1 = profile.Child1,
Child2 = profile.Child2,
Child3 = profile.Child3,
Child4 = profile.Child4,
RootId = profile.RootId,
Child1Id = profile.Child1Id,
Child2Id = profile.Child2Id,
Child3Id = profile.Child3Id,
Child4Id = profile.Child4Id,
Gender = profile.Gender,
ProfileId = profile.Id,
ProfileType = profile.ProfileType,
RootDnaId = profile.RootDnaId,
Child1DnaId = profile.Child1DnaId,
Child2DnaId = profile.Child2DnaId,
Child3DnaId = profile.Child3DnaId,
Child4DnaId = profile.Child4DnaId,
};
await _userTimeStampRepository.AddAsync(checkin);
await _processUserTimeStampRepository.AddAsync(checkin_process);
}
else
{
var checkout = await _userTimeStampRepository.GetByIdAsync(data.CheckInId.Value);
var currentCheckInProcess = await _processUserTimeStampRepository.GetTimestampByDateAsync(userId, checkout.CheckIn.Date);
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);
}
// fix issue : SIT ระบบบันทึกเวลาปฏิบัติงาน>>ลงเวลาเข้า-ออกงาน (กรณีลงเวลาออกอีกวัน) #921
var checkOutStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) <
DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ?
// "ABSENT" :
checkout.CheckIn.Date < currentDate.Date ? "NORMAL" :
"ABSENT" :
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);
}
}
var checkInType = data.CheckInId == null ? "check-in" : "check-out";
return Success(new { user = $"{profile.FirstName} {profile.LastName}", date = currentDate, type = checkInType }); ;
}
/// <summary>
/// LV1_005 - ลงเวลาเข้า-ออกงาน (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("check-in-old"), DisableRequestSizeLimit]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CheckInOldAsync([FromForm] CheckTimeDto data)
{
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
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 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,
Prefix = profile.Prefix,
FirstName = profile.FirstName,
LastName = profile.LastName,
};
var checkInStatus = DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ?
DateTime.Parse(currentDate.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{currentDate.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"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,
Prefix = profile.Prefix,
FirstName = profile.FirstName,
LastName = profile.LastName,
};
await _userTimeStampRepository.AddAsync(checkin);
await _processUserTimeStampRepository.AddAsync(checkin_process);
}
else
{
var checkout = await _userTimeStampRepository.GetByIdAsync(data.CheckInId.Value);
var currentCheckInProcess = await _processUserTimeStampRepository.GetTimestampByDateAsync(Guid.Parse(UserId), checkout.CheckIn.Date);
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}") ?
"ABSENT" :
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 });
}
/// <summary>
/// LV1_007 - ประวัติการลงเวลา (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("check-in/history")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> 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, AccessToken);
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 test = await _processUserTimeStampRepository.GetTimeStampHistoryAsync(userId, year);
// return Success(test);
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 = d.CheckInStatus != null || d.CheckInStatus != "" ? d.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 :
d.CheckOutStatus != null || d.CheckOutStatus != "" ? d.CheckOutStatus :
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.CheckInLocationName!.Contains(keyword) || x.CheckInLocation!.Contains(keyword) ||
x.CheckOutLocationName!.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 });
}
/// <summary>
/// LV1_010 - รายการลงเวลาปฏิบัติงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("log-record")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> LogRecordAsync([Required] DateTime startDate, [Required] DateTime endDate, int page = 1, int pageSize = 10, string keyword = "", string profileType = "ALL", string? sortBy = "", bool? descending = false)
{
var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_CHECKIN");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
if (startDate.Date > endDate.Date)
{
return Error(new Exception("วันเริ่มต้นต้องมีค่าน้อยกว่าหรือเท่ากับวันสิ้นสุด"), StatusCodes.Status400BadRequest);
}
//var count = await _userTimeStampRepository.CountRecordAsync();
var imgUrl = $"{_configuration["MinIO:Endpoint"]}{_configuration["MinIO:BucketName"]}";
string role = jsonData["result"]?.ToString();
var nodeId = string.Empty;
var profileAdmin = new GetUserOCAllDto();
profileAdmin = await _userProfileRepository.GetUserOCAll(Guid.Parse(UserId!), AccessToken);
if (role == "NORMAL" || role == "CHILD")
{
nodeId = profileAdmin?.Node == 4
? profileAdmin?.Child4DnaId
: profileAdmin?.Node == 3
? profileAdmin?.Child3DnaId
: profileAdmin?.Node == 2
? profileAdmin?.Child2DnaId
: profileAdmin?.Node == 1
? profileAdmin?.Child1DnaId
: profileAdmin?.Node == 0
? profileAdmin?.RootDnaId
: "";
}
else if (role == "ROOT" || role == "PARENT")
{
nodeId = profileAdmin?.RootDnaId;
}
//var data = (await _userTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate))
var data = (await _userTimeStampRepository.GetTimeStampHistoryForAdminRoleAsync(startDate, endDate, role, nodeId, profileAdmin?.Node))
.Select(d => new CheckInHistoryForAdminDto
{
Id = d.Id,
//FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId, AccessToken),
FullName = $"{d.Prefix ?? ""}{d.FirstName ?? ""} {d.LastName ?? ""}",
Prefix = d.Prefix ?? "",
FirstName = d.FirstName ?? "",
LastName = d.LastName ?? "",
ProfileType = d.ProfileType ?? "",
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?.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();
}
if (profileType.Trim().ToUpper() != "ALL")
data = data.Where(x => x.ProfileType == profileType.Trim().ToUpper()).ToList();
if (!string.IsNullOrWhiteSpace(sortBy))
{
switch (sortBy.ToUpper())
{
case "FULLNAME":
if (descending == true)
data = data.OrderByDescending(x => x.Prefix)
.ThenByDescending(x => x.FirstName)
.ThenByDescending(x => x.LastName)
.ToList();
else
data = data.OrderBy(x => x.Prefix)
.ThenBy(x => x.FirstName)
.ThenBy(x => x.LastName)
.ToList();
break;
case "CHECKINTIME":
if (descending == true)
data = data.OrderByDescending(x => x.CheckInTime).ToList();
else
data = data.OrderBy(x => x.CheckInTime).ToList();
break;
case "CHECKINLOCATION":
if (descending == true)
data = data.OrderByDescending(x => x.CheckInLocation)
.ThenByDescending(x => x.CheckInLat)
.ThenByDescending(x => x.CheckInLon)
.ToList();
else
data = data.OrderBy(x => x.CheckInLocation)
.ThenBy(x => x.CheckInLat)
.ThenBy(x => x.CheckInLon)
.ToList();
break;
case "CHECKOUTTIME":
if (descending == true)
data = data.OrderByDescending(x => x.CheckOutTime).ToList();
else
data = data.OrderBy(x => x.CheckOutTime).ToList();
break;
case "CHECKOUTLOCATION":
if (descending == true)
data = data.OrderByDescending(x => x.CheckOutLocation)
.ThenByDescending(x => x.CheckOutLat)
.ThenByDescending(x => x.CheckOutLon)
.ToList();
else
data = data.OrderBy(x => x.CheckOutLocation)
.ThenBy(x => x.CheckOutLat)
.ThenBy(x => x.CheckOutLon)
.ToList();
break;
default: break;
}
}
var pageData = data
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
return Success(new { data = pageData, total = data.Count });
}
/// <summary>
/// LV1_011 - รายละเอียดการลงเวลาปฎิบัติงานรายบุคคล Tabรายากรลงเวลาที่ประมวลผลแล้ว (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("time-record/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetTimeRecordAsync([Required] Guid id)
{
var getWorkflow = await _permission.GetPermissionAPIWorkflowAsync(id.ToString(), "SYS_CHECKIN");
if (getWorkflow == false)
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_CHECKIN");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
}
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, AccessToken);
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 = $"{d.Prefix}{d.FirstName} {d.LastName}",
ProfileType = (d.ProfileType != "" || d.ProfileType != null) ? d.ProfileType : (profile.ProfileType ?? ""),
//FullName = $"{profile.Prefix}{profile.FirstName} {profile.LastName}", // _userProfileRepository.GetUserFullName(d.KeycloakUserId, AccessToken),
CheckInDate = d.CheckIn.Date,
CheckInTime = d.CheckIn.ToString("HH:mm"),
CheckInPOI = d.CheckInPOI,
CheckInLat = d.CheckInLat,
CheckInLon = d.CheckInLon,
CheckInImg = $"{imgUrl}/{d.CheckInImageUrl}",
CheckInStatus = d.CheckInStatus != null || d.CheckInStatus != "" ? d.CheckInStatus :
DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ?
DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{d.CheckIn.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"LATE" :
"NORMAL",
CheckInDescription = d.CheckInRemark ?? "",
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"),
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 :
d.CheckOutStatus != null || d.CheckOutStatus != "" ? d.CheckOutStatus :
DateTime.Parse(d.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) <
DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ?
"ABSENT" :
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 ?? "",
IsLocationCheckOut = d.IsLocationCheckOut,
CheckOutLocationName = d.CheckOutLocationName ?? ""
};
return Success(result);
}
}
/// <summary>
/// LV1_009 - รายการลงเวลาปฏิบัติงานที่ประมวลผลแล้ว (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("time-record")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[AllowAnonymous]
public async Task<ActionResult<ResponseObject>> GetTimeRecordAsync([Required] DateTime startDate, [Required] DateTime endDate, int page = 1, int pageSize = 10, string status = "NORMAL", string keyword = "", string profileType = "ALL", string? sortBy = "", bool? descending = false)
{
var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_CHECKIN");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
if (startDate.Date > endDate.Date)
{
return Error(new Exception("วันเริ่มต้นต้องมีค่าน้อยกว่าหรือเท่ากับวันสิ้นสุด"), StatusCodes.Status400BadRequest);
}
var profiles = new List<GetProfileByKeycloakIdDto>();
//var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
//var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
//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 duty = 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"]}";
string role = jsonData["result"]?.ToString();
var nodeId = string.Empty;
var profileAdmin = new GetUserOCAllDto();
profileAdmin = await _userProfileRepository.GetUserOCAll(Guid.Parse(UserId!), AccessToken);
if (role == "NORMAL" || role == "CHILD")
{
nodeId = profileAdmin?.Node == 4
? profileAdmin?.Child4DnaId
: profileAdmin?.Node == 3
? profileAdmin?.Child3DnaId
: profileAdmin?.Node == 2
? profileAdmin?.Child2DnaId
: profileAdmin?.Node == 1
? profileAdmin?.Child1DnaId
: profileAdmin?.Node == 0
? profileAdmin?.RootDnaId
: "";
}
else if (role == "ROOT" || role == "PARENT")
{
nodeId = profileAdmin?.RootDnaId;
}
//var resultData = await _processUserTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate);
var resultData = await _processUserTimeStampRepository.GetTimeStampHistoryForAdminRoleAsync(startDate, endDate, role, nodeId, profileAdmin?.Node);
var data = new List<CheckInProcessHistoryForAdminDto>();
foreach (var d in resultData)
{
//var pf = profiles.FirstOrDefault(x => x.Keycloak == d.KeycloakUserId);
//if (pf == null)
//{
// pf = await _userProfileRepository.GetProfileByKeycloakIdAsync(d.KeycloakUserId, AccessToken);
// if (pf == null)
// continue;
// else
// profiles.Add(pf);
//}
//var pf = await _userProfileRepository.GetProfileByKeycloakIdAsync(d.KeycloakUserId, AccessToken);
//if (pf == null) continue;
data.Add(new CheckInProcessHistoryForAdminDto
{
Id = d.Id,
FullName = $"{d.Prefix ?? ""}{d.FirstName ?? ""} {d.LastName ?? ""}",
Prefix = d.Prefix ?? "",
FirstName = d.FirstName ?? "",
LastName = d.LastName ?? "",
ProfileType = d.ProfileType ?? "",
CheckInDate = d.CheckIn.Date,
CheckInTime = d.CheckIn.ToString("HH:mm"),
CheckInLocation = d.CheckInPOI,
CheckInLat = d.CheckInLat,
CheckInLon = d.CheckInLon,
CheckInStatus = d.CheckInStatus != "" ? d.CheckInStatus :
DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ?
DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{d.CheckIn.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"LATE" :
"NORMAL",
CheckInIsLocation = d.IsLocationCheckIn,
CheckInLocationName = d.CheckInLocationName ?? "",
//CheckInImageUrl = $"{imgUrl}/{d.CheckInImageUrl}",
CheckOutDate = d.CheckOut?.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.CheckOutStatus != "" ? d.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}") ?
"ABSENT" :
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}",
});
}
// var data = (await _processUserTimeStampRepository.GetTimeStampHistoryForAdminAsync(startDate, endDate))
// .Select(d => new CheckInProcessHistoryForAdminDto
// {
// Id = d.Id,
// FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId, AccessToken),
// CheckInDate = d.CheckIn.Date,
// CheckInTime = d.CheckIn.ToString("HH:mm"),
// CheckInLocation = d.CheckInPOI,
// CheckInLat = d.CheckInLat,
// CheckInLon = d.CheckInLon,
// CheckInStatus = d.CheckInStatus != "" ? d.CheckInStatus :
// DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
// DateTime.Parse($"{d.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ?
// DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
// DateTime.Parse($"{d.CheckIn.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
// "ABSENT" :
// "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.CheckOutStatus != "" ? d.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}") ?
// "ABSENT" :
// 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();
}
if (profileType.Trim().ToUpper() != "ALL")
data = data.Where(x => x.ProfileType == profileType.Trim().ToUpper()).ToList();
if (!string.IsNullOrWhiteSpace(sortBy))
{
switch (sortBy.ToUpper())
{
case "FULLNAME":
if (descending == true)
data = data.OrderByDescending(x => x.Prefix)
.ThenByDescending(x => x.FirstName)
.ThenByDescending(x => x.LastName)
.ToList();
else
data = data.OrderBy(x => x.Prefix)
.ThenBy(x => x.FirstName)
.ThenBy(x => x.LastName)
.ToList();
break;
case "CHECKINTIME":
if (descending == true)
data = data.OrderByDescending(x => x.CheckInTime).ToList();
else
data = data.OrderBy(x => x.CheckInTime).ToList();
break;
case "CHECKINLOCATION":
if (descending == true)
data = data.OrderByDescending(x => x.CheckInLocation)
.ThenByDescending(x => x.CheckInLat)
.ThenByDescending(x => x.CheckInLon)
.ToList();
else
data = data.OrderBy(x => x.CheckInLocation)
.ThenBy(x => x.CheckInLat)
.ThenBy(x => x.CheckInLon)
.ToList();
break;
case "CHECKOUTTIME":
if (descending == true)
data = data.OrderByDescending(x => x.CheckOutTime).ToList();
else
data = data.OrderBy(x => x.CheckOutTime).ToList();
break;
case "CHECKOUTLOCATION":
if (descending == true)
data = data.OrderByDescending(x => x.CheckOutLocation)
.ThenByDescending(x => x.CheckOutLat)
.ThenByDescending(x => x.CheckOutLon)
.ToList();
else
data = data.OrderBy(x => x.CheckOutLocation)
.ThenBy(x => x.CheckOutLat)
.ThenBy(x => x.CheckOutLon)
.ToList();
break;
default: break;
}
}
var pageData = data
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
return Success(new { data = pageData, total = data.Count });
}
#endregion
#region " เปลี่ยนรอบการทำงาน "
/// <summary>
/// LV1_006 - เช็คเวลาต้องลงเวลาเข้าหรือออกงาน (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("search")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> SearchProfileAsync([FromBody] DTOs.ChangeRound.SearchProfileDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
string role = jsonData["result"]?.ToString();
var nodeId = string.Empty;
var profileAdmin = new GetUserOCAllDto();
profileAdmin = await _userProfileRepository.GetUserOCAll(Guid.Parse(UserId!), AccessToken);
if (role == "NORMAL" || role == "CHILD")
{
nodeId = profileAdmin?.Node == 4
? profileAdmin?.Child4DnaId
: profileAdmin?.Node == 3
? profileAdmin?.Child3DnaId
: profileAdmin?.Node == 2
? profileAdmin?.Child2DnaId
: profileAdmin?.Node == 1
? profileAdmin?.Child1DnaId
: profileAdmin?.Node == 0
? profileAdmin?.RootDnaId
: "";
}
else if (role == "ROOT")
{
nodeId = profileAdmin?.RootDnaId;
}
var profile = await _userProfileRepository.SearchProfile(req.CitizenId, req.FirstName, req.LastName, AccessToken ?? "", req.Page, req.PageSize, role, nodeId, profileAdmin?.Node);
// Get default round once
var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync();
var resultSet = new List<SearchProfileResultDto>();
// Create dictionaries to cache results and avoid duplicate queries
var effectiveDateCache = new Dictionary<Guid, UserDutyTime?>();
var dutyTimeCache = new Dictionary<Guid, DutyTime?>();
foreach (var p in profile.Data)
{
// Use cache for effective date
if (!effectiveDateCache.ContainsKey(p.Id))
{
effectiveDateCache[p.Id] = await _userDutyTimeRepository.GetLastEffectRound(p.Id);
}
var effectiveDate = effectiveDateCache[p.Id];
var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty;
// Use cache for duty time
DutyTime? userRound = null;
if (roundId != Guid.Empty)
{
if (!dutyTimeCache.ContainsKey(roundId))
{
dutyTimeCache[roundId] = await _dutyTimeRepository.GetByIdAsync(roundId);
}
userRound = dutyTimeCache[roundId];
}
var duty = userRound ?? getDefaultRound;
if (duty == null) continue; // Skip if no duty time found
var res = new SearchProfileResultDto
{
ProfileId = p.Id,
CitizenId = p.CitizenId ?? "",
FullName = $"{p.Prefix ?? ""}{p.FirstName ?? ""} {p.LastName ?? ""}",
StartTimeMorning = duty.StartTimeMorning,
LeaveTimeAfterNoon = duty.EndTimeAfternoon,
EffectiveDate = effectiveDate?.EffectiveDate?.Date
};
resultSet.Add(res);
}
return Success(new { data = resultSet, total = profile.Total });
}
/// <summary>
/// LV1_014 - เปลี่ยนรอบการลงเวลา (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("round")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CreateChangeRoundAsync([FromBody] CreateChangeRoundDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
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);
var profile = await _userProfileRepository.GetProfileByProfileIdAsync(req.ProfileId, AccessToken);
if (profile == null)
{
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
}
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,
RootDnaId = profile.RootDnaId,
Child1DnaId = profile.Child1DnaId,
Child2DnaId = profile.Child2DnaId,
Child3DnaId = profile.Child3DnaId,
Child4DnaId = profile.Child4DnaId,
};
await _userDutyTimeRepository.AddAsync(data);
return Success();
}
/// <summary>
/// LV1_015 - ประวัติการเปลี่ยนรอบการลงเวลา (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("round/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetChangeRoundHistoryByProfileIdAsync(Guid id, int page = 1, int pageSize = 10, string keyword = "", string? sortBy = "", bool? descending = false)
{
var getWorkflow = await _permission.GetPermissionAPIWorkflowAsync(id.ToString(), "SYS_WORK_ROUND_EDIT");
if (getWorkflow == false)
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
}
var data = await _userDutyTimeRepository.GetListByProfileIdAsync(id);
var resultSet = new List<ChangeRoundHistoryDto>();
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();
if (!string.IsNullOrWhiteSpace(sortBy))
{
switch (sortBy.ToUpper())
{
case "ROUNT":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.Round).ToList();
else
resultSet = resultSet.OrderBy(x => x.Round).ToList();
break;
case "STARTTIMEMORNIONG":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.StartTimeMorning).ToList();
else
resultSet = resultSet.OrderBy(x => x.StartTimeMorning).ToList();
break;
case "EFFECTIVEDATE":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.EffectiveDate).ToList();
else
resultSet = resultSet.OrderBy(x => x.EffectiveDate).ToList();
break;
case "REMARK":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.Remark).ToList();
else
resultSet = resultSet.OrderBy(x => x.Remark).ToList();
break;
default: break;
}
}
resultSet = resultSet
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
}
return Success(new { data = resultSet, total = data.Count });
}
#endregion
#region " เปลี่ยนรอบการทำงาน ลจ. "
/// <summary>
/// LV1_006 - เช็คเวลาต้องลงเวลาเข้าหรือออกงาน (USER) ลจ.
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("emp/search")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> SearchEmpProfileAsync([FromBody] DTOs.ChangeRound.SearchProfileDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
string role = jsonData["result"]?.ToString();
var nodeId = string.Empty;
var profileAdmin = new GetUserOCAllDto();
profileAdmin = await _userProfileRepository.GetUserOCAll(Guid.Parse(UserId!), AccessToken);
if (role == "NORMAL" || role == "CHILD")
{
nodeId = profileAdmin?.Node == 4
? profileAdmin?.Child4DnaId
: profileAdmin?.Node == 3
? profileAdmin?.Child3DnaId
: profileAdmin?.Node == 2
? profileAdmin?.Child2DnaId
: profileAdmin?.Node == 1
? profileAdmin?.Child1DnaId
: profileAdmin?.Node == 0
? profileAdmin?.RootDnaId
: "";
}
else if (role == "ROOT")
{
nodeId = profileAdmin?.RootDnaId;
}
var profile = await _userProfileRepository.SearchProfileEmployee(req.CitizenId, req.FirstName, req.LastName, AccessToken ?? "", req.Page, req.PageSize, role, nodeId, profileAdmin?.Node);
// Get default round once
var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync();
var resultSet = new List<SearchProfileResultDto>();
// Create dictionaries to cache results and avoid duplicate queries
var effectiveDateCache = new Dictionary<Guid, UserDutyTime?>();
var dutyTimeCache = new Dictionary<Guid, DutyTime?>();
foreach (var p in profile.Data)
{
// Use cache for effective date
if (!effectiveDateCache.ContainsKey(p.Id))
{
effectiveDateCache[p.Id] = await _userDutyTimeRepository.GetLastEffectRound(p.Id);
}
var effectiveDate = effectiveDateCache[p.Id];
var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty;
// Use cache for duty time
DutyTime? userRound = null;
if (roundId != Guid.Empty)
{
if (!dutyTimeCache.ContainsKey(roundId))
{
dutyTimeCache[roundId] = await _dutyTimeRepository.GetByIdAsync(roundId);
}
userRound = dutyTimeCache[roundId];
}
var duty = userRound ?? getDefaultRound;
if (duty == null) continue; // Skip if no duty time found
var res = new SearchProfileResultDto
{
ProfileId = p.Id,
CitizenId = p.CitizenId ?? "",
FullName = $"{p.Prefix ?? ""}{p.FirstName ?? ""} {p.LastName ?? ""}",
StartTimeMorning = duty.StartTimeMorning,
LeaveTimeAfterNoon = duty.EndTimeAfternoon,
EffectiveDate = effectiveDate?.EffectiveDate?.Date
};
resultSet.Add(res);
}
return Success(new { data = resultSet, total = profile.Total });
}
/// <summary>
/// LV1_014 - เปลี่ยนรอบการลงเวลา (ADMIN) Employee
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("emp/round")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CreateChangeEmpRoundAsync([FromBody] CreateChangeRoundDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
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);
var profile = await _userProfileRepository.GetProfileByProfileIdAsync(req.ProfileId, AccessToken);
if (profile == null)
{
return Error(GlobalMessages.DataNotFound, StatusCodes.Status404NotFound);
}
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,
RootDnaId = profile.RootDnaId,
Child1DnaId = profile.Child1DnaId,
Child2DnaId = profile.Child2DnaId,
Child3DnaId = profile.Child3DnaId,
Child4DnaId = profile.Child4DnaId,
};
await _userDutyTimeRepository.AddAsync(data);
return Success();
}
/// <summary>
/// LV1_015 - ประวัติการเปลี่ยนรอบการลงเวลา (ADMIN) Employee
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("emp/round/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetChangeEmpRoundHistoryByProfileIdAsync(Guid id, int page = 1, int pageSize = 10, string keyword = "", string? sortBy = "", bool? descending = false)
{
var getWorkflow = await _permission.GetPermissionAPIWorkflowAsync(id.ToString(), "SYS_WORK_ROUND_EDIT");
if (getWorkflow == false)
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
}
var data = await _userDutyTimeRepository.GetListByProfileIdAsync(id);
var resultSet = new List<ChangeRoundHistoryDto>();
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();
if (!string.IsNullOrWhiteSpace(sortBy))
{
switch (sortBy.ToUpper())
{
case "ROUNT":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.Round).ToList();
else
resultSet = resultSet.OrderBy(x => x.Round).ToList();
break;
case "STARTTIMEMORNIONG":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.StartTimeMorning).ToList();
else
resultSet = resultSet.OrderBy(x => x.StartTimeMorning).ToList();
break;
case "EFFECTIVEDATE":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.EffectiveDate).ToList();
else
resultSet = resultSet.OrderBy(x => x.EffectiveDate).ToList();
break;
case "REMARK":
if (descending == true)
resultSet = resultSet.OrderByDescending(x => x.Remark).ToList();
else
resultSet = resultSet.OrderBy(x => x.Remark).ToList();
break;
default: break;
}
}
resultSet = resultSet
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToList();
}
return Success(new { data = resultSet, total = data.Count });
}
#endregion
#region " Check Checkout Time "
/// <summary>
/// ตรวจสอบว่าเวลาปัจจุบัน ถ้า checkout จะขาดราชการหรือไม่?
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("user/checkout-check")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CheckoutCheckAsync()
{
var time = DateTime.Now;
var userId = UserId != null ? Guid.Parse(UserId) : Guid.Empty;
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
if (profile == null)
{
throw new Exception(GlobalMessages.DataNotFound);
}
var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync();
if (getDefaultRound == 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);
var duty = userRound ?? getDefaultRound;
var lastCheckIn = await _context.Set<UserTimeStamp>()
.Where(u => u.KeycloakUserId == userId)
.Where(d => d.CheckOut == null)
.OrderByDescending(u => u.CheckIn)
.FirstOrDefaultAsync();
//var endTime = DateTimeOffset.Parse($"{DateTime.Now.Date.ToString("yyyy-MM-dd")}T{duty.EndTimeAfternoon}:00.0000000+07:00").ToLocalTime().DateTime;
var endTime = DateTime.Parse($"{DateTime.Now.Date.ToString("yyyy-MM-dd")}T{duty.EndTimeAfternoon}:00.0000000+07:00");
var status = lastCheckIn == null ? "ABSENT" : lastCheckIn.CheckIn.Date < DateTime.Now.Date ? "NORMAL" : time < endTime ? "ABSENT" : "NORMAL";
return Success(new
{
Status = status,
StatusText = status == "ABSENT" ? "ขาดราชการ" : "ปกติ",
ServerTime = time,
EndTime = endTime
});
}
#endregion
#region " ขอลงเวลาเป็นกรณีพิเศษ "
/// <summary>
/// LV1_017 - เพิ่มลงเวลากรณีพิเศษ (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("user/edit")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> CreateAdditionalCheckRequestAsync([FromBody] CreateAdditionalCheckRequestDto req)
{
if (req.CheckDate.Date > DateTime.Now.Date)
{
return Error("ไม่สามารถขอลงเวลากรณีพิเศษในวันที่มากกว่าวันที่ปัจจุบันได้", StatusCodes.Status400BadRequest);
}
var userId = UserId != null ? Guid.Parse(UserId) : Guid.Empty;
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
if (profile == null)
{
throw new Exception(GlobalMessages.DataNotFound);
}
var request = new AdditionalCheckRequest
{
KeycloakUserId = UserId != null ? Guid.Parse(UserId) : Guid.Empty,
CheckDate = req.CheckDate,
CheckInEdit = req.CheckInEdit,
CheckOutEdit = req.CheckOutEdit,
Description = req.Description,
Prefix = profile.Prefix,
FirstName = profile.FirstName,
LastName = profile.LastName,
// fix issue #1547
POI = req.POI,
Latitude = req.Latitude,
Longitude = req.Longitude,
// add all Dna Id
RootDnaId = profile.RootDnaId ?? Guid.Empty,
Child1DnaId = profile.Child1DnaId ?? Guid.Empty,
Child2DnaId = profile.Child2DnaId ?? Guid.Empty,
Child3DnaId = profile.Child3DnaId ?? Guid.Empty,
Child4DnaId = profile.Child4DnaId ?? Guid.Empty,
};
await _additionalCheckRequestRepository.AddAsync(request);
return Success();
}
/// <summary>
/// LV1_018 - รายการลงเวลากรณีพิเศษ (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("admin/edit")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetAdditionalCheckRequestAsync([Required] int year, [Required] int month, [Required] int page = 1, [Required] int pageSize = 10, string keyword = "", string? sortBy = "", bool? descending = false)
{
var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_CHECKIN_SPECIAL");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
string role = jsonData["result"]?.ToString();
var nodeId = string.Empty;
var profileAdmin = new GetUserOCAllDto();
profileAdmin = await _userProfileRepository.GetUserOCAll(Guid.Parse(UserId!), AccessToken);
if (role == "NORMAL" || role == "CHILD")
{
nodeId = profileAdmin?.Node == 4
? profileAdmin?.Child4DnaId
: profileAdmin?.Node == 3
? profileAdmin?.Child3DnaId
: profileAdmin?.Node == 2
? profileAdmin?.Child2DnaId
: profileAdmin?.Node == 1
? profileAdmin?.Child1DnaId
: profileAdmin?.Node == 0
? profileAdmin?.RootDnaId
: "";
}
else if (role == "ROOT" || role == "PARENT")
{
nodeId = profileAdmin?.RootDnaId;
}
//var rawData = await _additionalCheckRequestRepository.GetAdditionalCheckRequests(year, month);
var rawData = await _additionalCheckRequestRepository.GetAdditionalCheckRequestsByAdminRole(year, month, role, nodeId, profileAdmin?.Node);
var getDefaultRound = await _dutyTimeRepository.GetDefaultAsync();
if (getDefaultRound == null)
{
return Error("ไม่พบรอบลงเวลา Default", StatusCodes.Status404NotFound);
}
var result = new List<GetAdditionalCheckRequestDto>();
foreach (var data in rawData)
{
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(data.KeycloakUserId, AccessToken);
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;
//var duty = getDefaultRound;
// create result object to return
var resObj = new GetAdditionalCheckRequestDto
{
Id = data.Id,
FullName = $"{data.Prefix}{data.FirstName} {data.LastName}",
Prefix = data.Prefix ?? "",
FirstName = data.FirstName ?? "",
LastName = data.LastName ?? "",
//FullName = $"{profile.Prefix}{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}") ?
DateTime.Parse(checkInData.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{checkInData.CheckIn.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"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}") ?
"ABSENT" :
DateTime.Parse(checkInData.CheckOut.Value.ToString("yyyy-MM-dd HH:mm")) <
DateTime.Parse($"{checkInData.CheckIn.Date.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"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,
POI = data.POI,
Latitude = data.Latitude,
Longitude = data.Longitude,
};
result.Add(resObj);
}
if (keyword != "")
{
result = result.Where(x => x.FullName.Contains(keyword)).ToList();
}
if (string.IsNullOrWhiteSpace(sortBy))
{
sortBy = "default";
}
if (!string.IsNullOrWhiteSpace(sortBy))
{
switch (sortBy.ToUpper())
{
case "FULLNAME":
if (descending == true)
result = result.OrderByDescending(x => x.Prefix)
.ThenByDescending(x => x.FirstName)
.ThenByDescending(x => x.LastName)
.ToList();
else
result = result.OrderBy(x => x.Prefix)
.ThenBy(x => x.FirstName)
.ThenBy(x => x.LastName)
.ToList();
break;
case "CREATEDAT":
if (descending == true)
result = result.OrderByDescending(x => x.CreatedAt).ToList();
else
result = result.OrderBy(x => x.CreatedAt).ToList();
break;
case "CHECKDATE":
if (descending == true)
result = result.OrderByDescending(x => x.CheckDate).ToList();
else
result = result.OrderBy(x => x.CheckDate).ToList();
break;
case "STARTTIMEMORNING":
if (descending == true)
result = result.OrderByDescending(x => x.StartTimeMorning).ToList();
else
result = result.OrderBy(x => x.StartTimeMorning).ToList();
break;
case "STARTTIMEAFTERNOON":
if (descending == true)
result = result.OrderByDescending(x => x.StartTimeAfternoon).ToList();
else
result = result.OrderBy(x => x.StartTimeAfternoon).ToList();
break;
case "DESCRIPTION":
if (descending == true)
result = result.OrderByDescending(x => x.Description).ToList();
else
result = result.OrderBy(x => x.Description).ToList();
break;
default:
result = result.OrderBy(x => x.StatusSort).ToList();
break;
}
}
var pageResult = result.Skip((page - 1) * pageSize).Take(pageSize)
.ToList();
return Success(new { data = pageResult, total = result.Count });
}
/// <summary>
/// LV1_019 - อนุมัติลงเวลากรณีพิเศษ (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/edit/approve/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> ApproveRequestAsync(Guid id, [FromBody] ApproveRequestDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_CHECKIN_SPECIAL");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
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);
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(requestData.KeycloakUserId, AccessToken);
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,
Prefix = profile.Prefix,
FirstName = profile.FirstName,
LastName = profile.LastName,
// Add ข้อมูลจาก profile
CitizenId = profile.CitizenId,
ProfileType = profile.ProfileType,
Root = profile.Root,
RootId = profile.RootId,
Child1 = profile.Child1,
Child1Id = profile.Child1Id,
Child2 = profile.Child2,
Child2Id = profile.Child2Id,
Child3 = profile.Child3,
Child3Id = profile.Child3Id,
Child4 = profile.Child4,
Child4Id = profile.Child4Id,
Gender = profile.Gender,
ProfileId = profile.Id,
};
processTimeStamp.EditStatus = "APPROVE";
processTimeStamp.EditReason = req.Reason;
if (requestData.CheckInEdit)
{
processTimeStamp.CheckInPOI = requestData.POI ?? "";
processTimeStamp.CheckInLat = requestData.Latitude ?? 0;
processTimeStamp.CheckInLon = requestData.Longitude ?? 0;
}
if (requestData.CheckOutEdit)
{
processTimeStamp.CheckOutPOI = requestData.POI ?? "";
processTimeStamp.CheckOutLat = requestData.Latitude ?? 0;
processTimeStamp.CheckOutLon = requestData.Longitude ?? 0;
}
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;
processTimeStamp.CheckInPOI = requestData.POI ?? "";
processTimeStamp.CheckInLat = requestData.Latitude ?? 0;
processTimeStamp.CheckInLon = requestData.Longitude ?? 0;
}
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.CheckOutPOI = requestData.POI ?? "";
processTimeStamp.CheckOutLat = requestData.Latitude ?? 0;
processTimeStamp.CheckOutLon = requestData.Longitude ?? 0;
}
processTimeStamp.EditStatus = "APPROVE";
processTimeStamp.EditReason = req.Reason;
await _processUserTimeStampRepository.UpdateAsync(processTimeStamp);
}
var recvId = new List<Guid> { profile.Id };
await _notificationRepository.PushNotificationsAsync(recvId.ToArray(), "ลงเวลากรณีพิเศษ", "การขอลงเวลากรณีพิเศษของคุณได้รับการอนุมัติ", "", "", true, false);
return Success();
}
/// <summary>
/// LV1_020 - ไม่อนุมัติลงเวลากรณีพิเศษ (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/edit/reject/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> RejectRequestAsync(Guid id, [FromBody] RejectRequestDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_CHECKIN_SPECIAL");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
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);
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(requestData.KeycloakUserId, AccessToken);
var recvId = new List<Guid> { profile.Id };
await _notificationRepository.PushNotificationsAsync(recvId.ToArray(), "ลงเวลากรณีพิเศษ", "การขอลงเวลากรณีพิเศษของคุณไม่ได้รับการอนุมัติ", "", "", true, false);
return Success();
}
/// <summary>
/// LV1_021 - รายละเอียดการลงเวลาปฎิบัติงานรายบุคคล Tabรายการลงเวลา (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("log-record/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetLogRecordAsync([Required] Guid id)
{
var getWorkflow = await _permission.GetPermissionAPIWorkflowAsync(id.ToString(), "SYS_CHECKIN");
if (getWorkflow == false)
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_CHECKIN");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
}
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, AccessToken);
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 = $"{d.Prefix}{d.FirstName} {d.LastName}",
//FullName = _userProfileRepository.GetUserFullName(d.KeycloakUserId, AccessToken),
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}") ?
DateTime.Parse(d.CheckIn.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{d.CheckIn.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"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}") ?
"ABSENT" :
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);
}
}
/// <summary>
/// LV1_022 - ประวัติการยื่นขอลงเวลาพิเศษ (USER)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("edit/history")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> 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<GetAdditionalCheckRequestHistoryDto>();
foreach (var data in rawData)
{
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(data.KeycloakUserId, AccessToken);
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 checkInData = await _processUserTimeStampRepository.GetTimestampByDateAsync(data.KeycloakUserId, data.CheckDate);
var duty = userRound ?? getDefaultRound;
DateTime? resultCheckInDate, resultCheckOutDate, resultCheckInDateAndTime, resultCheckOutDateAndTime;
string resultCheckInTime, resultCheckOutTime;
string resultCheckInLocation = "", resultCheckOutLocation = "";
if (data.CheckInEdit)
{
resultCheckInDate = data.CheckDate.Date;
resultCheckInTime = duty.StartTimeMorning;
resultCheckInLocation = data.POI ?? "";
}
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;
resultCheckOutLocation = data.POI ?? "";
}
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");
}
resultCheckInDateAndTime = resultCheckInDate is null ? null : DateTime.Parse($"{resultCheckInDate.Value.Date.ToString("yyyy-MM-dd")} {resultCheckInTime}");
resultCheckOutDateAndTime = resultCheckOutDate is null ? null : DateTime.Parse($"{resultCheckOutDate.Value.Date.ToString("yyyy-MM-dd")} {resultCheckOutTime}");
// create result object to return
var resObj = new GetAdditionalCheckRequestHistoryDto
{
Id = data.Id,
CheckInDate = resultCheckInDate,
CheckOutDate = resultCheckOutDate,
CheckInTime = resultCheckInTime,
CheckOutTime = resultCheckOutTime,
CheckInStatus = resultCheckInDateAndTime == null ? null :
DateTime.Parse(resultCheckInDateAndTime.Value.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{resultCheckInDate.Value.Date.ToString("yyyy-MM-dd")} {duty.StartTimeMorning}") ?
DateTime.Parse(resultCheckInDateAndTime.Value.ToString("yyyy-MM-dd HH:mm")) >
DateTime.Parse($"{resultCheckInDate.Value.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"LATE" :
"NORMAL",
CheckOutStatus = resultCheckInDateAndTime == null ? null :
resultCheckOutDateAndTime == null ? null :
DateTime.Parse(resultCheckOutDateAndTime.Value.ToString("yyyy-MM-dd HH:mm")) <
DateTime.Parse($"{resultCheckInDate.Value.Date.ToString("yyyy-MM-dd")} {duty.EndTimeAfternoon}") ?
"ABSENT" :
DateTime.Parse(resultCheckOutDateAndTime.Value.ToString("yyyy-MM-dd HH:mm")) <
DateTime.Parse($"{resultCheckInDate.Value.Date.ToString("yyyy-MM-dd")} {duty.EndTimeMorning}") ?
"ABSENT" :
"NORMAL",
//CheckInLocation = checkInData == null ? "" : checkInData.CheckInPOI,
//CheckOutLocation = checkInData == null ? "" : checkInData.CheckOutPOI ?? "",
CheckInLocation = resultCheckInLocation,
CheckOutLocation = resultCheckOutLocation,
EditReason = data.Comment ?? "",
EditStatus = data.Status,
};
result.Add(resObj);
}
if (keyword != "")
{
result = result.Where(x => x.EditReason!.Contains(keyword) || x.CheckInLocation!.Contains(keyword) || x.CheckOutLocation!.Contains(keyword)).ToList();
}
var pageResult = result.Skip((page - 1) * pageSize).Take(pageSize)
.ToList();
return Success(new { data = pageResult, total = result.Count });
}
#endregion
#region " ปฏิทินการทำงานของ ขรก. "
/// <summary>
/// LV1_023 - แสดงปฏิทินวันทำงานรายคน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("admin/work/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetCalendarByProfileAsync(Guid id)
{
var getWorkflow = await _permission.GetPermissionAPIWorkflowAsync(id.ToString(), "SYS_WORK_ROUND_EDIT");
if (getWorkflow == false)
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
}
var data = await _userCalendarRepository.GetExist(id);
if (data == null)
return Success(new { Work = "NORMAL" });
else
return Success(new { Work = data.Calendar });
}
/// <summary>
/// LV1_024 - บันทึกแก้ไขปฏิทินวันทำงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/work/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> UpdateCalendarByProfileAsync(Guid id, [FromBody] UpdateCalendarDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
var data = await _userCalendarRepository.GetExist(id);
if (data != null)
{
data.Calendar = req.Work;
await _userCalendarRepository.UpdateAsync(data);
return Success();
}
else
{
data = new UserCalendar
{
ProfileId = id,
Calendar = req.Work
};
await _userCalendarRepository.AddAsync(data);
return Success();
}
}
#endregion
#region " ปฏิทินการทำงานของ ลจ. "
/// <summary>
/// LV1_023 - แสดงปฏิทินวันทำงานรายคน (ADMIN) Employee
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpGet("admin/emp/work/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetCalendarEmpByProfileAsync(Guid id)
{
var getWorkflow = await _permission.GetPermissionAPIWorkflowAsync(id.ToString(), "SYS_WORK_ROUND_EDIT");
if (getWorkflow == false)
{
var getPermission = await _permission.GetPermissionAPIAsync("GET", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
}
var data = await _userCalendarRepository.GetExist(id);
if (data == null)
return Success(new { Work = "NORMAL" });
else
return Success(new { Work = data.Calendar });
}
/// <summary>
/// LV1_024 - บันทึกแก้ไขปฏิทินวันทำงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/emp/work/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> UpdateEmpCalendarByProfileAsync(Guid id, [FromBody] UpdateCalendarDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_WORK_ROUND_EDIT");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
var data = await _userCalendarRepository.GetExist(id);
if (data != null)
{
data.Calendar = req.Work;
await _userCalendarRepository.UpdateAsync(data);
return Success();
}
else
{
data = new UserCalendar
{
ProfileId = id,
Calendar = req.Work
};
await _userCalendarRepository.AddAsync(data);
return Success();
}
}
#endregion
#region " แก้ไขสถานะการลงเวลา "
/// <summary>
/// LV1_025 - บันทึกแก้ไขสถานะการเข้า-ออกงาน (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/edit/checkin/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> EditCheckInStatusAsync(Guid id, [FromBody] EditCheckInStatusDto req)
{
var getPermission = await _permission.GetPermissionAPIAsync("UPDATE", "SYS_CHECKIN");
var jsonData = JsonConvert.DeserializeObject<JObject>(getPermission);
if (jsonData["status"]?.ToString() != "200")
{
return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
}
var data = await _processUserTimeStampRepository.GetByIdAsync(id);
if (data == null)
return Error(GlobalMessages.DataNotFound);
data.CheckInStatus = req.CheckInStatus;
data.CheckOutStatus = req.CheckOutStatus;
data.EditReason = req.Reason;
await _processUserTimeStampRepository.UpdateAsync(data);
return Success();
}
#endregion
#region " รายการลารายบุคคล "
/// <summary>
/// LV1_026 - รายการลารายบุคคล (ADMIN)
/// </summary>
/// <returns>
/// </returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPut("admin/summary/keycloak/{id:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> GetLeaveSummaryByProfileAsync(Guid id, [FromBody] GetLeaveSummaryDto req)
{
var profile = await _userProfileRepository.GetProfileByKeycloakIdAsync(id, AccessToken);
var thisYear = DateTime.Now.Year;
var startDate = req.StartDate;
var endDate = req.EndDate;
var leaveDayCount = await _leaveRequestRepository.GetSumApproveLeaveByRangeForUser(id, startDate, endDate);
var timeStamps = await _processUserTimeStampRepository.GetTimeStampHistoryByRangeForUserAsync(id, startDate, endDate);
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);
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");
return Success(new
{
leave = leaveDayCount,
late = lateCount
});
}
#endregion
#endregion
}
}