using System.Drawing; using ClosedXML.Excel; using Microsoft.AspNetCore.Mvc.Rendering; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Localization; namespace Nop.Services.ExportImport.Help; /// /// Class for working with PropertyByName object list /// /// Object type /// Language public partial class PropertyManager where L : Language { /// /// Default properties /// protected readonly Dictionary> _defaultProperties; /// /// Localized properties /// protected readonly Dictionary> _localizedProperties; /// /// Catalog settings /// protected readonly CatalogSettings _catalogSettings; /// /// Languages /// protected readonly IList _languages; /// /// Ctor /// /// Default access properties /// Catalog settings /// Localized access properties /// Languages public PropertyManager(IEnumerable> defaultProperties, CatalogSettings catalogSettings, IEnumerable> localizedProperties = null, IList languages = null) { _defaultProperties = new Dictionary>(); _catalogSettings = catalogSettings; _localizedProperties = new Dictionary>(); _languages = new List(); if (languages != null) _languages = languages; var poz = 1; foreach (var propertyByName in defaultProperties.Where(p => !p.Ignore)) { propertyByName.PropertyOrderPosition = poz; poz++; _defaultProperties.Add(propertyByName.PropertyName, propertyByName); } if (_languages.Count >= 2 && localizedProperties != null) { var lpoz = 1; foreach (var propertyByName in localizedProperties.Where(p => !p.Ignore)) { propertyByName.PropertyOrderPosition = lpoz; lpoz++; _localizedProperties.Add(propertyByName.PropertyName, propertyByName); } } } /// /// Sets the cell's value. /// /// The cell to set value /// The cell value protected void SetCellValue(IXLCell cell, object value) { if (value == null) { cell.SetValue(Blank.Value); return; } cell.Value = value switch { int intValue => intValue, bool boolValue => boolValue, DateTime dateTimeValue => dateTimeValue, decimal decimalValue => decimalValue, double doubleValue => doubleValue, float floatValue => floatValue, _ => value.ToString() }; } /// /// Export objects to XLSX /// /// Type of object /// The objects to export /// /// A task that represents the asynchronous operation /// The task result contains the /// public virtual async Task ExportToXlsxAsync(IEnumerable itemsToExport) { await using var stream = new MemoryStream(); // ok, we can run the real code of the sample now using (var workbook = new XLWorkbook()) { // uncomment this line if you want the XML written out to the outputDir //xlPackage.DebugMode = true; // get handles to the worksheets var worksheet = workbook.Worksheets.Add(typeof(T).Name); var fWorksheet = workbook.Worksheets.Add("DataForFilters"); fWorksheet.Visibility = XLWorksheetVisibility.VeryHidden; //create Headers and format them WriteDefaultCaption(worksheet); var lwss = new Dictionary(); if (_languages.Count >= 2) { foreach (var language in _languages) { var lws = workbook.Worksheets.Add(language.UniqueSeoCode); lwss.Add(language, lws); WriteLocalizedCaption(lws); } } var row = 2; foreach (var items in itemsToExport) { CurrentObject = items; await WriteDefaultToXlsxAsync(worksheet, row, fWorksheet: fWorksheet); foreach (var lws in lwss) { CurrentLanguage = lws.Key; await WriteLocalizedToXlsxAsync(lws.Value, row, fWorksheet: fWorksheet); } row++; } workbook.SaveAs(stream); } CurrentObject = default; return stream.ToArray(); } /// /// Current object to access /// public T CurrentObject { get; set; } /// /// Current language to access /// public L CurrentLanguage { get; set; } /// /// Return property index /// /// Property name /// public int GetIndex(string propertyName) { if (!_defaultProperties.TryGetValue(propertyName, out var value)) return -1; return value.PropertyOrderPosition; } /// /// Remove object by property name /// /// Property name public void Remove(string propertyName) { _defaultProperties.Remove(propertyName); } /// /// Write default object data to XLSX worksheet /// /// Data worksheet /// Row index /// Cell offset /// Filters worksheet /// A task that represents the asynchronous operation public virtual async Task WriteDefaultToXlsxAsync(IXLWorksheet worksheet, int row, int cellOffset = 0, IXLWorksheet fWorksheet = null) { if (CurrentObject == null) return; var xlRrow = worksheet.Row(row); xlRrow.Style.Alignment.WrapText = false; foreach (var prop in _defaultProperties.Values) { var cell = xlRrow.Cell(prop.PropertyOrderPosition + cellOffset); if (prop.IsDropDownCell && _catalogSettings.ExportImportRelatedEntitiesByName) { var dropDownElements = prop.GetDropDownElements(); if (!dropDownElements.Any()) { cell.Value = string.Empty; continue; } cell.Value = prop.GetItemText(await prop.GetProperty(CurrentObject, CurrentLanguage)); if (!UseDropdownLists) continue; var validator = cell.GetDataValidation(); validator.InCellDropdown = true; validator.IgnoreBlanks = prop.AllowBlank; if (fWorksheet == null) continue; var fRow = 1; foreach (var dropDownElement in dropDownElements) { var fCell = fWorksheet.Row(fRow++).Cell(prop.PropertyOrderPosition); if (!fCell.IsEmpty() && fCell.Value.ToString() == dropDownElement) break; fCell.Value = dropDownElement; } validator.List(fWorksheet.Range(1, prop.PropertyOrderPosition, dropDownElements.Length, prop.PropertyOrderPosition), true); } else { var value = await prop.GetProperty(CurrentObject, CurrentLanguage); SetCellValue(cell, value); } cell.Style.Alignment.WrapText = false; } } /// /// Write localized data to XLSX worksheet /// /// Data worksheet /// Row index /// Cell offset /// Filters worksheet /// A task that represents the asynchronous operation public virtual async Task WriteLocalizedToXlsxAsync(IXLWorksheet worksheet, int row, int cellOffset = 0, IXLWorksheet fWorksheet = null) { if (CurrentObject == null) return; var xlRrow = worksheet.Row(row); xlRrow.Style.Alignment.WrapText = false; foreach (var prop in _localizedProperties.Values) { var cell = xlRrow.Cell(prop.PropertyOrderPosition + cellOffset); if (prop.IsDropDownCell && _catalogSettings.ExportImportRelatedEntitiesByName) { var dropDownElements = prop.GetDropDownElements(); if (!dropDownElements.Any()) { cell.Value = string.Empty; continue; } cell.Value = prop.GetItemText(await prop.GetProperty(CurrentObject, CurrentLanguage)); if (!UseDropdownLists) continue; var validator = cell.GetDataValidation(); validator.InCellDropdown = true; validator.IgnoreBlanks = prop.AllowBlank; if (fWorksheet == null) continue; var fRow = 1; foreach (var dropDownElement in dropDownElements) { var fCell = fWorksheet.Row(fRow++).Cell(prop.PropertyOrderPosition); if (!fCell.IsEmpty() && fCell.Value.ToString() == dropDownElement) break; fCell.Value = dropDownElement; } validator.List(fWorksheet.Range(1, prop.PropertyOrderPosition, dropDownElements.Length, prop.PropertyOrderPosition), true); } else { var value = await prop.GetProperty(CurrentObject, CurrentLanguage); SetCellValue(cell, value); } cell.Style.Alignment.WrapText = false; } } /// /// Read object data from default XLSX worksheet /// /// worksheet /// Row index /// /// Cell offset public virtual void ReadDefaultFromXlsx(IXLWorksheet worksheet, int row, int cellOffset = 0) { if (worksheet?.Cells() == null) return; foreach (var prop in _defaultProperties.Values) { prop.PropertyValue = worksheet.Row(row).Cell(prop.PropertyOrderPosition + cellOffset).Value; } } /// /// Read object data from localized XLSX worksheet /// /// worksheet /// Row index /// /// Cell offset public virtual void ReadLocalizedFromXlsx(IXLWorksheet worksheet, int row, int cellOffset = 0) { if (worksheet?.Cells() == null) return; foreach (var prop in _localizedProperties.Values) { prop.PropertyValue = worksheet.Row(row).Cell(prop.PropertyOrderPosition + cellOffset).Value; } } /// /// Write caption (first row) to default XLSX worksheet /// /// worksheet /// Row number /// Cell offset public virtual void WriteDefaultCaption(IXLWorksheet worksheet, int row = 1, int cellOffset = 0) { foreach (var caption in _defaultProperties.Values) { var cell = worksheet.Row(row).Cell(caption.PropertyOrderPosition + cellOffset); cell.Value = caption.ToString(); SetCaptionStyle(cell); } } /// /// Write caption (first row) to localized XLSX worksheet /// /// worksheet /// Row number /// Cell offset public virtual void WriteLocalizedCaption(IXLWorksheet worksheet, int row = 1, int cellOffset = 0) { foreach (var caption in _localizedProperties.Values) { var cell = worksheet.Row(row).Cell(caption.PropertyOrderPosition + cellOffset); cell.Value = caption.ToString(); SetCaptionStyle(cell); } } /// /// Set caption style to excel cell /// /// Excel cell public void SetCaptionStyle(IXLCell cell) { cell.Style.Fill.PatternType = XLFillPatternValues.Solid; cell.Style.Fill.BackgroundColor = XLColor.FromColor(Color.FromArgb(184, 204, 228)); cell.Style.Font.Bold = true; } /// /// Count of default properties /// public int Count => _defaultProperties.Count; /// /// Get default property by name /// /// /// public PropertyByName GetDefaultProperty(string propertyName) { return _defaultProperties.TryGetValue(propertyName, out var value) ? value : null; } /// /// Get localized property by name /// /// /// public PropertyByName GetLocalizedProperty(string propertyName) { return _localizedProperties.TryGetValue(propertyName, out var value) ? value : null; } /// /// Get default property array /// public PropertyByName[] GetDefaultProperties => _defaultProperties.Values.ToArray(); /// /// Get localized property array /// public PropertyByName[] GetLocalizedProperties => _localizedProperties.Values.ToArray(); /// /// Set SelectList /// /// Property name /// SelectList public void SetSelectList(string propertyName, SelectList list) { var tempProperty = GetDefaultProperty(propertyName); if (tempProperty != null) tempProperty.DropDownElements = list; } /// /// Is caption /// public bool IsCaption => _defaultProperties.Values.All(p => p.IsCaption); /// /// Gets a value indicating whether need create dropdown list for export /// public bool UseDropdownLists => _catalogSettings.ExportImportUseDropdownlistsForAssociatedEntities && _catalogSettings.ExportImportRelatedEntitiesByName; }