diff --git a/BMA.EHR.Leave/Controllers/LeaveReportController.cs b/BMA.EHR.Leave/Controllers/LeaveReportController.cs
index 7f190f3b..ab028941 100644
--- a/BMA.EHR.Leave/Controllers/LeaveReportController.cs
+++ b/BMA.EHR.Leave/Controllers/LeaveReportController.cs
@@ -26,7 +26,9 @@ using System.Diagnostics.Metrics;
using System.Globalization;
using System.Security.Claims;
using static Nest.JoinField;
-
+using Microsoft.AspNetCore.Mvc;
+using OfficeOpenXml;
+using Microsoft.AspNetCore.Routing.Template;
namespace BMA.EHR.Leave.Service.Controllers
{
[Route("api/v{version:apiVersion}/leave/report")]
@@ -52,6 +54,7 @@ namespace BMA.EHR.Leave.Service.Controllers
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly PermissionRepository _permission;
private readonly LeaveBeginningRepository _leaveBeginningRepository;
+ private readonly IWebHostEnvironment _hostingEnvironment;
#endregion
@@ -68,7 +71,8 @@ namespace BMA.EHR.Leave.Service.Controllers
UserCalendarRepository userCalendarRepository,
IHttpContextAccessor httpContextAccessor,
PermissionRepository permission,
- LeaveBeginningRepository leaveBeginningRepository)
+ LeaveBeginningRepository leaveBeginningRepository,
+ IWebHostEnvironment hostingEnvironment)
{
_leaveRequestRepository = leaveRequestRepository;
_userProfileRepository = userProfileRepository;
@@ -82,6 +86,7 @@ namespace BMA.EHR.Leave.Service.Controllers
_httpContextAccessor = httpContextAccessor;
_permission = permission;
_leaveBeginningRepository = leaveBeginningRepository;
+ _hostingEnvironment = hostingEnvironment;
}
private class LoopDate
{
@@ -1678,6 +1683,354 @@ namespace BMA.EHR.Leave.Service.Controllers
}
}
+ ///
+ /// LV2_037 - รายงานการเข้างานจำแนกรายวัน รายสัปดาห์ รายเดือน แยกรายหน่วยงาน/ส่วนราชการ
+ ///
+ ///
+ ///
+ /// เมื่อทำรายการสำเร็จ
+ /// ไม่ได้ Login เข้าระบบ
+ /// เมื่อเกิดข้อผิดพลาดในการทำงาน
+ [HttpPost("download/time-records/{type}")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status500InternalServerError)]
+ public async Task> GetTimeRecordsNewOfficerReport([FromBody] GetLeaveDetailByNodeReportDto req, string type)
+ {
+ try
+ {
+ var getPermission = await _permission.GetPermissionAPIAsync("LIST", "SYS_LEAVE_REPORT");
+ var jsonData = JsonConvert.DeserializeObject(getPermission);
+ if (jsonData["status"]?.ToString() != "200")
+ {
+ return Error(jsonData["message"]?.ToString(), StatusCodes.Status403Forbidden);
+ }
+ var profile = new List();
+ string role = jsonData["result"]?.ToString();
+ var nodeId = string.Empty;
+ var profileAdmin = new GetUserOCAllDto();
+ profileAdmin = await _userProfileRepository.GetUserOCAll(Guid.Parse(UserId!), AccessToken);
+ if (role == "NORMAL" || role == "CHILD")
+ {
+ nodeId = profileAdmin?.Node == 4
+ ? profileAdmin?.Child4DnaId
+ : profileAdmin?.Node == 3
+ ? profileAdmin?.Child3DnaId
+ : profileAdmin?.Node == 2
+ ? profileAdmin?.Child2DnaId
+ : profileAdmin?.Node == 1
+ ? profileAdmin?.Child1DnaId
+ : profileAdmin?.Node == 0
+ ? profileAdmin?.RootDnaId
+ : "";
+ }
+ else if (role == "ROOT")
+ {
+ nodeId = profileAdmin?.RootDnaId;
+ }
+ if (type.Trim().ToUpper() == "OFFICER")
+ {
+ profile = await _userProfileRepository.GetProfileByAdminRole(AccessToken, profileAdmin?.Node, nodeId, role, req.revisionId);
+ }
+ else
+ {
+ profile = await _userProfileRepository.GetEmployeeByAdminRole(AccessToken, profileAdmin?.Node, nodeId, role, req.revisionId);
+ }
+ var date = req.StartDate.Date;
+
+ var holidays = await _holidayRepository.GetHolidayAsync(req.StartDate.Date, req.EndDate.Date);
+ var weekend = _holidayRepository.GetWeekEnd(req.StartDate.Date, req.EndDate.Date);
+ var excludeDates = holidays.Union(weekend).ToList();
+
+ var dateList = new List();
+ for (DateTime i = req.StartDate.Date; i <= req.EndDate.Date; i = i.AddDays(1))
+ {
+
+ if (holidays.Contains(i))
+ {
+ var d = await _holidayRepository.GetHolidayAsync(i);
+ dateList.Add(new LoopDate
+ {
+ date = i,
+ isHoliday = true,
+ isWeekEnd = false,
+ dateRemark = d
+ });
+ }
+ else if (weekend.Contains(i))
+ {
+ dateList.Add(new LoopDate
+ {
+ date = i,
+ isHoliday = true,
+ isWeekEnd = false,
+ dateRemark = "วันหยุด"
+ });
+ }
+ else
+ {
+ dateList.Add(new LoopDate
+ {
+ date = i,
+ isHoliday = false,
+ isWeekEnd = false,
+ dateRemark = ""
+ });
+ }
+ }
+
+ var employees = new List();
+ var count = 1;
+
+ var restTotal = 0;
+ var sickTotal = 0;
+ var lateTotal = 0;
+ var wfhTotal = 0;
+ var studyTotal = 0;
+ var workTotal = 0;
+ var seminarTotal = 0;
+ // กรองตามที่ fe ส่งมา
+ if (role == "ROOT" || role == "OWNER" || role == "CHILD")
+ {
+ profile = profile
+ .Where(x => req.node == 4 ? x.OrgChild4Id == req.nodeId : req.node == 3 ? x.OrgChild3Id == req.nodeId : req.node == 2 ? x.OrgChild2Id == req.nodeId : req.node == 1 ? x.OrgChild1Id == req.nodeId : req.node == 0 ? x.OrgRootId == req.nodeId : true)
+ .ToList();
+ }
+ var defaultRound = await _dutyTimeRepository.GetDefaultAsync();
+ if (defaultRound == null)
+ {
+ return Error("ไม่พบรอบการลงเวลา Default", StatusCodes.Status404NotFound);
+ }
+ foreach (var dd in dateList)
+ {
+ foreach (var p in profile)
+ {
+ var keycloakUserId = p.Keycloak ?? Guid.Empty;
+
+ var timeStamps = await _processUserTimeStampRepository.GetTimestampByDateAsync(keycloakUserId, dd.date);
+
+ var fullName = $"{p.Prefix}{p.FirstName} {p.LastName}";
+
+ var effectiveDate = await _userDutyTimeRepository.GetLastEffectRound(p.Id);
+ var roundId = effectiveDate != null ? effectiveDate.DutyTimeId : Guid.Empty;
+ var userRound = await _dutyTimeRepository.GetByIdAsync(roundId);
+
+ var duty = userRound ?? defaultRound;
+
+ // check วันลาของแต่ละคน
+ var leaveReq = await _leaveRequestRepository.GetLeavePeriodAsync(keycloakUserId, dd.date);
+ var remarkStr = string.Empty;
+
+ if (leaveReq != null)
+ {
+ switch (leaveReq.Type.Code.ToUpper())
+ {
+ case "LV-001":
+ case "LV-002":
+ case "LV-005":
+ remarkStr += leaveReq.Type.Name;
+ var leaveRange = leaveReq.LeaveRange == null ? "" : leaveReq.LeaveRange.ToUpper();
+ if (leaveRange == "MORNING")
+ remarkStr += "ครึ่งวันเช้า";
+ else if (leaveRange == "AFTERNOON")
+ remarkStr += "ครึ่งวันบ่าย";
+
+
+ var leaveRangeEnd = leaveReq.LeaveRangeEnd == null ? "" : leaveReq.LeaveRangeEnd.ToUpper();
+ if (leaveRangeEnd == "MORNING")
+ remarkStr += "ครึ่งวันเช้า";
+ else if (leaveRangeEnd == "AFTERNOON")
+ remarkStr += "ครึ่งวันบ่าย";
+ break;
+ default:
+ remarkStr += leaveReq.Type.Name;
+ break;
+ }
+ }
+ else
+ {
+ if (timeStamps == null)
+ {
+ if (dd.date <= DateTime.Now.Date)
+ {
+ remarkStr = "ขาดราชการ";
+ if (dd.isHoliday == true)
+ {
+ remarkStr = $"วันหยุด ({dd.dateRemark})";
+ }
+ else if (dd.isWeekEnd)
+ {
+ remarkStr = dd.dateRemark;
+ }
+ }
+ else remarkStr = "";
+ }
+ else
+ {
+ // check status ของการลงเวลา
+ if (timeStamps.CheckOut != null)
+ {
+ if (timeStamps.CheckOutStatus == "ABSENT")
+ remarkStr = "ขาดราชการ" + (!timeStamps.IsLocationCheckOut ? $" (นอกสถานที่:{timeStamps.CheckOutLocationName})".Trim() : "");
+ else if (timeStamps.CheckInStatus == "ABSENT")
+ remarkStr = "ขาดราชการ" + (!timeStamps.IsLocationCheckIn ? $" (นอกสถานที่:{timeStamps.CheckInLocationName})".Trim() : "");
+ else if (timeStamps.CheckInStatus == "LATE")
+ {
+ remarkStr = "สาย" + (!timeStamps.IsLocationCheckIn ? $" (นอกสถานที่:{timeStamps.CheckInLocationName})".Trim() : "");
+ lateTotal += 1;
+ }
+ else
+ remarkStr = !timeStamps.IsLocationCheckIn ? $" นอกสถานที่:{timeStamps.CheckInLocationName}".Trim() : "";
+ }
+ else
+ {
+ if (timeStamps.CheckInStatus == "ABSENT")
+ remarkStr = "ขาดราชการ" + (!timeStamps.IsLocationCheckIn ? $" (นอกสถานที่:{timeStamps.CheckInLocationName})".Trim() : "");
+ else if (timeStamps.CheckInStatus == "LATE")
+ {
+ remarkStr = "สาย" + (!timeStamps.IsLocationCheckIn ? $" (นอกสถานที่:{timeStamps.CheckInLocationName})".Trim() : "");
+ lateTotal += 1;
+ }
+ else
+ remarkStr = !timeStamps.IsLocationCheckIn ? $" นอกสถานที่:{timeStamps.CheckInLocationName}".Trim() : "";
+ }
+ }
+ }
+
+ var emp = new DateResultReport
+ {
+ no = count,
+ fullName = fullName,
+ dutyTimeName = $"{duty.StartTimeMorning} - {duty.EndTimeAfternoon} น.",
+ checkInLocation = timeStamps == null ? "" : timeStamps.CheckInPOI,
+ checkInTime = timeStamps == null ? "" : $"{timeStamps.CheckIn.ToString("HH:mm")} น.",
+ checkOutLocation = timeStamps == null ? "" : timeStamps.CheckOutPOI ?? "",
+ checkOutTime = timeStamps == null ? "" :
+ timeStamps.CheckOut != null ?
+ $"{timeStamps.CheckOut.Value.ToString("HH:mm")} น." :
+ "",
+ remark = remarkStr,
+ checkInDate = timeStamps == null ? dd.date.Date.ToThaiFullDate2() : timeStamps.CheckIn.Date.ToThaiFullDate2(),
+ checkedOutDate = timeStamps == null ? dd.date.Date.ToThaiFullDate2() :
+ timeStamps.CheckOut != null ?
+ timeStamps.CheckOut.Value.ToThaiFullDate2() :
+ "",
+ checkInTimeRaw = timeStamps?.CheckIn,
+ checkOutTimeRaw = timeStamps?.CheckOut,
+ };
+
+ if (timeStamps != null)
+ {
+ workTotal += 1;
+ if (!timeStamps.IsLocationCheckIn)
+ {
+ if (timeStamps.CheckInLocationName == "ปฏิบัติงานที่บ้าน")
+ wfhTotal += 1;
+ else if (timeStamps.CheckInLocationName == "ไปประชุม/อบรม/สัมมนา/ปฏิบัติงานที่บ้านนอกสถานที่")
+ seminarTotal += 1;
+ }
+ }
+
+ if (leaveReq != null)
+ {
+ switch (leaveReq.Type.Code.ToUpper())
+ {
+ case "LV-001":
+ case "LV-002":
+ sickTotal += 1;
+ break;
+ case "LV-005":
+ restTotal += 1;
+ break;
+ case "LV-008":
+ studyTotal += 1;
+ break;
+ }
+ }
+
+ employees.Add(emp);
+ count++;
+ }
+ }
+ employees = employees.OrderBy(x => x.checkInDate).ThenBy(x => x.checkInTimeRaw ?? DateTime.MaxValue).ThenBy(x => x.checkOutTimeRaw ?? DateTime.MaxValue).ToList();
+ for (int i = 0; i < employees.Count; i++)
+ {
+ employees[i].no = i + 1;
+ }
+
+ var enddate = req.EndDate.Date == req.StartDate.Date ? "" : $" - {req.EndDate.Date.ToThaiShortDate()}";
+ var org = _userProfileRepository.GetOc(Guid.Parse(req.nodeId), req.node, AccessToken);
+ var organizationName = $"{(!string.IsNullOrEmpty(org.Child4) ? org.Child4 + "/" : "")}{(!string.IsNullOrEmpty(org.Child3) ? org.Child3 + "/" : "")}{(!string.IsNullOrEmpty(org.Child2) ? org.Child2 + "/" : "")}{(!string.IsNullOrEmpty(org.Child1) ? org.Child1 + "/" : "")}{org.Root ?? ""}";
+ var dateTimeStamp = $"ประจำ ณ วัน{req.StartDate.Date.GetThaiDayOfWeek()} ที่ {req.StartDate.Date.ToThaiShortDate()}{enddate}";
+ var template = System.IO.Path.Combine(_hostingEnvironment.ContentRootPath, "Reports", "TimeStampRecords.xlsx");
+ FileInfo reportFile = new FileInfo(template);
+ using (var package = new ExcelPackage(reportFile))
+ {
+ var worksheet = package.Workbook.Worksheets[0];
+ worksheet.Cells[2, 1].Value = organizationName;
+ worksheet.Cells[3, 1].Value = dateTimeStamp;
+ int startRow = 5;
+ foreach (var emp in employees)
+ {
+ worksheet.Cells[startRow, 1].Value = emp.no;
+ worksheet.Cells[startRow, 2].Value = emp.fullName;
+ worksheet.Cells[startRow, 3].Value = emp.dutyTimeName;
+ worksheet.Cells[startRow, 4].Value = emp.checkInDate;
+ worksheet.Cells[startRow, 5].Value = emp.checkInLocation;
+ worksheet.Cells[startRow, 6].Value = emp.checkInTime;
+ worksheet.Cells[startRow, 7].Value = emp.checkedOutDate;
+ worksheet.Cells[startRow, 8].Value = emp.checkOutLocation;
+ worksheet.Cells[startRow, 9].Value = emp.checkOutTime;
+ worksheet.Cells[startRow, 10].Value = emp.remark;
+ // ใส่กรอบให้ตาราง
+ using (var range = worksheet.Cells[startRow, 1, startRow, 10])
+ {
+ range.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
+ range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
+ range.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
+ range.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
+ }
+ startRow++;
+ }
+ int lastRow = startRow + 2;
+ worksheet.Cells[lastRow, 2].Value = type.Trim().ToUpper() == "OFFICER" ? "ข้าราชการทั้งหมด" : "ลูกจ้างประจำทั้งหมด";
+ worksheet.Cells[lastRow, 5].Value = profile?.Count;
+ worksheet.Cells[lastRow, 6].Value = "คน";
+ worksheet.Cells[lastRow, 8].Value = "นอกสถานที่ตั้ง";
+ worksheet.Cells[lastRow + 1, 2].Value = "มาปฏิบัติราชการ";
+ worksheet.Cells[lastRow + 1, 5].Value = workTotal;
+ worksheet.Cells[lastRow + 1, 6].Value = "คน";
+ worksheet.Cells[lastRow + 1, 8].Value = "WFH";
+ worksheet.Cells[lastRow + 1, 9].Value = wfhTotal;
+ worksheet.Cells[lastRow + 1, 10].Value = "คน";
+ worksheet.Cells[lastRow + 2, 2].Value = "ลาพักผ่อน";
+ worksheet.Cells[lastRow + 2, 5].Value = restTotal;
+ worksheet.Cells[lastRow + 2, 6].Value = "คน";
+ worksheet.Cells[lastRow + 2, 8].Value = "อบรม ประชุม สัมมนาฯ";
+ worksheet.Cells[lastRow + 2, 9].Value = seminarTotal;
+ worksheet.Cells[lastRow + 2, 10].Value = "คน";
+ worksheet.Cells[lastRow + 3, 2].Value = "ลาป่วย/ลากิจ";
+ worksheet.Cells[lastRow + 3, 5].Value = sickTotal;
+ worksheet.Cells[lastRow + 3, 6].Value = "คน";
+ worksheet.Cells[lastRow + 4, 2].Value = "มาสาย";
+ worksheet.Cells[lastRow + 4, 5].Value = lateTotal;
+ worksheet.Cells[lastRow + 4, 6].Value = "คน";
+ worksheet.Cells[lastRow + 6, 2].Value = "เรียน";
+ worksheet.Cells[lastRow + 7, 2].Value = "เพื่อโปรดทราบ";
+ worksheet.Cells[lastRow + 7, 9].Value = "ทราบ";
+ worksheet.Cells[lastRow + 8, 2].Value = "................................";
+ worksheet.Cells[lastRow + 8, 9].Value = "................................";
+ worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
+ var fileBytes = package.GetAsByteArray();
+ return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "TimeStampRecords.xlsx");
+ }
+ }
+ catch (Exception ex)
+ {
+ return Error(ex);
+ }
+ }
+
///
/// LV2_035 - รายงานการเข้างานสาย จำแนกเป็นรายบุคคลและหรือรายหน่วยงาน/ส่วนราชการ
///
diff --git a/BMA.EHR.Leave/Reports/TimeStampRecords.xlsx b/BMA.EHR.Leave/Reports/TimeStampRecords.xlsx
new file mode 100644
index 00000000..3c84bb60
Binary files /dev/null and b/BMA.EHR.Leave/Reports/TimeStampRecords.xlsx differ