From 71a4748d39bc29b1eb9cd6bf2f60520ba88654df Mon Sep 17 00:00:00 2001 From: harid Date: Fri, 29 May 2026 15:32:26 +0700 Subject: [PATCH] =?UTF-8?q?Job:=20=E0=B8=AD=E0=B8=B1=E0=B8=9E=E0=B9=80?= =?UTF-8?q?=E0=B8=94=E0=B8=97=E0=B8=AA=E0=B8=96=E0=B8=B2=E0=B8=99=E0=B8=B0?= =?UTF-8?q?=E0=B8=9C=E0=B8=B9=E0=B9=89=E0=B8=AA=E0=B8=AD=E0=B8=9A=E0=B8=9C?= =?UTF-8?q?=E0=B9=88=E0=B8=B2=E0=B8=99=E0=B8=97=E0=B8=B5=E0=B9=88=E0=B8=A5?= =?UTF-8?q?=E0=B8=B2=E0=B8=AD=E0=B8=AD=E0=B8=81=E0=B9=84=E0=B8=9B=E0=B9=81?= =?UTF-8?q?=E0=B8=A5=E0=B9=89=E0=B8=A7=E0=B9=81=E0=B8=95=E0=B9=88=E0=B8=A2?= =?UTF-8?q?=E0=B8=B1=E0=B8=87=E0=B9=84=E0=B8=A1=E0=B9=88=E0=B8=AA=E0=B9=88?= =?UTF-8?q?=E0=B8=87=E0=B9=84=E0=B8=9B=E0=B8=AD=E0=B8=AD=E0=B8=81=E0=B8=84?= =?UTF-8?q?=E0=B8=B3=E0=B8=AA=E0=B8=B1=E0=B9=88=E0=B8=87=20=E0=B8=97?= =?UTF-8?q?=E0=B8=B3=E0=B8=87=E0=B8=B2=E0=B8=99=E0=B8=97=E0=B8=B8=E0=B8=81?= =?UTF-8?q?=E0=B8=A7=E0=B8=B1=E0=B8=99=E0=B9=80=E0=B8=A7=E0=B8=A5=E0=B8=B2?= =?UTF-8?q?=2005:00=20=E0=B8=99.=20#2518?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/PlacementRepository.cs | 95 ++++++++++++++++++- BMA.EHR.Placement.Service/Program.cs | 3 + 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/BMA.EHR.Application/Repositories/PlacementRepository.cs b/BMA.EHR.Application/Repositories/PlacementRepository.cs index 49f1175c..82b71b79 100644 --- a/BMA.EHR.Application/Repositories/PlacementRepository.cs +++ b/BMA.EHR.Application/Repositories/PlacementRepository.cs @@ -2,6 +2,9 @@ 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 { @@ -11,15 +14,17 @@ namespace BMA.EHR.Application.Repositories 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 +81,94 @@ namespace BMA.EHR.Application.Repositories return data; } + /// + /// Job อัพเดทสถานะผู้สอบผ่านที่ลาออกไปแล้วแต่ยังไม่ส่งไปออกคำสั่ง + /// ทำงานทุกวันเวลา 05:00 น. + /// + public async Task UpdateStatusPlacementProfiles() + { + Console.WriteLine("[Job:UpdateStatusPlacementProfiles] === STARTED ==="); + + var officerProfileIds = await _dbContext.Set() + .Where(p => !string.IsNullOrEmpty(p.profileId) + && p.IsOfficer == true + && p.PlacementStatus != "DONE" + // && p.Id == Guid.Parse("08deb7de-3030-4d1b-8519-8148584949fc") + ) + .Select(p => p.profileId) + .ToListAsync(); + + if (!officerProfileIds.Any()) + { + Console.WriteLine("[Job:UpdateStatusPlacementProfiles] No profiles to process"); + return; + } + + Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] พบข้าราชการที่สอบผ่านทั้งหมด {officerProfileIds.Count} คน ที่ยังไม่ส่งไปออกคำสั่ง"); + + var apiUrl = $"{_configuration["API"]}/org/dotnet/check-isLeave"; + List leaveProfileIds = new(); + + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.Add("api-key", _configuration["API_KEY"]); + var payload = new + { + profileIds = officerProfileIds.Distinct().ToList() + }; + 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() + }); + + leaveProfileIds = responseObj.result ?? new(); + Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] พบ {leaveProfileIds.Count} รายการที่ลาออก"); + } + catch (Exception ex) + { + Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] Call API failed: {ex.Message}"); + return; + } + } + + if (leaveProfileIds.Any()) + { + var batchSize = 500; + var totalUpdated = 0; + var totalBatches = (int)Math.Ceiling((double)leaveProfileIds.Count / batchSize); + + for (int i = 0; i < totalBatches; i++) + { + var batch = leaveProfileIds.Skip(i * batchSize).Take(batchSize).ToList(); + + var profilesToUpdate = await _dbContext.Set() + .Where(p => !string.IsNullOrEmpty(p.profileId) && batch.Contains(p.profileId)) + .ToListAsync(); + + foreach (var profile in profilesToUpdate) + { + profile.IsOfficer = false; + } + + await _dbContext.SaveChangesAsync(); + + totalUpdated += profilesToUpdate.Count; + Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] Batch {i + 1}/{totalBatches} → อัปเดต {profilesToUpdate.Count} รายการ"); + } + Console.WriteLine($"[Job:UpdateStatusPlacementProfiles] อัปเดตรวมทั้งหมด {totalUpdated} รายการ → IsOfficer = false"); + } + Console.WriteLine("[Job:UpdateStatusPlacementProfiles] === COMPLETED ==="); + } + #endregion } } diff --git a/BMA.EHR.Placement.Service/Program.cs b/BMA.EHR.Placement.Service/Program.cs index f954f343..bd4eb6e8 100644 --- a/BMA.EHR.Placement.Service/Program.cs +++ b/BMA.EHR.Placement.Service/Program.cs @@ -21,6 +21,7 @@ using System.Text; using System.Transactions; using BMA.EHR.Placement.Service.Filters; using BMA.EHR.Application.Repositories.Reports; +using BMA.EHR.Application.Repositories; var builder = WebApplication.CreateBuilder(args); { @@ -164,6 +165,8 @@ var app = builder.Build(); if (manager != null) { manager.AddOrUpdate("แจ้งเตือนระบบทดลองงาน", Job.FromExpression(x => x.NotifyProbation()), Cron.Daily(Int32.Parse(builder.Configuration["KeycloakCron:Hour"]), Int32.Parse(builder.Configuration["KeycloakCron:Minute"])), TimeZoneInfo.Local); + // Job: อัพเดทสถานะผู้สอบผ่านที่ลาออกไปแล้วแต่ยังไม่ส่งไปออกคำสั่ง ทำงานทุกวันเวลา 05:00 น. + manager.AddOrUpdate("ประมวลผลข้าราชการฯ กทม.", Job.FromExpression(x => x.UpdateStatusPlacementProfiles()), Cron.Daily(5), TimeZoneInfo.Local); } // apply migrations