using ClosedXML.Excel; using System.IO; using PSTW_CentralSystem.Models; using PSTW_CentralSystem.Areas.OTcalculate.Models; using System; using System.Collections.Generic; using System.Linq; namespace PSTW_CentralSystem.Areas.OTcalculate.Services { public class OvertimeExcelService { public MemoryStream GenerateOvertimeExcel( List records, int departmentId, string userFullName, string departmentName, int userStateId, int weekendId, List publicHolidays, bool isAdminUser = false, byte[]? logoImage = null // This parameter is missing in the call ) { var workbook = new XLWorkbook(); var worksheet = workbook.Worksheets.Add("Overtime Records"); int currentRow = 1; // Add Header Information if (!string.IsNullOrEmpty(userFullName)) { worksheet.Cell(currentRow, 1).Value = $"Name: {userFullName}"; currentRow++; } if (!string.IsNullOrEmpty(departmentName)) { worksheet.Cell(currentRow, 1).Value = $"Department: {departmentName}"; currentRow++; } currentRow++; // Add an empty row after header // Header titles var headers = new List { "Day", "Date", "Office From", "Office To", "Office Break", "After From", "After To", "After Break", "Total OT", "Break Minutes", "Net OT" }; if (departmentId == 2 || isAdminUser) headers.Add("Station"); headers.Add("Description"); // Set header row int headerRow = currentRow; for (int i = 0; i < headers.Count; i++) { var cell = worksheet.Cell(headerRow, i + 1); cell.Value = headers[i]; cell.Style.Font.Bold = true; cell.Style.Fill.BackgroundColor = XLColor.LightGray; cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; cell.Style.Border.OutsideBorder = XLBorderStyleValues.Thin; cell.Style.Border.InsideBorder = XLBorderStyleValues.Thin; } currentRow++; // Fill data rows foreach (var r in records) { TimeSpan totalOT = CalculateTotalOT(r); int totalBreak = (r.OfficeBreak ?? 0) + (r.AfterBreak ?? 0); TimeSpan netOT = totalOT - TimeSpan.FromMinutes(totalBreak); int col = 1; var dayCell = worksheet.Cell(currentRow, col++); dayCell.Value = r.OtDate.ToString("ddd"); dayCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; dayCell.Style.Border.OutsideBorder = XLBorderStyleValues.Thin; dayCell.Style.Border.InsideBorder = XLBorderStyleValues.Thin; var dateCell = worksheet.Cell(currentRow, col++); dateCell.Value = r.OtDate.ToString("yyyy-MM-dd"); dateCell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; dateCell.Style.Border.OutsideBorder = XLBorderStyleValues.Thin; dateCell.Style.Border.InsideBorder = XLBorderStyleValues.Thin; // Apply background color for weekends and public holidays var dayOfWeek = r.OtDate.DayOfWeek; bool isWeekend = (weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) || (weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)); bool isPublicHoliday = publicHolidays.Any(h => h.HolidayDate.Date == r.OtDate.Date); if (isPublicHoliday) { dayCell.Style.Fill.BackgroundColor = XLColor.Pink; dateCell.Style.Fill.BackgroundColor = XLColor.Pink; } else if (isWeekend) { dayCell.Style.Fill.BackgroundColor = XLColor.LightBlue; dateCell.Style.Fill.BackgroundColor = XLColor.LightBlue; } worksheet.Cell(currentRow, col++).Value = FormatTime(r.OfficeFrom); worksheet.Cell(currentRow, col++).Value = FormatTime(r.OfficeTo); worksheet.Cell(currentRow, col++).Value = r.OfficeBreak; worksheet.Cell(currentRow, col++).Value = FormatTime(r.AfterFrom); worksheet.Cell(currentRow, col++).Value = FormatTime(r.AfterTo); worksheet.Cell(currentRow, col++).Value = r.AfterBreak; worksheet.Cell(currentRow, col++).Value = totalOT.ToString(@"hh\:mm"); worksheet.Cell(currentRow, col++).Value = totalBreak; worksheet.Cell(currentRow, col++).Value = netOT.ToString(@"hh\:mm"); if (departmentId == 2 || isAdminUser) worksheet.Cell(currentRow, col++).Value = r.Stations?.StationName ?? ""; worksheet.Cell(currentRow, col++).Value = r.OtDescription ?? ""; // Apply border and alignment for the rest of the row for (int i = headers.IndexOf("Office From") + 1; i <= headers.Count; i++) { var cell = worksheet.Cell(currentRow, i); cell.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; cell.Style.Border.OutsideBorder = XLBorderStyleValues.Thin; cell.Style.Border.InsideBorder = XLBorderStyleValues.Thin; } currentRow++; } // Add Total row int totalRow = currentRow; worksheet.Cell(totalRow, 1).Value = "TOTAL"; worksheet.Cell(totalRow, 1).Style.Font.Bold = true; worksheet.Cell(totalRow, headers.IndexOf("Total OT") + 1).Value = $"=SUM(I{headerRow + 1}:I{totalRow - 1})"; worksheet.Cell(totalRow, headers.IndexOf("Total OT") + 1).Style.Font.Bold = true; worksheet.Cell(totalRow, headers.IndexOf("Break Minutes") + 1).Value = $"=SUM(J{headerRow + 1}:J{totalRow - 1})"; worksheet.Cell(totalRow, headers.IndexOf("Break Minutes") + 1).Style.Font.Bold = true; worksheet.Cell(totalRow, headers.IndexOf("Net OT") + 1).Value = $"=SUM(K{headerRow + 1}:K{totalRow - 1})"; worksheet.Cell(totalRow, headers.IndexOf("Net OT") + 1).Style.Font.Bold = true; worksheet.Columns().AdjustToContents(); var stream = new MemoryStream(); workbook.SaveAs(stream); stream.Position = 0; return stream; } private TimeSpan CalculateTotalOT(OtRegisterModel r) { TimeSpan office = (r.OfficeTo ?? TimeSpan.Zero) - (r.OfficeFrom ?? TimeSpan.Zero); TimeSpan after = (r.AfterTo ?? TimeSpan.Zero) - (r.AfterFrom ?? TimeSpan.Zero); if (after < TimeSpan.Zero) after += TimeSpan.FromHours(24); return office + after; } private string FormatTime(TimeSpan? time) { return time == null || time == TimeSpan.Zero ? "" : time.Value.ToString(@"hh\:mm"); } } }