using _0_Framework.Application; using CompanyManagement.Infrastructure.Excel.CWS; using CompanyManagment.App.Contracts.InstitutionContract; using OfficeOpenXml; using OfficeOpenXml.Style; using System.Drawing; using System.Text.RegularExpressions; namespace CompanyManagement.Infrastructure.Excel.InstitutionContract; // Enum برای تعریف ستون‌های موجود public enum ExcelColumnType { RowNumber, // ردیف PhysicalContract, // قرارداد فیزیکی ContractNo, // شماره قرارداد Representative, // معرف ContractingPartyName, // طرف حساب ArchiveCode, // شماره کارفرما EmployerName, // کارفرما WorkshopName, // کارگاه‌ها (چندخطی) WorkshopCount, // تعداد کارگاه EmployeeCount, // مجموع پرسنل ContractStartDate, // شروع قرارداد ContractEndDate, // پایان قرارداد InstallmentAmount, // مبلغ قسط ContractAmount, // مبلغ قرارداد FinancialStatus // وضعیت مالی } // کلاس کانفیگ برای تنظیم ستون‌های نمایشی public class ExcelColumnConfig { public List VisibleColumns { get; set; } public ExcelColumnConfig() { // فعلاً تمام ستون‌ها فعال هستند VisibleColumns = new List { ExcelColumnType.PhysicalContract, ExcelColumnType.ContractNo, ExcelColumnType.Representative, ExcelColumnType.ContractingPartyName, ExcelColumnType.ArchiveCode, ExcelColumnType.EmployerName, ExcelColumnType.WorkshopName, ExcelColumnType.WorkshopCount, ExcelColumnType.EmployeeCount, ExcelColumnType.ContractStartDate, ExcelColumnType.ContractEndDate, ExcelColumnType.InstallmentAmount, ExcelColumnType.ContractAmount, ExcelColumnType.FinancialStatus }; } } public class InstitutionContractExcelGenerator { private static ExcelColumnConfig _columnConfig = new ExcelColumnConfig(); public static byte[] GenerateExcel(List contractViewModels) { ExcelPackage.License.SetNonCommercialOrganization("Gozareshgir Noncommercial organization"); using var package = new ExcelPackage(); // ایجاد شیت برای هر تب با داده‌های مربوطه foreach (var viewModel in contractViewModels) { var worksheet = CreateWorksheet(package, viewModel.Tab); CreateExcelSheet(viewModel.GetInstitutionContractListItemsViewModels ?? new List(), worksheet); } return package.GetAsByteArray(); } /// /// ایجاد شیت بر اساس نوع تب /// private static ExcelWorksheet CreateWorksheet(ExcelPackage package, InstitutionContractListStatus? status) { return status switch { InstitutionContractListStatus.DeactiveWithDebt => CreateColoredWorksheet(package, "غیرفعال دارای بدهی", Color.LightBlue), InstitutionContractListStatus.Deactive => CreateColoredWorksheet(package, "غیرفعال", Color.LightGray), InstitutionContractListStatus.PendingForRenewal => CreateColoredWorksheet(package, "در انتظار تمدید", Color.LightCoral), InstitutionContractListStatus.Free => CreateColoredWorksheet(package, "بنفش", Color.MediumPurple), InstitutionContractListStatus.Block => CreateColoredWorksheet(package, "بلاک", Color.DimGray), InstitutionContractListStatus.WithoutWorkshop => CreateColoredWorksheet(package, "بدون کارگاه", Color.Yellow), InstitutionContractListStatus.Active => CreateColoredWorksheet(package, "فعال", Color.White), InstitutionContractListStatus.PendingForVerify => CreateColoredWorksheet(package, "در انتظار تایید", Color.OrangeRed), null => CreateColoredWorksheet(package, "کل قرارداد ها", Color.White), _ => throw new ArgumentOutOfRangeException(nameof(status), status, null) }; } /// /// ایجاد شیت با رنگ تب /// private static ExcelWorksheet CreateColoredWorksheet(ExcelPackage package, string sheetName, Color tabColor) { var worksheet = package.Workbook.Worksheets.Add(sheetName); worksheet.TabColor = tabColor; return worksheet; } private static void CreateExcelSheet(List contractItems, ExcelWorksheet worksheet) { // دریافت نقشه ستون‌های مرئی var visibleColumnIndices = GetVisibleColumnIndices(); int columnCount = visibleColumnIndices.Count; // تنظیم Headers SetupHeaders(worksheet, visibleColumnIndices, columnCount); using (var range = worksheet.Cells[1, 1, 1, columnCount]) { range.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; range.Style.VerticalAlignment = ExcelVerticalAlignment.Center; range.Style.Font.Bold = true; range.Style.Fill.PatternType = ExcelFillStyle.Solid; range.Style.Fill.BackgroundColor.SetColor(Color.LightGray); // رنگ پس زمینه خاکستری // اعمال بوردر به همه خطوط range.Style.Border.Top.Style = ExcelBorderStyle.Thin; range.Style.Border.Bottom.Style = ExcelBorderStyle.Thin; range.Style.Border.Left.Style = ExcelBorderStyle.Thin; range.Style.Border.Right.Style = ExcelBorderStyle.Thin; // اعمال رنگ مشکی برای بوردرها range.Style.Border.Top.Color.SetColor(Color.Black); range.Style.Border.Bottom.Color.SetColor(Color.Black); range.Style.Border.Left.Color.SetColor(Color.Black); range.Style.Border.Right.Color.SetColor(Color.Black); } int row = 2; for (int i = 0; i < contractItems.Count; i++) { var contract = contractItems[i]; var employers = contract.EmployerNames?.ToList() ?? new(); var workshops = contract.WorkshopNames?.ToList() ?? new(); int maxRows = 1; // هر قرارداد فقط یک ردیف؛ نیازی به مرج عمودی نیست int startRow = row; int endRow = row + maxRows - 1; // 🎨 دریافت رنگ پس‌زمینه بر اساس وضعیت قرارداد var fillColor = GetColorByStatus(contract.ListStatus, contract.WorkshopsCount); for (int j = 0; j < maxRows; j++) { int currentRow = row + j; // پر کردن ستون‌های employer و workshop var employerColIndex = GetColumnIndexForType(ExcelColumnType.EmployerName, visibleColumnIndices); var workshopColIndex = GetColumnIndexForType(ExcelColumnType.WorkshopName, visibleColumnIndices); if (employerColIndex > 0) worksheet.Cells[currentRow, employerColIndex].Value = j < employers.Count ? employers[j] : null; if (workshopColIndex > 0) worksheet.Cells[currentRow, workshopColIndex].Value = j < workshops.Count ? workshops[j] : null; for (int col = 1; col <= columnCount; col++) { var cell = worksheet.Cells[currentRow, col]; // 📏 بوردرهای داخلی نازک / نقطه‌چین cell.Style.Border.Top.Style = ExcelBorderStyle.Dotted; cell.Style.Border.Bottom.Style = ExcelBorderStyle.Dotted; cell.Style.Border.Left.Style = ExcelBorderStyle.Thin; cell.Style.Border.Right.Style = ExcelBorderStyle.Thin; // 🎯 تراز متن cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; cell.Style.VerticalAlignment = ExcelVerticalAlignment.Center; // 🎨 اعمال رنگ پس‌زمینه cell.Style.Fill.PatternType = ExcelFillStyle.Solid; cell.Style.Fill.BackgroundColor.SetColor(fillColor); } } // 🧱 مرج و مقداردهی ستون‌های اصلی FillColumnData(worksheet, contract, startRow, endRow, visibleColumnIndices); // 📦 بوردر ضخیم خارجی برای هر سطر var boldRange = worksheet.Cells[startRow, 1, endRow, columnCount]; boldRange.Style.Border.BorderAround(ExcelBorderStyle.Medium); row += maxRows; } SetupPrintSettings(worksheet, visibleColumnIndices, columnCount); } /// /// دریافت فهرست ستون‌های مرئی بر اساس کانفیگ /// private static List GetVisibleColumnIndices() { return _columnConfig.VisibleColumns; } /// /// دریافت شماره ستون برای یک نوع ستون خاص /// private static int GetColumnIndexForType(ExcelColumnType columnType, List visibleColumns) { var index = visibleColumns.IndexOf(columnType); return index >= 0 ? index + 1 : 0; // 1-based indexing } /// /// دریافت متن header برای یک نوع ستون /// private static string GetColumnHeader(ExcelColumnType columnType) { return columnType switch { ExcelColumnType.RowNumber => "ردیف", ExcelColumnType.PhysicalContract => "قرارداد فیزیکی", ExcelColumnType.ContractNo => "شماره قرارداد", ExcelColumnType.Representative => "معرف", ExcelColumnType.ContractingPartyName => "طرف حساب", ExcelColumnType.ArchiveCode => "شماره کارفرما", ExcelColumnType.EmployerName => "کارفرما", ExcelColumnType.WorkshopName => "کارگاه‌ها", ExcelColumnType.WorkshopCount => "تعداد کارگاه", ExcelColumnType.EmployeeCount => "مجموع پرسنل", ExcelColumnType.ContractStartDate => "شروع قرارداد", ExcelColumnType.ContractEndDate => "پایان قرارداد", ExcelColumnType.InstallmentAmount => "مبلغ قسط", ExcelColumnType.ContractAmount => "مبلغ قرارداد", ExcelColumnType.FinancialStatus => "وضعیت مالی", _ => "" }; } /// /// تنظیم Header‌های ستون‌ها /// private static void SetupHeaders(ExcelWorksheet worksheet, List visibleColumns, int columnCount) { for (int i = 0; i < visibleColumns.Count; i++) { worksheet.Cells[1, i + 1].Value = GetColumnHeader(visibleColumns[i]); } } /// /// پر کردن داده‌های ستون‌ها برای یک قرارداد /// private static void FillColumnData(ExcelWorksheet worksheet, GetInstitutionContractListItemsViewModel contract, int startRow, int endRow, List visibleColumns) { for (int i = 0; i < visibleColumns.Count; i++) { int columnIndex = i + 1; // 1-based indexing var columnType = visibleColumns[i]; // Merge cells for non-repeating columns worksheet.Cells[startRow, columnIndex, endRow, columnIndex].Merge = true; var cell = worksheet.Cells[startRow, columnIndex]; switch (columnType) { case ExcelColumnType.PhysicalContract: var physicalText = contract.IsOldContract ? (contract.HasSigniture ? "موجود" : "ناموجود") : (contract.IsInPersonContract ? "الکترونیکی حضوری" : "الکترونیکی غیر حضوری"); cell.Value = physicalText; cell.Style.Font.Bold = true; cell.Style.Font.Color.SetColor(physicalText switch { "موجود" => Color.Green, "ناموجود" => Color.Red, "الکترونیکی حضوری" => Color.Purple, _ => Color.Blue }); break; case ExcelColumnType.ContractNo: cell.Value = contract.ContractNo; break; case ExcelColumnType.Representative: cell.Value = contract.RepresentativeName; break; case ExcelColumnType.ContractingPartyName: cell.Value = contract.ContractingPartyName; break; case ExcelColumnType.ArchiveCode: cell.Value = contract.ArchiveNo; break; case ExcelColumnType.EmployerName: // این ستون چندخطی است و داخل loop پر می‌شود break; case ExcelColumnType.WorkshopName: // این ستون چندخطی است و داخل loop پر می‌شود break; case ExcelColumnType.WorkshopCount: cell.Value = contract.WorkshopsCount; break; case ExcelColumnType.EmployeeCount: cell.Value = contract.EmployeesCount; break; case ExcelColumnType.ContractStartDate: cell.Value = contract.ContractStartFa; break; case ExcelColumnType.ContractEndDate: cell.Value = contract.ContractEndFa; break; case ExcelColumnType.InstallmentAmount: cell.Value = contract.InstallmentAmount; cell.Style.Numberformat.Format = "#,##0"; break; case ExcelColumnType.ContractAmount: cell.Value = contract.ContractAmount; cell.Style.Numberformat.Format = "#,##0"; break; case ExcelColumnType.FinancialStatus: cell.Value = contract.Balance; cell.Style.Numberformat.Format = "#,##0"; if (contract.Balance > 0) cell.Style.Font.Color.SetColor(Color.Red); else if (contract.Balance < 0) cell.Style.Font.Color.SetColor(Color.Green); break; } } } /// /// تنظیم تنظیمات چاپ و عرض ستون‌ها /// private static void SetupPrintSettings(ExcelWorksheet worksheet, List visibleColumns, int columnCount) { worksheet.PrinterSettings.PaperSize = ePaperSize.A4; worksheet.PrinterSettings.Orientation = eOrientation.Landscape; worksheet.PrinterSettings.FitToPage = true; worksheet.PrinterSettings.FitToWidth = 1; worksheet.PrinterSettings.FitToHeight = 0; worksheet.PrinterSettings.Scale = 85; // تنظیم عرض ستون‌ها بر اساس نوع ستون for (int i = 0; i < visibleColumns.Count; i++) { int columnIndex = i + 1; worksheet.Columns[columnIndex].Width = GetColumnWidth(visibleColumns[i]); } worksheet.View.RightToLeft = true; // فارسی } /// /// دریافت عرض ستون پیش‌فرض برای هر نوع ستون /// private static double GetColumnWidth(ExcelColumnType columnType) { return columnType switch { ExcelColumnType.RowNumber => 8, ExcelColumnType.PhysicalContract => 15, ExcelColumnType.ContractNo => 17, ExcelColumnType.Representative => 15, ExcelColumnType.ContractingPartyName => 40, ExcelColumnType.ArchiveCode => 10, ExcelColumnType.EmployerName => 40, ExcelColumnType.WorkshopName => 45, ExcelColumnType.WorkshopCount => 12, ExcelColumnType.EmployeeCount => 12, ExcelColumnType.ContractStartDate => 12, ExcelColumnType.ContractEndDate => 12, ExcelColumnType.InstallmentAmount => 15, ExcelColumnType.ContractAmount => 15, ExcelColumnType.FinancialStatus => 12, _ => 12 }; } private static double MoneyToDouble(string value) { if (string.IsNullOrEmpty(value)) return 0; var min = value.Length > 1 ? value.Substring(0, 2) : ""; var test = min == "\u200e\u2212" ? value.MoneyToDouble() * -1 : value.MoneyToDouble(); return test; } /// /// دریافت رنگ بر اساس وضعیت قرارداد /// private static Color GetColorByStatus(InstitutionContractListStatus status, int workshopsCount) { return status switch { InstitutionContractListStatus.DeactiveWithDebt => Color.LightBlue, InstitutionContractListStatus.Deactive => Color.LightGray, InstitutionContractListStatus.PendingForRenewal => Color.LightCoral, InstitutionContractListStatus.Free => Color.MediumPurple, InstitutionContractListStatus.Block => Color.DimGray, InstitutionContractListStatus.WithoutWorkshop => Color.Yellow, InstitutionContractListStatus.Active => Color.White, _ => Color.White }; } } public class InstitutionContractExcelViewModel { public InstitutionContractListStatus? Tab { get; set; } public List GetInstitutionContractListItemsViewModels { get; set; } }