Merge branch 'develop' into adiDev
This commit is contained in:
commit
aeb2ceea6f
13 changed files with 332 additions and 64 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -74,6 +74,9 @@
|
|||
<Content Update="wwwroot\keycloak.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="wwwroot\blank.jpeg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -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,35 +1154,31 @@ 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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
BIN
BMA.EHR.Leave/wwwroot/blank.jpeg
Normal file
BIN
BMA.EHR.Leave/wwwroot/blank.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -1217,7 +1218,14 @@ namespace BMA.EHR.Placement.Service.Controllers
|
|||
bodyPosition = new
|
||||
{
|
||||
posmasterId = p.posmasterId,
|
||||
positionId = p.positionId
|
||||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue