Merge branch 'develop' into adiDev

This commit is contained in:
Adisak 2026-05-25 17:20:46 +07:00
commit aeb2ceea6f
13 changed files with 332 additions and 64 deletions

View file

@ -114,6 +114,60 @@ namespace BMA.EHR.Application.Repositories.Leaves.TimeAttendants
return job!;
}
/// <summary>
/// ดึงข้อมูลงานที่ค้างอยู่ในสถานะ PENDING หรือ PROCESSING เกินเวลาที่กำหนด (นาที)
/// </summary>
public async Task<List<CheckInJobStatus>> GetStalePendingOrProcessingJobsAsync(int timeoutMinutes = 30)
{
var cutoffDate = DateTime.Now.AddMinutes(-timeoutMinutes);
var staleJobs = await _dbContext.Set<CheckInJobStatus>()
.Where(x => (x.Status == "PENDING" || x.Status == "PROCESSING")
&& x.CreatedDate < cutoffDate)
.OrderBy(x => x.CreatedDate)
.ToListAsync();
return staleJobs;
}
/// <summary>
/// ดึงข้อมูลงานที่ค้างอยู่ในสถานะ PENDING หรือ PROCESSING เกินเวลาที่กำหนด (นาที) ของ user คนใดคนหนึ่ง
/// </summary>
public async Task<List<CheckInJobStatus>> GetStalePendingOrProcessingJobsByUserAsync(Guid userId, int timeoutMinutes = 30)
{
var cutoffDate = DateTime.Now.AddMinutes(-timeoutMinutes);
var staleJobs = await _dbContext.Set<CheckInJobStatus>()
.Where(x => x.KeycloakUserId == userId
&& (x.Status == "PENDING" || x.Status == "PROCESSING")
&& x.CreatedDate < cutoffDate)
.OrderBy(x => x.CreatedDate)
.ToListAsync();
return staleJobs;
}
/// <summary>
/// Mark งานที่ค้างเกินเวลาที่กำหนดเป็น FAILED
/// </summary>
public async Task<int> 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<CheckInJobStatus>().UpdateRange(staleJobs);
await _dbContext.SaveChangesAsync();
}
return staleJobs.Count;
}
/// <summary>
/// ล้างข้อมูล Job Status ที่เก่าเกิน X วัน
/// </summary>

View file

@ -74,6 +74,9 @@
<Content Update="wwwroot\keycloak.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\blank.jpeg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>

View file

@ -537,6 +537,17 @@ namespace BMA.EHR.Leave.Service.Controllers
var userId = UserId == null ? Guid.Empty : Guid.Parse(UserId);
var currentDate = DateTime.Now;
// ตรวจสอบและ mark งานเก่าที่ค้างเกิน 30 นาทีเป็น FAILED อัตโนมัติ
var staleJobs = await _checkInJobStatusRepository.GetStalePendingOrProcessingJobsByUserAsync(userId, 30);
if (staleJobs != null && staleJobs.Count > 0)
{
foreach (var staleJob in staleJobs)
{
await _checkInJobStatusRepository.UpdateToFailedAsync(staleJob.TaskId,
$"งานค้างในสถานะ {staleJob.Status} เกิน 30 นาที ระบบทำเครื่องหมายเป็น FAILED อัตโนมัติ");
}
}
// ตรวจสอบว่ามีงานที่กำลัง pending หรือ processing อยู่หรือไม่
var existingJobs = await _checkInJobStatusRepository.GetPendingOrProcessingJobsAsync(userId);
if (existingJobs != null && existingJobs.Count > 0)
@ -604,7 +615,16 @@ namespace BMA.EHR.Leave.Service.Controllers
properties.Persistent = true;
properties.MessageId = taskId;
// บันทึกสถานะงานก่อนส่งไป RabbitMQ
// ส่งไป RabbitMQ
channel.BasicPublish(exchange: "",
routingKey: queue,
basicProperties: properties,
body: body);
// Clear Byte data Before Save to DB
checkData.CheckInFileBytes = new byte[0];
// บันทึกสถานะงานหลังส่งไป RabbitMQ
jobStatus = new CheckInJobStatus
{
TaskId = Guid.Parse(taskId),
@ -613,23 +633,10 @@ namespace BMA.EHR.Leave.Service.Controllers
Status = "PENDING",
CheckType = data.CheckInId == null ? "CHECK_IN" : "CHECK_OUT",
CheckInId = data.CheckInId,
AdditionalData = JsonConvert.SerializeObject(new
{
IsLocation = data.IsLocation,
LocationName = data.LocationName,
POI = data.POI,
KeycloakId = userId,
Token = AccessToken,
})
AdditionalData = JsonConvert.SerializeObject(checkData)
};
await _checkInJobStatusRepository.AddAsync(jobStatus);
// ส่งไป RabbitMQ
channel.BasicPublish(exchange: "",
routingKey: queue,
basicProperties: properties,
body: body);
return Success(new { date = currentDate, taskId = taskId, keycloakId = userId });
}
catch (Exception ex)
@ -727,6 +734,117 @@ namespace BMA.EHR.Leave.Service.Controllers
return Success(new { count = result.Count, jobs = result });
}
/// <summary>
/// ประมวลผลงาน CheckIn ที่ค้างอยู่ในสถานะ PENDING/PROCESSING เกินเวลาที่กำหนดใหม่อีกครั้ง
/// </summary>
/// <returns></returns>
/// <response code="200">เมื่อทำรายการสำเร็จ</response>
/// <response code="401">ไม่ได้ Login เข้าระบบ</response>
/// <response code="500">เมื่อเกิดข้อผิดพลาดในการทำงาน</response>
[HttpPost("reprocess-stale-checkin-jobs")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public async Task<ActionResult<ResponseObject>> ReprocessStaleCheckInJobsAsync([FromQuery] int timeoutMinutes = 30)
{
try
{
var staleJobs = await _checkInJobStatusRepository.GetStalePendingOrProcessingJobsAsync(timeoutMinutes);
if (staleJobs == null || staleJobs.Count == 0)
{
return Success(new { message = "ไม่พบงานที่ค้างอยู่", count = 0 });
}
var results = new List<object>();
foreach (var job in staleJobs)
{
try
{
// อ่านข้อมูลเดิมจาก AdditionalData
if (string.IsNullOrEmpty(job.AdditionalData))
{
await _checkInJobStatusRepository.UpdateToFailedAsync(job.TaskId,
"ไม่พบข้อมูลสำหรับประมวลผลซ้ำ (AdditionalData is null)");
results.Add(new
{
taskId = job.TaskId,
keycloakUserId = job.KeycloakUserId,
checkType = job.CheckType,
createdDate = job.CreatedDate,
previousStatus = job.Status,
newStatus = "FAILED",
errorMessage = "ไม่พบข้อมูลสำหรับประมวลผลซ้ำ"
});
continue;
}
var checkData = JsonConvert.DeserializeObject<CheckTimeDtoRB>(job.AdditionalData);
checkData.UserId = job.KeycloakUserId;
checkData.CurrentDate = job.CreatedDate;
if (checkData == null)
{
await _checkInJobStatusRepository.UpdateToFailedAsync(job.TaskId,
"ไม่สามารถอ่านข้อมูลสำหรับประมวลผลซ้ำได้");
results.Add(new
{
taskId = job.TaskId,
keycloakUserId = job.KeycloakUserId,
checkType = job.CheckType,
createdDate = job.CreatedDate,
previousStatus = job.Status,
newStatus = "FAILED",
errorMessage = "ไม่สามารถอ่านข้อมูลสำหรับประมวลผลซ้ำได้"
});
continue;
}
// ตั้ง TaskId ให้ตรงกับ job เดิม
checkData.TaskId = job.TaskId;
// เรียก ProcessCheckInAsync ด้วยข้อมูลเดิม
var processResult = await ProcessCheckInAsync(checkData);
results.Add(new
{
taskId = job.TaskId,
keycloakUserId = job.KeycloakUserId,
checkType = job.CheckType,
createdDate = job.CreatedDate,
previousStatus = job.Status,
result = processResult
});
}
catch (Exception ex)
{
await _checkInJobStatusRepository.UpdateToFailedAsync(job.TaskId,
$"เกิดข้อผิดพลาดในการประมวลผลซ้ำ: {ex.Message}");
results.Add(new
{
taskId = job.TaskId,
keycloakUserId = job.KeycloakUserId,
checkType = job.CheckType,
createdDate = job.CreatedDate,
previousStatus = job.Status,
newStatus = "FAILED",
errorMessage = ex.Message
});
}
}
return Success(new
{
message = $"ประมวลผลซ้ำงาน {staleJobs.Count} รายการเสร็จสิ้น",
count = staleJobs.Count,
jobs = results
});
}
catch (Exception ex)
{
return Error(ex);
}
}
[HttpGet("check-status")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
@ -962,12 +1080,14 @@ namespace BMA.EHR.Leave.Service.Controllers
{
//throw new Exception(GlobalMessages.NoFileToUpload);
await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, GlobalMessages.NoFileToUpload);
await _notificationService.SendNotificationAsync(data.Token, true, $"ลงเวลาไม่สำเร็จ \r\nเนื่องจาก {GlobalMessages.NoFileToUpload}\r\nกรุณาลองใหม่อีกครั้ง");
await _notificationService.SendNotificationAsync(data.Token, true,
$"ลงเวลาไม่สำเร็จ \r\nเนื่องจาก {GlobalMessages.NoFileToUpload}\r\nกรุณาลองใหม่อีกครั้ง");
// send notification to user
var noti1 = new Notification
{
Body = $"ประมวลผลการลงเวลาวันที่ {currentDate.ToString("dd-MM-yyyy")} ไม่สำเร็จ \r\nเนื่องจาก {GlobalMessages.NoFileToUpload}",
Body =
$"ประมวลผลการลงเวลาวันที่ {currentDate.ToString("dd-MM-yyyy")} ไม่สำเร็จ \r\nเนื่องจาก {GlobalMessages.NoFileToUpload}",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
@ -984,39 +1104,47 @@ namespace BMA.EHR.Leave.Service.Controllers
var check_status = data.CheckInId == null ? "check-in-picture" : "check-out-picture";
var check_out_status = "check-out-picture";
var fileName = $"{_bucketName}/{userId}/{currentDate.ToString("dd-MM-yyyy")}/{check_status}/{data.CheckInFileName}";
var fileNameCheckOut = $"{_bucketName}/{userId}/{currentDate.ToString("dd-MM-yyyy")}/{check_out_status}/{data.CheckInFileName}";
using (var ms = new MemoryStream(data.CheckInFileBytes ?? new byte[0]))
// ถ้าไม่มี CheckInFileBytes ให้ใช้ภาพ blank.jpeg แทน
var fileBytes = data.CheckInFileBytes;
if (fileBytes == null || fileBytes.Length == 0)
{
var blankPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot", "blank.jpeg");
fileBytes = await System.IO.File.ReadAllBytesAsync(blankPath);
data.CheckInFileName = "blank.jpeg";
}
var fileName =
$"{_bucketName}/{userId}/{currentDate.ToString("dd-MM-yyyy")}/{check_status}/{data.CheckInFileName}";
var fileNameCheckOut =
$"{_bucketName}/{userId}/{currentDate.ToString("dd-MM-yyyy")}/{check_out_status}/{data.CheckInFileName}";
using (var ms = new MemoryStream(fileBytes))
{
try
{
await _minIOService.UploadFileAsync(fileName, ms);
// if (lastCheckIn != null && lastCheckIn.CheckOut == null)
// {
// // ยังไม่เคย check-out มาก่อน หรือ check-out เป็น null ให้ใช้ชื่อไฟล์แบบ check-out
// await _minIOService.UploadFileAsync(fileNameCheckOut, ms);
// }
}
catch (Exception ex)
{
await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, $"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}");
await _notificationService.SendNotificationAsync(data.Token, true, $"ลงเวลาไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}\r\nกรุณาลองใหม่อีกครั้ง");
await _checkInJobStatusRepository.UpdateToFailedAsync(taskId,
$"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}");
await _notificationService.SendNotificationAsync(data.Token, true,
$"ลงเวลาไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}\r\nกรุณาลองใหม่อีกครั้ง");
// send notification to user
var noti1 = new Notification
var noti2 = new Notification
{
Body = $"ประมวลผลการลงเวลาวันที่ {currentDate.ToString("dd-MM-yyyy")} ไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}",
Body =
$"ประมวลผลการลงเวลาวันที่ {currentDate.ToString("dd-MM-yyyy")} ไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti1);
_appDbContext.Set<Notification>().Add(noti2);
await _appDbContext.SaveChangesAsync();
return Error($"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}", StatusCodes.Status500InternalServerError);
return Error($"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}",
StatusCodes.Status500InternalServerError);
}
}
if (lastCheckIn != null && lastCheckIn.CheckOut == null)
@ -1026,36 +1154,32 @@ namespace BMA.EHR.Leave.Service.Controllers
try
{
await _minIOService.UploadFileAsync(fileNameCheckOut, ms2);
// if (lastCheckIn != null && lastCheckIn.CheckOut == null)
// {
// // ยังไม่เคย check-out มาก่อน หรือ check-out เป็น null ให้ใช้ชื่อไฟล์แบบ check-out
// await _minIOService.UploadFileAsync(fileNameCheckOut, ms);
// }
}
catch (Exception ex)
{
await _checkInJobStatusRepository.UpdateToFailedAsync(taskId, $"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}");
await _notificationService.SendNotificationAsync(data.Token, true, $"ลงเวลาไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}\r\nกรุณาลองใหม่อีกครั้ง");
await _checkInJobStatusRepository.UpdateToFailedAsync(taskId,
$"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}");
await _notificationService.SendNotificationAsync(data.Token, true,
$"ลงเวลาไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}\r\nกรุณาลองใหม่อีกครั้ง");
// send notification to user
var noti1 = new Notification
var noti3 = new Notification
{
Body = $"ประมวลผลการลงเวลาวันที่ {currentDate.ToString("dd-MM-yyyy")} ไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}",
Body =
$"ประมวลผลการลงเวลาวันที่ {currentDate.ToString("dd-MM-yyyy")} ไม่สำเร็จ \r\nเนื่องจากไม่สามารถอัปโหลดรูปภาพได้ {ex.Message}",
ReceiverUserId = profile.Id,
Type = "",
Payload = "",
};
_appDbContext.Set<Notification>().Add(noti1);
_appDbContext.Set<Notification>().Add(noti3);
await _appDbContext.SaveChangesAsync();
return Error($"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}", StatusCodes.Status500InternalServerError);
return Error($"ไม่สามารถอัปโหลดรูปภาพได้: {ex.Message}",
StatusCodes.Status500InternalServerError);
}
}
}
var defaultRound = await _dutyTimeRepository.GetDefaultAsync();
if (defaultRound == null)
{

View file

@ -198,12 +198,20 @@ if (manager != null)
// ทำความสะอาดข้อมูล CheckIn Job Status ที่เก่ากว่า 30 วัน - รันทุกวันเวลา 02:00 น.
manager.AddOrUpdate("ทำความสะอาดข้อมูล CheckIn Job Status", Job.FromExpression<CheckInJobStatusRepository>(x => x.CleanupOldJobsAsync(30)), "0 2 * * *", bangkokTimeZone);
manager.AddOrUpdate("ประมวลผลงานที่ค้างอยู่ในสถานะ Pending หรือ Processing", Job.FromExpression<LeaveProcessJobStatusRepository>(x => x.ProcessPendingJobsAsync()), "0 3 * * *",
new RecurringJobOptions
{
TimeZone = bangkokTimeZone,
QueueName = "leave" // ← กำหนด queue
});
// ตรวจสอบและ mark งาน CheckIn ที่ค้างเกิน 30 นาทีเป็น FAILED - รันทุก 15 นาที
// manager.AddOrUpdate("ตรวจสอบงาน CheckIn ที่ค้างเกินเวลา", Job.FromExpression<CheckInJobStatusRepository>(x => x.MarkStaleJobsAsFailedAsync(30)), "*/15 * * * *",
// new RecurringJobOptions
// {
// TimeZone = bangkokTimeZone,
// QueueName = "leave"
// });
//
// manager.AddOrUpdate("ประมวลผลงานที่ค้างอยู่ในสถานะ Pending หรือ Processing", Job.FromExpression<LeaveProcessJobStatusRepository>(x => x.ProcessPendingJobsAsync()), "0 3 * * *",
// new RecurringJobOptions
// {
// TimeZone = bangkokTimeZone,
// QueueName = "leave" // ← กำหนด queue
// });
}
// apply migrations

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -676,6 +676,7 @@ namespace BMA.EHR.Placement.Service.Controllers
uppdated.posMasterNo = req.posMasterNo;
uppdated.position = req.positionName;
uppdated.PositionExecutive = req.posExecutiveName;
uppdated.posExecutiveId = req.posExecutiveId;
uppdated.positionExecutiveField = req.positionExecutiveField;
uppdated.positionArea = req.positionArea;
uppdated.positionField = req.positionField;
@ -1014,6 +1015,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,
@ -1226,6 +1229,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,
@ -1855,6 +1860,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,
@ -2016,6 +2023,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,

View file

@ -1065,6 +1065,7 @@ namespace BMA.EHR.Placement.Service.Controllers
person.positionId = req.positionId;
person.posMasterNo = req.posMasterNo;
person.positionName = req.positionName;
person.posExecutiveId = req.posExecutiveId;
person.PositionExecutive = req.posExecutiveName;
person.positionExecutiveField = req.positionExecutiveField;
person.positionArea = req.positionArea;
@ -1453,6 +1454,10 @@ namespace BMA.EHR.Placement.Service.Controllers
profile.posTypeName = null;
profile.posLevelId = null;
profile.posLevelName = null;
profile.PositionExecutive = null;
profile.posExecutiveId = null;
profile.positionArea = null;
profile.positionExecutiveField = null;
// profile.PositionLevel = null;
// profile.PositionType = null;
@ -1810,16 +1815,27 @@ namespace BMA.EHR.Placement.Service.Controllers
[HttpPost("recruit/report/excecute")]
public async Task<ActionResult<ResponseObject>> PostReportExecuteRecruit([FromBody] ReportExecuteRequest req)
{
Console.WriteLine($"[RecruitReportExcecute] Starting execution at {DateTime.Now}");
try
{
Console.WriteLine($"[RecruitReportExcecute] Request received with {req?.refIds?.Length ?? 0} refIds");
var placementProfile = await _context.PlacementProfiles
.Include(x => x.PlacementCertificates)
.Include(x => x.PlacementEducations)
.Where(x => req.refIds.Select(x => x.refId).Contains(x.Id.ToString()))
.ToListAsync();
Console.WriteLine($"[RecruitReportExcecute] Found {placementProfile?.Count ?? 0} placement profiles");
if (placementProfile == null)
{
Console.Error.WriteLine("[RecruitReportExcecute] PlacementProfile is null - returning NotFound");
return NotFound();
}
Console.WriteLine("[RecruitReportExcecute] Building resultData from placement profiles and refIds");
var resultData = (from p in placementProfile
join r in req.refIds
@ -1936,7 +1952,14 @@ namespace BMA.EHR.Placement.Service.Controllers
bodyPosition = new
{
posmasterId = p.posmasterId,
positionId = p.positionId
positionId = p.positionId,
positionName = p.positionName,
positionField = p.positionField,
posTypeId = p.posTypeId,
posLevelId = p.posLevelId,
posExecutiveId = p.posExecutiveId,
positionExecutiveField = p.positionExecutiveField,
positionArea = p.positionArea,
},
bodyMarry = new
{
@ -1965,6 +1988,9 @@ namespace BMA.EHR.Placement.Service.Controllers
},
}).ToList();
Console.WriteLine($"[RecruitReportExcecute] resultData built successfully with {resultData?.Count ?? 0} records");
Console.WriteLine($"[RecruitReportExcecute] Calling external API: {_configuration["API"]}/org/command/excexute/create-officer-profile");
var apiUrl = $"{_configuration["API"]}/org/command/excexute/create-officer-profile";
using (var client = new HttpClient())
{
@ -1976,8 +2002,10 @@ namespace BMA.EHR.Placement.Service.Controllers
data = resultData
});
var _result = await _res.Content.ReadAsStringAsync();
Console.WriteLine($"[RecruitReportExcecute] External API response status: {_res.StatusCode}");
if (_res.IsSuccessStatusCode)
{
Console.WriteLine("[RecruitReportExcecute] External API call successful - updating placement profiles");
placementProfile.ForEach(profile =>
{
profile.PlacementStatus = "DONE";
@ -1991,14 +2019,24 @@ namespace BMA.EHR.Placement.Service.Controllers
profile.templateDoc = req.refIds[0].remark;
}
});
Console.WriteLine($"[RecruitReportExcecute] Saving changes to database for {placementProfile.Count} profiles");
await _context.SaveChangesAsync();
Console.WriteLine("[RecruitReportExcecute] Database save completed successfully");
}
else
{
Console.Error.WriteLine($"[RecruitReportExcecute] External API call failed with status: {_res.StatusCode}");
Console.Error.WriteLine($"[RecruitReportExcecute] Response content: {_result}");
}
}
Console.WriteLine($"[RecruitReportExcecute] Process completed successfully at {DateTime.Now}");
return Success();
}
catch
catch (Exception ex)
{
Console.Error.WriteLine($"[RecruitReportExcecute] Error occurred: {ex.Message}");
Console.Error.WriteLine($"[RecruitReportExcecute] Stack trace: {ex.StackTrace}");
throw;
}
}
@ -2292,7 +2330,14 @@ namespace BMA.EHR.Placement.Service.Controllers
bodyPosition = new
{
posmasterId = p.posmasterId,
positionId = p.positionId
positionId = p.positionId,
positionName = p.positionName,
positionField = p.positionField,
posTypeId = p.posTypeId,
posLevelId = p.posLevelId,
posExecutiveId = p.posExecutiveId,
positionExecutiveField = p.positionExecutiveField,
positionArea = p.positionArea,
},
bodyMarry = new
{
@ -2563,6 +2608,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,
@ -2804,6 +2851,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,
@ -3030,6 +3079,8 @@ namespace BMA.EHR.Placement.Service.Controllers
positionLevel = p.posLevelName,
posmasterId = p.posmasterId,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
commandId = r.commandId,
orgRoot = p.root,
orgChild1 = p.child1,

View file

@ -782,6 +782,7 @@ namespace BMA.EHR.Placement.Service.Controllers
uppdated.posMasterNo = req.posMasterNo;
uppdated.position = req.positionName;
uppdated.PositionExecutive = req.posExecutiveName;
uppdated.posExecutiveId = req.posExecutiveId;
uppdated.positionExecutiveField = req.positionExecutiveField;
uppdated.positionArea = req.positionArea;
uppdated.positionField = req.positionField;
@ -1216,8 +1217,15 @@ namespace BMA.EHR.Placement.Service.Controllers
},
bodyPosition = new
{
posmasterId = p.posmasterId,
positionId = p.positionId
posmasterId = p.posmasterId,
positionId = p.positionId,
positionName = p.position,
positionField = p.positionField,
posTypeId = p.posTypeId,
posLevelId = p.posLevelId,
posExecutiveId = p.posExecutiveId,
positionExecutiveField = p.positionExecutiveField,
positionArea = p.positionArea,
}
}).ToList();

View file

@ -30,6 +30,7 @@ namespace BMA.EHR.Placement.Service.Requests
public string? posLevelName { get; set; }
public string? typeCommand { get; set; }
public string? posExecutiveName { get; set; }
public string? posExecutiveId { get; set; }
public string? positionExecutiveField { get; set; }
public string? positionArea { get; set; }
}

View file

@ -30,6 +30,7 @@ namespace BMA.EHR.Placement.Service.Requests
public string? posLevelName { get; set; }
public string? typeCommand { get; set; }
public string? posExecutiveName { get; set; }
public string? posExecutiveId { get; set; }
public string? positionExecutiveField { get; set; }
public string? positionArea { get; set; }
}

View file

@ -39,6 +39,7 @@ namespace BMA.EHR.Placement.Service.Requests
public string? posLevelName { get; set; }
public string? typeCommand { get; set; }
public string? posExecutiveName { get; set; }
public string? posExecutiveId { get; set; }
public string? positionExecutiveField { get; set; }
public string? positionArea { get; set; }

View file

@ -569,6 +569,7 @@ namespace BMA.EHR.Retirement.Service.Controllers
uppdated.positionId = req.positionId;
uppdated.posMasterNo = req.posMasterNo;
uppdated.position = req.positionName;
uppdated.posExecutiveId = req.posExecutiveId;
uppdated.PositionExecutive = req.posExecutiveName;
uppdated.positionExecutiveField = req.positionExecutiveField;
uppdated.positionArea = req.positionArea;
@ -889,6 +890,9 @@ namespace BMA.EHR.Retirement.Service.Controllers
commandCode = r.commandCode,
commandName = r.commandName,
remark = r.remark,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
positionTypeNew = p.posTypeId,
positionLevelNew = p.posLevelId,
positionNameNew = p.position,
@ -1138,6 +1142,9 @@ namespace BMA.EHR.Retirement.Service.Controllers
commandCode = r.commandCode,
commandName = r.commandName,
remark = r.remark,
positionId = p.positionId,
posExecutiveId = p.posExecutiveId,
positionField = p.positionField,
positionTypeNew = p.posTypeId,
positionLevelNew = p.posLevelId,
positionNameNew = p.position,

View file

@ -29,6 +29,7 @@ namespace BMA.EHR.Retirement.Service.Requests
public string? posLevelId { get; set; }
public string? posLevelName { get; set; }
public string? typeCommand { get; set; }
public string? posExecutiveId { get; set; }
public string? posExecutiveName { get; set; }
public string? positionExecutiveField { get; set; }
public string? positionArea { get; set; }