Merge branch 'develop'

This commit is contained in:
harid 2025-11-21 10:41:00 +07:00
commit 58d2160b76
12 changed files with 21362 additions and 22 deletions

View file

@ -5,6 +5,7 @@ using BMA.EHR.Domain.Shared;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using static BMA.EHR.Domain.Extensions.DateTimeExtension; using static BMA.EHR.Domain.Extensions.DateTimeExtension;
namespace BMA.EHR.Application.Repositories.Reports namespace BMA.EHR.Application.Repositories.Reports
@ -139,6 +140,22 @@ namespace BMA.EHR.Application.Repositories.Reports
ContactTel = p.ContactTel == null ? "-" : p.ContactTel, ContactTel = p.ContactTel == null ? "-" : p.ContactTel,
RegisterDate = p.RegisterDate == null ? "-" : p.RegisterDate.Value.ToThaiFullDate(), RegisterDate = p.RegisterDate == null ? "-" : p.RegisterDate.Value.ToThaiFullDate(),
IsBachelors = p.PositionExam != null && !string.IsNullOrEmpty(p.PositionExam.EducationLevel) && p.PositionExam.EducationLevel.Trim().ToUpper() == "BACHELOR"
? new List<object> {
$"ชื่อปริญญา {(p.Educations.FirstOrDefault() == null ? "-" : p.Educations.FirstOrDefault().EducationLevelExamName)}",
$"สาขาวิชา/วิชาเอก {(p.Educations.FirstOrDefault() == null ? "-" : p.Educations.FirstOrDefault().EducationMajor)}"
}
: new List<object> {
$"สาขาวิชา/วิชาเอก {(p.Educations.FirstOrDefault() == null ? "-" : p.Educations.FirstOrDefault().EducationMajor)}"
},
EditorConfirm = p.PeriodExam == null || p.PeriodExam.EditorConfirm == null
? "1. ข้าพเจ้าขอให้คำรับรองว่า ข้อความดังกล่าวข้างต้นเป็นจริงทุกประการ และข้าพเจ้ามีคุณสมบัติทั่วไปและไม่มีลักษณะต้องห้ามตามมาตรา 43 แห่งพระราชบัญญัติระเบียบข้าราชการกรุงเทพมหานครและบุคลากรกรุงเทพมหานคร พ.ศ. 2554 และมีคุณสมบัติเฉพาะสำหรับตำแหน่งที่สมัครตรงตามประกาศรับสมัคร\r\n"
+ "2. กรณีข้าพเจ้ามีลักษณะต้องห้าม ตามมาตรา 43 ข. แห่งพระราชบัญญัติระเบียบข้าราชการกรุงเทพมหานครและบุคลากรกรุงเทพมหานคร พ.ศ. 2554 และประสงค์จะยื่นคำขอยกเว้นเข้ารับราชการฯ ต่อสำนักงาน ก.ก. ตามระเบียบ ก.ก. ว่าด้วยการยกเว้นให้ผู้มีลักษณะต้องห้ามเข้ารับราชการเป็นข้าราชการกรุงเทพมหานคร พ.ศ. 2556 ตามมติ ก.ก. ครั้งที่ 7/2556 เมื่อวันที่ 15 สิงหาคม 2556 ข้าพเจ้าจะยื่นคำขอยกเว้นฯ ภายในวันปิดรับสมัคร ทั้งนี้ หากยื่นภายหลังกำหนด สำนักงาน ก.ก. จะไม่รับคำขอดังกล่าว\r\n"
+ "3. ข้าพเจ้าจะยื่นหลักฐานและเอกสารที่แสดงว่า เป็นผู้มีคุณสมบัติทั่วไปและมีคุณสมบัติเฉพาะสำหรับตำแหน่งที่สมัครตรงตามประกาศรับสมัครภายในระยะเวลาที่กำหนดตามประกาศฯ หากมีการตรวจสอบหลักฐานและเอกสาร และหรือคุณวุฒิการศึกษาของข้าพเจ้าในภายหลังปรากฏว่าข้าพเจ้ามีคุณสมบัติไม่ตรงหรือมีลักษณะต้องห้ามตามประกาศรับสมัครหรือไม่ได้รับการยกเว้น ให้ถือว่า ข้าพเจ้าเป็นผู้ขาดคุณสมบัติในการสมัครครั้งนี้มาตั้งแต่ต้น และไม่มีสิทธิได้รับการบรรจุและแต่งตั้งให้ดำรงตำแหน่ง และข้าพเจ้าจะไม่มีสิทธิเรียกร้องใดๆ ทั้งสิ้น และหากข้าพเจ้าจงใจกรอกข้อความอันเป็นเท็จ อาจมีความผิดทางอาญาฐานแจ้งความเท็จต่อเจ้าพนักงาน ตามประมวลกฎหมายอาญา มาตรา 137\r\n"
+ "4. ข้าพเจ้าได้ศึกษาและทำความเข้าใจพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 ตลอดจนประกาศและระเบียบที่เกี่ยวข้องโดยละเอียดครบถ้วนแล้ว ข้าพเจ้าขอแสดงความยินยอมให้หน่วยงานหรือบุคคลที่เกี่ยวข้องกับการดำเนินการสรรหา สามารถเก็บ รวบรวม ใช้ และเปิดเผยข้อมูลส่วนบุคคลที่เกี่ยวข้องกับข้าพเจ้า เพื่อประโยชน์ของทางราชการตามกฎหมายที่เกี่ยวข้อง\r\n"
+ "5. ข้าพเจ้ารับทราบว่า การส่งใบสมัครคัดเลือกฯ พร้อมเอกสารนี้ ยังไม่ได้รับการตรวจสอบคุณสมบัติตามหลักเกณฑ์ ประกาศรับสมัครคัดเลือก และเงื่อนไขต่างๆ โดยจะได้รับการตรวจสอบคุณสมบัติเมื่อเป็นผู้สอบผ่านข้อเขียนภาคความรู้ความสามารถที่ใช้เฉพาะตำแหน่งแล้วเท่านั้น"
: Regex.Replace(Regex.Match(p.PeriodExam.EditorConfirm, @"1\..*", RegexOptions.Singleline).Value,"<.*?>", string.Empty).Replace("&nbsp;", " ").Trim(),
}) })
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();
if (data == null) if (data == null)

View file

@ -1126,6 +1126,29 @@ namespace BMA.EHR.Application.Repositories
} }
public async Task PostInsigniaMessageToSocket(string message, string userId, string? accessToken)
{
try
{
var apiPath = $"{_configuration["API"]}/org/through-socket/notify";
var apiKey = _configuration["API_KEY"];
var body = new
{
message = message,
userId = userId
};
var apiResult = await PostExternalAPIBooleanAsync(apiPath, accessToken ?? "", body, apiKey);
}
catch
{
throw;
}
}
public async Task PostProfileEmpInsigniaAsync(PostProfileEmpInsigniaDto body, string? accessToken) public async Task PostProfileEmpInsigniaAsync(PostProfileEmpInsigniaDto body, string? accessToken)
{ {
try try

View file

@ -37,5 +37,11 @@ namespace BMA.EHR.Application.Responses.Organizations
public string? Child4 { get; set; } public string? Child4 { get; set; }
public string? Child4ShortName { get; set; } public string? Child4ShortName { get; set; }
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; }
} }
} }

View file

@ -15,5 +15,7 @@ namespace BMA.EHR.Domain.Models.Insignias
[Comment("Fk Table InsigniaManage")] [Comment("Fk Table InsigniaManage")]
public InsigniaManage InsigniaManage { get; set; } public InsigniaManage InsigniaManage { get; set; }
public virtual List<InsigniaManageProfile> InsigniaManageProfiles { get; set; } = new List<InsigniaManageProfile>(); public virtual List<InsigniaManageProfile> InsigniaManageProfiles { get; set; } = new List<InsigniaManageProfile>();
public Guid? RootDnaId { get; set; }
} }
} }

View file

@ -33,5 +33,8 @@ namespace BMA.EHR.Domain.ModelsExam.Candidate
[Comment("รหัสประจำตำแหน่งที่สอบ")] [Comment("รหัสประจำตำแหน่งที่สอบ")]
public string? Code { get; set; } public string? Code { get; set; }
[Comment("ขีดจำกัดวุฒิการศึกษา")]
public string? EducationLevel { get; set; }
} }
} }

View file

@ -16,11 +16,9 @@ namespace BMA.EHR.Infrastructure.MessageQueue
{ {
#region " Fields " #region " Fields "
private readonly UserProfileRepository _userProfileRepository;
private readonly InsigniaPeriodsRepository _insigniaPeriodsRepository;
private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHttpContextAccessor _httpContextAccessor;
private const string INSIGNIA_QUEUE = "bma_insignia_request"; private const string INSIGNIA_QUEUE = "bma_insignia_request";
private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
private IConnection _connection; private IConnection _connection;
@ -30,33 +28,29 @@ namespace BMA.EHR.Infrastructure.MessageQueue
#region " Constructor and Destructor " #region " Constructor and Destructor "
public RabbitMQConsumer(UserProfileRepository userProfileRepository, public RabbitMQConsumer(IHttpContextAccessor httpContextAccessor,
InsigniaPeriodsRepository insigniaPeriodsRepository,
IHttpContextAccessor httpContextAccessor,
IServiceScopeFactory serviceScopeFactory, IServiceScopeFactory serviceScopeFactory,
IConfiguration configuration) IConfiguration configuration)
{ {
_serviceScopeFactory = serviceScopeFactory; _serviceScopeFactory = serviceScopeFactory;
_configuration = configuration; _configuration = configuration;
_userProfileRepository = userProfileRepository;
_insigniaPeriodsRepository = insigniaPeriodsRepository;
_httpContextAccessor = httpContextAccessor; _httpContextAccessor = httpContextAccessor;
var host = _configuration["RabbitMQ:URL"]; var host = _configuration["RabbitMQ:URL"];
var userName = _configuration["RabbitMQ:UserName"]; var userName = _configuration["RabbitMQ:UserName"];
var password = _configuration["RabbitMQ:Password"]; var password = _configuration["RabbitMQ:Password"];
var factory = new ConnectionFactory() var factory = new ConnectionFactory()
{ {
HostName = host, HostName = host,
UserName = userName, UserName = userName,
Password = password Password = password
}; };
_connection = factory.CreateConnection(); _connection = factory.CreateConnection();
_channel = _connection.CreateModel(); _channel = _connection.CreateModel();
_channel.QueueDeclare(queue: INSIGNIA_QUEUE, durable: false, exclusive: false, autoDelete: false, arguments: null); _channel.QueueDeclare(queue: INSIGNIA_QUEUE, durable: false, exclusive: false, autoDelete: false, arguments: null);
} }
public override void Dispose() public override void Dispose()
@ -85,19 +79,19 @@ namespace BMA.EHR.Infrastructure.MessageQueue
var userRepo = scope.ServiceProvider.GetRequiredService<UserProfileRepository>(); var userRepo = scope.ServiceProvider.GetRequiredService<UserProfileRepository>();
var insigniaRepo = scope.ServiceProvider.GetRequiredService<InsigniaPeriodsRepository>(); var insigniaRepo = scope.ServiceProvider.GetRequiredService<InsigniaPeriodsRepository>();
var selectPeriod = await _insigniaPeriodsRepository.GetByIdAsync(periodId); var selectPeriod = await insigniaRepo.GetByIdAsync(periodId);
if (selectPeriod == null) if (selectPeriod == null)
{ {
throw new Exception(GlobalMessages.InsigniaPeriodNotFound); throw new Exception(GlobalMessages.InsigniaPeriodNotFound);
} }
var organizations = await userRepo.GetActiveRootAsync(AccessToken, selectPeriod.RevisionId); var organizations = await userRepo.GetActiveRootAsync(AccessToken, selectPeriod.RevisionId);
foreach (var organization in organizations) foreach (var organization in organizations)
{ {
if (organization == null) if (organization == null)
continue; continue;
var result = await insigniaRepo.GetInsigniaRequest(periodId, organization.Id); var result = await insigniaRepo.GetInsigniaRequest(periodId, organization.Id);
if (result != null) if (result != null)
{ {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace BMA.EHR.Infrastructure.Migrations
{
/// <inheritdoc />
public partial class AddrootdnatoInsigniaMagOrgTable : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "RootDnaId",
table: "InsigniaManageOrganiations",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "RootDnaId",
table: "InsigniaManageOrganiations");
}
}
}

View file

@ -5832,6 +5832,9 @@ namespace BMA.EHR.Infrastructure.Migrations
.HasColumnType("char(36)") .HasColumnType("char(36)")
.HasComment("รหัสหน่วยงาน"); .HasComment("รหัสหน่วยงาน");
b.Property<Guid?>("RootDnaId")
.HasColumnType("char(36)");
b.Property<int>("Total") b.Property<int>("Total")
.HasColumnType("int") .HasColumnType("int")
.HasComment("จำนวนทั้งหมด"); .HasComment("จำนวนทั้งหมด");

View file

@ -330,7 +330,10 @@ namespace BMA.EHR.Insignia.Service.Controllers
var total = insigniaManage.InsigniaManageOrganiations.Where(x => x.OrganizationId != req.OrganizationOrganizationId).Sum(x => x.Total); var total = insigniaManage.InsigniaManageOrganiations.Where(x => x.OrganizationId != req.OrganizationOrganizationId).Sum(x => x.Total);
if (req.Total + total > insigniaManage.Total) if (req.Total + total > insigniaManage.Total)
return Error(GlobalMessages.InsigniaManageOrgLimit); return Error(GlobalMessages.InsigniaManageOrgLimit);
var root = _userProfileRepository.GetOc(req.OrganizationOrganizationId, 0, AccessToken)?.Root ?? null;
var ocData = _userProfileRepository.GetOc(req.OrganizationOrganizationId, 0, AccessToken);
var root = ocData?.Root ?? null;
var rootDnaId = ocData?.RootDnaId ?? null;
await _context.InsigniaManageOrganiations.AddAsync( await _context.InsigniaManageOrganiations.AddAsync(
new InsigniaManageOrganiation new InsigniaManageOrganiation
{ {
@ -344,6 +347,7 @@ namespace BMA.EHR.Insignia.Service.Controllers
LastUpdateFullName = FullName ?? "System Administrator", LastUpdateFullName = FullName ?? "System Administrator",
LastUpdateUserId = UserId ?? "", LastUpdateUserId = UserId ?? "",
LastUpdatedAt = DateTime.Now, LastUpdatedAt = DateTime.Now,
RootDnaId = rootDnaId
}); });
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
@ -791,7 +795,7 @@ namespace BMA.EHR.Insignia.Service.Controllers
var insigniaManageOrganiation = await _context.InsigniaManageOrganiations.AsQueryable() var insigniaManageOrganiation = await _context.InsigniaManageOrganiations.AsQueryable()
.Include(x => x.InsigniaManageProfiles) .Include(x => x.InsigniaManageProfiles)
.FirstOrDefaultAsync(x => x.OrganizationId == insigniaNoteProfile.RootId && x.InsigniaManage.Id == insigniaManage.Id); // แก้เป็นหาจากหน่วยงานยืมเพิม manage id .FirstOrDefaultAsync(x => x.RootDnaId == insigniaNoteProfile.RootDnaId && x.InsigniaManage.Id == insigniaManage.Id); // แก้เป็นหาจากหน่วยงานยืมเพิม manage id
if (insigniaManageOrganiation == null) if (insigniaManageOrganiation == null)
return Error(GlobalMessages.InsigniaManageOrgNotFound); return Error(GlobalMessages.InsigniaManageOrgNotFound);

View file

@ -1,4 +1,5 @@
using BMA.EHR.Insignia.Service.Configuration; using BMA.EHR.Application.Repositories;
using BMA.EHR.Insignia.Service.Configuration;
using SocketIOClient; using SocketIOClient;
using System.Security.Claims; using System.Security.Claims;
@ -9,16 +10,17 @@ public class InsigniaRequestProcessService : BackgroundService
{ {
private readonly IBackgroundTaskQueue _queue; private readonly IBackgroundTaskQueue _queue;
private readonly IHttpContextAccessor _httpContextAccessor; private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IServiceScopeFactory _serviceScopeFactory;
public InsigniaRequestProcessService( public InsigniaRequestProcessService(
IBackgroundTaskQueue queue, IBackgroundTaskQueue queue,
IHttpContextAccessor httpContextAccessor) IHttpContextAccessor httpContextAccessor,
IServiceScopeFactory serviceScopeFactory)
{ {
_queue = queue; _queue = queue;
_httpContextAccessor = httpContextAccessor; _httpContextAccessor = httpContextAccessor;
_serviceScopeFactory = serviceScopeFactory;
} }
#region " Properties " #region " Properties "
@ -93,6 +95,14 @@ public class InsigniaRequestProcessService : BackgroundService
var endTime = DateTime.Now; var endTime = DateTime.Now;
var duration = endTime - startTime; var duration = endTime - startTime;
// Resolve repository from a scope because DbContext is scoped/transient.
using var scope = _serviceScopeFactory.CreateScope();
var userProfileRepository = (UserProfileRepository)scope.ServiceProvider.GetService(typeof(UserProfileRepository));
if (userProfileRepository != null)
{
await userProfileRepository.PostInsigniaMessageToSocket("Task completed", UserId ?? "", AccessToken);
}
} }
} }
catch (OperationCanceledException) catch (OperationCanceledException)

View file

@ -3540,6 +3540,8 @@ namespace BMA.EHR.Placement.Service.Controllers
RegisterDate = candidate.GetType().GetProperty("RegisterDate").GetValue(candidate), RegisterDate = candidate.GetType().GetProperty("RegisterDate").GetValue(candidate),
Url = picContent ?? "https://bma-ehr.frappet.synology.me/assets/avatar_user-89f22423.jpg", Url = picContent ?? "https://bma-ehr.frappet.synology.me/assets/avatar_user-89f22423.jpg",
Careers = careers, Careers = careers,
IsBachelors = candidate.GetType().GetProperty("IsBachelors").GetValue(candidate),
EditorConfirm = candidate.GetType().GetProperty("EditorConfirm").GetValue(candidate)
}; };
var data = new var data = new