ปรับให้เก็บข้อมูลเพิ่มเติมใน CheckinJobStatus
This commit is contained in:
parent
2146e0e0ca
commit
f6bf1ab026
5 changed files with 238 additions and 52 deletions
|
|
@ -536,7 +536,18 @@ namespace BMA.EHR.Leave.Service.Controllers
|
|||
// prepare data and convert request body and send to queue
|
||||
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)
|
||||
|
|
@ -544,10 +555,10 @@ namespace BMA.EHR.Leave.Service.Controllers
|
|||
// กรองเฉพาะงานที่เป็นประเภทเดียวกัน (CHECK_IN หรือ CHECK_OUT)
|
||||
var checkType = data.CheckInId == null ? "CHECK_IN" : "CHECK_OUT";
|
||||
var sameTypeJob = existingJobs.FirstOrDefault(j => j.CheckType == checkType);
|
||||
|
||||
|
||||
if (sameTypeJob != null)
|
||||
{
|
||||
|
||||
|
||||
return Error($"มีงาน {checkType} กำลังดำเนินการอยู่", StatusCodes.Status500InternalServerError);
|
||||
// var timeDiff = (currentDate - sameTypeJob.CreatedDate).TotalMinutes;
|
||||
// if (timeDiff < 2)
|
||||
|
|
@ -586,7 +597,7 @@ namespace BMA.EHR.Leave.Service.Controllers
|
|||
LocationName = data.LocationName,
|
||||
Remark = data.Remark,
|
||||
CheckInFileName = data.Img == null ? "no-file" : data.Img.FileName,
|
||||
CheckInFileBytes = checkFileBytes,
|
||||
//CheckInFileBytes = checkFileBytes,
|
||||
Token = AccessToken ?? ""
|
||||
};
|
||||
|
||||
|
|
@ -613,14 +624,7 @@ 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);
|
||||
|
||||
|
|
@ -727,6 +731,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)]
|
||||
|
|
@ -958,16 +1073,18 @@ namespace BMA.EHR.Leave.Service.Controllers
|
|||
|
||||
var currentDate = data.CurrentDate ?? DateTime.Now;
|
||||
|
||||
if (data.CheckInFileName == "no-file")
|
||||
if (data.CheckInFileName == "no-file")
|
||||
{
|
||||
//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 = "",
|
||||
|
|
@ -977,46 +1094,54 @@ namespace BMA.EHR.Leave.Service.Controllers
|
|||
|
||||
return Error(GlobalMessages.NoFileToUpload, StatusCodes.Status400BadRequest);
|
||||
}
|
||||
|
||||
|
||||
// last check-in record
|
||||
var lastCheckIn = await _userTimeStampRepository.GetLastRecord(userId);
|
||||
|
||||
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 +1151,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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue