Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 53s
All checks were successful
Build & Deploy on Dev / build (push) Successful in 53s
* develop: add time out test error revert code throw error revert test test revert test fixbug โอนคนไปบรรจุ (#7) migrate + ปรับสอบแข่งขัน (#6)
This commit is contained in:
commit
bf95079804
9 changed files with 1940 additions and 161 deletions
|
|
@ -1104,19 +1104,18 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
r.LastName = workSheet?.Cells[row, 8]?.GetValue<string>() ?? "";
|
||||
r.Gendor = workSheet?.Cells[row, 98]?.GetValue<string>() ?? "";
|
||||
r.National = workSheet?.Cells[row, 9]?.GetValue<string>() ?? "";
|
||||
r.Race = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "";
|
||||
r.Race = "";
|
||||
r.Religion = workSheet?.Cells[row, 10]?.GetValue<string>() ?? "";
|
||||
r.DateOfBirth = !string.IsNullOrWhiteSpace(workSheet?.Cells[row, 11]?.GetValue<string>()) ? _recruitService.CheckDateTime(workSheet?.Cells[row, 11]?.GetValue<string>() ?? "", "dd/MM/yyyy") : DateTime.MinValue;
|
||||
r.DateOfBirth = !string.IsNullOrWhiteSpace(workSheet?.Cells[row, 11]?.GetValue<string>()) ? _recruitService.CheckDateTime(workSheet?.Cells[row, 11]?.GetValue<string>() ?? "", "dd/MM/yyyy") : null;
|
||||
r.CitizenId = workSheet?.Cells[row, 12]?.GetValue<string>() ?? "";
|
||||
r.typeTest = workSheet?.Cells[row, 13]?.GetValue<string>() ?? "";
|
||||
r.Marry = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "";
|
||||
r.Marry = "";
|
||||
r.Isspecial = "N";
|
||||
r.CitizenCardIssuer = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "";
|
||||
r.CitizenCardExpireDate = Convert.ToDateTime(workSheet?.Cells[row, 9999]?.GetValue<string>().ToDateTime(DateTimeFormat.Ymd, "-"));
|
||||
r.ApplyDate = !string.IsNullOrWhiteSpace(workSheet?.Cells[row, 87]?.GetValue<string>()) ? _recruitService.CheckDateTime(workSheet?.Cells[row, 87]?.GetValue<string>() ?? "", "dd/MM/yyyy") : DateTime.MinValue;
|
||||
r.PositionType = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "";
|
||||
r.PositionLevel = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "";
|
||||
|
||||
r.CitizenCardExpireDate = null;
|
||||
r.ModifiedDate = null;
|
||||
r.ApplyDate = !string.IsNullOrWhiteSpace(workSheet?.Cells[row, 87]?.GetValue<string>()) ? _recruitService.CheckDateTime(workSheet?.Cells[row, 87]?.GetValue<string>() ?? "", "dd/MM/yyyy") : null;
|
||||
r.PositionType = "";
|
||||
r.PositionLevel = "";
|
||||
r.CreatedAt = DateTime.Now;
|
||||
r.CreatedUserId = UserId ?? "";
|
||||
r.CreatedFullName = FullName ?? "System Administrator";
|
||||
|
|
@ -1129,13 +1128,13 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
{
|
||||
Degree = workSheet?.Cells[row, 18]?.GetValue<string>() ?? "",
|
||||
Major = workSheet?.Cells[row, 19]?.GetValue<string>() == "อื่น ๆ" ? workSheet?.Cells[row, 20]?.GetValue<string>() ?? "" : workSheet?.Cells[row, 19]?.GetValue<string>() ?? "",
|
||||
MajorGroupId = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
MajorGroupName = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
MajorGroupId = "",
|
||||
MajorGroupName = "",
|
||||
University = workSheet?.Cells[row, 21]?.GetValue<string>() == "อื่น ๆ" ? workSheet?.Cells[row, 22]?.GetValue<string>() ?? "" : workSheet?.Cells[row, 21]?.GetValue<string>() ?? "",
|
||||
GPA = (double)workSheet?.Cells[row, 26]?.GetValue<double>(),
|
||||
Specialist = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
Specialist = "",
|
||||
HighDegree = workSheet?.Cells[row, 27]?.GetValue<string>() ?? "",
|
||||
BachelorDate = !string.IsNullOrWhiteSpace(workSheet?.Cells[row, 25]?.GetValue<string>()) ? _recruitService.CheckDateTime(workSheet?.Cells[row, 11]?.GetValue<string>() ?? "", "dd/MM/yyyy") : DateTime.MinValue,
|
||||
BachelorDate = !string.IsNullOrWhiteSpace(workSheet?.Cells[row, 25]?.GetValue<string>()) ? _recruitService.CheckDateTime(workSheet?.Cells[row, 25]?.GetValue<string>() ?? "", "dd/MM/yyyy") : null,
|
||||
CreatedAt = DateTime.Now,
|
||||
CreatedUserId = UserId ?? "",
|
||||
CreatedFullName = FullName ?? "System Administrator",
|
||||
|
|
@ -1172,7 +1171,7 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
Province = workSheet?.Cells[row, 56]?.GetValue<string>() ?? "",
|
||||
ZipCode = workSheet?.Cells[row, 57]?.GetValue<string>() ?? "",
|
||||
Telephone = workSheet?.Cells[row, 58]?.GetValue<string>() ?? "",
|
||||
Mobile = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
Mobile = "",
|
||||
Address1 = $"{(workSheet?.Cells[row, 61]?.GetValue<string>() ?? "")} {(workSheet?.Cells[row, 62]?.GetValue<string>() ?? "")}",
|
||||
Moo1 = workSheet?.Cells[row, 63]?.GetValue<string>() ?? "",
|
||||
Soi1 = workSheet?.Cells[row, 64]?.GetValue<string>() ?? "",
|
||||
|
|
@ -1215,21 +1214,21 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
LastUpdateUserId = UserId ?? "",
|
||||
LastUpdateFullName = FullName ?? "System Administrator"
|
||||
});
|
||||
|
||||
// certificate
|
||||
r.Certificates.Add(new RecruitCertificate()
|
||||
{
|
||||
CertificateNo = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
Description = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
IssueDate = Convert.ToDateTime(workSheet?.Cells[row, 9999]?.GetValue<string>().ToDateTime(DateTimeFormat.Ymd, "-")),
|
||||
ExpiredDate = Convert.ToDateTime(workSheet?.Cells[row, 9999]?.GetValue<string>().ToDateTime(DateTimeFormat.Ymd, "-")),
|
||||
CreatedAt = DateTime.Now,
|
||||
CreatedUserId = UserId ?? "",
|
||||
CreatedFullName = FullName ?? "System Administrator",
|
||||
LastUpdatedAt = DateTime.Now,
|
||||
LastUpdateUserId = UserId ?? "",
|
||||
LastUpdateFullName = FullName ?? "System Administrator"
|
||||
});
|
||||
/*Comment ข้อมูลใบประกอบวิชาชีพ เพราะในไฟล์นำเข้ายังไม่มีคอลัมน์ที่ระบุข้อมูลส่วนนี้*/
|
||||
//// certificate
|
||||
//r.Certificates.Add(new RecruitCertificate()
|
||||
//{
|
||||
// CertificateNo = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
// Description = workSheet?.Cells[row, 9999]?.GetValue<string>() ?? "",
|
||||
// IssueDate = Convert.ToDateTime(workSheet?.Cells[row, 9999]?.GetValue<string>().ToDateTime(DateTimeFormat.Ymd, "-")),
|
||||
// ExpiredDate = Convert.ToDateTime(workSheet?.Cells[row, 9999]?.GetValue<string>().ToDateTime(DateTimeFormat.Ymd, "-")),
|
||||
// CreatedAt = DateTime.Now,
|
||||
// CreatedUserId = UserId ?? "",
|
||||
// CreatedFullName = FullName ?? "System Administrator",
|
||||
// LastUpdatedAt = DateTime.Now,
|
||||
// LastUpdateUserId = UserId ?? "",
|
||||
// LastUpdateFullName = FullName ?? "System Administrator"
|
||||
//});
|
||||
|
||||
r.RecruitImport = imported;
|
||||
_context.Recruits.Add(r);
|
||||
|
|
@ -1980,13 +1979,8 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
);
|
||||
}
|
||||
|
||||
int total = await query.CountAsync();
|
||||
|
||||
query = query
|
||||
.Skip((req.Page - 1) * req.PageSize)
|
||||
.Take(req.PageSize);
|
||||
|
||||
var data = await query
|
||||
// join กับ DisableScores ก่อน เพื่อ filter ตาม ExamStatus
|
||||
var queryWithScores = query
|
||||
.GroupJoin(
|
||||
_context.RecruitScores.Include(x => x.ScoreImport),
|
||||
rc => new { rc.RecruitImport!.Id, rc.ExamId },
|
||||
|
|
@ -1995,49 +1989,78 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
)
|
||||
.SelectMany(
|
||||
x => x.scores.DefaultIfEmpty(),
|
||||
(x, sr) => new
|
||||
{
|
||||
examID = x.recruit.ExamId,
|
||||
profileID = x.recruit.CitizenId,
|
||||
prefix = x.recruit.Prefix,
|
||||
fullName = $"{x.recruit.FirstName} {x.recruit.LastName}",
|
||||
dateOfBirth = x.recruit.DateOfBirth != null && x.recruit.DateOfBirth != DateTime.MinValue
|
||||
? x.recruit.DateOfBirth.ToThaiShortDate()
|
||||
: "",
|
||||
gender = x.recruit.Gendor,
|
||||
degree = x.recruit.Educations.Any() ? x.recruit.Educations.First().Degree : "",
|
||||
major = x.recruit.Educations.Any() ? x.recruit.Educations.First().Major : "",
|
||||
certificateNo = x.recruit.Certificates.Any()
|
||||
? x.recruit.Certificates.First().CertificateNo ?? ""
|
||||
: "",
|
||||
certificateIssueDate = x.recruit.Certificates.Any() && x.recruit.Certificates.First().IssueDate != null && x.recruit.Certificates.First().IssueDate != DateTime.MinValue
|
||||
? x.recruit.Certificates.First().IssueDate.ToThaiShortDate()
|
||||
: "",
|
||||
examScore = sr == null ? 0.0 : sr.TotalScore,
|
||||
examResult = sr == null ? "" : sr.ExamStatus,
|
||||
examAttribute = x.recruit.Certificates.Any() && x.recruit.Certificates.First().IssueDate != null
|
||||
? _recruitService.CheckValidCertificate(x.recruit.Certificates.First().IssueDate, 5)
|
||||
? "มีคุณสมบัติ" : "ไม่มีคุณสมบัติ"
|
||||
: "ไม่มีคุณสมบัติ",
|
||||
remark = x.recruit.Remark,
|
||||
isSpecial = x.recruit.Isspecial == "Y" ? x.recruit.Isspecial : "",
|
||||
applyDate = x.recruit.ApplyDate != null && x.recruit.ApplyDate != DateTime.MinValue
|
||||
? x.recruit.ApplyDate.ToThaiShortDate()
|
||||
: "",
|
||||
university = x.recruit.Educations.Any() ? x.recruit.Educations.First().University : "",
|
||||
position_name = x.recruit.PositionName,
|
||||
hddPosition = x.recruit.HddPosition,
|
||||
typeTest = x.recruit.typeTest,
|
||||
position_level = x.recruit.PositionLevel,
|
||||
position_type = x.recruit.PositionType,
|
||||
exam_name = x.recruit.RecruitImport!.Name,
|
||||
exam_order = x.recruit.RecruitImport != null && x.recruit.RecruitImport.Order != null
|
||||
? x.recruit.RecruitImport.Order.ToString()
|
||||
: "",
|
||||
score_year = x.recruit.RecruitImport != null && x.recruit.RecruitImport.Year != null
|
||||
? x.recruit.RecruitImport.Year.ToThaiYear().ToString()
|
||||
: "",
|
||||
})
|
||||
(x, sr) => new { x.recruit, score = sr }
|
||||
);
|
||||
|
||||
// filter ตาม req.ExamResult
|
||||
if (!string.IsNullOrWhiteSpace(req.ExamResult))
|
||||
{
|
||||
switch (req.ExamResult.ToLower())
|
||||
{
|
||||
case "missed_exam":
|
||||
queryWithScores = queryWithScores.Where(x => x.score != null && x.score.ExamStatus == "ขส.");
|
||||
break;
|
||||
case "pass":
|
||||
queryWithScores = queryWithScores.Where(x => x.score != null && x.score.ExamStatus == "ผ่าน");
|
||||
break;
|
||||
case "notpass":
|
||||
queryWithScores = queryWithScores.Where(x => x.score != null && x.score.ExamStatus == "ไม่ผ่าน");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// total count หลังกรอง
|
||||
int total = await queryWithScores.CountAsync();
|
||||
|
||||
// pagination
|
||||
queryWithScores = queryWithScores
|
||||
.Skip((req.Page - 1) * req.PageSize)
|
||||
.Take(req.PageSize);
|
||||
|
||||
// mapping
|
||||
var data = await queryWithScores
|
||||
.Select(x => new
|
||||
{
|
||||
examID = x.recruit.ExamId,
|
||||
profileID = x.recruit.CitizenId,
|
||||
prefix = x.recruit.Prefix,
|
||||
fullName = $"{x.recruit.FirstName} {x.recruit.LastName}",
|
||||
dateOfBirth = x.recruit.DateOfBirth.HasValue && x.recruit.DateOfBirth.Value != DateTime.MinValue
|
||||
? x.recruit.DateOfBirth.Value.ToThaiShortDate()
|
||||
: "",
|
||||
gender = x.recruit.Gendor,
|
||||
degree = x.recruit.Educations.Any() ? x.recruit.Educations.First().Degree : "",
|
||||
major = x.recruit.Educations.Any() ? x.recruit.Educations.First().Major : "",
|
||||
certificateNo = x.recruit.Certificates.Any() ? x.recruit.Certificates.First().CertificateNo ?? "" : "",
|
||||
certificateIssueDate = x.recruit.Certificates.Any() && x.recruit.Certificates.First().IssueDate != null && x.recruit.Certificates.First().IssueDate != DateTime.MinValue
|
||||
? x.recruit.Certificates.First().IssueDate.ToThaiShortDate()
|
||||
: "",
|
||||
examScore = x.score == null ? 0.0 : x.score.TotalScore,
|
||||
examResult = x.score == null ? "" : x.score.ExamStatus,
|
||||
examAttribute = x.recruit.Certificates.Any() && x.recruit.Certificates.First().IssueDate != null
|
||||
? _recruitService.CheckValidCertificate(x.recruit.Certificates.First().IssueDate, 5)
|
||||
? "มีคุณสมบัติ" : "ไม่มีคุณสมบัติ"
|
||||
: "ไม่มีคุณสมบัติ",
|
||||
remark = x.recruit.Remark,
|
||||
isSpecial = x.recruit.Isspecial == "Y" ? x.recruit.Isspecial : "",
|
||||
applyDate = x.recruit.ApplyDate.HasValue && x.recruit.ApplyDate.Value != DateTime.MinValue
|
||||
? x.recruit.ApplyDate.Value.ToThaiShortDate()
|
||||
: "",
|
||||
university = x.recruit.Educations.Any() ? x.recruit.Educations.First().University : "",
|
||||
position_name = x.recruit.PositionName,
|
||||
hddPosition = x.recruit.HddPosition ?? "",
|
||||
typeTest = x.recruit.typeTest ?? "",
|
||||
position_level = x.recruit.PositionLevel ?? "",
|
||||
position_type = x.recruit.PositionType ?? "",
|
||||
exam_name = x.recruit.RecruitImport!.Name,
|
||||
exam_order = x.recruit.RecruitImport != null && x.recruit.RecruitImport.Order != null
|
||||
? x.recruit.RecruitImport.Order.ToString()
|
||||
: "",
|
||||
score_year = x.recruit.RecruitImport != null && x.recruit.RecruitImport.Year != null
|
||||
? (x.recruit.RecruitImport.Year > 2500 ? x.recruit.RecruitImport.Year : x.recruit.RecruitImport.Year + 543).ToString()
|
||||
: "",
|
||||
number = x.score == null ? "" : x.score.Number,
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
// ---------------------------
|
||||
|
|
@ -2133,10 +2156,8 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
ProfileID = p.CitizenId,
|
||||
p.Prefix,
|
||||
FullName = $"{p.FirstName} {p.LastName}",
|
||||
DateOfBirth = p.DateOfBirth != null
|
||||
? p.DateOfBirth != DateTime.MinValue
|
||||
? p.DateOfBirth.ToThaiShortDate()
|
||||
: ""
|
||||
DateOfBirth = p.DateOfBirth.HasValue && p.DateOfBirth.Value != DateTime.MinValue
|
||||
? p.DateOfBirth.Value.ToThaiShortDate()
|
||||
: "",
|
||||
Gender = p.Gendor,
|
||||
Degree = p.Educations.First().Degree,
|
||||
|
|
@ -2150,7 +2171,11 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
: ""
|
||||
: "",
|
||||
ExamResult = sr == null ? "" : sr.ExamStatus,
|
||||
ExamAttribute = _recruitService.CheckValidCertificate(p.Certificates.First().IssueDate, 5) ? "มีคุณสมบัติ" : "ไม่มีคุณสมบัติ",
|
||||
ExamAttribute = p.Certificates.Count > 0 ?
|
||||
_recruitService.CheckValidCertificate(p.Certificates.First().IssueDate, 5)
|
||||
? "มีคุณสมบัติ"
|
||||
: "ไม่มีคุณสมบัติ"
|
||||
: "ไม่มีคุณสมบัติ",
|
||||
IsSpecial = p.Isspecial,
|
||||
Remark = p.Remark,
|
||||
University = p.Educations.First().University,
|
||||
|
|
@ -2852,10 +2877,8 @@ namespace BMA.EHR.Recruit.Service.Controllers
|
|||
ExamID = p.ExamId != null ? p.ExamId.ToThaiNumber() : "",
|
||||
CitizenId = p.CitizenId != null ? p.CitizenId.ToThaiNumber() : "",
|
||||
FullName = $"{p.Prefix}{p.FirstName} {p.LastName}",
|
||||
DateOfBirth = p.DateOfBirth != null
|
||||
? p.DateOfBirth != DateTime.MinValue
|
||||
? p.DateOfBirth.ToThaiShortDate().ToString().ToThaiNumber()
|
||||
: ""
|
||||
DateOfBirth = p.DateOfBirth.HasValue && p.DateOfBirth.Value != DateTime.MinValue
|
||||
? p.DateOfBirth.Value.ToThaiShortDate().ToThaiNumber()
|
||||
: "",
|
||||
Gender = p.Gendor,
|
||||
Degree = p.Educations.First().Degree,
|
||||
|
|
|
|||
|
|
@ -37,21 +37,32 @@ namespace BMA.EHR.Recruit.Service.Core
|
|||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
// Set timeout to 30 seconds instead of default 100 seconds
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Replace("Bearer ", ""));
|
||||
client.DefaultRequestHeaders.Add("api_key", apiKey);
|
||||
var _res = await client.GetAsync(apiPath);
|
||||
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||
var _res = await client.GetAsync(apiPath, cts.Token);
|
||||
if (_res.IsSuccessStatusCode)
|
||||
{
|
||||
var _result = await _res.Content.ReadAsStringAsync();
|
||||
|
||||
return _result;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
throw;
|
||||
// Log timeout but don't throw - return empty result instead
|
||||
Console.WriteLine($"API call timed out: {apiPath}");
|
||||
return string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log other exceptions but don't throw - return empty result instead
|
||||
Console.WriteLine($"API call failed: {apiPath}, Error: {ex.Message}");
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,10 +71,10 @@ namespace BMA.EHR.Recruit.Service.Core
|
|||
try
|
||||
{
|
||||
var apiPath = $"{_configuration["API"]}/org/dotnet/keycloak/{keycloakId}";
|
||||
var apiKey = _configuration["API_KEY"];
|
||||
var apiKey = _configuration["API_KEY"] ?? "";
|
||||
|
||||
var apiResult = await GetExternalAPIAsync(apiPath, accessToken ?? "", apiKey);
|
||||
if (apiResult != null)
|
||||
if (!string.IsNullOrEmpty(apiResult))
|
||||
{
|
||||
var raw = JsonConvert.DeserializeObject<GetProfileByKeycloakIdResultLocal>(apiResult);
|
||||
if (raw != null)
|
||||
|
|
@ -72,9 +83,11 @@ namespace BMA.EHR.Recruit.Service.Core
|
|||
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
// Log exception but don't throw - return null instead
|
||||
Console.WriteLine($"GetProfileByKeycloakIdAsync failed for {keycloakId}: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
1601
Migrations/20251016094447_update_nullable.Designer.cs
generated
Normal file
1601
Migrations/20251016094447_update_nullable.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
109
Migrations/20251016094447_update_nullable.cs
Normal file
109
Migrations/20251016094447_update_nullable.cs
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace BMA.EHR.Recruit.Service.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class update_nullable : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "ModifiedDate",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "DateOfBirth",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CitizenCardExpireDate",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "ApplyDate",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "BachelorDate",
|
||||
table: "RecruitEducations",
|
||||
type: "datetime(6)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "ModifiedDate",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "DateOfBirth",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CitizenCardExpireDate",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "ApplyDate",
|
||||
table: "Recruits",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "BachelorDate",
|
||||
table: "RecruitEducations",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "datetime(6)",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,10 +62,10 @@ namespace BMA.EHR.Recruit.Service.Migrations
|
|||
.HasComment("PrimaryKey")
|
||||
.HasAnnotation("Relational:JsonPropertyName", "id");
|
||||
|
||||
b.Property<DateTime>("ApplyDate")
|
||||
b.Property<DateTime?>("ApplyDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<DateTime>("CitizenCardExpireDate")
|
||||
b.Property<DateTime?>("CitizenCardExpireDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("CitizenCardIssuer")
|
||||
|
|
@ -101,7 +101,7 @@ namespace BMA.EHR.Recruit.Service.Migrations
|
|||
.HasColumnOrder(101)
|
||||
.HasComment("User Id ที่สร้างข้อมูล");
|
||||
|
||||
b.Property<DateTime>("DateOfBirth")
|
||||
b.Property<DateTime?>("DateOfBirth")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("ExamId")
|
||||
|
|
@ -157,7 +157,7 @@ namespace BMA.EHR.Recruit.Service.Migrations
|
|||
.HasMaxLength(20)
|
||||
.HasColumnType("varchar(20)");
|
||||
|
||||
b.Property<DateTime>("ModifiedDate")
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("National")
|
||||
|
|
@ -512,7 +512,7 @@ namespace BMA.EHR.Recruit.Service.Migrations
|
|||
.HasComment("PrimaryKey")
|
||||
.HasAnnotation("Relational:JsonPropertyName", "id");
|
||||
|
||||
b.Property<DateTime>("BachelorDate")
|
||||
b.Property<DateTime?>("BachelorDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ namespace BMA.EHR.Recruit.Service.Models.Recruits
|
|||
[MaxLength(200)]
|
||||
public string Religion { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public DateTime DateOfBirth { get; set; }
|
||||
//[Required]
|
||||
public DateTime? DateOfBirth { get; set; }
|
||||
|
||||
[MaxLength(20)]
|
||||
public string Marry { get; set; } = string.Empty;
|
||||
|
|
@ -48,7 +48,7 @@ namespace BMA.EHR.Recruit.Service.Models.Recruits
|
|||
[MaxLength(200)]
|
||||
public string CitizenCardIssuer { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CitizenCardExpireDate { get; set; }
|
||||
public DateTime? CitizenCardExpireDate { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
public string Remark { get; set; } = string.Empty;
|
||||
|
|
@ -72,9 +72,9 @@ namespace BMA.EHR.Recruit.Service.Models.Recruits
|
|||
|
||||
public DateTime CreatedDate { get; set; } = DateTime.Now;
|
||||
|
||||
public DateTime ModifiedDate { get; set; }
|
||||
public DateTime? ModifiedDate { get; set; }
|
||||
|
||||
public DateTime ApplyDate { get; set; }
|
||||
public DateTime? ApplyDate { get; set; }
|
||||
|
||||
public string? PositionName { get; set; }
|
||||
public string? PositionType { get; set; }
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace BMA.EHR.Recruit.Service.Models.Recruits
|
|||
[MaxLength(200)]
|
||||
public string HighDegree { get; set; }
|
||||
|
||||
public DateTime BachelorDate { get; set; }
|
||||
public DateTime? BachelorDate { get; set; }
|
||||
|
||||
public Recruit Recruit { get; set; }
|
||||
}
|
||||
|
|
|
|||
13
Program.cs
13
Program.cs
|
|
@ -67,6 +67,12 @@ builder.Services.AddTransient<RecruitService>();
|
|||
builder.Services.AddTransient<MinIOService>();
|
||||
builder.Services.AddTransient<PermissionRepository>();
|
||||
|
||||
// Configure HttpClient with timeout
|
||||
builder.Services.AddHttpClient("default", client =>
|
||||
{
|
||||
client.Timeout = TimeSpan.FromSeconds(30);
|
||||
});
|
||||
|
||||
// use serilog
|
||||
//ConfigureLogs();
|
||||
//builder.Host.UseSerilog();
|
||||
|
|
@ -107,10 +113,6 @@ builder.Services.AddSwaggerGen();
|
|||
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();
|
||||
builder.Services.AddHealthChecks();
|
||||
|
||||
// Register Service
|
||||
builder.Services.AddTransient<RecruitService>();
|
||||
builder.Services.AddTransient<MinIOService>();
|
||||
|
||||
var app = builder.Build();
|
||||
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
|
||||
|
||||
|
|
@ -133,12 +135,11 @@ app.UseHttpsRedirection();
|
|||
app.UseCors();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseMiddleware<RequestLoggingMiddleware>();
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
app.MapControllers();
|
||||
|
||||
app.UseMiddleware<RequestLoggingMiddleware>();
|
||||
|
||||
// apply migrations
|
||||
await using var scope = app.Services.CreateAsyncScope();
|
||||
await using var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -23,6 +24,7 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
private readonly MetadataDbContext _contextMetadata;
|
||||
private readonly OrgDbContext _contextOrg;
|
||||
private readonly MinIOService _minIOService;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
|
|
@ -31,12 +33,14 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
OrgDbContext contextOrg,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
MinIOService minIOService,
|
||||
IConfiguration configuration)
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_context = context;
|
||||
_contextMetadata = contextMetadata;
|
||||
_contextOrg = contextOrg;
|
||||
_minIOService = minIOService;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
|
@ -180,13 +184,25 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
// 🚀 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"]);
|
||||
// 🚀 Prepare HTTP client once via factory with timeout
|
||||
var clientForPos = _httpClientFactory.CreateClient("default");
|
||||
clientForPos.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token?.Replace("Bearer ", ""));
|
||||
clientForPos.DefaultRequestHeaders.Remove("api_key");
|
||||
clientForPos.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"] ?? "");
|
||||
var apiUrl1 = $"{_configuration["API"]}/org/pos/level";
|
||||
var response1 = await httpClient1.GetStringAsync(apiUrl1);
|
||||
var posOptions = JsonConvert.DeserializeObject<RecruitPosRequest>(response1);
|
||||
var response1 = string.Empty;
|
||||
try
|
||||
{
|
||||
using var ctsPos = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||
response1 = await clientForPos.GetStringAsync(apiUrl1, ctsPos.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// timeout - fallback to empty posOptions
|
||||
response1 = string.Empty;
|
||||
}
|
||||
|
||||
var posOptions = string.IsNullOrWhiteSpace(response1) ? null : JsonConvert.DeserializeObject<RecruitPosRequest>(response1);
|
||||
|
||||
var recruitImport = await _context.RecruitImports.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.Id == examId);
|
||||
|
|
@ -245,26 +261,41 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
.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 using IHttpClientFactory with concurrency limit and cancellation
|
||||
var clientForOrg = _httpClientFactory.CreateClient("default");
|
||||
clientForOrg.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token?.Replace("Bearer ", ""));
|
||||
clientForOrg.DefaultRequestHeaders.Remove("api_key");
|
||||
clientForOrg.DefaultRequestHeaders.Add("api_key", _configuration["API_KEY"] ?? "");
|
||||
|
||||
// 🚀 Batch HTTP requests
|
||||
var semaphore = new SemaphoreSlim(10); // limit concurrency
|
||||
var orgTasks = candidates.Select(async candidate =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(candidate.CitizenId))
|
||||
return new { CitizenId = candidate.CitizenId ?? "", org = (dynamic?)null };
|
||||
|
||||
var apiUrl = $"{_configuration["API"]}/org/profile/citizenid/position/{candidate.CitizenId}";
|
||||
await semaphore.WaitAsync();
|
||||
try
|
||||
{
|
||||
var response = await httpClient.GetStringAsync(apiUrl);
|
||||
return new { CitizenId = candidate.CitizenId, org = JsonConvert.DeserializeObject<dynamic>(response) };
|
||||
var apiUrl = $"{_configuration["API"]}/org/profile/citizenid/position/{candidate.CitizenId}";
|
||||
try
|
||||
{
|
||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
|
||||
var response = await clientForOrg.GetStringAsync(apiUrl, cts.Token);
|
||||
return new { CitizenId = candidate.CitizenId, org = JsonConvert.DeserializeObject<dynamic>(response) };
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// timeout
|
||||
return new { CitizenId = candidate.CitizenId ?? "", org = (dynamic?)null };
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new { CitizenId = candidate.CitizenId ?? "", org = (dynamic?)null };
|
||||
}
|
||||
}
|
||||
catch
|
||||
finally
|
||||
{
|
||||
return new { CitizenId = candidate.CitizenId ?? "", org = (dynamic?)null };
|
||||
semaphore.Release();
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
|
|
@ -274,7 +305,8 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
// 🚀 Prepare batch inserts
|
||||
var placementProfiles = new List<PlacementProfile>();
|
||||
var placementEducations = new List<PlacementEducation>();
|
||||
var placementCertificates = new List<PlacementCertificate>();
|
||||
/*Comment ข้อมูลใบประกอบวิชาชีพ เพราะในไฟล์นำเข้ายังไม่มีคอลัมน์ที่ระบุข้อมูลส่วนนี้*/
|
||||
//var placementCertificates = new List<PlacementCertificate>();
|
||||
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
|
|
@ -417,33 +449,33 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
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);
|
||||
/*Comment ข้อมูลใบประกอบวิชาชีพ เพราะในไฟล์นำเข้ายังไม่มีคอลัมน์ที่ระบุข้อมูลส่วนนี้*/
|
||||
//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);
|
||||
/*Comment ข้อมูลใบประกอบวิชาชีพ เพราะในไฟล์นำเข้ายังไม่มีคอลัมน์ที่ระบุข้อมูลส่วนนี้*/
|
||||
//await _contextMetadata.PlacementCertificates.AddRangeAsync(placementCertificates);
|
||||
|
||||
// 🚀 Single SaveChanges at the end
|
||||
await _contextMetadata.SaveChangesAsync();
|
||||
|
||||
httpClient.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
@ -460,13 +492,13 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
if (!string.IsNullOrWhiteSpace(road)) parts.Add($"ถนน {road}");
|
||||
return string.Join(" ", parts);
|
||||
}
|
||||
public DateTime CheckDateTime(string Date, string Formate)
|
||||
public DateTime? CheckDateTime(string Date, string Formate)
|
||||
{
|
||||
// ตอนนี้ทำไว้ให้รองรับแค่ "dd/MM/yyyy", "yyyy-MM-dd"
|
||||
Date = Date.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Date))
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
|
||||
// จะเข้าเฉพาะกรณีที่ string เป็นตัวเลข เช่น "35635", "44561.5"
|
||||
if (double.TryParse(Date, out double oaDate))
|
||||
|
|
@ -484,7 +516,7 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
string[] parts = Date.Trim().Replace("-", "/").Split("/");
|
||||
|
||||
if (parts.Length != 3)
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
|
||||
int year;
|
||||
int month;
|
||||
|
|
@ -498,14 +530,14 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
}
|
||||
else if (!int.TryParse(parts[2], out year))
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!int.TryParse(parts[1], out month))
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
|
||||
if (!int.TryParse(parts[0], out day))
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
|
||||
break;
|
||||
|
||||
|
|
@ -516,18 +548,18 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
}
|
||||
else if (!int.TryParse(parts[0], out year))
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!int.TryParse(parts[1], out month))
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
|
||||
if (!int.TryParse(parts[2], out day))
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
break;
|
||||
|
||||
default:
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (month < 1 || month > 12)
|
||||
|
|
@ -540,13 +572,13 @@ namespace BMA.EHR.Recruit.Service.Services
|
|||
else if (day > maxDay)
|
||||
day = maxDay;
|
||||
|
||||
var normalDate = $"{day}/{(month >= 1 && month <= 9 ? $"0{month}" : month)}/{year}";
|
||||
var normalDate = $"{(day >= 1 && day <= 9 ? $"0{day}" : day)}/{(month >= 1 && month <= 9 ? $"0{month}" : month)}/{year}";
|
||||
if (DateTime.TryParseExact(normalDate, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate))
|
||||
{
|
||||
return parsedDate;
|
||||
}
|
||||
|
||||
return DateTime.MinValue;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue