Files
Backend-Api/CompanyManagement.Infrastructure.Excel/RollCall/RollCallExcelGenerator.cs

468 lines
22 KiB
C#

using _0_Framework.Excel;
using _0_Framework.Application;
using CompanyManagment.App.Contracts.RollCall;
using OfficeOpenXml;
using OfficeOpenXml.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace CompanyManagement.Infrastructure.Excel.RollCall;
public class RollCallExcelGenerator : ExcelGenerator
{
public static byte[] CaseHistoryExcelForEmployee(CaseHistoryRollCallExcelForEmployeeViewModel data)
{
OfficeOpenXml.ExcelPackage.License.SetNonCommercialOrganization("Gozareshgir Noncommercial organization");
using var package = new OfficeOpenXml.ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
var rollCalls = data.RollCalls;
var row = 6;
worksheet.Cells.Style.Locked = false;
// Merge cells from row 1 to 4, covering columns A to G
worksheet.Cells["A1:H4"].Merge = true;
// Add the image to the merged cell
var headerImagePath = Path.Combine("wwwroot", "Excel", "header", "21.png");
using (var stream = new FileStream(headerImagePath, FileMode.Open, FileAccess.Read))
{
var picture = worksheet.Drawings.AddPicture("HeaderImage", stream);
picture.SetPosition(0, 0, 0, 0); // Set position to the merged
picture.ChangeCellAnchor(eEditAs.TwoCell);
picture.EditAs = eEditAs.Absolute;
}
// Add border to the merged cell
var mergedCell = worksheet.Cells["A1:H4"];
mergedCell.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
mergedCell.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
mergedCell.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
mergedCell.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
// Add merged cells below the image
worksheet.Cells["A5:C5"].Merge = true; // ماه
worksheet.Cells["D5:F5"].Merge = true; // نام کارمند
worksheet.Cells["G5:H5"].Merge = true; // شماره پرسنلی
// Add data from ViewModel
worksheet.Cells["A5"].Value = $"{data.PersianMonthName} {data.PersianYear}"; // ماه و سال
worksheet.Cells["D5"].Value = data.EmployeeFullName; // نام کارمند
worksheet.Cells["G5"].Value = $"شماره پرسنلی: {data.PersonnelCode}"; // شماره پرسنلی
// Style merged cells
for (int i = 5; i <= 5; i++)
{
worksheet.Cells[$"A{i}:B{i}"].Style.Font.Bold = true;
worksheet.Cells[$"A{i}:B{i}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
worksheet.Cells[$"A{i}:B{i}"].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
worksheet.Cells[$"A{i}:B{i}"].Style.Font.Size = 14; // Larger font size
worksheet.Cells[$"C{i}:E{i}"].Style.Font.Bold = true;
worksheet.Cells[$"C{i}:E{i}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
worksheet.Cells[$"C{i}:E{i}"].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
worksheet.Cells[$"C{i}:E{i}"].Style.Font.Size = 14; // Larger font size
worksheet.Cells[$"F{i}:G{i}"].Style.Font.Bold = true;
worksheet.Cells[$"F{i}:G{i}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
worksheet.Cells[$"F{i}:G{i}"].Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
worksheet.Cells[$"F{i}:G{i}"].Style.Font.Size = 14; // Larger font size
}
//add border to headers
worksheet.Cells["A5"].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells["H5"].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells["A6"].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells["H6"].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells["B6:C6"].Merge = true;
// Lock cells A1 to H6
worksheet.Cells["A1:H6"].Style.Locked = true;
// Set worksheet protection with password
worksheet.Protection.IsProtected = true;
worksheet.Protection.SetPassword("Gozareshgir2049"); // Set your desired password here
worksheet.Protection.AllowSelectLockedCells = true; // Unlock all other cells
// Add headers
worksheet.Cells["A6"].Value = "ردیف";
worksheet.Cells["B6"].Value = "تاریخ";
worksheet.Cells["D6"].Value = "تاخیر در ورود";
worksheet.Cells["E6"].Value = "ورود";
worksheet.Cells["F6"].Value = "خروج";
worksheet.Cells["G6"].Value = "تعجیل در خروج";
worksheet.Cells["H6"].Value = "مجموع ساعات کاری";
// Style headers
using (var range = worksheet.Cells[row, 1, row, 8])
{
range.Style.Font.Bold = true;
range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray);
range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
range.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
range.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
range.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
}
// Add data
for (int i = 0; i < rollCalls.Count; i++)
{
var rollCall = rollCalls[i];
worksheet.Cells[i + row + 1, 1].Value = i + 1;
worksheet.Cells[i + row + 1, 2].Value = rollCall.DayOfWeekFa;
worksheet.Cells[i + row + 1, 3].Value = rollCall.DateFa;
worksheet.Cells[i + row + 1, 4].Value = rollCall.EnterTimeDifferences;
worksheet.Cells[i + row + 1, 5].Value = rollCall.StartsItems;
worksheet.Cells[i + row + 1, 6].Value = rollCall.EndsItems;
worksheet.Cells[i + row + 1, 7].Value = rollCall.ExitTimeDifferences;
worksheet.Cells[i + row + 1, 8].Value = rollCall.TotalWorkingHours == string.Empty
? "ندارد" : rollCall.TotalWorkingHours;
// Style data cells
for (int j = 1; j <= 8; j++)
{
var cell = worksheet.Cells[i + row + 1, j];
cell.Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin);
cell.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
cell.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
if (j == 5 || j == 6)
{
cell.Style.WrapText = true;
}
}
}
// Merge the last row
int lastRow = rollCalls.Count + row +1;
worksheet.Cells[$"A{lastRow}:G{lastRow}"].Merge = true;
worksheet.Cells[$"A{lastRow}"].Value = $"مجموع کل ساعات کاری : {data.TotalWorkingHoursFa}"; // Replace with your actual data
worksheet.Cells[$"A{lastRow}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Left; // Align left
worksheet.Cells[$"A{lastRow}"].Style.Font.Bold = true;
// Add border to the merged last row
worksheet.Cells[$"A{lastRow}:G{lastRow}"].Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"A{lastRow}:G{lastRow}"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"A{lastRow}:G{lastRow}"].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"A{lastRow}:G{lastRow}"].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"H{lastRow}"].Value = data.TotalWorkingTimeSpan;
worksheet.Cells[$"H{lastRow}"].Style.Font.Bold = true;
worksheet.Cells[$"H{lastRow}"].Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"H{lastRow}"].Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"H{lastRow}"].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"H{lastRow}"].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells[$"H{lastRow}"].Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
// Adjust column widths
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
// Set the sheet to A4 size
worksheet.PrinterSettings.PaperSize = ePaperSize.A4;
worksheet.PrinterSettings.Orientation = eOrientation.Portrait; // or Landscape
worksheet.PrinterSettings.FitToWidth = 1;
worksheet.PrinterSettings.FitToHeight = 0;
worksheet.View.RightToLeft = true;
// Repeat headers on every page
worksheet.PrinterSettings.RepeatRows = new OfficeOpenXml.ExcelAddress("1:6"); // Repeat rows 1 to 6 on every page
return package.GetAsByteArray();
}
public static byte[] CaseHistoryExcelForOneDay(CaseHistoryRollCallForOneDayViewModel data)
{
OfficeOpenXml.ExcelPackage.License.SetNonCommercialOrganization("Gozareshgir Noncommercial organization");
using var package = new OfficeOpenXml.ExcelPackage();
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
var rollCalls = data.RollCalls;
var row = 6;
worksheet.Cells.Style.Locked = false;
// Merge cells from row 1 to 4, covering columns A to H
worksheet.Cells["A1:H4"].Merge = true;
// Add the image to the merged cell
var headerImagePath = Path.Combine("wwwroot", "Excel", "header", "21.OneDay.png");
using (var stream = new FileStream(headerImagePath, FileMode.Open, FileAccess.Read))
{
var picture = worksheet.Drawings.AddPicture("HeaderImage", stream);
picture.SetPosition(0, 0, 0, 0); // Set position to the merged cell
//picture.SetSize(600, 75); // Adjust the size as needed
}
// Add border to the merged cell
var mergedCell = worksheet.Cells["A1:H4"];
mergedCell.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
mergedCell.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
mergedCell.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
mergedCell.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
// Add merged cells below the image
worksheet.Cells["A5:H5"].Merge = true;
// Add data from ViewModel
worksheet.Cells["A5"].Value = $"پرینت حضور و غیاب کل پرسنل به تاریخ {data.DateFa}"; // تاریخ
// Style merged cells
var mergedHeaderCell = worksheet.Cells["A5:H5"];
mergedHeaderCell.Style.Font.Bold = true;
mergedHeaderCell.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
mergedHeaderCell.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
mergedHeaderCell.Style.Font.Size = 14; // Larger font size
// Add border to header cell
worksheet.Cells["A5"].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
worksheet.Cells["H5"].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
// Add headers
worksheet.Cells[row, 1].Value = "ردیف";
worksheet.Cells[row, 2].Value = "نام و نام خانوادگی";
worksheet.Cells[row, 3].Value = "شماره پرسنلی";
worksheet.Cells[row, 4].Value = "تاخیر در ورود";
worksheet.Cells[row, 5].Value = "ورود";
worksheet.Cells[row, 6].Value = "خروج";
worksheet.Cells[row, 7].Value = "تعجیل در خروج";
worksheet.Cells[row, 8].Value = "مجموع ساعات کاری";
// Style headers with left and right borders
worksheet.Cells[row, 1].Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; // Right border for first column
worksheet.Cells[row, 8].Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; // Left border for last column
// Style headers
using (var range = worksheet.Cells[row, 1, row, 8])
{
range.Style.Font.Bold = true;
range.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
range.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray);
range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
range.Style.Border.Right.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
range.Style.Border.Left.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
range.Style.Border.Top.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin;
}
// Lock cells A1 to H6
worksheet.Cells["A1:H6"].Style.Locked = true;
// Set worksheet protection with password
worksheet.Protection.IsProtected = true;
worksheet.Protection.SetPassword("Gozareshgir2049");
// Add data
for (int i = 0; i < rollCalls.Count; i++)
{
var rollCall = rollCalls[i];
worksheet.Cells[i + row + 1, 1].Value = i + 1;
worksheet.Cells[i + row + 1, 2].Value = rollCall.EmployeeFullName;
worksheet.Cells[i + row + 1, 3].Value = rollCall.PersonnelCode;
worksheet.Cells[i + row + 1, 4].Value = "-";
worksheet.Cells[i + row + 1, 5].Value = rollCall.StartsItems;
worksheet.Cells[i + row + 1, 6].Value = rollCall.EndsItems;
worksheet.Cells[i + row + 1, 7].Value = "-";
worksheet.Cells[i + row + 1, 8].Value = rollCall.TotalWorkingHours;
// Style data cells
for (int j = 1; j <= 8; j++)
{
var cell = worksheet.Cells[i + row + 1, j];
cell.Style.Border.BorderAround(OfficeOpenXml.Style.ExcelBorderStyle.Thin);
cell.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center;
cell.Style.VerticalAlignment = OfficeOpenXml.Style.ExcelVerticalAlignment.Center;
if (j == 5 || j == 6)
{
cell.Style.WrapText = true;
}
}
}
// Adjust column widths
worksheet.Cells[worksheet.Dimension.Address].AutoFitColumns();
// Set the sheet to A4 size
worksheet.PrinterSettings.PaperSize = ePaperSize.A4;
worksheet.PrinterSettings.Orientation = eOrientation.Portrait;
worksheet.PrinterSettings.FitToPage = true;
worksheet.PrinterSettings.FitToWidth = 1;
worksheet.PrinterSettings.FitToHeight = 0;
worksheet.PrinterSettings.Scale = 85; // Scale to fit content within A4 width
worksheet.View.RightToLeft = true;
// Repeat headers on every page
worksheet.PrinterSettings.RepeatRows = new OfficeOpenXml.ExcelAddress("1:6"); // Repeat rows 1 to 6 on every page
return package.GetAsByteArray();
}
public static byte[] CaseHistoryExcelForEmployee(List<RollCallCaseHistoryDetail> data, string titleId)
{
if (!Regex.IsMatch(titleId, @"^\d{4}_\d{2}$"))
throw new ArgumentException("Invalid titleId format.", nameof(titleId));
var splitDate = titleId.Split("_");
var year = Convert.ToInt32(splitDate.First());
var month = Convert.ToInt32(splitDate.Last());
var startDateFa = $"{year:D4}/{month:D2}/01";
var startDate = startDateFa.ToGeorgianDateTime();
var endDateFa = startDateFa.FindeEndOfMonth();
var endDate = endDateFa.ToGeorgianDateTime();
var dateRange = (int)(endDate.Date - startDate.Date).TotalDays + 1;
var dates = Enumerable.Range(0, dateRange).Select(x => startDate.AddDays(x)).ToList();
var safeData = data ?? new List<RollCallCaseHistoryDetail>();
var first = safeData.FirstOrDefault();
var totalWorkingTime = new TimeSpan(safeData.Sum(x => x.TotalWorkingTime.Ticks));
var viewModel = new CaseHistoryRollCallExcelForEmployeeViewModel
{
EmployeeId = first?.EmployeeId ?? 0,
DateGr = startDate,
PersonnelCode = first?.PersonnelCode,
EmployeeFullName = first?.EmployeeFullName,
PersianMonthName = month.ToFarsiMonthByIntNumber(),
PersianYear = year.ToString(),
TotalWorkingHoursFa = totalWorkingTime.ToFarsiHoursAndMinutes("-"),
TotalWorkingTimeSpan = $"{(int)totalWorkingTime.TotalHours}:{totalWorkingTime.Minutes:00}",
RollCalls = dates.Select((date, index) =>
{
var item = index < safeData.Count ? safeData[index] : null;
var records = item?.Records ?? new List<RollCallCaseHistoryDetailRecord>();
return new RollCallItemForEmployeeExcelViewModel
{
DateGr = date,
DateFa = date.ToFarsi(),
DayOfWeekFa = date.DayOfWeek.DayOfWeeKToPersian(),
PersonnelCode = item?.PersonnelCode,
EmployeeFullName = item?.EmployeeFullName,
IsAbsent = item?.Status == RollCallRecordStatus.Absent,
HasLeave = item?.Status == RollCallRecordStatus.Leaved,
IsHoliday = false,
TotalWorkingHours = (item?.TotalWorkingTime ?? TimeSpan.Zero).ToFarsiHoursAndMinutes("-"),
StartsItems = JoinRecords(records, r => r.StartTime),
EndsItems = JoinRecords(records, r => r.EndTime),
EnterTimeDifferences = JoinRecords(records, r => FormatSignedTimeSpan(r.EntryTimeDifference)),
ExitTimeDifferences = JoinRecords(records, r => FormatSignedTimeSpan(r.ExitTimeDifference))
};
}).ToList()
};
return CaseHistoryExcelForEmployee(viewModel);
}
public static byte[] CaseHistoryExcelForOneDay(List<RollCallCaseHistoryDetail> data, string titleId)
{
if (!Regex.IsMatch(titleId, @"^\d{4}/\d{2}/\d{2}$"))
throw new ArgumentException("Invalid titleId format.", nameof(titleId));
var dateGr = titleId.ToGeorgianDateTime();
var safeData = data ?? new List<RollCallCaseHistoryDetail>();
var viewModel = new CaseHistoryRollCallForOneDayViewModel
{
DateFa = titleId,
DateGr = dateGr,
DayOfWeekFa = dateGr.DayOfWeek.DayOfWeeKToPersian(),
RollCalls = safeData.Select(item =>
{
var records = item.Records ?? new List<RollCallCaseHistoryDetailRecord>();
return new RollCallItemForOneDayExcelViewModel
{
EmployeeFullName = item.EmployeeFullName,
PersonnelCode = item.PersonnelCode,
StartsItems = JoinRecords(records, r => r.StartTime),
EndsItems = JoinRecords(records, r => r.EndTime),
TotalWorkingHours = item.TotalWorkingTime.ToFarsiHoursAndMinutes("-")
};
}).ToList()
};
return CaseHistoryExcelForOneDay(viewModel);
}
private static string JoinRecords(IEnumerable<RollCallCaseHistoryDetailRecord> records, Func<RollCallCaseHistoryDetailRecord, string> selector)
{
var safeRecords = records ?? Enumerable.Empty<RollCallCaseHistoryDetailRecord>();
var values = safeRecords.Select(selector).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
return values.Count == 0 ? string.Empty : string.Join(Environment.NewLine, values);
}
private static string FormatSignedTimeSpan(TimeSpan value)
{
if (value == TimeSpan.Zero)
return "-";
var abs = value.Duration();
var sign = value.Ticks < 0 ? "-" : "+";
return $"{(int)abs.TotalHours}:{abs.Minutes:00}{sign}";
}
private string CalculateExitMinuteDifference(TimeSpan early, TimeSpan late)
{
if (early == TimeSpan.Zero && late == TimeSpan.Zero)
{
return "-";
}
else if (late != TimeSpan.Zero)
{
var minutes = late.TotalMinutes > 999 ? "999" : late.TotalMinutes.ToString();
return $"{minutes}+";
}
else if (early != TimeSpan.Zero)
{
var minutes = early.TotalMinutes > 999 ? "999" : early.TotalMinutes.ToString();
return $"{minutes}-";
}
else
{
return $"";
}
}
private string CalculateEntryMinuteDifference(TimeSpan early, TimeSpan late)
{
if (early == TimeSpan.Zero && late == TimeSpan.Zero)
{
return "-";
}
else if (late != TimeSpan.Zero)
{
var minutes = late.TotalMinutes > 999 ? "999" : late.TotalMinutes.ToString();
return $"{minutes}-";
}
else if (early != TimeSpan.Zero)
{
var minutes = early.TotalMinutes > 999 ? "999" : early.TotalMinutes.ToString();
return $"{minutes}+";
}
else
{
return $"";
}
}
}