diff --git a/.gitignore b/.gitignore
index 7391825f..f60d8ec1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -373,4 +373,10 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
-FodyWeavers.xsd
\ No newline at end of file
+FodyWeavers.xsd
+
+# VS Code C# Dev Kit cache
+*.lscache
+
+# Claude Code
+.claude/
\ No newline at end of file
diff --git a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveBeginingRepository.cs b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveBeginingRepository.cs
index a62aa291..c98ca11e 100644
--- a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveBeginingRepository.cs
+++ b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveBeginingRepository.cs
@@ -9,6 +9,7 @@ using BMA.EHR.Domain.Shared;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
+using System.Collections.Concurrent;
namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
{
@@ -23,6 +24,12 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
private readonly IConfiguration _configuration;
private readonly EmailSenderService _emailSenderService;
+ ///
+ /// Keyed locks to serialize get-or-create for LeaveBeginning rows by (ProfileId, LeaveYear, LeaveTypeId).
+ /// Prevents duplicate inserts when concurrent requests (e.g. UI calling /user/check twice) hit the same key.
+ ///
+ private static readonly ConcurrentDictionary _getOrAddLocks = new();
+
#endregion
#region " Constructor and Destuctor "
@@ -121,6 +128,30 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
await _dbContext.SaveChangesAsync();
}
+ public async Task ProcessEarlyLeaveRequest(int year)
+ {
+ // Get Early Leave Request (กรองตามปีงบประมาณ: 1 ต.ค. (year-1) – 30 ก.ย. (year))
+ var fiscalStart = new DateTime(year - 1, 10, 1);
+ var fiscalEnd = new DateTime(year, 9, 30);
+
+ var leaveReq = await _dbContext.Set()
+ .Include(x => x.Type)
+ .Where(x => x.LeaveStatus == "APPROVE")
+ .Where(x => x.LeaveStartDate.Date <= fiscalEnd && x.LeaveEndDate.Date >= fiscalStart)
+ .ToListAsync();
+
+ foreach (var leave in leaveReq)
+ {
+ await GetByYearAndTypeIdForUserWithUpdateAsync(year, leave.Type.Id, leave.KeycloakUserId);
+ }
+ }
+
+ public async Task ProcessEarlyLeaveRequestSchedule()
+ {
+ int year = DateTime.Now.Year;
+ await ProcessEarlyLeaveRequest(year);
+ }
+
public async Task GetByYearAndTypeIdForUserAsync(int year, Guid typeId, Guid userId)
{
// var pf = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
@@ -134,22 +165,18 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
var leaveType = await _dbContext.Set().FirstOrDefaultAsync(x => x.Id == typeId);
- var data = await _dbContext.Set()
- .Include(x => x.LeaveType)
- .FirstOrDefaultAsync(x => x.LeaveYear == year && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
-
- if (data == null)
+ LeaveBeginning Factory()
{
var limit = 0.0;
- var prev = await _dbContext.Set()
+ var prev = _dbContext.Set()
.Include(x => x.LeaveType)
- .FirstOrDefaultAsync(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
+ .FirstOrDefault(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
var prevRemain = 0.0;
if (prev != null)
{
- prevRemain = prev.LeaveDays - prev.LeaveDaysUsed;
+ prevRemain = prev.LeaveDays - (prev.LeaveDaysUsed ?? 0.0);
}
if (govAge >= 180)
@@ -170,7 +197,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
limit = 0.0;
}
- data = new LeaveBeginning
+ return new LeaveBeginning
{
LeaveYear = year,
LeaveTypeId = typeId,
@@ -186,36 +213,104 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
Child3DnaId = pf.Child3DnaId,
Child4DnaId = pf.Child4DnaId
};
+ }
- _dbContext.Set().Add(data);
+ return await GetOrAddForUserAsync(year, typeId, pf.Id, Factory);
+ }
+
+ public async Task GetByYearAndTypeIdForUserWithUpdateAsync(int year, Guid typeId, Guid userId)
+ {
+ // var pf = await _userProfileRepository.GetProfileByKeycloakIdAsync(userId, AccessToken);
+ var pf = await _userProfileRepository.GetProfileByKeycloakIdNew2Async(userId, AccessToken);
+ if (pf == null)
+ {
+ throw new Exception(GlobalMessages.DataNotFound);
+ }
+
+ var govAge = (pf?.DateStart?.Date ?? DateTime.Now.Date).DiffDay(DateTime.Now.Date);
+
+ var leaveType = await _dbContext.Set().FirstOrDefaultAsync(x => x.Id == typeId);
+
+
+ var limit = 0.0;
+
+ var prev = _dbContext.Set()
+ .Include(x => x.LeaveType)
+ .FirstOrDefault(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
+
+ var prevRemain = 0.0;
+ if (prev != null)
+ {
+ prevRemain = prev.LeaveDays - (prev.LeaveDaysUsed ?? 0.0);
+ }
+
+ if (govAge >= 180)
+ {
+ if (govAge >= 3650)
+ {
+ limit = 10 + prevRemain;
+ if (limit > 30) limit = 30;
+ }
+ else
+ {
+ limit = 10 + prevRemain;
+ if (limit > 20) limit = 20;
+ }
+ }
+ else
+ {
+ limit = 0.0;
+ }
+
+ var data = await _dbContext.Set()
+ .Where(x => x.LeaveYear == year && x.LeaveTypeId == typeId && x.ProfileId == pf.Id)
+ .FirstOrDefaultAsync();
+
+ if (data != null)
+ {
+ data.LeaveDays = leaveType?.Code == "LV-005" ? limit : 0;
await _dbContext.SaveChangesAsync();
}
+ // return new LeaveBeginning
+ // {
+ // LeaveYear = year,
+ // LeaveTypeId = typeId,
+ // ProfileId = pf.Id,
+ // Prefix = pf.Prefix,
+ // FirstName = pf.FirstName,
+ // LastName = pf.LastName,
+ // LeaveDaysUsed = 0,
+ // LeaveDays = leaveType?.Code == "LV-005" ? limit : 0,
+ // RootDnaId = pf.RootDnaId,
+ // Child1DnaId = pf.Child1DnaId,
+ // Child2DnaId = pf.Child2DnaId,
+ // Child3DnaId = pf.Child3DnaId,
+ // Child4DnaId = pf.Child4DnaId
+ // };
return data;
- }
+ }
+
+
public async Task GetByYearAndTypeIdForUser(int year, Guid typeId, GetProfileByKeycloakIdDto? pf)
{
var govAge = (pf?.DateStart?.Date ?? DateTime.Now.Date).DiffDay(DateTime.Now.Date);
var leaveType = await _dbContext.Set().FirstOrDefaultAsync(x => x.Id == typeId);
- var data = await _dbContext.Set()
- .Include(x => x.LeaveType)
- .FirstOrDefaultAsync(x => x.LeaveYear == year && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
-
- if (data == null)
+ LeaveBeginning Factory()
{
var limit = 0.0;
- var prev = await _dbContext.Set()
+ var prev = _dbContext.Set()
.Include(x => x.LeaveType)
- .FirstOrDefaultAsync(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
+ .FirstOrDefault(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
var prevRemain = 0.0;
if (prev != null)
{
- prevRemain = prev.LeaveDays - prev.LeaveDaysUsed;
+ prevRemain = prev.LeaveDays - (prev.LeaveDaysUsed ?? 0.0);
}
if (govAge >= 180)
@@ -236,7 +331,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
limit = 0.0;
}
- data = new LeaveBeginning
+ return new LeaveBeginning
{
LeaveYear = year,
LeaveTypeId = typeId,
@@ -252,12 +347,9 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
Child3DnaId = pf.Child3DnaId,
Child4DnaId = pf.Child4DnaId
};
-
- _dbContext.Set().Add(data);
- await _dbContext.SaveChangesAsync();
}
- return data;
+ return await GetOrAddForUserAsync(year, typeId, pf.Id, Factory);
}
public async Task GetByYearAndTypeIdForUser2Async(int year, Guid typeId, Guid userId)
@@ -273,22 +365,18 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
var leaveType = await _dbContext.Set().FirstOrDefaultAsync(x => x.Id == typeId);
- var data = await _dbContext.Set()
- .Include(x => x.LeaveType)
- .FirstOrDefaultAsync(x => x.LeaveYear == year && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
-
- if (data == null)
+ LeaveBeginning Factory()
{
var limit = 0.0;
- var prev = await _dbContext.Set()
+ var prev = _dbContext.Set()
.Include(x => x.LeaveType)
- .FirstOrDefaultAsync(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
+ .FirstOrDefault(x => x.LeaveYear == year - 1 && x.LeaveTypeId == typeId && x.ProfileId == pf.Id);
var prevRemain = 0.0;
if (prev != null)
{
- prevRemain = prev.LeaveDays - prev.LeaveDaysUsed;
+ prevRemain = prev.LeaveDays - (prev.LeaveDaysUsed ?? 0.0);
}
if (govAge >= 180)
@@ -309,7 +397,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
limit = 0.0;
}
- data = new LeaveBeginning
+ return new LeaveBeginning
{
LeaveYear = year,
LeaveTypeId = typeId,
@@ -325,17 +413,59 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
Child3DnaId = pf.Child3DnaId,
Child4DnaId = pf.Child4DnaId
};
-
- _dbContext.Set().Add(data);
- await _dbContext.SaveChangesAsync();
}
- return data;
+ return await GetOrAddForUserAsync(year, typeId, pf.Id, Factory);
+ }
+
+ ///
+ /// Get-or-create a LeaveBeginning row for (ProfileId, LeaveYear, LeaveTypeId) with concurrency protection.
+ /// Uses a keyed SemaphoreSlim to serialize within-process requests, and re-queries after acquiring the lock.
+ /// If a cross-process insert wins (unique index violation), the duplicate key exception is caught and the row
+ /// created by the winner is returned.
+ ///
+ private async Task GetOrAddForUserAsync(int year, Guid typeId, Guid profileId, Func factory)
+ {
+ var key = $"{profileId}_{year}_{typeId}";
+ var semaphore = _getOrAddLocks.GetOrAdd(key, _ => new SemaphoreSlim(1, 1));
+ await semaphore.WaitAsync();
+ try
+ {
+ // Re-query inside the lock — another thread may have created it while we waited.
+ var existing = await _dbContext.Set()
+ .Include(x => x.LeaveType)
+ .FirstOrDefaultAsync(x => x.LeaveYear == year && x.LeaveTypeId == typeId && x.ProfileId == profileId);
+ if (existing != null)
+ {
+ return existing;
+ }
+
+ var entity = factory();
+ _dbContext.Set().Add(entity);
+ try
+ {
+ await _dbContext.SaveChangesAsync();
+ return entity;
+ }
+ catch (DbUpdateException)
+ {
+ // Cross-process/cross-server race hit the unique index (IX_LeaveBeginnings_ProfileId_LeaveYear_LeaveTypeId).
+ // Detach the failed insert and return the row created by the winner.
+ _dbContext.Detach(entity);
+ var winner = await _dbContext.Set()
+ .Include(x => x.LeaveType)
+ .FirstOrDefaultAsync(x => x.LeaveYear == year && x.LeaveTypeId == typeId && x.ProfileId == profileId);
+ return winner;
+ }
+ }
+ finally
+ {
+ semaphore.Release();
+ }
}
public async Task> GetAllByYearAndTypeAsync(int year, Guid typeId, List userIdList)
{
-
var updateList = new List();
var result = new List();
@@ -376,7 +506,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
var prevRemain = 0.0;
if (prev != null)
{
- prevRemain = prev.LeaveDays - prev.LeaveDaysUsed;
+ prevRemain = prev.LeaveDays - (prev.LeaveDaysUsed ?? 0.0);
}
if (govAge >= 180)
diff --git a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs
index 792b57cb..3070ee88 100644
--- a/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs
+++ b/BMA.EHR.Application/Repositories/Leaves/LeaveRequests/LeaveRequestRepository.cs
@@ -11,6 +11,8 @@ using Microsoft.Extensions.Configuration;
using System.IO.Compression;
using System.Net.Http.Headers;
using System.Net.Http.Json;
+using BMA.EHR.Application.Repositories.Leaves.TimeAttendants;
+using BMA.EHR.Domain.Models.Leave.TimeAttendants;
namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
{
@@ -29,6 +31,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
private readonly MinIOLeaveService _minIOService;
private readonly LeaveBeginningRepository _leaveBeginningRepository;
+ private readonly ProcessUserTimeStampRepository _processUserTimeStampRepository;
private readonly string URL = string.Empty;
@@ -44,7 +47,8 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
EmailSenderService emailSenderService,
IApplicationDBContext appDbContext,
MinIOLeaveService minIOService,
- LeaveBeginningRepository leaveBeginningRepository) : base(dbContext, httpContextAccessor)
+ LeaveBeginningRepository leaveBeginningRepository,
+ ProcessUserTimeStampRepository processUserTimeStampRepository) : base(dbContext, httpContextAccessor)
{
_dbContext = dbContext;
_httpContextAccessor = httpContextAccessor;
@@ -58,6 +62,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
Console.WriteLine($"URL : {URL}");
_minIOService = minIOService;
_leaveBeginningRepository = leaveBeginningRepository;
+ _processUserTimeStampRepository = processUserTimeStampRepository;
}
#endregion
@@ -354,7 +359,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
var rawData = _dbContext.Set().AsNoTracking()
.Include(x => x.Type)
.Where(x => x.LeaveStatus != "DRAFT")
- .OrderByDescending(x => x.CreatedAt)
+ .OrderByDescending(x => (x.DateSendLeave ?? x.CreatedAt))
.AsQueryable();
if (year != 0)
@@ -380,7 +385,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
var rawData = _dbContext.Set().AsNoTracking()
.Include(x => x.Type)
.Where(x => x.LeaveStatus != "DRAFT")
- .OrderByDescending(x => x.CreatedAt)
+ .OrderByDescending(x => (x.DateSendLeave ?? x.CreatedAt))
.AsQueryable();
// fix issue : 1830
if (year != 0)
@@ -447,7 +452,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
.Include(x => x.Type)
.Where(x => keycloakIdList.Contains(x.KeycloakUserId))
.Where(x => x.LeaveStatus != "DRAFT")
- .OrderByDescending(x => x.CreatedAt)
+ .OrderByDescending(x =>(x.DateSendLeave ?? x.CreatedAt))
.AsQueryable();
if (year != 0)
@@ -522,7 +527,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
//.Where(x => x.LeaveStatus != "REJECT" && x.LeaveStatus != "DELETE")
.ToListAsync();
- return data.Sum(x => x.LeaveTotal) + (beginningLeave == null ? 0 : beginningLeave.LeaveDaysUsed);
+ return data.Sum(x => x.LeaveTotal) + (beginningLeave == null ? 0 : (beginningLeave.LeaveDaysUsed ?? 0.0));
}
//public async Task GetSumApproveLeaveByTypeForUserAsync(Guid keycloakUserId, Guid leaveTypeId, int year)
@@ -574,12 +579,12 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
var data = await _dbContext.Set().AsQueryable().AsNoTracking()
.Include(x => x.Type)
//.Where(x => x.LeaveStartDate.Date < beforeDate.Date)
- .Where(x => x.CreatedAt < beforeDate)
+ .Where(x => (x.DateSendLeave ?? x.CreatedAt) < beforeDate)
.Where(x => x.KeycloakUserId == keycloakUserId)
.Where(x => x.Type.Id == leaveTypeId)
.Where(x => x.LeaveStatus == "APPROVE" || x.LeaveStatus == "DELETING")
//.Where(x => x.LeaveStatus != "REJECT" && x.LeaveStatus != "DELETE")
- .OrderByDescending(x => x.CreatedAt)
+ .OrderByDescending(x => (x.DateSendLeave ?? x.CreatedAt))
.FirstOrDefaultAsync();
return data;
@@ -904,6 +909,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
rawData.LeaveStatus = "NEW";
+ rawData.DateSendLeave = DateTime.Now; // Update วันที่ยื่นลาเป็นวันที่ปัจจุบัน
//rawData.ApproveStep = "st2";
await UpdateAsync(rawData);
@@ -1324,9 +1330,68 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
}
await _appDbContext.SaveChangesAsync();
- // insert to process timestamp
-
-
+ // ปรับสถานะการลงเวลา
+ if (rawData.LeaveStartDate.Date == rawData.LeaveEndDate.Date)
+ {
+ var processCheckIn = await _dbContext.Set()
+ .Where(x => x.KeycloakUserId == rawData.KeycloakUserId)
+ .Where(x => x.CheckIn.Date == rawData.LeaveStartDate.Date)
+ .FirstOrDefaultAsync();
+
+
+ if (processCheckIn is not null)
+ {
+ switch (rawData.LeaveRange.Trim().ToUpper())
+ {
+ case "MORNING":
+ processCheckIn.CheckInStatus = "NORMAL";
+ break;
+ case "AFTERNOON":
+ processCheckIn.CheckOutStatus = "NORMAL";
+ break;
+ case "ALL":
+ processCheckIn.CheckInStatus = "NORMAL";
+ processCheckIn.CheckOutStatus = "NORMAL";
+ break;
+ default:
+ break;
+ }
+ }
+ await _dbContext.SaveChangesAsync();
+ }
+ else
+ {
+ var from = rawData.LeaveStartDate.Date;
+ var to = rawData.LeaveEndDate.Date;
+ for (var day = from.Date; day <= to.Date; day = day.AddDays(1))
+ {
+ var processCheckIn = await _dbContext.Set()
+ .Where(x => x.KeycloakUserId == rawData.KeycloakUserId)
+ .Where(x => x.CheckIn.Date == day.Date)
+ .FirstOrDefaultAsync();
+
+ if (processCheckIn is not null)
+ {
+ switch (rawData.LeaveRange.Trim().ToUpper())
+ {
+ case "MORNING":
+ processCheckIn.CheckInStatus = "NORMAL";
+ break;
+ case "AFTERNOON":
+ processCheckIn.CheckOutStatus = "NORMAL";
+ break;
+ case "ALL":
+ processCheckIn.CheckInStatus = "NORMAL";
+ processCheckIn.CheckOutStatus = "NORMAL";
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ await _dbContext.SaveChangesAsync();
+ }
+
// Send Noti
var noti = new Notification
{
@@ -1485,7 +1550,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
KeycloakUserId = pf.Keycloak == null ? Guid.Empty : pf.Keycloak.Value,
LeaveTypeId = b.LeaveTypeId,
LeaveTypeCode = b.LeaveType!.Code,
- SumLeaveDay = b.LeaveDaysUsed
+ SumLeaveDay = b.LeaveDaysUsed ?? 0.0
});
}
}
@@ -1876,7 +1941,7 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
.Include(x => x.Type)
.Where(x => x.KeycloakUserId == keycloakUserId)
.Where(x => x.Type.Id == leaveTypeId)
- .Where(x => x.CreatedAt.Date >= startDate && x.CreatedAt < endDate)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt) >= startDate && (x.DateSendLeave ??x.CreatedAt) <= endDate))
//.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
.Where(x => x.LeaveStatus == "APPROVE" || x.LeaveStatus == "DELETING")
.ToListAsync();
@@ -1886,6 +1951,119 @@ namespace BMA.EHR.Application.Repositories.Leaves.LeaveRequests
else
return 0;
}
+
+ public async Task GetSumApproveLeaveTotalByTypeAndRangeForUserBefore(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
+ {
+ var data = await _dbContext.Set().AsQueryable().AsNoTracking()
+ .Include(x => x.Type)
+ .Where(x => x.KeycloakUserId == keycloakUserId)
+ .Where(x => x.Type.Id == leaveTypeId)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt) >= startDate && (x.DateSendLeave ?? x.CreatedAt) < endDate))
+ //.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
+ .Where(x => x.LeaveStatus == "APPROVE" || x.LeaveStatus == "DELETING")
+ .ToListAsync();
+
+ if (data.Count > 0)
+ return data.Sum(x => x.LeaveTotal);
+ else
+ return 0;
+ }
+
+ public async Task GetSumApproveLeaveTotalByTypeAndRangeForUserByProfile(Guid profileId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
+ {
+ var data = await _dbContext.Set().AsQueryable().AsNoTracking()
+ .Include(x => x.Type)
+ .Where(x => x.ProfileId == profileId)
+ .Where(x => x.Type.Id == leaveTypeId)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt) >= startDate && (x.DateSendLeave ??x.CreatedAt) <= endDate))
+ //.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
+ .Where(x => x.LeaveStatus == "APPROVE" || x.LeaveStatus == "DELETING")
+ .ToListAsync();
+
+ if (data.Count > 0)
+ return data.Sum(x => x.LeaveTotal);
+ else
+ return 0;
+ }
+
+ public async Task GetSumApproveLeaveCountByTypeAndRangeForUserByProfile(Guid profileId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
+ {
+ var data = await _dbContext.Set().AsQueryable().AsNoTracking()
+ .Include(x => x.Type)
+ .Where(x => x.ProfileId == profileId)
+ .Where(x => x.Type.Id == leaveTypeId)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt) >= startDate && (x.DateSendLeave ??x.CreatedAt) <= endDate))
+ //.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
+ .Where(x => x.LeaveStatus == "APPROVE" || x.LeaveStatus == "DELETING")
+ .ToListAsync();
+
+ return data.Count;
+ }
+
+ public async Task GetSumApproveLeaveCountByTypeAndRangeForUser2(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
+ {
+ var data = await _dbContext.Set().AsQueryable().AsNoTracking()
+ .Include(x => x.Type)
+ .Where(x => x.KeycloakUserId == keycloakUserId)
+ .Where(x => x.Type.Id == leaveTypeId)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt) >= startDate && (x.DateSendLeave ??x.CreatedAt) <= endDate))
+ //.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
+ .Where(x => x.LeaveStatus == "APPROVE" || x.LeaveStatus == "DELETING")
+ .ToListAsync();
+
+ return data.Count;
+ }
+
+ ///
+ /// วันลาที่สร้างแบบร่างยังไม่ได้ยื่น
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task GetSumDraftLeaveTotalByTypeAndRangeForUser2(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
+ {
+ var data = await _dbContext.Set().AsQueryable().AsNoTracking()
+ .Include(x => x.Type)
+ .Where(x => x.KeycloakUserId == keycloakUserId)
+ .Where(x => x.Type.Id == leaveTypeId)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt).Date >= startDate
+ && (x.DateSendLeave ?? x.CreatedAt).Date < endDate))
+ //.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
+ .Where(x => x.LeaveStatus == "DRAFT")
+ .ToListAsync();
+
+ if (data.Count > 0)
+ return data.Sum(x => x.LeaveTotal);
+ else
+ return 0;
+ }
+
+ ///
+ /// วันลาที่ยื่นแล้วรอพิจารณา
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task GetSumNewLeaveTotalByTypeAndRangeForUser2(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
+ {
+ var data = await _dbContext.Set().AsQueryable().AsNoTracking()
+ .Include(x => x.Type)
+ .Where(x => x.KeycloakUserId == keycloakUserId)
+ .Where(x => x.Type.Id == leaveTypeId)
+ .Where(x => ((x.DateSendLeave ?? x.CreatedAt) >= startDate && (x.DateSendLeave ??x.CreatedAt) < endDate))
+ //.Where(x => x.LeaveStartDate.Date >= startDate.Date && x.LeaveStartDate.Date <= endDate.Date)
+ .Where(x => (x.LeaveStatus == "NEW" || x.LeaveStatus == "PENDING"))
+ .ToListAsync();
+
+ if (data.Count > 0)
+ return data.Sum(x => x.LeaveTotal);
+ else
+ return 0;
+ }
public async Task GetCountApproveLeaveByTypeAndRangeForUser(Guid keycloakUserId, Guid leaveTypeId, DateTime startDate, DateTime endDate)
{
diff --git a/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/AdditionalCheckRequestRepository.cs b/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/AdditionalCheckRequestRepository.cs
index 0544e261..d4bc0ea8 100644
--- a/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/AdditionalCheckRequestRepository.cs
+++ b/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/AdditionalCheckRequestRepository.cs
@@ -213,6 +213,79 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants
}
}
+ public async Task> GetAdditionalCheckRequestsByAdminRole2(DateTime startDate, DateTime endDate, string role, string nodeId, int? node, string? keyword, string? status)
+ {
+ try
+ {
+ var data = await _dbContext.Set().AsQueryable()
+ .Where(x => (x.CheckDate.Date >= startDate.Date && x.CheckDate.Date <= endDate.Date))
+ .OrderByDescending(x => x.CreatedAt.Date)
+ .ToListAsync();
+
+ if(!string.IsNullOrEmpty(status))
+ data = data.Where(x => x.Status == status).ToList();
+
+
+ if (!string.IsNullOrEmpty(keyword))
+ {
+ data = data.Where(x =>
+ (
+ (x.Prefix ?? "") + (x.FirstName ?? "") + " " + (x.LastName ?? "")).Contains(keyword)
+ || x.Description.Contains(keyword)
+
+ ).ToList();
+ }
+
+ if (role == "OWNER")
+ {
+ node = null;
+ }
+ if (role == "OWNER" || role == "CHILD")
+ {
+ data = data
+ .Where(x => node == 4 ? x.Child4DnaId == Guid.Parse(nodeId!) : (node == 3 ? x.Child3DnaId == Guid.Parse(nodeId!) : (node == 2 ? x.Child2DnaId == Guid.Parse(nodeId!) : (node == 1 ? x.Child1DnaId == Guid.Parse(nodeId!) : (node == 0 ? x.RootDnaId == Guid.Parse(nodeId!) : (node == null ? true : true))))))
+ .ToList();
+ }
+ else if (role == "BROTHER")
+ {
+ data = data
+ .Where(x => node == 4 ? x.Child3DnaId == Guid.Parse(nodeId!) : (node == 3 ? x.Child2DnaId == Guid.Parse(nodeId!) : (node == 2 ? x.Child1DnaId == Guid.Parse(nodeId!) : (node == 1 || node == 0 ? x.RootDnaId == Guid.Parse(nodeId!) : (node == null ? true : true)))))
+ .ToList();
+ }
+ else if (role == "ROOT")
+ {
+ data = data
+ .Where(x => x.RootDnaId == Guid.Parse(nodeId!)).ToList();
+ }
+ // else if (role == "PARENT")
+ // {
+ // data = data
+ // .Where(x => x.RootDnaId == Guid.Parse(nodeId!) && x.Child1DnaId != null && x.Child1DnaId != Guid.Empty).ToList();
+ // }
+ else if (role == "NORMAL")
+ {
+ data = data.Where(x =>
+ node == 0 ? x.RootDnaId == Guid.Parse(nodeId!) &&
+ (x.Child1DnaId == Guid.Empty || x.Child1DnaId == null) :
+ node == 1 ? x.Child1DnaId == Guid.Parse(nodeId!) &&
+ (x.Child2DnaId == Guid.Empty || x.Child2DnaId == null) :
+ node == 2 ? x.Child2DnaId == Guid.Parse(nodeId!) &&
+ (x.Child3DnaId == Guid.Empty || x.Child3DnaId == null) :
+ node == 3 ? x.Child3DnaId == Guid.Parse(nodeId!) &&
+ (x.Child4DnaId == Guid.Empty || x.Child4DnaId == null) :
+ node == 4 ? x.Child4DnaId == Guid.Parse(nodeId!) :
+ true
+ ).ToList();
+ }
+ return data;
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+
#endregion
}
}
diff --git a/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/CheckInJobStatusRepository.cs b/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/CheckInJobStatusRepository.cs
index 302bdd12..e0967a5c 100644
--- a/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/CheckInJobStatusRepository.cs
+++ b/BMA.EHR.Application/Repositories/Leaves/TimeAttendants/CheckInJobStatusRepository.cs
@@ -114,6 +114,62 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants
return job!;
}
+ ///
+ /// ดึงข้อมูลงานที่ค้างอยู่ในสถานะ PENDING หรือ PROCESSING เกินเวลาที่กำหนด (นาที)
+ ///
+ public async Task> GetStalePendingOrProcessingJobsAsync(int timeoutMinutes = 30)
+ {
+ //var cutoffDate = DateTime.Now.AddMinutes(-timeoutMinutes);
+ var cutoffDate = DateTime.Now.AddMinutes(-timeoutMinutes);
+ var staleJobs = await _dbContext.Set()
+ .Where(x => (x.Status == "PENDING" || x.Status == "PROCESSING")
+ && x.CreatedDate <= cutoffDate)
+ .OrderBy(x => x.CreatedDate)
+ .ToListAsync();
+
+ return staleJobs;
+ }
+
+ ///
+ /// ดึงข้อมูลงานที่ค้างอยู่ในสถานะ PENDING หรือ PROCESSING เกินเวลาที่กำหนด (นาที) ของ user คนใดคนหนึ่ง
+ ///
+ public async Task> GetStalePendingOrProcessingJobsByUserAsync(Guid userId, int timeoutMinutes = 30)
+ {
+ var cutoffDate = DateTime.Now.AddMinutes(-timeoutMinutes);
+ //var cutoffDate = new DateTime(2026, 5, 28, 23, 59, 59);
+ var staleJobs = await _dbContext.Set()
+ .Where(x => x.KeycloakUserId == userId
+ && (x.Status == "PENDING" || x.Status == "PROCESSING")
+ && x.CreatedDate < cutoffDate)
+ .OrderBy(x => x.CreatedDate)
+ .ToListAsync();
+
+ return staleJobs;
+ }
+
+ ///
+ /// Mark งานที่ค้างเกินเวลาที่กำหนดเป็น FAILED
+ ///
+ public async Task MarkStaleJobsAsFailedAsync(int timeoutMinutes = 30)
+ {
+ var staleJobs = await GetStalePendingOrProcessingJobsAsync(timeoutMinutes);
+
+ foreach (var job in staleJobs)
+ {
+ job.Status = "FAILED";
+ job.CompletedDate = DateTime.Now;
+ job.ErrorMessage = $"งานค้างในสถานะ {job.Status} เกิน {timeoutMinutes} นาที ระบบทำเครื่องหมายเป็น FAILED อัตโนมัติ";
+ }
+
+ if (staleJobs.Any())
+ {
+ _dbContext.Set().UpdateRange(staleJobs);
+ await _dbContext.SaveChangesAsync();
+ }
+
+ return staleJobs.Count;
+ }
+
///
/// ล้างข้อมูล Job Status ที่เก่าเกิน X วัน
///
diff --git a/BMA.EHR.Application/Repositories/MetaData/HolidayRepository.cs b/BMA.EHR.Application/Repositories/MetaData/HolidayRepository.cs
index c5c09a44..1c8ae006 100644
--- a/BMA.EHR.Application/Repositories/MetaData/HolidayRepository.cs
+++ b/BMA.EHR.Application/Repositories/MetaData/HolidayRepository.cs
@@ -49,12 +49,16 @@ namespace BMA.EHR.Application.Repositories.MetaData
public async Task GetHolidayCountAsync(DateTime startDate, DateTime endDate, string category = "NORMAL")
{
- var data = await _dbContext.Set().AsQueryable()
+ var query = _dbContext.Set().AsQueryable()
.Where(x => x.Category == category)
- .Where(x => x.HolidayDate.Date >= startDate && x.HolidayDate.Date <= endDate)
- .CountAsync();
+ .Where(x => x.HolidayDate.Date >= startDate && x.HolidayDate.Date <= endDate);
- return data;
+ if (category == "NORMAL")
+ query = query.Where(x => x.HolidayDate.DayOfWeek != DayOfWeek.Saturday && x.HolidayDate.DayOfWeek != DayOfWeek.Sunday);
+ else
+ query = query.Where(x => x.HolidayDate.DayOfWeek != DayOfWeek.Sunday);
+
+ return await query.CountAsync();
}
public List GetWeekEnd(DateTime startDate, DateTime endDate, string category = "NORMAL")
diff --git a/BMA.EHR.Application/Repositories/PermissionRepository.cs b/BMA.EHR.Application/Repositories/PermissionRepository.cs
index 84191f91..a63207ec 100644
--- a/BMA.EHR.Application/Repositories/PermissionRepository.cs
+++ b/BMA.EHR.Application/Repositories/PermissionRepository.cs
@@ -10,6 +10,7 @@ using System.Net.Http.Headers;
using Microsoft.Extensions.Configuration;
using System.Security.Claims;
using System.Net.Http.Json;
+using BMA.EHR.Application.Responses.Leaves;
namespace BMA.EHR.Application.Repositories
{
@@ -76,6 +77,39 @@ namespace BMA.EHR.Application.Repositories
}
}
+ public async Task GetPermissionWithActingAPIAsync(string action, string system)
+ {
+ try
+ {
+ var apiPath = $"{_configuration["API"]}/org/permission/dotnet-acting/{action}/{system}";
+
+ using (var client = new HttpClient())
+ {
+ client.DefaultRequestHeaders.Authorization =
+ new AuthenticationHeaderValue("Bearer", AccessToken.Replace("Bearer ", ""));
+ client.DefaultRequestHeaders.Add("api-key", _configuration["API_KEY"]);
+ var req = await client.GetAsync(apiPath);
+ if (!req.IsSuccessStatusCode)
+ {
+ throw new Exception("Error calling permission API");
+ }
+ var apiResult = await req.Content.ReadAsStringAsync();
+ //return res;
+
+ if (apiResult != null)
+ {
+ var raw = JsonConvert.DeserializeObject(apiResult);
+ return raw;
+ }
+ return null;
+ }
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
public async Task GetPermissionOrgAPIAsync(string action, string system, string profileId)
{
try
diff --git a/BMA.EHR.Application/Repositories/PlacementRepository.cs b/BMA.EHR.Application/Repositories/PlacementRepository.cs
index 49f1175c..eb7c3617 100644
--- a/BMA.EHR.Application/Repositories/PlacementRepository.cs
+++ b/BMA.EHR.Application/Repositories/PlacementRepository.cs
@@ -2,24 +2,40 @@
using BMA.EHR.Domain.Models.Placement;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using System.Net.Http.Headers;
+using Newtonsoft.Json;
namespace BMA.EHR.Application.Repositories
{
+ ///
+ /// Response model จาก Org API (check-isLeave)
+ ///
+ public class OrgProfileResult
+ {
+ public string citizenId { get; set; } = "";
+ public string? profileId { get; set; }
+ public bool isLeave { get; set; }
+ public bool isActive { get; set; }
+ }
+
public class PlacementRepository : GenericRepository
{
#region " Fields "
private readonly IApplicationDBContext _dbContext;
private readonly IHttpContextAccessor _httpContextAccessor;
+ private readonly IConfiguration _configuration;
#endregion
#region " Constructor and Destructor "
- public PlacementRepository(IApplicationDBContext dbContext, IHttpContextAccessor httpContextAccessor) : base(dbContext, httpContextAccessor)
+ public PlacementRepository(IApplicationDBContext dbContext, IHttpContextAccessor httpContextAccessor, IConfiguration configuration) : base(dbContext, httpContextAccessor)
{
_dbContext = dbContext;
_httpContextAccessor = httpContextAccessor;
+ _configuration = configuration;
}
#endregion
@@ -76,6 +92,148 @@ namespace BMA.EHR.Application.Repositories
return data;
}
+ ///
+ /// Job อัพเดทสถานะผู้สอบผ่านที่ลาออกไปแล้วแต่ยังไม่ส่งไปออกคำสั่ง
+ /// และอัพเดทบุคคลภายนอกที่เข้ามาอยู่ในระบบแล้ว
+ /// ทำงานทุกวันเวลา 05:00 น.
+ ///
+ public async Task UpdateStatusPlacementProfiles()
+ {
+ Console.WriteLine("[Job:UpdateStatusPlacementProfiles] === STARTED ===");
+
+ // 1. Query ทั้ง 2 กรณี: ทุกคนที่ยังไม่ DONE
+ var allCitizenIds = await _dbContext.Set()
+ .Where(p => !string.IsNullOrEmpty(p.CitizenId)
+ && p.PlacementStatus != "DONE"
+ // && p.CitizenId == "2536721883131"
+ )
+ .Select(p => new { p.CitizenId, p.IsOfficer })
+ .ToListAsync();
+
+ if (!allCitizenIds.Any())
+ {
+ Console.WriteLine("[Job:UpdateStatusPlacementProfiles] No profiles to process");
+ return;
+ }
+
+ var officerCount = allCitizenIds.Count(x => x.IsOfficer == true);
+ var notOfficerCount = allCitizenIds.Count(x => x.IsOfficer == false);
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] พบข้าราชการ {officerCount} คน, บุคคลภายนอก {notOfficerCount} คน");
+
+ // 2. ส่ง citizenIds ทั้งหมดไป Org API ครั้งเดียว
+ var citizenIds = allCitizenIds.Select(x => x.CitizenId).Distinct().ToList();
+ var apiUrl = $"{_configuration["API"]}/org/dotnet/check-isLeave";
+
+ List orgResults = new();
+
+ using (var client = new HttpClient())
+ {
+ client.DefaultRequestHeaders.Add("api-key", _configuration["API_KEY"]);
+
+ var payload = new { citizenIds };
+ var jsonPayload = JsonConvert.SerializeObject(payload);
+ var content = new StringContent(jsonPayload, System.Text.Encoding.UTF8, "application/json");
+
+ try
+ {
+ var response = await client.PostAsync(apiUrl, content);
+ var result = await response.Content.ReadAsStringAsync();
+
+ var responseObj = JsonConvert.DeserializeAnonymousType(result, new
+ {
+ status = 0,
+ message = "",
+ result = new List()
+ });
+
+ orgResults = responseObj?.result ?? new();
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] Org API ตอบกลับ {orgResults.Count} รายการ");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] Call API failed: {ex.Message}");
+ return;
+ }
+ }
+
+ if (!orgResults.Any())
+ {
+ Console.WriteLine("[Job:UpdateStatusPlacementProfiles] ไม่มีรายการต้องอัปเดต");
+ Console.WriteLine("[Job:UpdateStatusPlacementProfiles] === COMPLETED ===");
+ return;
+ }
+
+ // 3. แยกข้อมูลตามเงื่อนไข
+ var leaveCitizenIds = orgResults.Where(x => x.isLeave).Select(x => x.citizenId).ToList();
+ var inSystemProfiles = orgResults.Where(x => x.isActive && !x.isLeave && !string.IsNullOrEmpty(x.profileId)).ToList();
+
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] ลาออก {leaveCitizenIds.Count} รายการ, อยู่ที่ทะเบียนประวัติ {inSystemProfiles.Count} รายการ");
+
+ // 4. Split Batch Update (500 รายการ/batch)
+ var batchSize = 500;
+ var totalUpdated = 0;
+
+ // 4.1 Update คนลาออก → IsOfficer = false
+ if (leaveCitizenIds.Any())
+ {
+ var totalBatches = (int)Math.Ceiling((double)leaveCitizenIds.Count / batchSize);
+ for (int i = 0; i < totalBatches; i++)
+ {
+ var batch = leaveCitizenIds.Skip(i * batchSize).Take(batchSize).ToList();
+
+ var profilesToUpdate = await _dbContext.Set()
+ .Where(p => !string.IsNullOrEmpty(p.CitizenId)
+ && batch.Contains(p.CitizenId)
+ && p.IsOfficer == true)
+ .ToListAsync();
+
+ foreach (var profile in profilesToUpdate)
+ {
+ profile.profileId = null;
+ profile.IsOfficer = false;
+ }
+
+ await _dbContext.SaveChangesAsync();
+ totalUpdated += profilesToUpdate.Count;
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] [ลาออก] Batch {i + 1}/{totalBatches} → อัปเดต {profilesToUpdate.Count} รายการ");
+ }
+ }
+
+ // 4.2 Update คนที่อยู่ในทะเบียนประวัติ → profileId + IsOfficer = true
+ if (inSystemProfiles.Any())
+ {
+ var totalBatches = (int)Math.Ceiling((double)inSystemProfiles.Count / batchSize);
+ for (int i = 0; i < totalBatches; i++)
+ {
+ var batch = inSystemProfiles.Skip(i * batchSize).Take(batchSize).ToList();
+ var batchCitizenIds = batch.Select(x => x.citizenId).ToList();
+
+ var profilesToUpdate = await _dbContext.Set()
+ .Where(p => !string.IsNullOrEmpty(p.CitizenId)
+ && batchCitizenIds.Contains(p.CitizenId)
+ && p.IsOfficer == false)
+ .ToListAsync();
+
+ foreach (var profile in profilesToUpdate)
+ {
+ var orgProfile = batch.FirstOrDefault(x => x.citizenId == profile.CitizenId);
+ if (orgProfile != null)
+ {
+ profile.profileId = orgProfile.profileId;
+ profile.IsOfficer = true;
+ }
+ }
+
+ await _dbContext.SaveChangesAsync();
+ totalUpdated += profilesToUpdate.Count;
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] [เข้าระบบ] Batch {i + 1}/{totalBatches} → อัปเดต {profilesToUpdate.Count} รายการ");
+ }
+ }
+
+ Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] อัปเดตรวมทั้งหมด {totalUpdated} รายการ");
+ Console.WriteLine("[Job:UpdateStatusPlacementProfiles] === COMPLETED ===");
+ }
+
#endregion
}
}
diff --git a/BMA.EHR.Application/Repositories/Reports/RetireReportRepository.cs b/BMA.EHR.Application/Repositories/Reports/RetireReportRepository.cs
index ecb65e2f..6ad5a61a 100644
--- a/BMA.EHR.Application/Repositories/Reports/RetireReportRepository.cs
+++ b/BMA.EHR.Application/Repositories/Reports/RetireReportRepository.cs
@@ -192,7 +192,7 @@ namespace BMA.EHR.Application.Repositories.Reports
}).ToList();
}
string SignDate = retireHistorys.SignDate != null ? DateTime.Parse(retireHistorys.SignDate.ToString()).ToThaiFullDate().ToString().ToThaiNumber() : "-";
- return new { SignDate, retireHistorys.Detail, retireHistorys.Id, retireHistorys.CreatedAt, Year = retireHistorys.Year.ToThaiYear().ToString().ToThaiNumber(), retireHistorys.Round, retireHistorys.Type, retireHistorys.TypeReport, Total = retireHistorys.Total.ToString().ToThaiNumber(), profiles = mapProfiles };
+ return new { SignDate, Detail = retireHistorys.Detail.ToThaiNumber(), retireHistorys.Id, retireHistorys.CreatedAt, Year = retireHistorys.Year.ToThaiYear().ToString().ToThaiNumber(), retireHistorys.Round, retireHistorys.Type, retireHistorys.TypeReport, Total = retireHistorys.Total.ToString().ToThaiNumber(), profiles = mapProfiles };
}
}
else
@@ -312,7 +312,7 @@ namespace BMA.EHR.Application.Repositories.Reports
root = (isDuplicateRoot ? "" : profile.root + "\n") +
(isDuplicateHospital || !hospital.ToObject>().Contains(profile.child1) ? "" : profile.child1 + "\n") +
(isDuplicatePosType ? "" : $"ตำแหน่งประเภท{profile.posTypeName}" + "\n") +
- (isDuplicatePosLevel ? "" : $"ระดับ{profile.posLevelName}"),
+ (isDuplicatePosLevel ? "" : $"ระดับ{profile.posLevelName}").ToThaiNumber(),
child = (profile.posExecutiveName == null ? "" : profile.posExecutiveName + "\n") +
(profile.child4 == null ? "" : profile.child4 + "\n") +
(profile.child3 == null ? "" : profile.child3 + "\n") +
@@ -326,7 +326,7 @@ namespace BMA.EHR.Application.Repositories.Reports
}).ToList();
}
string SignDate = retire.SignDate != null ? DateTime.Parse(retire.SignDate.ToString()).ToThaiFullDate().ToString().ToThaiNumber() : "-";
- return new { SignDate, retire.Detail, retire.Id, retire.CreatedAt, Year = retire.Year.ToThaiYear().ToString().ToThaiNumber(), retire.Round, retire.Type, retire.TypeReport, Total = profile_retire.Count.ToString().ToThaiNumber(), profiles = mapProfiles };
+ return new { SignDate, Detail = retire.Detail.ToThaiNumber(), retire.Id, retire.CreatedAt, Year = retire.Year.ToThaiYear().ToString().ToThaiNumber(), retire.Round, retire.Type, retire.TypeReport, Total = profile_retire.Count.ToString().ToThaiNumber(), profiles = mapProfiles };
}
}
#endregion
diff --git a/BMA.EHR.Application/Repositories/UserProfileRepository.cs b/BMA.EHR.Application/Repositories/UserProfileRepository.cs
index 4f081f77..aa89d9b9 100644
--- a/BMA.EHR.Application/Repositories/UserProfileRepository.cs
+++ b/BMA.EHR.Application/Repositories/UserProfileRepository.cs
@@ -233,6 +233,29 @@ namespace BMA.EHR.Application.Repositories
throw;
}
}
+
+ public async Task GetProfileByCheckInAsync(Guid keycloakId, string? accessToken)
+ {
+ try
+ {
+ var apiPath = $"{_configuration["API"]}/org/dotnet/check-keycloak/{keycloakId}";
+ var apiKey = _configuration["API_KEY"];
+
+ var apiResult = await GetExternalAPIAsync(apiPath, accessToken ?? "", apiKey);
+ if (apiResult != null)
+ {
+ var raw = JsonConvert.DeserializeObject(apiResult);
+ if (raw != null)
+ return raw.Result;
+ }
+
+ return null;
+ }
+ catch
+ {
+ throw;
+ }
+ }
public async Task GetProfileLeaveByKeycloakIdAsync(Guid keycloakId, string? accessToken)
@@ -1039,6 +1062,42 @@ namespace BMA.EHR.Application.Repositories
}
}
+ public async Task> GetEmployeeByAdminRolev2(string? accessToken, int? node, string? nodeId, string role, string? revisionId, int? reqNode, string? reqNodeId, DateTime? startDate, DateTime? endDate)
+ {
+ try
+ {
+ var apiPath = $"{_configuration["API"]}/org/dotnet/employee-by-admin-rolev2";
+ var apiKey = _configuration["API_KEY"];
+ var body = new
+ {
+ node = node,
+ nodeId = nodeId,
+ role = role,
+ // isRetirement
+ reqNode = reqNode,
+ reqNodeId = reqNodeId,
+ date = endDate
+ };
+ Console.WriteLine(body);
+
+ var profiles = new List();
+
+ var apiResult = await PostExternalAPIAsync(apiPath, accessToken, body, apiKey);
+ if (apiResult != null)
+ {
+ var raw = JsonConvert.DeserializeObject(apiResult);
+ if (raw != null)
+ return raw.Result;
+ }
+
+ return new List();
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
public async Task SearchProfile(string? citizenId, string? firstName, string? lastName, string accessToken, int page, int pageSize, string? role, string? nodeId, int? node,string? selectedNodeId,int? selectedNode )
{
try
diff --git a/BMA.EHR.Application/Responses/Leaves/GetPermissionWithActingDto.cs b/BMA.EHR.Application/Responses/Leaves/GetPermissionWithActingDto.cs
new file mode 100644
index 00000000..083c4b20
--- /dev/null
+++ b/BMA.EHR.Application/Responses/Leaves/GetPermissionWithActingDto.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using BMA.EHR.Domain.Shared;
+using Newtonsoft.Json;
+
+namespace BMA.EHR.Application.Responses.Leaves
+{
+ public class GetPermissionWithActingDto
+ {
+ public string privilege {get; set;} = string.Empty;
+ public bool isAct {get; set;} = false;
+ public List posMasterActs {get; set;} = new();
+ }
+
+ public class ActingPermission
+ {
+ public string posNo {get; set;} = string.Empty;
+ //public string? privilege {get; set;} = "PARENT";
+ [JsonConverter(typeof(PrivilegeConverter))]
+ public string privilege {get; set;} = "CHILD";
+
+ public Guid? rootDnaId {get; set;}
+ public Guid? child1DnaId {get; set;}
+ public Guid? child2DnaId {get; set;}
+ public Guid? child3DnaId {get; set;}
+ public Guid? child4DnaId {get; set;}
+ }
+
+ public class GetPermissionWithActingResultDto
+ {
+ public int status {get; set;} = 0;
+ public string message {get; set;} = string.Empty;
+ public GetPermissionWithActingDto result {get; set;} = new();
+ }
+}
\ No newline at end of file
diff --git a/BMA.EHR.CheckInConsumer/Program.cs b/BMA.EHR.CheckInConsumer/Program.cs
index 0ae439cf..95dac001 100644
--- a/BMA.EHR.CheckInConsumer/Program.cs
+++ b/BMA.EHR.CheckInConsumer/Program.cs
@@ -1,4 +1,4 @@
-using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Configuration;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
@@ -21,77 +21,101 @@ var queue = configuration["Rabbit:Queue"] ?? "basic-queue";
// create connection
var factory = new ConnectionFactory()
{
- //Uri = new Uri("amqp://admin:P@ssw0rd@192.168.4.11:5672")
- HostName = host,// หรือ hostname ของ RabbitMQ Server ที่คุณใช้
- UserName = user, // ใส่ชื่อผู้ใช้ของคุณ
- Password = pass // ใส่รหัสผ่านของคุณ
+ HostName = host,
+ UserName = user,
+ Password = pass,
+ DispatchConsumersAsync = true
};
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
-//channel.QueueDeclare(queue: "bma-checkin-queue", durable: true, exclusive: false, autoDelete: false, arguments: null);
channel.QueueDeclare(queue: queue, durable: true, exclusive: false, autoDelete: false, arguments: null);
-var consumer = new EventingBasicConsumer(channel);
+// Create a SINGLE static HttpClient instance to prevent socket exhaustion
+using var httpClient = new HttpClient();
+httpClient.Timeout = TimeSpan.FromSeconds(300); // 5 นาที
+
+var consumer = new AsyncEventingBasicConsumer(channel);
consumer.Received += async (model, ea) =>
{
- var body = ea.Body.ToArray();
- var message = Encoding.UTF8.GetString(body);
- await CallRestApi(message);
+ try
+ {
+ var body = ea.Body.ToArray();
+ var message = Encoding.UTF8.GetString(body);
- // convert string into object
- //var request = JsonConvert.DeserializeObject(message);
- //using (var db = new ApplicationDbContext())
- //{
- // var item = new AttendantItem
- // {
- // Name = request.Name,
- // CheckInDateTime = request.CheckInDateTime,
- // };
- // db.AttendantItems.Add(item);
- // db.SaveChanges();
+ WriteToConsole($"Received message: {message}");
- // WriteToConsole($"ได้รับคำขอจาก Queue: {message}");
- // WriteToConsole($"ตอบกลับจาก REST API: {JsonConvert.SerializeObject(item)}");
- //}
+ var success = await CallRestApi(message, httpClient, configuration);
- WriteToConsole($"ได้รับคำขอจาก Queue: {message}");
- //WriteToConsole($"ตอบกลับจาก REST API: {JsonConvert.SerializeObject(item)}");
+ if (success)
+ {
+ channel.BasicAck(ea.DeliveryTag, multiple: false);
+ WriteToConsole("Message processed successfully");
+ }
+ else
+ {
+ channel.BasicNack(ea.DeliveryTag, multiple: false, requeue: false);
+ WriteToConsole("Message processing failed - message rejected");
+ }
+ }
+ catch (Exception ex)
+ {
+ WriteToConsole($"Error processing message: {ex.Message}");
+ channel.BasicNack(ea.DeliveryTag, multiple: false, requeue: false);
+ }
};
-//channel.BasicConsume(queue: "bma-checkin-queue", autoAck: true, consumer: consumer);
-channel.BasicConsume(queue: queue, autoAck: true, consumer: consumer);
+channel.BasicConsume(queue: queue, autoAck: false, consumer: consumer);
-//Console.WriteLine("\nPress 'Enter' to exit the process...");
+WriteToConsole("Consumer started. Waiting for messages...");
+// Keep the application running
await Task.Delay(-1);
static void WriteToConsole(string message)
{
- Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} : {message}");
+ Console.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} : {message}");
}
-async Task CallRestApi(string requestData)
+static async Task CallRestApi(string requestData, HttpClient client, IConfiguration configuration)
{
- using var client = new HttpClient();
- var apiPath = $"{configuration["API"]}/leave/process-check-in";
-
- var content = new StringContent(requestData, Encoding.UTF8, "application/json");
-
- var response = await client.PostAsync(apiPath, content);
-
- if (response.IsSuccessStatusCode)
+ try
{
- var responseContent = await response.Content.ReadAsStringAsync();
- WriteToConsole(responseContent);
+ var apiPath = $"{configuration["API"]}/leave/process-check-in";
+ var content = new StringContent(requestData, Encoding.UTF8, "application/json");
+
+ var response = await client.PostAsync(apiPath, content);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var responseContent = await response.Content.ReadAsStringAsync();
+ WriteToConsole($"API Success: {responseContent}");
+ return true;
+ }
+ else
+ {
+ var errorMessage = await response.Content.ReadAsStringAsync();
+ var res = JsonSerializer.Deserialize(errorMessage);
+ WriteToConsole($"API Error ({response.StatusCode}): {res?.Message ?? errorMessage}");
+ return false;
+ }
}
- else
+ catch (HttpRequestException ex)
{
- var errorMessage = await response.Content.ReadAsStringAsync();
- var res = JsonSerializer.Deserialize(errorMessage);
- WriteToConsole($"Error: {res.Message}");
+ WriteToConsole($"HTTP Error: {ex.Message}");
+ return false;
+ }
+ catch (TaskCanceledException ex)
+ {
+ WriteToConsole($"Timeout: {ex.Message}");
+ return false;
+ }
+ catch (Exception ex)
+ {
+ WriteToConsole($"Unexpected Error: {ex.Message}");
+ return false;
}
}
@@ -110,28 +134,14 @@ public class ResponseObject
public class CheckTimeDtoRB
{
public Guid? CheckInId { get; set; }
-
-
public double Lat { get; set; } = 0;
-
-
public double Lon { get; set; } = 0;
-
-
public string POI { get; set; } = string.Empty;
-
-
public bool IsLocation { get; set; } = true;
-
public string? LocationName { get; set; } = string.Empty;
-
public string? Remark { get; set; } = string.Empty;
-
public Guid? UserId { get; set; }
-
public DateTime? CurrentDate { get; set; }
-
public string? CheckInFileName { get; set; }
-
public byte[]? CheckInFileBytes { get; set; }
-}
\ No newline at end of file
+}
diff --git a/BMA.EHR.Discipline.Service/Controllers/DisciplineResultController.cs b/BMA.EHR.Discipline.Service/Controllers/DisciplineResultController.cs
index 85388209..35a9dfa2 100644
--- a/BMA.EHR.Discipline.Service/Controllers/DisciplineResultController.cs
+++ b/BMA.EHR.Discipline.Service/Controllers/DisciplineResultController.cs
@@ -968,12 +968,20 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command19/report")]
- public async Task> PostReportCommand19([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand19([FromBody] ReportPersonAndCommandRequest req)
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -993,7 +1001,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1013,6 +1027,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "REPORTED"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
var resultData = (from p in data
join r in req.refIds
on p.Id.ToString() equals r.refId
@@ -1061,8 +1080,8 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
var _result = await _res.Content.ReadAsStringAsync();
if (_res.IsSuccessStatusCode)
{
- // คำสั่งไล่ออก หรือ ปลดออก Status หลังออกคำสั่งใช้ "REPORTED" เพื่อไม่ให้ส่งรายชื่อไปออกคำสั่งซ้ำได้
- data.ForEach(profile => { profile.Status = "REPORTED"; profile.CommandTypeId = null; });
+ //// คำสั่งไล่ออก หรือ ปลดออก Status หลังออกคำสั่งใช้ "REPORTED" เพื่อไม่ให้ส่งรายชื่อไปออกคำสั่งซ้ำได้
+ // data.ForEach(profile => { profile.Status = "REPORTED"; profile.CommandTypeId = null; });
var _profile = new List();
DateTime _date = DateTime.Now;
foreach (var item in data)
@@ -1105,12 +1124,20 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command20/report")]
- public async Task> PostReportcommand20([FromBody] ReportPersonRequest req)
+ public async Task> PostReportcommand20([FromBody] ReportPersonAndCommandRequest req)
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1130,7 +1157,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1150,6 +1183,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "REPORTED"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
var resultData = (from p in data
join r in req.refIds
on p.Id.ToString() equals r.refId
@@ -1198,8 +1236,8 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
var _result = await _res.Content.ReadAsStringAsync();
if (_res.IsSuccessStatusCode)
{
- // คำสั่งไล่ออก หรือ ปลดออก Status หลังออกคำสั่งใช้ "REPORTED" เพื่อไม่ให้ส่งรายชื่อไปออกคำสั่งซ้ำได้
- data.ForEach(profile => { profile.Status = "REPORTED"; profile.CommandTypeId = null; });
+ //// คำสั่งไล่ออก หรือ ปลดออก Status หลังออกคำสั่งใช้ "REPORTED" เพื่อไม่ให้ส่งรายชื่อไปออกคำสั่งซ้ำได้
+ // data.ForEach(profile => { profile.Status = "REPORTED"; profile.CommandTypeId = null; });
var _profile = new List();
DateTime _date = DateTime.Now;
foreach (var item in data)
@@ -1379,6 +1417,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
// .Where(x => x.Status == "REPORT")
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => profile.Status = "DONE");
+ await _context.SaveChangesAsync();
+
var resultData = (from p in data
join r in req.refIds
on p.Id.ToString() equals r.refId
@@ -1424,12 +1467,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => profile.Status = "DONE");
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => profile.Status = "DONE");
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -1518,6 +1561,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
// .Where(x => x.Status == "REPORT")
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => profile.Status = "DONE");
+ await _context.SaveChangesAsync();
+
var resultData = (from p in data
join r in req.refIds
on p.Id.ToString() equals r.refId
@@ -1563,12 +1611,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => profile.Status = "DONE");
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => profile.Status = "DONE");
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -1582,14 +1630,22 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command27/report")]
- public async Task> PostReportCommand27([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand27([FromBody] ReportPersonAndCommandRequest req)
{
try
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1616,7 +1672,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1641,6 +1703,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
string? _null = null;
var resultData = (from p in data
join r in req.refIds
@@ -1686,12 +1753,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -1705,14 +1772,22 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command28/report")]
- public async Task> PostReportCommand28([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand28([FromBody] ReportPersonAndCommandRequest req)
{
try
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1739,7 +1814,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1764,6 +1845,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
string? _null = null;
var resultData = (from p in data
join r in req.refIds
@@ -1809,12 +1895,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -1828,14 +1914,22 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command29/report")]
- public async Task> PostReportCommand29([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand29([FromBody] ReportPersonAndCommandRequest req)
{
try
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1862,7 +1956,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1887,6 +1987,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
string? _null = null;
var resultData = (from p in data
join r in req.refIds
@@ -1932,12 +2037,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -1951,14 +2056,22 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command30/report")]
- public async Task> PostReportCommand30([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand30([FromBody] ReportPersonAndCommandRequest req)
{
try
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -1985,7 +2098,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -2010,6 +2129,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
string? _null = null;
var resultData = (from p in data
join r in req.refIds
@@ -2055,12 +2179,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -2074,14 +2198,22 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command31/report")]
- public async Task> PostReportCommand31([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand31([FromBody] ReportPersonAndCommandRequest req)
{
try
{
var data = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ // data.ForEach(profile => profile.Status = req.status.Trim().ToUpper());
+ data.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -2108,7 +2240,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
// .Where(x => x.Status.ToUpper() == "REPORT")
.ToListAsync();
- data.ForEach(profile => profile.Status = "NEW");
+ // data.ForEach(profile => profile.Status = "NEW");
+ data.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
}
@@ -2133,6 +2271,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Include(x => x.DisciplineDisciplinary)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ await _context.SaveChangesAsync();
+
string? _null = null;
var resultData = (from p in data
join r in req.refIds
@@ -2178,12 +2321,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => { profile.Status = "NEW"; profile.CommandTypeId = null; });
+ //// await _context.SaveChangesAsync();
+ //// }
}
return Success();
}
@@ -2197,7 +2340,7 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
[HttpPost("command32/report")]
- public async Task> PostReportCommand32([FromBody] ReportPersonRequest req)
+ public async Task> PostReportCommand32([FromBody] ReportPersonAndCommandRequest req)
{
try
{
@@ -2210,7 +2353,15 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
.Where(x => req.refIds.Contains(x.Id.ToString()))
.ToListAsync();
- data2.ForEach(profile => profile.IsReport = req.status.Trim().ToUpper());
+ // data2.ForEach(profile => profile.IsReport = req.status.Trim().ToUpper());
+ data2.ForEach(profile =>
+ {
+ profile.Status = !string.IsNullOrEmpty(req.status)
+ ? req.status.Trim().ToUpper() : null;
+ profile.CommandTypeId = !string.IsNullOrEmpty(req.commandTypeId) && Guid.TryParse(req.commandTypeId, out var cmdTypeId)
+ ? cmdTypeId : null;
+ profile.CommandCode = req.commandCode ?? null;
+ });
await _context.SaveChangesAsync();
return Success();
@@ -2245,7 +2396,13 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
// .Where(x => x.IsReport == "REPORT")
.ToListAsync();
- data2.ForEach(profile => profile.IsReport = "NEW");
+ // data2.ForEach(profile => profile.IsReport = "NEW");
+ data2.ForEach(profile =>
+ {
+ profile.Status = "NEW";
+ profile.CommandTypeId = null;
+ profile.CommandCode = null;
+ });
await _context.SaveChangesAsync();
return Success();
@@ -2272,6 +2429,11 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
// .Where(x => x.IsReport == "REPORT")
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
+
+ // Task #224 ปรับให้เป็น process ที่ควรบันทึกตามลำดับ
+ data.ForEach(profile => profile.IsReport = "DONE");
+ await _context.SaveChangesAsync();
+
string? _null = null;
var resultData = (from p in data
join r in req.refIds
@@ -2317,12 +2479,12 @@ namespace BMA.EHR.DisciplineResult.Service.Controllers
{
data = resultData,
});
- var _result = await _res.Content.ReadAsStringAsync();
- if (_res.IsSuccessStatusCode)
- {
- data.ForEach(profile => profile.IsReport = "DONE");
- await _context.SaveChangesAsync();
- }
+ //// var _result = await _res.Content.ReadAsStringAsync();
+ //// if (_res.IsSuccessStatusCode)
+ //// {
+ //// data.ForEach(profile => profile.IsReport = "DONE");
+ //// await _context.SaveChangesAsync();
+ //// }
}
var data1 = await _context.DisciplineDisciplinary_ProfileComplaintInvestigates
diff --git a/BMA.EHR.Domain/Common/BaseController.cs b/BMA.EHR.Domain/Common/BaseController.cs
index 26f71bf5..0b382d95 100644
--- a/BMA.EHR.Domain/Common/BaseController.cs
+++ b/BMA.EHR.Domain/Common/BaseController.cs
@@ -95,6 +95,9 @@ namespace BMA.EHR.Domain.Common
protected Guid? ProfileId => User.GetProfileId();
protected string? Prefix => User.GetPrefix();
protected string? FullNameFromClaim => User.GetName();
+
+ protected string? FirstName => User.GetFirstName();
+ protected string? LastName => User.GetLastName();
#endregion
diff --git a/BMA.EHR.Domain/Extensions/ClaimsPrincipalExtensions.cs b/BMA.EHR.Domain/Extensions/ClaimsPrincipalExtensions.cs
index 26a7c189..cc44f8a1 100644
--- a/BMA.EHR.Domain/Extensions/ClaimsPrincipalExtensions.cs
+++ b/BMA.EHR.Domain/Extensions/ClaimsPrincipalExtensions.cs
@@ -26,5 +26,7 @@ namespace BMA.EHR.Domain.Extensions
public static Guid? GetProfileId(this ClaimsPrincipal user) => user.GetGuidClaim(BmaClaimTypes.ProfileId);
public static string? GetPrefix(this ClaimsPrincipal user) => user.GetClaimValue(BmaClaimTypes.Prefix);
public static string? GetName(this ClaimsPrincipal user) => user.GetClaimValue(BmaClaimTypes.Name);
+ public static string? GetFirstName(this ClaimsPrincipal user) => user.GetClaimValue(BmaClaimTypes.GivenName);
+ public static string? GetLastName(this ClaimsPrincipal user) => user.GetClaimValue(BmaClaimTypes.FamilyName);
}
}
diff --git a/BMA.EHR.Domain/Models/Leave/Requests/LeaveBeginning.cs b/BMA.EHR.Domain/Models/Leave/Requests/LeaveBeginning.cs
index 153b7d22..0bb9a1c1 100644
--- a/BMA.EHR.Domain/Models/Leave/Requests/LeaveBeginning.cs
+++ b/BMA.EHR.Domain/Models/Leave/Requests/LeaveBeginning.cs
@@ -27,11 +27,11 @@ namespace BMA.EHR.Domain.Models.Leave.Requests
[Required, Comment("จำนวนวันลาทั้งหมด")]
public double LeaveDays { get; set; } = 0.0;
- [Required, Comment("จำนวนวันลาที่ใช้ไป")]
- public double LeaveDaysUsed { get; set; } = 0.0;
+ [Comment("จำนวนวันลาที่ใช้ไป")]
+ public double? LeaveDaysUsed { get; set; } = 0.0;
[Comment("จำนวนครั้งที่ลาสะสม")]
- public int LeaveCount { get; set; } = 0;
+ public int? LeaveCount { get; set; } = 0;
public Guid? RootDnaId { get; set; }
diff --git a/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequest.cs b/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequest.cs
index 69088cbb..f6c9ce2d 100644
--- a/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequest.cs
+++ b/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequest.cs
@@ -210,5 +210,7 @@ namespace BMA.EHR.Domain.Models.Leave.Requests
public Guid? Child4DnaId { get; set; } = Guid.Empty;
+ public DateTime? DateSendLeave { get; set; }
+
}
}
diff --git a/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequestApprover.cs b/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequestApprover.cs
index f974d004..0a46c199 100644
--- a/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequestApprover.cs
+++ b/BMA.EHR.Domain/Models/Leave/Requests/LeaveRequestApprover.cs
@@ -38,5 +38,10 @@ namespace BMA.EHR.Domain.Models.Leave.Requests
public string Comment { get; set; } = string.Empty;
public string? ApproveType { get; set; } = string.Empty; // ผู้บังคับบัญชา = commander, ผู้มีอำนาจอนุมัติ = Approver
+
+
+ public bool IsAct { get; set; } = false;
+
+ public string KeyId { get; set; } = string.Empty;
}
}
diff --git a/BMA.EHR.Domain/Models/Placement/PlacementAppointment.cs b/BMA.EHR.Domain/Models/Placement/PlacementAppointment.cs
index 870a7817..474dcb69 100644
--- a/BMA.EHR.Domain/Models/Placement/PlacementAppointment.cs
+++ b/BMA.EHR.Domain/Models/Placement/PlacementAppointment.cs
@@ -119,6 +119,10 @@ namespace BMA.EHR.Domain.Models.Placement
public string? position { get; set; }
[Comment("ตำแหน่งทางการบริหาร")]
public string? PositionExecutive { get; set; }
+
+ [Comment("id ตำแหน่งทางการบริหาร")]
+ public string? posExecutiveId { get; set; }
+
[Comment("id ประเภทตำแหน่ง")]
public string? posTypeId { get; set; }
[Comment("ชื่อประเภทตำแหน่ง")]
diff --git a/BMA.EHR.Domain/Models/Placement/PlacementProfile.cs b/BMA.EHR.Domain/Models/Placement/PlacementProfile.cs
index 5a94e63b..c660c8ca 100644
--- a/BMA.EHR.Domain/Models/Placement/PlacementProfile.cs
+++ b/BMA.EHR.Domain/Models/Placement/PlacementProfile.cs
@@ -321,6 +321,10 @@ namespace BMA.EHR.Domain.Models.Placement
public string? positionName { get; set; }
[Comment("ตำแหน่งทางการบริหาร")]
public string? PositionExecutive { get; set; }
+
+ [Comment("id ตำแหน่งทางการบริหาร")]
+ public string? posExecutiveId { get; set; }
+
[Comment("สายงาน")]
public string? positionField { get; set; }
[Comment("id ประเภทตำแหน่ง")]
diff --git a/BMA.EHR.Domain/Models/Placement/PlacementReceive.cs b/BMA.EHR.Domain/Models/Placement/PlacementReceive.cs
index 9d366d19..3b1b625c 100644
--- a/BMA.EHR.Domain/Models/Placement/PlacementReceive.cs
+++ b/BMA.EHR.Domain/Models/Placement/PlacementReceive.cs
@@ -64,6 +64,10 @@ namespace BMA.EHR.Domain.Models.Placement
public string? profileId { get; set; }
[Comment("คำนำหน้า")]
public string? prefix { get; set; }
+
+ [Comment("ยศ")]
+ public string? rank { get; set; }
+
[Comment("ชื่อ")]
public string? firstName { get; set; }
[Comment("นามสกุล")]
@@ -128,6 +132,10 @@ namespace BMA.EHR.Domain.Models.Placement
public string? position { get; set; }
[Comment("ตำแหน่งทางการบริหาร")]
public string? PositionExecutive { get; set; }
+
+ [Comment("id ตำแหน่งทางการบริหาร")]
+ public string? posExecutiveId { get; set; }
+
[Comment("id ประเภทตำแหน่ง")]
public string? posTypeId { get; set; }
[Comment("ชื่อประเภทตำแหน่ง")]
diff --git a/BMA.EHR.Domain/Models/Retirement/RetirementOther.cs b/BMA.EHR.Domain/Models/Retirement/RetirementOther.cs
index b37e47aa..c1f69ece 100644
--- a/BMA.EHR.Domain/Models/Retirement/RetirementOther.cs
+++ b/BMA.EHR.Domain/Models/Retirement/RetirementOther.cs
@@ -173,6 +173,10 @@ namespace BMA.EHR.Domain.Models.Retirement
public string? position { get; set; }
[Comment("ตำแหน่งทางการบริหาร")]
public string? PositionExecutive { get; set; }
+
+ [Comment("id ตำแหน่งทางการบริหาร")]
+ public string? posExecutiveId { get; set; }
+
[Comment("id ประเภทตำแหน่ง")]
public string? posTypeId { get; set; }
[Comment("ชื่อประเภทตำแหน่ง")]
diff --git a/BMA.EHR.Domain/Shared/PrivilegeConverter.cs b/BMA.EHR.Domain/Shared/PrivilegeConverter.cs
new file mode 100644
index 00000000..59f8168c
--- /dev/null
+++ b/BMA.EHR.Domain/Shared/PrivilegeConverter.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace BMA.EHR.Domain.Shared
+{
+ public class PrivilegeConverter : JsonConverter
+{
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(string);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ {
+ return "EMPTY";
+ }
+ return reader.Value;
+ }
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ writer.WriteValue(value);
+ }
+}
+}
\ No newline at end of file
diff --git a/BMA.EHR.Infrastructure/Migrations/20260512073417_update_PlacementReceives_add_rank.Designer.cs b/BMA.EHR.Infrastructure/Migrations/20260512073417_update_PlacementReceives_add_rank.Designer.cs
new file mode 100644
index 00000000..b65f0774
--- /dev/null
+++ b/BMA.EHR.Infrastructure/Migrations/20260512073417_update_PlacementReceives_add_rank.Designer.cs
@@ -0,0 +1,21250 @@
+//
+using System;
+using BMA.EHR.Infrastructure.Persistence;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace BMA.EHR.Infrastructure.Migrations
+{
+ [DbContext(typeof(ApplicationDBContext))]
+ [Migration("20260512073417_update_PlacementReceives_add_rank")]
+ partial class update_PlacementReceives_add_rank
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "7.0.9")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.Command", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("ActEndDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("วันที่สิ้นสุดการรักษาการแทน");
+
+ b.Property("ActStartDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("วันที่เริ่มรักษาการแทน");
+
+ b.Property("AuthorizedPosition")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("ตำแหน่งผู้มีอำนาจลงนาม");
+
+ b.Property("AuthorizedUserFullName")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("ชื่อผู้มีอำนาจลงนาม");
+
+ b.Property("AuthorizedUserId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงผู้มีอำนาจลงนาม");
+
+ b.Property("CaseFault")
+ .HasColumnType("longtext")
+ .HasComment("กรณีความผิด");
+
+ b.Property("ChairManFullName")
+ .HasColumnType("longtext")
+ .HasComment("ประธานคณะกรรมการ");
+
+ b.Property("CommandAffectDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("วันที่คำสั่งมีผล");
+
+ b.Property("CommandExcecuteDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("วันที่ออกคำสั่ง");
+
+ b.Property("CommandNo")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)")
+ .HasComment("เลขที่คำสั่ง");
+
+ b.Property("CommandStatusId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงสถานะคำสั่ง");
+
+ b.Property("CommandSubject")
+ .IsRequired()
+ .HasMaxLength(500)
+ .HasColumnType("varchar(500)")
+ .HasComment("คำสั่งเรื่อง");
+
+ b.Property("CommandTypeId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงประเภทคำสั่ง");
+
+ b.Property("CommandYear")
+ .IsRequired()
+ .HasMaxLength(4)
+ .HasColumnType("varchar(4)")
+ .HasComment("ปีที่ออกคำสั่ง");
+
+ b.Property("ComplaintId")
+ .HasColumnType("char(36)")
+ .HasComment("Id เรื่องร้องเรียน");
+
+ b.Property("ConclusionFireDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (เรื่องการดำเนินการทางวินัย)");
+
+ b.Property("ConclusionFireNo")
+ .HasColumnType("longtext")
+ .HasComment("ครั้งที่ (เรื่องการดำเนินการทางวินัย)");
+
+ b.Property("ConclusionFireResolution")
+ .HasColumnType("longtext")
+ .HasComment("มติที่ประชุม (เรื่องการดำเนินการทางวินัย)");
+
+ b.Property("ConclusionMeetingDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("การประชุม ลงวันที่");
+
+ b.Property("ConclusionMeetingNo")
+ .HasColumnType("longtext")
+ .HasComment("การประชุม ครั้งที่");
+
+ b.Property("ConclusionReceiveDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (การรับโอน)");
+
+ b.Property("ConclusionReceiveNo")
+ .HasColumnType("longtext")
+ .HasComment("มติ กก. ครั้งที่ (การรับโอน)");
+
+ b.Property("ConclusionRegisterDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (เรื่อง รับสมัครสอบฯ)");
+
+ b.Property("ConclusionRegisterNo")
+ .HasColumnType("longtext")
+ .HasComment("มติ กก. ครั้งที่ (เรื่อง รับสมัครสอบฯ)");
+
+ b.Property("ConclusionResultDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (เรื่อง ผลการสอบแข่งขัน)");
+
+ b.Property("ConclusionResultNo")
+ .HasColumnType("longtext")
+ .HasComment("มติ กก. ครั้งที่ (เรื่อง ผลการสอบแข่งขัน)");
+
+ b.Property("ConclusionReturnDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (เรื่อง กลับเข้ารับราชการ)");
+
+ b.Property("ConclusionReturnNo")
+ .HasColumnType("longtext")
+ .HasComment("มติ กก. ครั้งที่ (เรื่อง กลับเข้ารับราชการ)");
+
+ b.Property("ConclusionTranferDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("การประชุม ลงวันที่");
+
+ b.Property("ConclusionTranferNo")
+ .HasColumnType("longtext")
+ .HasComment("การประชุม ครั้งที่");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("Fault")
+ .HasColumnType("longtext")
+ .HasComment("รายละเอียดการกระทำผิด");
+
+ b.Property("FaultLevel")
+ .HasColumnType("longtext")
+ .HasComment("ระดับความผิด");
+
+ b.Property("GovAidCommandDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (คำสั่งช่วยราชการ)");
+
+ b.Property("GovAidCommandNo")
+ .HasColumnType("longtext")
+ .HasComment("คำสั่งเลขที่ (คำสั่งช่วยราชการ)");
+
+ b.Property("GuiltyBasis")
+ .HasColumnType("longtext")
+ .HasComment("ฐานความผิด");
+
+ b.Property("IssuerOrganizationId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงหน่วยงานที่ออกคำสั่ง");
+
+ b.Property("IssuerOrganizationName")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("หน่วยงานที่ออกคำสั่ง");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.Property("Member1FullName")
+ .HasColumnType("longtext")
+ .HasComment("กรรมการคนที่ 1");
+
+ b.Property("Member2FullName")
+ .HasColumnType("longtext")
+ .HasComment("กรรมการคนที่ 2");
+
+ b.Property("MilitaryCommanDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("ลงวันที่ (ให้เข้ารับราชการทหาร)");
+
+ b.Property("MilitaryCommandNo")
+ .HasColumnType("longtext")
+ .HasComment("คำสั่งที่ (ให้เข้ารับราชการทหาร)");
+
+ b.Property("OwnerGovId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสส่วนราชการผู้ออกคำสั่ง");
+
+ b.Property("PlacementCommandDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("คำสั่งบรรจุลงวันที่");
+
+ b.Property("PlacementCommandIssuer")
+ .HasColumnType("longtext")
+ .HasComment("หน่วยงานที่ออกคำสั่งบรรจุ");
+
+ b.Property("PlacementCommandNo")
+ .HasColumnType("longtext")
+ .HasComment("เลขที่คำสั่งบรรจุ");
+
+ b.Property("PlacementId")
+ .HasColumnType("char(36)")
+ .HasComment("อ้างอิงรอบการสอบ");
+
+ b.Property("PlacementOrganizationName")
+ .HasColumnType("longtext")
+ .HasComment("สังกัดที่บรรจุ");
+
+ b.Property("PlacementPositionName")
+ .HasColumnType("longtext")
+ .HasComment("ตำแหน่งที่บรรจุ");
+
+ b.Property("PositionName")
+ .HasColumnType("longtext")
+ .HasComment("ตำแหน่งที่บรรจุ");
+
+ b.Property("ProbationEndDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("วันที่สิ้นสุดการทดลองปฏิบัติราชการ");
+
+ b.Property("ProbationStartDate")
+ .HasColumnType("datetime(6)")
+ .HasComment("วันที่เริ่มทดลองปฏิบัติราชการ");
+
+ b.Property("ReceiveOrganizationName")
+ .HasColumnType("longtext")
+ .HasComment("ส่วนราชการที่รับโอน");
+
+ b.Property("RefRaw")
+ .HasColumnType("longtext")
+ .HasComment("อ้างอิงมาตราตามกฏหมาย");
+
+ b.Property("Result")
+ .HasColumnType("longtext")
+ .HasComment("ผลดำเนินการพิจารณา");
+
+ b.Property("SalaryPeriod")
+ .HasColumnType("longtext")
+ .HasComment("รอบเงินเดือน");
+
+ b.Property("SalaryPeriodId")
+ .HasColumnType("char(36)")
+ .HasComment("Id เรื่องเงินเดือน");
+
+ b.Property("SourceOrganizationName")
+ .HasColumnType("longtext")
+ .HasComment("หน่วยงานต้นสังกัด ก่อนรับราชการทหาร");
+
+ b.Property("TransferOrganizationName")
+ .HasColumnType("longtext")
+ .HasComment("ส่วนราชการที่ให้โอน");
+
+ b.Property("Year")
+ .HasMaxLength(4)
+ .HasColumnType("varchar(4)")
+ .HasComment("ปีรอบเงินเดือน");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CommandStatusId");
+
+ b.HasIndex("CommandTypeId");
+
+ b.HasIndex("PlacementId");
+
+ b.ToTable("Commands");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.CommandDeployment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("CitizenId")
+ .IsRequired()
+ .HasMaxLength(13)
+ .HasColumnType("varchar(13)")
+ .HasComment("เลขประจำตัวประชาชน");
+
+ b.Property("CommandId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงคำสั่ง");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasComment("ชื่อ");
+
+ b.Property("IsSendInbox")
+ .HasColumnType("tinyint(1)")
+ .HasComment("ส่งกล่องข้อความหรือไม่?");
+
+ b.Property("IsSendMail")
+ .HasColumnType("tinyint(1)")
+ .HasComment("ส่งอีเมล์หรือไม่?");
+
+ b.Property("IsSendNotification")
+ .HasColumnType("tinyint(1)")
+ .HasComment("ส่งแจ้งเตือนหรือไม่?");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasComment("นามสกุล");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.Property("OrganizationName")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("ชื่อหน่วยงานของผู้รับสำเนาคำสั่ง");
+
+ b.Property("PositionName")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("ชื่อตำแหน่งของผู้รับสำเนาคำสั่ง");
+
+ b.Property("Prefix")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasComment("คำนำหน้านาม");
+
+ b.Property("ReceiveUserId")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("รหัสอ้างอิงผู้ใช้งานระบบ");
+
+ b.Property("Sequence")
+ .HasColumnType("int")
+ .HasComment("ลำดับ");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CommandId");
+
+ b.ToTable("CommandDeployments");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.CommandDocument", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("Category")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("ประเภทเอกสาร");
+
+ b.Property("CommandId")
+ .HasColumnType("char(36)");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("DocumentId")
+ .HasColumnType("char(36)");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CommandId");
+
+ b.HasIndex("DocumentId");
+
+ b.ToTable("CommandDocuments");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.CommandReceiver", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("Amount")
+ .HasColumnType("double")
+ .HasComment("เงินเดือน");
+
+ b.Property("BirthDate")
+ .HasMaxLength(40)
+ .HasColumnType("datetime(6)")
+ .HasComment("วันเกิด");
+
+ b.Property("CitizenId")
+ .IsRequired()
+ .HasMaxLength(13)
+ .HasColumnType("varchar(13)")
+ .HasComment("เลขประจำตัวประชาชน");
+
+ b.Property("CommandId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงคำสั่ง");
+
+ b.Property("Comment")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasComment("หมายเหตุ");
+
+ b.Property("Comment2")
+ .IsRequired()
+ .HasColumnType("text")
+ .HasComment("หมายเหตุแนวนอน");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("FirstName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasComment("ชื่อ");
+
+ b.Property("LastName")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasComment("นามสกุล");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.Property("MouthSalaryAmount")
+ .HasColumnType("double")
+ .HasComment("เงินค่าตอบแทนรายเดือน");
+
+ b.Property("Organization")
+ .HasColumnType("longtext")
+ .HasComment("ชื่อหน่วยงาน root");
+
+ b.Property("PositionLevel")
+ .HasColumnType("longtext")
+ .HasComment("ระดับ");
+
+ b.Property("PositionName")
+ .HasColumnType("longtext")
+ .HasComment("ตำแหน่ง");
+
+ b.Property("PositionNumber")
+ .HasColumnType("longtext")
+ .HasComment("เลขที่ตำแหน่ง");
+
+ b.Property("PositionSalaryAmount")
+ .HasColumnType("double")
+ .HasComment("เงินประจำตำแหน่ง");
+
+ b.Property("PositionType")
+ .HasColumnType("longtext")
+ .HasComment("ประเภท");
+
+ b.Property("Prefix")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasComment("คำนำหน้านาม");
+
+ b.Property("RefDisciplineId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงไปยังข้อมูลวินัย");
+
+ b.Property("RefPlacementProfileId")
+ .HasColumnType("char(36)")
+ .HasComment("รหัสอ้างอิงไปยังข้อมูลผู้บรรจุ");
+
+ b.Property("Sequence")
+ .HasColumnType("int")
+ .HasComment("ลำดับในบัญชีแนบท้าย");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CommandId");
+
+ b.ToTable("CommandReceivers");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.CommandStatus", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasComment("สถานะของคำสั่ง");
+
+ b.Property("Sequence")
+ .HasColumnType("int")
+ .HasComment("ลำดับการทำงาน");
+
+ b.HasKey("Id");
+
+ b.ToTable("CommandStatuses");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.CommandType", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("Category")
+ .IsRequired()
+ .HasMaxLength(100)
+ .HasColumnType("varchar(100)")
+ .HasComment("ประเภทคำสั่ง");
+
+ b.Property("CommandCode")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasComment("รหัสของประเภทคำสั่ง");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasComment("ชื่อคำสั่ง");
+
+ b.HasKey("Id");
+
+ b.ToTable("CommandTypes");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Commands.Core.DeploymentChannel", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)")
+ .HasColumnOrder(0)
+ .HasComment("PrimaryKey")
+ .HasAnnotation("Relational:JsonPropertyName", "id");
+
+ b.Property("CreatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(100)
+ .HasComment("สร้างข้อมูลเมื่อ");
+
+ b.Property("CreatedFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(104)
+ .HasComment("ชื่อ User ที่สร้างข้อมูล");
+
+ b.Property("CreatedUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(101)
+ .HasComment("User Id ที่สร้างข้อมูล");
+
+ b.Property("IsSendEmail")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("IsSendInbox")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LastUpdateFullName")
+ .IsRequired()
+ .HasMaxLength(200)
+ .HasColumnType("varchar(200)")
+ .HasColumnOrder(105)
+ .HasComment("ชื่อ User ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdateUserId")
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnOrder(103)
+ .HasComment("User Id ที่แก้ไขข้อมูลล่าสุด");
+
+ b.Property("LastUpdatedAt")
+ .HasColumnType("datetime(6)")
+ .HasColumnOrder(102)
+ .HasComment("แก้ไขข้อมูลล่าสุดเมื่อ");
+
+ b.HasKey("Id");
+
+ b.ToTable("DeploymentChannels");
+ });
+
+ modelBuilder.Entity("BMA.EHR.Domain.Models.Documents.Document", b =>
+ {
+ b.Property