diff --git a/Controllers/DisableController.cs b/Controllers/DisableController.cs
index ea0477b..8ff0ff8 100644
--- a/Controllers/DisableController.cs
+++ b/Controllers/DisableController.cs
@@ -27,6 +27,7 @@ using System.Text;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System.Net.Http.Headers;
+using BMA.EHR.Recurit.Exam.Service.Request;
namespace BMA.EHR.Recurit.Exam.Service.Controllers
{
@@ -2098,7 +2099,7 @@ namespace BMA.EHR.Recurit.Exam.Service.Controllers
// 3️. ดึงสรุปคะแนน
// ---------------------------
dynamic header = null;
- int _count = await _context.Disables.Where(x=> x.PeriodExam.Id == id).CountAsync();
+ int _count = await _context.Disables.Where(x => x.PeriodExam.Id == id).CountAsync();
if (data.Count > 0)
{
header = await _context.DisableScores
@@ -2432,15 +2433,15 @@ namespace BMA.EHR.Recurit.Exam.Service.Controllers
/// เมื่อโอนคนสรรหาไปบรรจุสำเร็จ
/// ไม่ได้ Login เข้าระบบ
/// เมื่อเกิดข้อผิดพลาดในการทำงาน
- [HttpGet("placement/{examId:length(36)}")]
+ [HttpPost("placement/{examId:length(36)}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
- public async Task> UpdateAsyncDisableToPlacement(Guid examId)
+ public async Task> UpdateAsyncDisableToPlacement(Guid examId, [FromBody] RecruitDateRequest req)
{
try
{
- await _periodExamService.UpdateAsyncDisableToPlacement(examId);
+ await _periodExamService.UpdateAsyncDisableToPlacement(examId, req.AccountStartDate);
return Success();
}
catch (Exception ex)
diff --git a/Models/EducationLevel.cs b/Models/EducationLevel.cs
index 55f249e..c33cf6c 100644
--- a/Models/EducationLevel.cs
+++ b/Models/EducationLevel.cs
@@ -6,8 +6,8 @@ namespace BMA.EHR.Recurit.Exam.Service.Models
{
public class EducationLevel : EntityBase
{
- [Required, MaxLength(100), Column(Order = 1), Comment("ระดับการศึกษา")]
- public string name { get; set; } = string.Empty;
+ [MaxLength(255), Column(Order = 1), Comment("ระดับการศึกษา")]
+ public string? name { get; set; } = null;
// [Column(Order = 2), Comment("สถานะการใช้งาน")]
// public bool IsActive { get; set; } = true;
diff --git a/Models/SubDistrict.cs b/Models/SubDistrict.cs
index 71688a1..0610c37 100644
--- a/Models/SubDistrict.cs
+++ b/Models/SubDistrict.cs
@@ -6,11 +6,11 @@ namespace BMA.EHR.Recurit.Exam.Service.Models
{
public class SubDistrict : EntityBase
{
- [Required, MaxLength(150), Column(Order = 1), Comment("เขต/อำเภอ")]
- public string name { get; set; } = string.Empty;
+ [MaxLength(255), Column(Order = 1), Comment("แขวง")]
+ public string? name { get; set; } = null;
- [Required, MaxLength(10), Column(Order = 2), Comment("รหัสไปรษณีย์")]
- public string zipCode { get; set; } = string.Empty;
+ [MaxLength(10), Column(Order = 2), Comment("รหัสไปรษณีย์")]
+ public string? zipCode { get; set; } = null;
// [Column(Order = 3), Comment("สถานะการใช้งาน")]
// public bool IsActive { get; set; } = true;
diff --git a/Request/RecruitDateRequest.cs b/Request/RecruitDateRequest.cs
new file mode 100644
index 0000000..b5eaee7
--- /dev/null
+++ b/Request/RecruitDateRequest.cs
@@ -0,0 +1,9 @@
+using System.Net;
+
+namespace BMA.EHR.Recurit.Exam.Service.Request
+{
+ public class RecruitDateRequest
+ {
+ public DateTime AccountStartDate { get; set; }
+ }
+}
diff --git a/Request/RecruitPosTypeRequest.cs b/Request/RecruitPosTypeRequest.cs
new file mode 100644
index 0000000..ffd4e7a
--- /dev/null
+++ b/Request/RecruitPosTypeRequest.cs
@@ -0,0 +1,18 @@
+using System.Net;
+
+namespace BMA.EHR.Recurit.Exam.Service.Request
+{
+ public class RecruitPosRequest
+ {
+ public List result { get; set; } = new();
+ }
+ public class RecruitPosLevelRequest
+ {
+ public string posLevelName { get; set; }
+ public RecruitPosTypeRequest posTypes { get; set; } = new();
+ }
+ public class RecruitPosTypeRequest
+ {
+ public string posTypeName { get; set; }
+ }
+}
diff --git a/Services/PeriodExamService.cs b/Services/PeriodExamService.cs
index fc0d0d3..d206a1f 100644
--- a/Services/PeriodExamService.cs
+++ b/Services/PeriodExamService.cs
@@ -2999,213 +2999,291 @@ namespace BMA.EHR.Recurit.Exam.Service.Services
await _contextMetadata.SaveChangesAsync();
}
- public async Task UpdateAsyncDisableToPlacement(Guid examId)
+ public async Task UpdateAsyncDisableToPlacement(Guid examId, DateTime accountStartDate)
{
- var periodExam = await _context.PeriodExams.AsQueryable()
- .Where(x => x.CheckDisability == true)
- .FirstOrDefaultAsync(x => x.Id == examId);
-
- if (periodExam == null)
- throw new Exception(GlobalMessages.ExamNotFound);
-
- var _placement = await _contextMetadata.Placements.AsQueryable()
- .FirstOrDefaultAsync(x => x.PlacementType.Name == "คัดเลือกคนพิการ" && x.RefId == periodExam.Id);
- if (_placement != null)
- throw new Exception("รอบการสอบนี้ได้ทำการบรรจุไปแล้ว");
-
- var placement = new Placement
+ try
{
- Name = periodExam.Name,
- RefId = periodExam.Id,
- Round = periodExam.Round == null ? "" : periodExam.Round.ToString(),
- Year = (int)(periodExam.Year == null ? 0 : periodExam.Year),
- Number = await _context.Disables.AsQueryable().Where(x => x.PeriodExam == periodExam).CountAsync(),
- PlacementType = await _contextMetadata.PlacementTypes.FirstOrDefaultAsync(x => x.Name.Trim().ToUpper().Contains("คัดเลือกคนพิการ")) == null ? await _contextMetadata.PlacementTypes.FirstOrDefaultAsync() : await _contextMetadata.PlacementTypes.FirstOrDefaultAsync(x => x.Name.Trim().ToUpper().Contains("คัดเลือกคนพิการ")),
- StartDate = DateTime.Now,
- EndDate = DateTime.Now.AddYears(2).AddDays(-1),
- CreatedAt = DateTime.Now,
- CreatedUserId = UserId ?? "",
- CreatedFullName = FullName ?? "",
- LastUpdatedAt = DateTime.Now,
- LastUpdateUserId = UserId ?? "",
- LastUpdateFullName = FullName ?? "",
- };
- await _contextMetadata.Placements.AddAsync(placement);
- var candidates = await _context.Disables.AsQueryable()
- .Include(x => x.Addresses)
- .Include(x => x.Certificates)
- .Include(x => x.Educations)
- .Include(x => x.Occupations)
- .Where(x => x.PeriodExam == periodExam)
- .ToListAsync();
- foreach (var candidate in candidates)
- {
- var IsOfficer = false;
- dynamic org = null;
- var apiUrl = $"{_configuration["API"]}/org/profile/citizenid/position/{candidate.CitizenId}";
- using (var client = new HttpClient())
+ // 🚀 Prepare HTTP client once
+ var httpClient1 = new HttpClient();
+ httpClient1.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token?.Replace("Bearer ", ""));
+ httpClient1.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
+ var apiUrl1 = $"{_configuration["API"]}/org/pos/level";
+ var response1 = await httpClient1.GetStringAsync(apiUrl1);
+ var posOptions = JsonConvert.DeserializeObject(response1);
+
+ var periodExam = await _context.PeriodExams.AsQueryable()
+ .Where(x => x.CheckDisability == true)
+ .FirstOrDefaultAsync(x => x.Id == examId);
+
+ if (periodExam == null)
+ throw new Exception(GlobalMessages.ExamNotFound);
+
+ var _placement = await _contextMetadata.Placements.AsQueryable()
+ .FirstOrDefaultAsync(x => x.PlacementType.Name == "คัดเลือกคนพิการ" && x.RefId == periodExam.Id);
+ if (_placement != null)
+ throw new Exception("รอบการสอบนี้ได้ทำการบรรจุไปแล้ว");
+
+ // 🚀 Pre-load all lookup data once
+ var placementTypesCache = await _contextMetadata.PlacementTypes.ToListAsync();
+ var provincesCache = await _contextOrg.province.ToListAsync();
+ var districtsCache = await _contextOrg.district.ToListAsync();
+ var subDistrictsCache = await _contextOrg.subDistrict.ToListAsync();
+ var educationLevelsCache = await _contextOrg.educationLevel.ToListAsync();
+
+ var placement = new Placement
{
- client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", ""));
- client.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
- var _req = new HttpRequestMessage(HttpMethod.Get, apiUrl);
- var _res = await client.SendAsync(_req);
- var _result = await _res.Content.ReadAsStringAsync();
+ Name = periodExam.Name,
+ RefId = periodExam.Id,
+ Round = periodExam.Round?.ToString() ?? "",
+ Year = (int)(periodExam.Year ?? 0),
+ Number = await _context.Disables.AsQueryable().Where(x => x.PeriodExam == periodExam).CountAsync(),
+ PlacementType = placementTypesCache.FirstOrDefault(x => x.Name.Trim().ToUpper().Contains("คัดเลือกคนพิการ")) ?? placementTypesCache.First(),
+ StartDate = accountStartDate,
+ EndDate = accountStartDate.AddYears(2).AddDays(-1),
+ CreatedAt = DateTime.Now,
+ CreatedUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "",
+ LastUpdatedAt = DateTime.Now,
+ LastUpdateUserId = UserId ?? "",
+ LastUpdateFullName = FullName ?? "",
+ };
+ await _contextMetadata.Placements.AddAsync(placement);
- org = JsonConvert.DeserializeObject(_result);
+ // 🚀 Load all related data with single queries
+ var candidates = await _context.Disables.AsQueryable()
+ .Include(x => x.Addresses)
+ .Include(x => x.Certificates)
+ .Include(x => x.Educations)
+ .Include(x => x.Occupations)
+ .Where(x => x.PeriodExam == periodExam)
+ .ToListAsync();
- if (org == null || org.result == null)
- {
- IsOfficer = false;
- }
- else
- {
- IsOfficer = true;
- }
- }
- var Address = candidate.Addresses.FirstOrDefault() == null ? null : $"{candidate.Addresses.FirstOrDefault().Address}";
- var Moo = candidate.Addresses.FirstOrDefault() == null ? null : $" หมู่ {candidate.Addresses.FirstOrDefault().Moo}";
- var Soi = candidate.Addresses.FirstOrDefault() == null ? null : $" ซอย {candidate.Addresses.FirstOrDefault().Soi}";
- var Road = candidate.Addresses.FirstOrDefault() == null ? null : $" ถนน {candidate.Addresses.FirstOrDefault().Road}";
- var Address1 = candidate.Addresses.FirstOrDefault() == null ? null : $"{candidate.Addresses.FirstOrDefault().Address1}";
- var Moo1 = candidate.Addresses.FirstOrDefault() == null ? null : $" หมู่ {candidate.Addresses.FirstOrDefault().Moo1}";
- var Soi1 = candidate.Addresses.FirstOrDefault() == null ? null : $" ซอย {candidate.Addresses.FirstOrDefault().Soi1}";
- var Road1 = candidate.Addresses.FirstOrDefault() == null ? null : $" ถนน {candidate.Addresses.FirstOrDefault().Road1}";
var scoreImport = await _context.ScoreImports.AsQueryable()
.FirstOrDefaultAsync(x => x.PeriodExam == periodExam);
- var disableScore = await _context.DisableScores.AsQueryable()
- .Where(x => x.ScoreImport == scoreImport)
- .Where(x => x.ExamId == candidate.ExamId)
- .Where(x => x.ExamStatus == "ผ่าน")
- .FirstOrDefaultAsync(x => x.ExamId == candidate.ExamId && x.ScoreImport == scoreImport);
- if (disableScore == null)
- continue;
- var placementProfile = new PlacementProfile
+
+ var disableScores = await _context.DisableScores.AsQueryable()
+ .Where(x => x.ScoreImport == scoreImport && x.ExamStatus == "ผ่าน")
+ .ToListAsync();
+
+ var disableScoresDict = disableScores
+ .Where(x => !string.IsNullOrWhiteSpace(x.ExamId))
+ .ToDictionary(x => x.ExamId, x => x);
+
+ // 🚀 Prepare HTTP client once
+ var httpClient = new HttpClient();
+ httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token?.Replace("Bearer ", ""));
+ httpClient.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"]);
+
+ // 🚀 Batch HTTP requests
+ var orgTasks = candidates.Select(async candidate =>
{
- Placement = placement,
- PositionCandidate = candidate.PositionName,
- PositionType = candidate.PositionType,
- PositionLevel = candidate.PositionLevel,
- Prefix = candidate.Prefix,
- Firstname = candidate.FirstName,
- Lastname = candidate.LastName,
- Gender = candidate.Gendor,
- Nationality = candidate.National,
- Race = candidate.Race,
- Religion = candidate.Religion,
- DateOfBirth = candidate.DateOfBirth,
- Relationship = candidate.Marry,
- CitizenId = candidate.CitizenId,
- CitizenProvinceId = _contextOrg.province.FirstOrDefault(x => x.name == candidate.CitizenCardIssuer)?.Id ?? null,
- CitizenDate = candidate.CitizenCardExpireDate,
- Telephone = candidate?.Addresses?.FirstOrDefault()?.Telephone ?? null,
- MobilePhone = candidate?.Addresses?.FirstOrDefault()?.Mobile ?? null,
- RegistAddress = $"{Address}{Moo}{Soi}{Road}",
- RegistProvinceId = _contextOrg.province.FirstOrDefault(x => x.name == (candidate!.Addresses!.FirstOrDefault()!.Province ?? ""))?.Id ?? null,
- RegistDistrictId = _contextOrg.district.FirstOrDefault(x => x.name == (candidate!.Addresses!.FirstOrDefault()!.District ?? ""))?.Id ?? null,
- RegistSubDistrictId = _contextOrg.subDistrict.FirstOrDefault(x => x.name == (candidate!.Addresses!.FirstOrDefault()!.Soi ?? ""))?.Id ?? null,
- RegistZipCode = candidate?.Addresses?.FirstOrDefault()?.ZipCode ?? null,
- RegistSame = false,
- CurrentAddress = $"{Address1}{Moo1}{Soi1}{Road1}",
- CurrentProvinceId = _contextOrg.province.FirstOrDefault(x => x.name == (candidate!.Addresses!.FirstOrDefault()!.Province1 ?? ""))?.Id ?? null,
- CurrentDistrictId = _contextOrg.district.FirstOrDefault(x => x.name == (candidate!.Addresses!.FirstOrDefault()!.District1 ?? ""))?.Id ?? null,
- CurrentSubDistrictId = _contextOrg.subDistrict.FirstOrDefault(x => x.name == (candidate!.Addresses!.FirstOrDefault()!.Soi1 ?? ""))?.Id ?? null,
- CurrentZipCode = candidate?.Addresses?.FirstOrDefault()?.ZipCode1 ?? null,
- Marry = candidate?.Marry?.Contains("สมรส") ?? false,
+ if (string.IsNullOrWhiteSpace(candidate.CitizenId))
+ return new { CitizenId = candidate.CitizenId ?? "", org = (dynamic?)null };
- OccupationPositionType = "other",
- OccupationTelephone = candidate?.Occupations?.FirstOrDefault()?.Telephone ?? null,
- OccupationPosition = candidate?.Occupations?.FirstOrDefault()?.Position ?? null,
+ var apiUrl = $"{_configuration["API"]}/org/profile/citizenid/position/{candidate.CitizenId}";
+ try
+ {
+ var response = await httpClient.GetStringAsync(apiUrl);
+ return new { CitizenId = candidate.CitizenId, org = JsonConvert.DeserializeObject(response) };
+ }
+ catch
+ {
+ return new { CitizenId = candidate.CitizenId ?? "", org = (dynamic?)null };
+ }
+ }).ToList();
- PointTotalA = disableScore == null ? null : Convert.ToDouble(disableScore.FullA),
- PointA = disableScore == null ? null : Convert.ToDouble(disableScore.SumA),
- PointTotalB = disableScore == null ? null : Convert.ToDouble(disableScore.FullB),
- PointB = disableScore == null ? null : Convert.ToDouble(disableScore.SumB),
- PointTotalC = disableScore == null ? null : Convert.ToDouble(disableScore.FullC),
- PointC = disableScore == null ? null : Convert.ToDouble(disableScore.SumC),
- ExamNumber = disableScore == null || int.TryParse(disableScore.Number, out int n) == false ? null : Convert.ToInt32(disableScore.Number),
- ExamRound = null,
- IsRelief = false,
- PlacementStatus = "UN-CONTAIN",
- Pass = disableScore == null ? null : disableScore.ExamStatus,
- RemarkHorizontal = "โดยมีเงื่อนไขว่าต้องปฏิบัติงานให้กรุงเทพมหานครเป็นระยะเวลาไม่น้อยกว่า ๕ ปี นับแต่วันที่ได้รับการบรรจุและแต่งตั้ง โดยห้ามโอนไปหน่วยงานหรือส่วนราชการอื่น เว้นเเต่ลาออกจากราชการ",
- Amount = org?.result?.amount ?? null,
- PositionSalaryAmount = org?.result?.positionSalaryAmount ?? null,
- MouthSalaryAmount = org?.result?.mouthSalaryAmount ?? null,
- CreatedAt = DateTime.Now,
- CreatedUserId = UserId ?? "",
- CreatedFullName = FullName ?? "",
- LastUpdatedAt = DateTime.Now,
- LastUpdateUserId = UserId ?? "",
- LastUpdateFullName = FullName ?? "",
- IsOfficer = IsOfficer,
- profileId = org?.result?.profileId ?? null,
- IsOld = org == null || org.result == null ? false : true,
- AmountOld = org?.result?.AmountOld ?? null,
- nodeOld = org?.result?.node ?? null,
- nodeIdOld = org?.result?.nodeId ?? null,
- posmasterIdOld = org?.result?.posmasterId ?? null,
- rootOld = org?.result?.root ?? null,
- rootIdOld = org?.result?.rootId ?? null,
- rootShortNameOld = org?.result?.rootShortName ?? null,
- child1Old = org?.result?.child1 ?? null,
- child1IdOld = org?.result?.child1Id ?? null,
- child1ShortNameOld = org?.result?.child1ShortName ?? null,
- child2Old = org?.result?.child2 ?? null,
- child2IdOld = org?.result?.child2Id ?? null,
- child2ShortNameOld = org?.result?.child2ShortName ?? null,
- child3Old = org?.result?.child3 ?? null,
- child3IdOld = org?.result?.child3Id ?? null,
- child3ShortNameOld = org?.result?.child3ShortName ?? null,
- child4Old = org?.result?.child4 ?? null,
- child4IdOld = org?.result?.child4Id ?? null,
- child4ShortNameOld = org?.result?.child4ShortName ?? null,
- orgRevisionIdOld = org?.result?.orgRevisionId ?? null,
- posMasterNoOld = org?.result?.posMasterNo ?? null,
- positionNameOld = org?.result?.position ?? null,
- posTypeIdOld = org?.result?.posTypeId ?? null,
- posTypeNameOld = org?.result?.posTypeName ?? null,
- posLevelIdOld = org?.result?.posLevelId ?? null,
- posLevelNameOld = org?.result?.posLevelName ?? null,
- };
- await _contextMetadata.PlacementProfiles.AddAsync(placementProfile);
+ var orgResults = await Task.WhenAll(orgTasks);
+ var orgDict = orgResults.ToDictionary(x => x.CitizenId ?? "", x => x.org);
- var placementEducation = new PlacementEducation
+ // 🚀 Prepare batch inserts
+ var placementProfiles = new List();
+ var placementEducations = new List();
+ var placementCertificates = new List();
+
+ foreach (var candidate in candidates)
{
- PlacementProfile = placementProfile,
- EducationLevelId = _contextOrg.educationLevel.FirstOrDefault(x => x.name == (candidate!.Educations!.FirstOrDefault()!.HighDegree ?? ""))?.Id ?? null,
- EducationLevelName = _contextOrg.educationLevel.FirstOrDefault(x => x.name == (candidate!.Educations!.FirstOrDefault()!.HighDegree ?? ""))?.name ?? null,
- Field = candidate?.Educations?.FirstOrDefault()?.Major ?? null,
- Gpa = candidate?.Educations?.FirstOrDefault()?.GPA!.ToString() ?? null,
- Institute = candidate?.Educations?.FirstOrDefault()?.University ?? null,
- Degree = candidate?.Educations?.FirstOrDefault()?.Degree ?? null,
- FinishDate = candidate?.Educations?.FirstOrDefault()?.BachelorDate ?? null,
- IsDate = true,
- CreatedAt = DateTime.Now,
- CreatedUserId = UserId ?? "",
- LastUpdatedAt = DateTime.Now,
- LastUpdateUserId = UserId ?? "",
- CreatedFullName = FullName ?? "",
- LastUpdateFullName = FullName ?? "",
- };
- await _contextMetadata.PlacementEducations.AddAsync(placementEducation);
+ if (string.IsNullOrWhiteSpace(candidate.ExamId) ||
+ !disableScoresDict.TryGetValue(candidate.ExamId, out var disableScore))
+ continue;
- var placementCertificate = new PlacementCertificate
- {
- PlacementProfile = placementProfile,
- CertificateNo = candidate?.Certificates?.FirstOrDefault()?.CertificateNo ?? null,
- IssueDate = candidate?.Certificates?.FirstOrDefault()?.IssueDate ?? null,
- ExpireDate = candidate?.Certificates?.FirstOrDefault()?.ExpiredDate ?? null,
- CertificateType = candidate?.Certificates?.FirstOrDefault()?.Description ?? null,
- CreatedAt = DateTime.Now,
- CreatedUserId = UserId ?? "",
- LastUpdatedAt = DateTime.Now,
- LastUpdateUserId = UserId ?? "",
- CreatedFullName = FullName ?? "",
- LastUpdateFullName = FullName ?? "",
- };
- await _contextMetadata.PlacementCertificates.AddAsync(placementCertificate);
+ var org = orgDict.TryGetValue(candidate.CitizenId ?? "", out var orgValue) ? orgValue : null;
+ var isOfficer = org?.result != null;
+
+ // 🚀 Cache repeated calculations
+ var firstAddress = candidate.Addresses?.FirstOrDefault();
+ var firstEducation = candidate.Educations?.FirstOrDefault();
+ var firstCertificate = candidate.Certificates?.FirstOrDefault();
+ var firstOccupation = candidate.Occupations?.FirstOrDefault();
+
+ var registAddress = string.Join("", new[] {
+ firstAddress?.Address ?? "",
+ string.IsNullOrWhiteSpace(firstAddress?.Moo) ? "" : $" หมู่ {firstAddress.Moo}",
+ string.IsNullOrWhiteSpace(firstAddress?.Soi) ? "" : $" ซอย {firstAddress.Soi}",
+ string.IsNullOrWhiteSpace(firstAddress?.Road) ? "" : $" ถนน {firstAddress.Road}"
+ });
+
+ var currentAddress = string.Join("", new[] {
+ firstAddress?.Address1 ?? "",
+ string.IsNullOrWhiteSpace(firstAddress?.Moo1) ? "" : $" หมู่ {firstAddress.Moo1}",
+ string.IsNullOrWhiteSpace(firstAddress?.Soi1) ? "" : $" ซอย {firstAddress.Soi1}",
+ string.IsNullOrWhiteSpace(firstAddress?.Road1) ? "" : $" ถนน {firstAddress.Road1}"
+ });
+
+ // หาค่า posLevelName หลังสุด
+ var posLevelObject = posOptions?.result?.FirstOrDefault(x =>
+ !string.IsNullOrWhiteSpace(x.posLevelName) &&
+ !string.IsNullOrWhiteSpace(candidate.PositionName) &&
+ candidate.PositionName.Contains(x.posLevelName));
+
+ // เก็บเฉพาะค่า posLevelName
+ var posLevelName = posLevelObject?.posLevelName;
+
+ // สร้างตัวแปร PositionName ที่ตัดค่า posLevelName ออก
+ var positionNameWithoutLevel = candidate.PositionName ?? "";
+ if (!string.IsNullOrWhiteSpace(posLevelName))
+ {
+ positionNameWithoutLevel = positionNameWithoutLevel.Replace(posLevelName, "").Trim();
+ }
+
+ var placementProfile = new PlacementProfile
+ {
+ Placement = placement,
+ PositionCandidate = positionNameWithoutLevel ?? "",
+ PositionType = posLevelObject?.posTypes?.posTypeName ?? "",
+ PositionLevel = posLevelName ?? "",
+ Prefix = candidate.Prefix ?? "",
+ Firstname = candidate.FirstName ?? "",
+ Lastname = candidate.LastName ?? "",
+ Gender = candidate.Gendor ?? "",
+ Nationality = candidate.National ?? "",
+ Race = candidate.Race ?? "",
+ Religion = candidate.Religion ?? "",
+ DateOfBirth = candidate.DateOfBirth,
+ Relationship = candidate.Marry ?? "",
+ CitizenId = candidate.CitizenId ?? "",
+ CitizenProvinceId = provincesCache.FirstOrDefault(x => x.name == candidate.CitizenCardIssuer)?.Id,
+ CitizenDate = candidate.CitizenCardExpireDate,
+ Telephone = firstAddress?.Telephone ?? "",
+ MobilePhone = firstAddress?.Mobile ?? "",
+ RegistAddress = registAddress,
+ RegistProvinceId = provincesCache.FirstOrDefault(x => x.name == firstAddress?.Province)?.Id,
+ RegistDistrictId = districtsCache.FirstOrDefault(x => x.name == firstAddress?.District)?.Id,
+ RegistSubDistrictId = subDistrictsCache.FirstOrDefault(x => x.name == firstAddress?.Soi)?.Id,
+ RegistZipCode = firstAddress?.ZipCode ?? "",
+ RegistSame = false,
+ CurrentAddress = currentAddress,
+ CurrentProvinceId = provincesCache.FirstOrDefault(x => x.name == firstAddress?.Province1)?.Id,
+ CurrentDistrictId = districtsCache.FirstOrDefault(x => x.name == firstAddress?.District1)?.Id,
+ CurrentSubDistrictId = subDistrictsCache.FirstOrDefault(x => x.name == firstAddress?.Soi1)?.Id,
+ CurrentZipCode = firstAddress?.ZipCode1,
+ Marry = candidate.Marry?.Contains("สมรส") ?? false,
+ OccupationPositionType = "other",
+ OccupationTelephone = firstOccupation?.Telephone ?? "",
+ OccupationPosition = firstOccupation?.Position ?? "",
+ PointTotalA = Convert.ToDouble(disableScore.FullA),
+ PointA = Convert.ToDouble(disableScore.SumA),
+ PointTotalB = Convert.ToDouble(disableScore.FullB),
+ PointB = Convert.ToDouble(disableScore.SumB),
+ PointTotalC = Convert.ToDouble(disableScore.FullC),
+ PointC = Convert.ToDouble(disableScore.SumC),
+ ExamNumber = !string.IsNullOrWhiteSpace(disableScore.Number) && int.TryParse(disableScore.Number, out int n) ? n : null,
+ ExamRound = null,
+ IsRelief = false,
+ PlacementStatus = "UN-CONTAIN",
+ Pass = disableScore.ExamStatus ?? "",
+ RemarkHorizontal = "โดยมีเงื่อนไขว่าต้องปฏิบัติงานให้กรุงเทพมหานครเป็นระยะเวลาไม่น้อยกว่า ๕ ปี นับแต่วันที่ได้รับการบรรจุและแต่งตั้ง โดยห้ามโอนไปหน่วยงานหรือส่วนราชการอื่น เว้นเเต่ลาออกจากราชการ",
+ Amount = org?.result?.amount,
+ PositionSalaryAmount = org?.result?.positionSalaryAmount,
+ MouthSalaryAmount = org?.result?.mouthSalaryAmount,
+ CreatedAt = DateTime.Now,
+ CreatedUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "",
+ LastUpdatedAt = DateTime.Now,
+ LastUpdateUserId = UserId ?? "",
+ LastUpdateFullName = FullName ?? "",
+ IsOfficer = isOfficer,
+ profileId = org?.result?.profileId ?? "",
+ IsOld = org?.result != null,
+ AmountOld = org?.result?.AmountOld,
+ nodeOld = org?.result?.node ?? "",
+ nodeIdOld = org?.result?.nodeId ?? "",
+ posmasterIdOld = org?.result?.posmasterId ?? "",
+ rootOld = org?.result?.root ?? "",
+ rootIdOld = org?.result?.rootId ?? "",
+ rootShortNameOld = org?.result?.rootShortName ?? "",
+ child1Old = org?.result?.child1 ?? "",
+ child1IdOld = org?.result?.child1Id ?? "",
+ child1ShortNameOld = org?.result?.child1ShortName ?? "",
+ child2Old = org?.result?.child2 ?? "",
+ child2IdOld = org?.result?.child2Id ?? "",
+ child2ShortNameOld = org?.result?.child2ShortName ?? "",
+ child3Old = org?.result?.child3 ?? "",
+ child3IdOld = org?.result?.child3Id ?? "",
+ child3ShortNameOld = org?.result?.child3ShortName ?? "",
+ child4Old = org?.result?.child4 ?? "",
+ child4IdOld = org?.result?.child4Id ?? "",
+ child4ShortNameOld = org?.result?.child4ShortName ?? "",
+ orgRevisionIdOld = org?.result?.orgRevisionId ?? "",
+ posMasterNoOld = org?.result?.posMasterNo,
+ positionNameOld = org?.result?.position ?? "",
+ posTypeIdOld = org?.result?.posTypeId ?? "",
+ posTypeNameOld = org?.result?.posTypeName ?? "",
+ posLevelIdOld = org?.result?.posLevelId ?? "",
+ posLevelNameOld = org?.result?.posLevelName ?? "",
+ };
+ placementProfiles.Add(placementProfile);
+
+ var placementEducation = new PlacementEducation
+ {
+ PlacementProfile = placementProfile,
+ EducationLevelId = educationLevelsCache.FirstOrDefault(x => x.name == firstEducation?.HighDegree)?.Id,
+ EducationLevelName = educationLevelsCache.FirstOrDefault(x => x.name == firstEducation?.HighDegree)?.name,
+ Field = firstEducation?.Major ?? "",
+ Gpa = firstEducation?.GPA.ToString() ?? "",
+ Institute = firstEducation?.University ?? "",
+ Degree = firstEducation?.Degree ?? "",
+ FinishDate = firstEducation?.BachelorDate,
+ IsDate = true,
+ CreatedAt = DateTime.Now,
+ CreatedUserId = UserId ?? "",
+ LastUpdatedAt = DateTime.Now,
+ LastUpdateUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "",
+ LastUpdateFullName = FullName ?? "",
+ };
+ placementEducations.Add(placementEducation);
+
+ var placementCertificate = new PlacementCertificate
+ {
+ PlacementProfile = placementProfile,
+ CertificateNo = firstCertificate?.CertificateNo ?? "",
+ IssueDate = firstCertificate?.IssueDate,
+ ExpireDate = firstCertificate?.ExpiredDate,
+ CertificateType = firstCertificate?.Description ?? "",
+ CreatedAt = DateTime.Now,
+ CreatedUserId = UserId ?? "",
+ LastUpdatedAt = DateTime.Now,
+ LastUpdateUserId = UserId ?? "",
+ CreatedFullName = FullName ?? "",
+ LastUpdateFullName = FullName ?? "",
+ };
+ placementCertificates.Add(placementCertificate);
+ }
+
+ // 🚀 Batch insert all records
+ await _contextMetadata.PlacementProfiles.AddRangeAsync(placementProfiles);
+ await _contextMetadata.PlacementEducations.AddRangeAsync(placementEducations);
+ await _contextMetadata.PlacementCertificates.AddRangeAsync(placementCertificates);
+
+ // 🚀 Single SaveChanges at the end
+ await _contextMetadata.SaveChangesAsync();
+
+ httpClient.Dispose();
+ }
+ catch
+ {
+ throw;
}
- await _contextMetadata.SaveChangesAsync();
}