diff --git a/NEW/src/JdeScoping.ExcelIO/Attributes/OutputColumnAttribute.cs b/NEW/src/JdeScoping.ExcelIO/Attributes/OutputColumnAttribute.cs
deleted file mode 100644
index 0e81025..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Attributes/OutputColumnAttribute.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-namespace JdeScoping.ExcelIO.Attributes;
-
-///
-/// Excel output column specification.
-///
-[AttributeUsage(AttributeTargets.Property)]
-public class OutputColumnAttribute : Attribute
-{
- ///
- /// Standard format (text).
- ///
- public const string StdFormat = "@";
-
- ///
- /// Standard date format.
- ///
- public const string DateFormat = "[$-409]MM/dd/yyyy;@";
-
- ///
- /// Standard timestamp format.
- ///
- public const string TimestampFormat = "[$-409]m/d/yy h:mm AM/PM;@";
-
- ///
- /// Wrapped text column default width.
- ///
- public const double WrappedColumnWidth = 65;
-
- ///
- /// Order to display column.
- ///
- public int Order { get; set; }
-
- ///
- /// Override text to display for column header.
- ///
- public string HeaderText { get; set; } = string.Empty;
-
- ///
- /// Column format (Excel formatting string).
- ///
- public string Format { get; set; } = StdFormat;
-
- ///
- /// Whether or not width should be set automatically.
- ///
- public bool AutoWidth { get; set; } = true;
-
- ///
- /// Manually set width (only used if AutoWidth = false).
- ///
- public double Width { get; set; }
-
- ///
- /// Whether or not text should be wrapped.
- ///
- public bool WrapText { get; set; }
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/Attributes/OutputTableAttribute.cs b/NEW/src/JdeScoping.ExcelIO/Attributes/OutputTableAttribute.cs
deleted file mode 100644
index 92e5d81..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Attributes/OutputTableAttribute.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace JdeScoping.ExcelIO.Attributes;
-
-///
-/// Excel output table specification.
-///
-[AttributeUsage(AttributeTargets.Class)]
-public class OutputTableAttribute : Attribute
-{
- ///
- /// Output tab name.
- ///
- public string TabName { get; set; } = string.Empty;
-
- ///
- /// Table name.
- ///
- public string TableName { get; set; } = string.Empty;
-
- ///
- /// Whether or not merged header should be shown.
- ///
- public bool ShowHeader { get; set; }
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/DependencyInjection.cs b/NEW/src/JdeScoping.ExcelIO/DependencyInjection.cs
index 4a107ad..f4e2ef1 100644
--- a/NEW/src/JdeScoping.ExcelIO/DependencyInjection.cs
+++ b/NEW/src/JdeScoping.ExcelIO/DependencyInjection.cs
@@ -2,7 +2,6 @@ using JdeScoping.Core.Interfaces;
using JdeScoping.ExcelIO;
using JdeScoping.ExcelIO.Options;
using JdeScoping.ExcelIO.Generators;
-using JdeScoping.ExcelIO.Helpers;
using JdeScoping.ExcelIO.Mapping;
using JdeScoping.ExcelIO.Mapping.Maps;
using JdeScoping.ExcelIO.Parsing;
@@ -42,18 +41,29 @@ public static class ExcelIODependencyInjection
// Register generators (scoped - they use options)
services.AddScoped();
- // Register helpers (singleton - stateless)
- services.AddSingleton();
- services.AddSingleton();
+ // Register template generator (singleton - stateless)
services.AddSingleton();
// Register Excel map registry with all maps
services.AddSingleton(sp =>
{
var registry = new ExcelMapRegistry();
+
+ // Search result maps
registry.Register(new SearchResultMap());
registry.Register(new MisSearchResultMap());
registry.Register(new MisNonMatchSearchResultMap());
+
+ // Filter entry maps (for criteria sheet)
+ registry.Register(new TimespanFilterMap());
+ registry.Register(new WorkOrderFilterEntryMap());
+ registry.Register(new ItemNumberFilterEntryMap());
+ registry.Register(new ProfitCenterFilterEntryMap());
+ registry.Register(new WorkCenterFilterEntryMap());
+ registry.Register(new OperatorFilterEntryMap());
+ registry.Register(new ComponentLotFilterEntryMap());
+ registry.Register(new ItemOperationMisFilterEntryMap());
+
return registry;
});
diff --git a/NEW/src/JdeScoping.ExcelIO/Formatting/ColumnFormatter.cs b/NEW/src/JdeScoping.ExcelIO/Formatting/ColumnFormatter.cs
deleted file mode 100644
index 6bcbd2b..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Formatting/ColumnFormatter.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using ClosedXML.Excel;
-using JdeScoping.ExcelIO.Attributes;
-
-namespace JdeScoping.ExcelIO.Formatting;
-
-///
-/// Column width and number format utilities.
-///
-public static class ColumnFormatter
-{
- ///
- /// Applies column formatting based on attribute settings.
- ///
- /// The column to format.
- /// The output column attribute with settings.
- public static void ApplyColumnFormat(IXLColumn column, OutputColumnAttribute attr)
- {
- // Set number format
- column.Style.NumberFormat.Format = attr.Format;
-
- // Handle wrap text
- if (attr.WrapText)
- {
- column.Style.Alignment.WrapText = true;
- }
-
- // Handle width
- if (attr.WrapText && !attr.AutoWidth)
- {
- // Wrapped columns with fixed width skip auto-fit
- column.Width = attr.Width;
- }
- else if (attr.AutoWidth)
- {
- column.AdjustToContents();
- column.Width *= ExcelFormats.DataPaddingFactor;
- }
- else
- {
- column.Width = attr.Width;
- }
- }
-
- ///
- /// Auto-fits a column with the specified padding factor.
- ///
- /// The column to auto-fit.
- /// The padding factor to apply (e.g., 1.15 for 15% padding).
- public static void AutoFitWithPadding(IXLColumn column, double paddingFactor)
- {
- column.AdjustToContents();
- column.Width *= paddingFactor;
- }
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/Generators/AttributeTableWriter.cs b/NEW/src/JdeScoping.ExcelIO/Generators/AttributeTableWriter.cs
deleted file mode 100644
index 3254ac2..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Generators/AttributeTableWriter.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-using System.Reflection;
-using ClosedXML.Excel;
-using JdeScoping.ExcelIO.Attributes;
-using JdeScoping.ExcelIO.Formatting;
-using JdeScoping.ExcelIO.Helpers;
-
-namespace JdeScoping.ExcelIO.Generators;
-
-///
-/// Generic attribute-driven table writer for Excel worksheets.
-///
-public class AttributeTableWriter
-{
- private readonly OutputColumnCache _cache;
-
- ///
- /// Initializes a new instance of the AttributeTableWriter class.
- ///
- /// The output column cache.
- public AttributeTableWriter(OutputColumnCache cache)
- {
- _cache = cache;
- }
-
- ///
- /// Writes a table to the worksheet using attribute-driven column definitions.
- ///
- /// The type of data items.
- /// The worksheet to write to.
- /// The starting row (1-indexed).
- /// The starting column (1-indexed).
- /// The data to write.
- /// Optional table name override.
- /// Optional override for showing merged header.
- /// Optional header text for merged header.
- /// The created table, or null if no data.
- public IXLTable? WriteTable(
- IXLWorksheet worksheet,
- int startRow,
- int startCol,
- IEnumerable data,
- string? tableNameOverride = null,
- bool? showHeader = null,
- string? headerText = null)
- {
- var tableAttr = typeof(T).GetCustomAttribute();
- var columns = _cache.GetColumns();
- var tableName = tableNameOverride ?? tableAttr?.TableName ?? typeof(T).Name;
- var shouldShowHeader = showHeader ?? (tableAttr?.ShowHeader ?? false);
- var header = headerText ?? tableAttr?.TabName ?? string.Empty;
-
- if (columns.Count == 0)
- {
- return null;
- }
-
- var dataList = data.ToList();
- var baseRow = startRow;
-
- // Write merged header if requested
- if (shouldShowHeader && !string.IsNullOrEmpty(header))
- {
- var mergedHeaderRange = worksheet.Range(baseRow, startCol, baseRow, startCol + columns.Count - 1);
- HeaderFormatter.ApplyHeaderFormat(mergedHeaderRange, header, merge: true);
- baseRow++;
- }
-
- // Write column headers
- var col = startCol;
- foreach (var column in columns)
- {
- var cell = worksheet.Cell(baseRow, col);
- HeaderFormatter.ApplyHeaderFormat(cell, column.Attribute.HeaderText);
-
- // Pre-set column formatting
- worksheet.Column(col).Style.Alignment.WrapText = column.Attribute.WrapText;
- if (!column.Attribute.AutoWidth)
- {
- worksheet.Column(col).Width = column.Attribute.Width;
- }
-
- col++;
- }
-
- // Write data rows
- var row = baseRow + 1;
- foreach (var item in dataList)
- {
- col = startCol;
- foreach (var column in columns)
- {
- var value = column.Property.GetValue(item);
- worksheet.Cell(row, col).Value = ConvertToXlValue(value);
- col++;
- }
- row++;
- }
-
- // Handle empty data case - add at least one empty row for valid table
- if (dataList.Count == 0)
- {
- row = baseRow + 1;
- }
-
- // Create table range
- var dataRange = worksheet.Range(
- baseRow, startCol,
- baseRow + dataList.Count, startCol + columns.Count - 1);
-
- // Create table
- var table = dataRange.CreateTable(tableName);
- table.Theme = XLTableTheme.TableStyleLight18;
- table.ShowTotalsRow = false;
-
- // Apply column formatting and number formats
- col = startCol;
- var tableStartRow = table.RangeAddress.FirstAddress.RowNumber;
- var tableEndRow = table.RangeAddress.LastAddress.RowNumber;
-
- foreach (var column in columns)
- {
- // Apply number format to the column data
- worksheet.Range(tableStartRow, col, tableEndRow, col)
- .Style.NumberFormat.Format = column.Attribute.Format;
-
- // Apply column width
- if (column.Attribute.WrapText && !column.Attribute.AutoWidth)
- {
- worksheet.Column(col).Width = column.Attribute.Width;
- }
- else if (column.Attribute.AutoWidth)
- {
- worksheet.Column(col).AdjustToContents();
- worksheet.Column(col).Width *= ExcelFormats.DataPaddingFactor;
- }
- else
- {
- worksheet.Column(col).Width = column.Attribute.Width;
- }
-
- col++;
- }
-
- return table;
- }
-
- ///
- /// Converts a value to an XLCellValue.
- ///
- private static XLCellValue ConvertToXlValue(object? value)
- {
- return value switch
- {
- null => Blank.Value,
- string s => s,
- int i => i,
- long l => l,
- decimal d => d,
- double dbl => dbl,
- float f => f,
- DateTime dt => dt,
- bool b => b,
- _ => value.ToString() ?? string.Empty
- };
- }
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/Generators/CriteriaSheetGenerator.cs b/NEW/src/JdeScoping.ExcelIO/Generators/CriteriaSheetGenerator.cs
index 2d1971d..ec4abbc 100644
--- a/NEW/src/JdeScoping.ExcelIO/Generators/CriteriaSheetGenerator.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Generators/CriteriaSheetGenerator.cs
@@ -12,16 +12,16 @@ namespace JdeScoping.ExcelIO.Generators;
public class CriteriaSheetGenerator
{
private readonly IOptions _options;
- private readonly AttributeTableWriter _tableWriter;
+ private readonly FluentTableWriter _tableWriter;
///
/// Initializes a new instance of the CriteriaSheetGenerator class.
///
/// Excel export options.
- /// Attribute table writer.
+ /// Fluent table writer.
public CriteriaSheetGenerator(
IOptions options,
- AttributeTableWriter tableWriter)
+ FluentTableWriter tableWriter)
{
_options = options;
_tableWriter = tableWriter;
diff --git a/NEW/src/JdeScoping.ExcelIO/Helpers/OutputColumnCache.cs b/NEW/src/JdeScoping.ExcelIO/Helpers/OutputColumnCache.cs
deleted file mode 100644
index 7c73e63..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Helpers/OutputColumnCache.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System.Collections.Concurrent;
-using System.Reflection;
-using JdeScoping.ExcelIO.Attributes;
-using JdeScoping.ExcelIO.Models;
-
-namespace JdeScoping.ExcelIO.Helpers;
-
-///
-/// Cached reflection for column metadata.
-///
-public class OutputColumnCache
-{
- private readonly ConcurrentDictionary> _cache = new();
-
- ///
- /// Gets the output columns for a given type.
- ///
- /// The type to get columns for.
- /// Ordered list of output columns.
- public IReadOnlyList GetColumns()
- {
- return GetColumns(typeof(T));
- }
-
- ///
- /// Gets the output columns for a given type.
- ///
- /// The type to get columns for.
- /// Ordered list of output columns.
- public IReadOnlyList GetColumns(Type type)
- {
- return _cache.GetOrAdd(type, BuildColumns);
- }
-
- private static IReadOnlyList BuildColumns(Type type)
- {
- var columns = new List();
-
- foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
- {
- var attr = property.GetCustomAttribute();
- if (attr != null)
- {
- columns.Add(new OutputColumn
- {
- Name = property.Name,
- Property = property,
- Attribute = attr
- });
- }
- }
-
- // Sort by Order ascending, then by Name alphabetically for tie-breaking
- return columns
- .OrderBy(c => c.Attribute.Order)
- .ThenBy(c => c.Name)
- .ToList()
- .AsReadOnly();
- }
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/Mapping/ExcelFormats.cs b/NEW/src/JdeScoping.ExcelIO/Mapping/ExcelFormats.cs
deleted file mode 100644
index f35e762..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Mapping/ExcelFormats.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace JdeScoping.ExcelIO.Mapping;
-
-///
-/// Standard Excel format strings for column configuration.
-///
-public static class ExcelFormats
-{
- /// Text format (default).
- public const string Text = "@";
-
- /// Date format: MM/dd/yyyy
- public const string Date = "[$-409]MM/dd/yyyy;@";
-
- /// Timestamp format: m/d/yy h:mm AM/PM
- public const string Timestamp = "[$-409]m/d/yy h:mm AM/PM;@";
-
- /// Default width for wrapped text columns.
- public const double WrappedColumnWidth = 65;
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/FilterEntryMaps.cs b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/FilterEntryMaps.cs
new file mode 100644
index 0000000..cc5db1a
--- /dev/null
+++ b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/FilterEntryMaps.cs
@@ -0,0 +1,119 @@
+using JdeScoping.ExcelIO.Formatting;
+using JdeScoping.ExcelIO.Models.Reporting;
+
+namespace JdeScoping.ExcelIO.Mapping.Maps;
+
+///
+/// Excel column mapping for TimespanFilter.
+///
+public sealed class TimespanFilterMap : ExcelClassMap
+{
+ public TimespanFilterMap()
+ {
+ Table("Timespan_Filter", "Timespan Filter");
+
+ Map(x => x.MinimumDt).Order(10).Header("Minimum Date").Format(ExcelFormats.DateFormat);
+ Map(x => x.MaximumDt).Order(20).Header("Maximum Date").Format(ExcelFormats.DateFormat);
+ }
+}
+
+///
+/// Excel column mapping for WorkOrderFilterEntry.
+///
+public sealed class WorkOrderFilterEntryMap : ExcelClassMap
+{
+ public WorkOrderFilterEntryMap()
+ {
+ Table("Work_Order_Filter", "Work Order Filter");
+
+ Map(x => x.WorkOrderNumber).Order(10).Header("Work Order Number");
+ Map(x => x.ItemNumber).Order(20).Header("Item Number");
+ }
+}
+
+///
+/// Excel column mapping for ItemNumberFilterEntry.
+///
+public sealed class ItemNumberFilterEntryMap : ExcelClassMap
+{
+ public ItemNumberFilterEntryMap()
+ {
+ Table("Item_Number_Filter", "Item Number Filter");
+
+ Map(x => x.ItemNumber).Order(10).Header("Item Number");
+ Map(x => x.ItemDescription).Order(20).Header("Item Description");
+ }
+}
+
+///
+/// Excel column mapping for ProfitCenterFilterEntry.
+///
+public sealed class ProfitCenterFilterEntryMap : ExcelClassMap
+{
+ public ProfitCenterFilterEntryMap()
+ {
+ Table("Profit_Center_Filter", "Profit Center Filter");
+
+ Map(x => x.Code).Order(10).Header("Profit Center");
+ Map(x => x.Description).Order(20).Header("Description");
+ }
+}
+
+///
+/// Excel column mapping for WorkCenterFilterEntry.
+///
+public sealed class WorkCenterFilterEntryMap : ExcelClassMap
+{
+ public WorkCenterFilterEntryMap()
+ {
+ Table("Work_Center_Filter", "Work Center Filter");
+
+ Map(x => x.Code).Order(10).Header("Work Center");
+ Map(x => x.Description).Order(20).Header("Description");
+ }
+}
+
+///
+/// Excel column mapping for OperatorFilterEntry.
+///
+public sealed class OperatorFilterEntryMap : ExcelClassMap
+{
+ public OperatorFilterEntryMap()
+ {
+ Table("Operator_Filter", "Operator Filter");
+
+ // Note: AddressNumber is not exported to Excel (no OutputColumn attribute in original)
+ Map(x => x.UserId).Order(10).Header("Username");
+ Map(x => x.FullName).Order(20).Header("Name");
+ }
+}
+
+///
+/// Excel column mapping for ComponentLotFilterEntry.
+///
+public sealed class ComponentLotFilterEntryMap : ExcelClassMap
+{
+ public ComponentLotFilterEntryMap()
+ {
+ Table("Component_Lot_Filter", "Component Lot Filter");
+
+ Map(x => x.LotNumber).Order(10).Header("Lot Number");
+ Map(x => x.ItemNumber).Order(20).Header("Item Number");
+ }
+}
+
+///
+/// Excel column mapping for ItemOperationMisFilterEntry.
+///
+public sealed class ItemOperationMisFilterEntryMap : ExcelClassMap
+{
+ public ItemOperationMisFilterEntryMap()
+ {
+ Table("Item_Operation_MIS_Filter", "Item/Operation/MIS Filter");
+
+ Map(x => x.ItemNumber).Order(10).Header("Item Number");
+ Map(x => x.OperationNumber).Order(20).Header("Operation Number");
+ Map(x => x.MisNumber).Order(30).Header("MIS Number");
+ Map(x => x.MisRevision).Order(40).Header("MIS Revision");
+ }
+}
diff --git a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisNonMatchSearchResultMap.cs b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisNonMatchSearchResultMap.cs
index 63c18f3..66ef306 100644
--- a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisNonMatchSearchResultMap.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisNonMatchSearchResultMap.cs
@@ -1,4 +1,5 @@
using JdeScoping.Core.Models.SearchResults;
+using JdeScoping.ExcelIO.Formatting;
namespace JdeScoping.ExcelIO.Mapping.Maps;
@@ -13,10 +14,10 @@ public sealed class MisNonMatchSearchResultMap : ExcelClassMap x.WorkCenterCode).Order(10).Header("Work Center Code");
Map(x => x.WorkOrderNumber).Order(20).Header("Work Order Number");
- Map(x => x.WorkOrderStartDate).Order(30).Header("Work Order Start Date").Format(ExcelFormats.Date);
+ Map(x => x.WorkOrderStartDate).Order(30).Header("Work Order Start Date").Format(ExcelFormats.DateFormat);
Map(x => x.JobStepNumber).Order(40).Header("Job Step Number");
Map(x => x.JobStepDescription).Order(50).Header("Function Operation Description");
- Map(x => x.JobStepEndDate).Order(60).Header("Job Step End Date").Format(ExcelFormats.Date);
+ Map(x => x.JobStepEndDate).Order(60).Header("Job Step End Date").Format(ExcelFormats.DateFormat);
Map(x => x.FunctionCode).Order(70).Header("Function Code");
Map(x => x.WasJobStepAdded).Order(75).Header("Was Job Step Added?");
Map(x => x.MatchedJobStepNumber).Order(76).Header("Matched Job Step Number");
diff --git a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisSearchResultMap.cs b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisSearchResultMap.cs
index e82d79d..857d7fe 100644
--- a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisSearchResultMap.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/MisSearchResultMap.cs
@@ -1,4 +1,5 @@
using JdeScoping.Core.Models.SearchResults;
+using JdeScoping.ExcelIO.Formatting;
namespace JdeScoping.ExcelIO.Mapping.Maps;
@@ -17,7 +18,7 @@ public sealed class MisSearchResultMap : ExcelClassMap
Map(x => x.RevId).Order(40).Header("MIS Revision");
Map(x => x.ItemDescription).Order(50).Header("Item Description");
Map(x => x.Status).Order(60).Header("MIS Release Status");
- Map(x => x.ReleaseDate).Order(70).Header("MIS Release Date").Format(ExcelFormats.Timestamp);
+ Map(x => x.ReleaseDate).Order(70).Header("MIS Release Date").Format(ExcelFormats.TimestampFormat);
Map(x => x.BranchCode).Order(80).Header("Branch Code");
Map(x => x.JobStepSequenceNumber).Order(90).Header("Job Step Sequence Number");
Map(x => x.MatchedSequenceNumber).Order(100).Header("Matched Sequence Number");
diff --git a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/SearchResultMap.cs b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/SearchResultMap.cs
index 42daadc..12ba329 100644
--- a/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/SearchResultMap.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Mapping/Maps/SearchResultMap.cs
@@ -1,4 +1,5 @@
using JdeScoping.Core.Models.SearchResults;
+using JdeScoping.ExcelIO.Formatting;
namespace JdeScoping.ExcelIO.Mapping.Maps;
@@ -25,10 +26,10 @@ public sealed class SearchResultMap : ExcelClassMap
Map(x => x.StepNumber).Order(110).Header("Operation Step");
Map(x => x.StepDescription).Order(120).Header("Operation Step Description");
Map(x => x.FunctionOperationDescription).Order(130).Header("Function Operation Description");
- Map(x => x.StepUpdateDt).Order(140).Header("Operation Step Update Timestamp").Format(ExcelFormats.Timestamp);
+ Map(x => x.StepUpdateDt).Order(140).Header("Operation Step Update Timestamp").Format(ExcelFormats.TimestampFormat);
Map(x => x.StatusCode).Order(150).Header("Status Code");
Map(x => x.StatusDescription).Order(160).Header("Status Description");
- Map(x => x.StatusUpdateDt).Order(170).Header("Status Update Timestamp").Format(ExcelFormats.Date);
+ Map(x => x.StatusUpdateDt).Order(170).Header("Status Update Timestamp").Format(ExcelFormats.DateFormat);
Map(x => x.InclusionReason).Order(180).Header("Inclusion Reason");
}
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/OutputColumn.cs b/NEW/src/JdeScoping.ExcelIO/Models/OutputColumn.cs
deleted file mode 100644
index ada8a92..0000000
--- a/NEW/src/JdeScoping.ExcelIO/Models/OutputColumn.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Reflection;
-using JdeScoping.ExcelIO.Attributes;
-
-namespace JdeScoping.ExcelIO.Models;
-
-///
-/// Column metadata model for Excel output.
-///
-public class OutputColumn
-{
- ///
- /// Property name.
- ///
- public string Name { get; init; } = string.Empty;
-
- ///
- /// Property info for reflection.
- ///
- public PropertyInfo Property { get; init; } = null!;
-
- ///
- /// Output column attribute.
- ///
- public OutputColumnAttribute Attribute { get; init; } = null!;
-}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ComponentLotFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ComponentLotFilterEntry.cs
index 6b92149..bed0e7e 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ComponentLotFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ComponentLotFilterEntry.cs
@@ -1,22 +1,17 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Component lot search filter entry.
///
-[OutputTable(TabName = "Component Lot Filter", ShowHeader = true, TableName = "Component_Lot_Filter")]
public class ComponentLotFilterEntry
{
///
/// Component lot number.
///
- [OutputColumn(Order = 10, HeaderText = "Lot Number")]
public string LotNumber { get; set; } = string.Empty;
///
/// Component lot item number.
///
- [OutputColumn(Order = 20, HeaderText = "Item Number")]
public string ItemNumber { get; set; } = string.Empty;
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemNumberFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemNumberFilterEntry.cs
index 43d359d..c644420 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemNumberFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemNumberFilterEntry.cs
@@ -1,22 +1,17 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Item number search filter entry.
///
-[OutputTable(TabName = "Item Number Filter", ShowHeader = true, TableName = "Item_Number_Filter")]
public class ItemNumberFilterEntry
{
///
/// Item number.
///
- [OutputColumn(Order = 10, HeaderText = "Item Number")]
public string ItemNumber { get; set; } = string.Empty;
///
/// Item description.
///
- [OutputColumn(Order = 20, HeaderText = "Item Description")]
public string ItemDescription { get; set; } = string.Empty;
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemOperationMisFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemOperationMisFilterEntry.cs
index 46323b9..6c5c79d 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemOperationMisFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ItemOperationMisFilterEntry.cs
@@ -1,34 +1,27 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Item/Operation/MIS search filter entry.
///
-[OutputTable(TabName = "Item/Operation/MIS Filter", ShowHeader = true, TableName = "Item_Operation_MIS_Filter")]
public class ItemOperationMisFilterEntry
{
///
/// Part's item number.
///
- [OutputColumn(Order = 10, HeaderText = "Item Number")]
public string ItemNumber { get; set; } = string.Empty;
///
/// Operation's job step number.
///
- [OutputColumn(Order = 20, HeaderText = "Operation Number")]
public string OperationNumber { get; set; } = string.Empty;
///
/// MIS number.
///
- [OutputColumn(Order = 30, HeaderText = "MIS Number")]
public string MisNumber { get; set; } = string.Empty;
///
/// MIS revision.
///
- [OutputColumn(Order = 40, HeaderText = "MIS Revision")]
public string MisRevision { get; set; } = string.Empty;
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/OperatorFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/OperatorFilterEntry.cs
index 14f779c..665d91a 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/OperatorFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/OperatorFilterEntry.cs
@@ -1,11 +1,8 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Operator search filter entry.
///
-[OutputTable(TabName = "Operator Filter", ShowHeader = true, TableName = "Operator_Filter")]
public class OperatorFilterEntry
{
///
@@ -16,12 +13,10 @@ public class OperatorFilterEntry
///
/// Operator login user ID.
///
- [OutputColumn(Order = 10, HeaderText = "Username")]
public string UserId { get; set; } = string.Empty;
///
/// Operator full name (FIRST + LAST).
///
- [OutputColumn(Order = 20, HeaderText = "Name")]
public string FullName { get; set; } = string.Empty;
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ProfitCenterFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ProfitCenterFilterEntry.cs
index 86bdeb6..29144a0 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ProfitCenterFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/ProfitCenterFilterEntry.cs
@@ -1,22 +1,17 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Profit center search filter entry.
///
-[OutputTable(TabName = "Profit Center Filter", ShowHeader = true, TableName = "Profit_Center_Filter")]
public class ProfitCenterFilterEntry
{
///
/// Profit center code.
///
- [OutputColumn(Order = 10, HeaderText = "Profit Center")]
public string Code { get; set; } = string.Empty;
///
/// Profit center description.
///
- [OutputColumn(Order = 20, HeaderText = "Description")]
public string Description { get; set; } = string.Empty;
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/TimespanFilter.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/TimespanFilter.cs
index c79d569..262f0d9 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/TimespanFilter.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/TimespanFilter.cs
@@ -1,22 +1,17 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Timespan filter entry for criteria sheet.
///
-[OutputTable(TabName = "Timespan Filter", ShowHeader = true, TableName = "Timespan_Filter")]
public class TimespanFilter
{
///
/// Minimum date/time.
///
- [OutputColumn(Order = 10, HeaderText = "Minimum Date", Format = OutputColumnAttribute.DateFormat)]
public DateTime? MinimumDt { get; set; }
///
/// Maximum date/time.
///
- [OutputColumn(Order = 20, HeaderText = "Maximum Date", Format = OutputColumnAttribute.DateFormat)]
public DateTime? MaximumDt { get; set; }
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkCenterFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkCenterFilterEntry.cs
index 539460a..056c716 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkCenterFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkCenterFilterEntry.cs
@@ -1,22 +1,17 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Work center search filter entry.
///
-[OutputTable(TabName = "Work Center Filter", ShowHeader = true, TableName = "Work_Center_Filter")]
public class WorkCenterFilterEntry
{
///
/// Work center code.
///
- [OutputColumn(Order = 10, HeaderText = "Work Center")]
public string Code { get; set; } = string.Empty;
///
/// Work center description.
///
- [OutputColumn(Order = 20, HeaderText = "Description")]
public string Description { get; set; } = string.Empty;
}
diff --git a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkOrderFilterEntry.cs b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkOrderFilterEntry.cs
index 9be7c41..0f79c7c 100644
--- a/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkOrderFilterEntry.cs
+++ b/NEW/src/JdeScoping.ExcelIO/Models/Reporting/WorkOrderFilterEntry.cs
@@ -1,22 +1,17 @@
-using JdeScoping.ExcelIO.Attributes;
-
namespace JdeScoping.ExcelIO.Models.Reporting;
///
/// Work order search filter entry.
///
-[OutputTable(TabName = "Work Order Filter", ShowHeader = true, TableName = "Work_Order_Filter")]
public class WorkOrderFilterEntry
{
///
/// Work order number.
///
- [OutputColumn(Order = 10, HeaderText = "Work Order Number")]
public long WorkOrderNumber { get; set; }
///
/// Work order item number.
///
- [OutputColumn(Order = 20, HeaderText = "Item Number")]
public string ItemNumber { get; set; } = string.Empty;
}
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/AttributeTableWriterTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/AttributeTableWriterTests.cs
deleted file mode 100644
index 2ef74c9..0000000
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/AttributeTableWriterTests.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using ClosedXML.Excel;
-using JdeScoping.ExcelIO.Attributes;
-using JdeScoping.ExcelIO.Generators;
-using JdeScoping.ExcelIO.Helpers;
-using Shouldly;
-using Xunit;
-
-namespace JdeScoping.ExcelIO.Tests;
-
-public class AttributeTableWriterTests
-{
- private readonly OutputColumnCache _cache = new();
- private readonly AttributeTableWriter _writer;
-
- public AttributeTableWriterTests()
- {
- _writer = new AttributeTableWriter(_cache);
- }
-
- [OutputTable(TabName = "Test Items", TableName = "Test_Items", ShowHeader = false)]
- private class TestItem
- {
- [OutputColumn(Order = 10, HeaderText = "ID")]
- public int Id { get; set; }
-
- [OutputColumn(Order = 20, HeaderText = "Name")]
- public string Name { get; set; } = string.Empty;
-
- [OutputColumn(Order = 30, HeaderText = "Value")]
- public decimal Value { get; set; }
- }
-
- [OutputTable(TabName = "Wrapped Table", TableName = "Wrapped_Table")]
- private class WrappedItem
- {
- [OutputColumn(Order = 10, HeaderText = "Description", WrapText = true, AutoWidth = false, Width = 65)]
- public string Description { get; set; } = string.Empty;
- }
-
- private class NoAttributeItem
- {
- public string Data { get; set; } = string.Empty;
- }
-
- [Fact]
- public void WriteTable_CreatesTableWithCorrectColumns()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List
- {
- new() { Id = 1, Name = "Item 1", Value = 10.5m },
- new() { Id = 2, Name = "Item 2", Value = 20.5m }
- };
-
- var table = _writer.WriteTable(worksheet, 1, 1, data);
-
- table.ShouldNotBeNull();
- table.ColumnCount().ShouldBe(3);
- table.RowCount().ShouldBe(3); // Header + 2 data rows
- }
-
- [Fact]
- public void WriteTable_UsesLight18TableStyle()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List { new() { Id = 1, Name = "Test", Value = 100m } };
-
- var table = _writer.WriteTable(worksheet, 1, 1, data);
-
- table.ShouldNotBeNull();
- table.Theme.ShouldBe(XLTableTheme.TableStyleLight18);
- }
-
- [Fact]
- public void WriteTable_SetsColumnHeaders()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List { new() { Id = 1, Name = "Test", Value = 100m } };
-
- _writer.WriteTable(worksheet, 1, 1, data);
-
- worksheet.Cell(1, 1).Value.GetText().ShouldBe("ID");
- worksheet.Cell(1, 2).Value.GetText().ShouldBe("Name");
- worksheet.Cell(1, 3).Value.GetText().ShouldBe("Value");
- }
-
- [Fact]
- public void WriteTable_WritesDataRows()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List
- {
- new() { Id = 1, Name = "Item 1", Value = 10.5m },
- new() { Id = 2, Name = "Item 2", Value = 20.5m }
- };
-
- _writer.WriteTable(worksheet, 1, 1, data);
-
- worksheet.Cell(2, 1).Value.GetNumber().ShouldBe(1);
- worksheet.Cell(2, 2).Value.GetText().ShouldBe("Item 1");
- worksheet.Cell(2, 3).Value.GetNumber().ShouldBe(10.5);
- worksheet.Cell(3, 1).Value.GetNumber().ShouldBe(2);
- }
-
- [Fact]
- public void WriteTable_WithShowHeader_CreatesMergedHeader()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List { new() { Id = 1, Name = "Test", Value = 100m } };
-
- _writer.WriteTable(worksheet, 1, 1, data, showHeader: true, headerText: "Test Header");
-
- // First row should be merged header
- var headerRange = worksheet.Range(1, 1, 1, 3);
- headerRange.IsMerged().ShouldBeTrue();
- worksheet.Cell(1, 1).Value.GetText().ShouldBe("Test Header");
-
- // Column headers should be on row 2
- worksheet.Cell(2, 1).Value.GetText().ShouldBe("ID");
- }
-
- [Fact]
- public void WriteTable_EmptyData_CreatesTableWithHeaderOnly()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List();
-
- var table = _writer.WriteTable(worksheet, 1, 1, data);
-
- table.ShouldNotBeNull();
- // Table should exist with headers
- table.ColumnCount().ShouldBe(3);
- }
-
- [Fact]
- public void WriteTable_NoAttributes_ReturnsNull()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List { new() { Data = "Test" } };
-
- var table = _writer.WriteTable(worksheet, 1, 1, data);
-
- table.ShouldBeNull();
- }
-
- [Fact]
- public void WriteTable_WrappedColumn_SetsFixedWidth()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List { new() { Description = "Long description text" } };
-
- _writer.WriteTable(worksheet, 1, 1, data);
-
- worksheet.Column(1).Width.ShouldBe(65);
- worksheet.Column(1).Style.Alignment.WrapText.ShouldBeTrue();
- }
-
- [Fact]
- public void WriteTable_TableNameOverride_UsesProvidedName()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var data = new List { new() { Id = 1, Name = "Test", Value = 100m } };
-
- var table = _writer.WriteTable(worksheet, 1, 1, data, tableNameOverride: "Custom_Table");
-
- table.ShouldNotBeNull();
- table.Name.ShouldBe("Custom_Table");
- }
-}
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/ColumnFormatterTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/ColumnFormatterTests.cs
deleted file mode 100644
index b830c90..0000000
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/ColumnFormatterTests.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using ClosedXML.Excel;
-using JdeScoping.ExcelIO.Attributes;
-using JdeScoping.ExcelIO.Formatting;
-using Shouldly;
-using Xunit;
-
-namespace JdeScoping.ExcelIO.Tests;
-
-public class ColumnFormatterTests
-{
- [Fact]
- public void ApplyColumnFormat_AutoWidth_AdjustsToContents()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
- worksheet.Cell(1, 1).Value = "Some Text Value";
-
- var attr = new OutputColumnAttribute
- {
- AutoWidth = true,
- Format = OutputColumnAttribute.StdFormat
- };
-
- ColumnFormatter.ApplyColumnFormat(worksheet.Column(1), attr);
-
- // Width should be greater than default after adjustment
- worksheet.Column(1).Width.ShouldBeGreaterThan(0);
- }
-
- [Fact]
- public void ApplyColumnFormat_FixedWidth_SetsExactWidth()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var attr = new OutputColumnAttribute
- {
- AutoWidth = false,
- Width = 50.0,
- Format = OutputColumnAttribute.StdFormat
- };
-
- ColumnFormatter.ApplyColumnFormat(worksheet.Column(1), attr);
-
- worksheet.Column(1).Width.ShouldBe(50.0);
- }
-
- [Fact]
- public void ApplyColumnFormat_WrapText_EnablesWrapping()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var attr = new OutputColumnAttribute
- {
- WrapText = true,
- AutoWidth = false,
- Width = 65.0,
- Format = OutputColumnAttribute.StdFormat
- };
-
- ColumnFormatter.ApplyColumnFormat(worksheet.Column(1), attr);
-
- worksheet.Column(1).Style.Alignment.WrapText.ShouldBeTrue();
- worksheet.Column(1).Width.ShouldBe(65.0);
- }
-
- [Fact]
- public void ApplyColumnFormat_DateFormat_AppliesCorrectFormat()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var attr = new OutputColumnAttribute
- {
- AutoWidth = false,
- Width = 20.0,
- Format = OutputColumnAttribute.DateFormat
- };
-
- ColumnFormatter.ApplyColumnFormat(worksheet.Column(1), attr);
-
- worksheet.Column(1).Style.NumberFormat.Format.ShouldBe(OutputColumnAttribute.DateFormat);
- }
-
- [Fact]
- public void ApplyColumnFormat_TimestampFormat_AppliesCorrectFormat()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
-
- var attr = new OutputColumnAttribute
- {
- AutoWidth = false,
- Width = 25.0,
- Format = OutputColumnAttribute.TimestampFormat
- };
-
- ColumnFormatter.ApplyColumnFormat(worksheet.Column(1), attr);
-
- worksheet.Column(1).Style.NumberFormat.Format.ShouldBe(OutputColumnAttribute.TimestampFormat);
- }
-
- [Fact]
- public void AutoFitWithPadding_AppliesPaddingFactor()
- {
- using var workbook = new XLWorkbook();
- var worksheet = workbook.Worksheets.Add("Test");
- worksheet.Cell(1, 1).Value = "Some Text";
-
- ColumnFormatter.AutoFitWithPadding(worksheet.Column(1), 1.30);
-
- // Width should be greater than 0 and include padding
- worksheet.Column(1).Width.ShouldBeGreaterThan(0);
- }
-}
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/CriteriaSheetGeneratorTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/CriteriaSheetGeneratorTests.cs
index 39b4d03..91080e2 100644
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/CriteriaSheetGeneratorTests.cs
+++ b/NEW/tests/JdeScoping.ExcelIO.Tests/CriteriaSheetGeneratorTests.cs
@@ -1,7 +1,8 @@
using ClosedXML.Excel;
using JdeScoping.ExcelIO.Options;
using JdeScoping.ExcelIO.Generators;
-using JdeScoping.ExcelIO.Helpers;
+using JdeScoping.ExcelIO.Mapping;
+using JdeScoping.ExcelIO.Mapping.Maps;
using JdeScoping.ExcelIO.Models.Reporting;
using Microsoft.Extensions.Options;
using Shouldly;
@@ -21,11 +22,25 @@ public class CriteriaSheetGeneratorTests
CriteriaSheetPassword = "TestPassword"
});
- var cache = new OutputColumnCache();
- var tableWriter = new AttributeTableWriter(cache);
+ var registry = CreateTestRegistry();
+ var tableWriter = new FluentTableWriter(registry);
_generator = new CriteriaSheetGenerator(_options, tableWriter);
}
+ private static ExcelMapRegistry CreateTestRegistry()
+ {
+ var registry = new ExcelMapRegistry();
+ registry.Register(new TimespanFilterMap());
+ registry.Register(new WorkOrderFilterEntryMap());
+ registry.Register(new ItemNumberFilterEntryMap());
+ registry.Register(new ProfitCenterFilterEntryMap());
+ registry.Register(new WorkCenterFilterEntryMap());
+ registry.Register(new OperatorFilterEntryMap());
+ registry.Register(new ComponentLotFilterEntryMap());
+ registry.Register(new ItemOperationMisFilterEntryMap());
+ return registry;
+ }
+
[Fact]
public void Generate_CreatesSearchCriteriaSheet()
{
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportIntegrationTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportIntegrationTests.cs
index f4e148b..6f4d9e9 100644
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportIntegrationTests.cs
+++ b/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportIntegrationTests.cs
@@ -1,7 +1,8 @@
using ClosedXML.Excel;
using JdeScoping.ExcelIO.Options;
using JdeScoping.ExcelIO.Generators;
-using JdeScoping.ExcelIO.Helpers;
+using JdeScoping.ExcelIO.Mapping;
+using JdeScoping.ExcelIO.Mapping.Maps;
using JdeScoping.ExcelIO.Models.Reporting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -9,6 +10,10 @@ using NSubstitute;
using Shouldly;
using Xunit;
+using SearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
+using MisSearchResult = JdeScoping.Core.Models.SearchResults.MisSearchResult;
+using MisNonMatchSearchResult = JdeScoping.Core.Models.SearchResults.MisNonMatchSearchResult;
+
namespace JdeScoping.ExcelIO.Tests;
///
@@ -29,11 +34,33 @@ public class ExcelExportIntegrationTests
DataSheetPassword = "TestDataPass"
});
- var cache = new OutputColumnCache();
- var tableWriter = new AttributeTableWriter(cache);
+ var registry = CreateTestRegistry();
+ var tableWriter = new FluentTableWriter(registry);
var criteriaGenerator = new CriteriaSheetGenerator(_options, tableWriter);
- _service = new ExcelExportService(_logger, _options, criteriaGenerator, tableWriter);
+ _service = new ExcelExportService(_logger, _options, criteriaGenerator, tableWriter, registry);
+ }
+
+ private static ExcelMapRegistry CreateTestRegistry()
+ {
+ var registry = new ExcelMapRegistry();
+
+ // Search result maps
+ registry.Register(new SearchResultMap());
+ registry.Register(new MisSearchResultMap());
+ registry.Register(new MisNonMatchSearchResultMap());
+
+ // Filter entry maps
+ registry.Register(new TimespanFilterMap());
+ registry.Register(new WorkOrderFilterEntryMap());
+ registry.Register(new ItemNumberFilterEntryMap());
+ registry.Register(new ProfitCenterFilterEntryMap());
+ registry.Register(new WorkCenterFilterEntryMap());
+ registry.Register(new OperatorFilterEntryMap());
+ registry.Register(new ComponentLotFilterEntryMap());
+ registry.Register(new ItemOperationMisFilterEntryMap());
+
+ return registry;
}
#region Sheet Count Tests
@@ -387,10 +414,13 @@ public class ExcelExportIntegrationTests
public async Task GenerateAsync_SearchResults_ContainsCorrectData()
{
var search = CreateMinimalSearchModel();
- var searchResult = CreateSampleSearchResult();
- searchResult.WorkOrderNumber = 99999;
- searchResult.ItemNumber = "TEST-ITEM-001";
- searchResult.LotNumber = "LOT-999";
+ var searchResult = new SearchResult
+ {
+ WorkOrderNumber = 99999,
+ ItemNumber = "TEST-ITEM-001",
+ LotNumber = "LOT-999",
+ Flagged = true
+ };
search.Results.Add(searchResult);
var result = await _service.GenerateAsync(search);
@@ -408,9 +438,16 @@ public class ExcelExportIntegrationTests
[Fact]
public async Task GenerateAsync_MisInfo_ContainsCorrectData()
{
- var search = CreateSearchModelWithMisData();
- search.MisResults![0].ItemNumber = "MIS-ITEM-001";
- search.MisResults[0].MisNumber = "MIS-12345";
+ var search = CreateMinimalSearchModel();
+ search.ExtractMisData = true;
+ search.MisResults = [
+ new MisSearchResult
+ {
+ ItemNumber = "MIS-ITEM-001",
+ MisNumber = "MIS-12345"
+ }
+ ];
+ search.MisNonMatchResults = [];
var result = await _service.GenerateAsync(search);
@@ -426,9 +463,16 @@ public class ExcelExportIntegrationTests
[Fact]
public async Task GenerateAsync_Investigation_ContainsCorrectData()
{
- var search = CreateSearchModelWithMisData();
- search.MisNonMatchResults![0].WorkOrderNumber = 77777;
- search.MisNonMatchResults[0].ItemNumber = "INV-ITEM-001";
+ var search = CreateMinimalSearchModel();
+ search.ExtractMisData = true;
+ search.MisResults = [];
+ search.MisNonMatchResults = [
+ new MisNonMatchSearchResult
+ {
+ WorkOrderNumber = 77777,
+ ItemNumber = "INV-ITEM-001"
+ }
+ ];
var result = await _service.GenerateAsync(search);
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportServiceTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportServiceTests.cs
index 15fc283..1e4e5bb 100644
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportServiceTests.cs
+++ b/NEW/tests/JdeScoping.ExcelIO.Tests/ExcelExportServiceTests.cs
@@ -1,7 +1,8 @@
using ClosedXML.Excel;
using JdeScoping.ExcelIO.Options;
using JdeScoping.ExcelIO.Generators;
-using JdeScoping.ExcelIO.Helpers;
+using JdeScoping.ExcelIO.Mapping;
+using JdeScoping.ExcelIO.Mapping.Maps;
using JdeScoping.ExcelIO.Models.Reporting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -9,6 +10,10 @@ using NSubstitute;
using Shouldly;
using Xunit;
+using SearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
+using MisSearchResult = JdeScoping.Core.Models.SearchResults.MisSearchResult;
+using MisNonMatchSearchResult = JdeScoping.Core.Models.SearchResults.MisNonMatchSearchResult;
+
namespace JdeScoping.ExcelIO.Tests;
public class ExcelExportServiceTests
@@ -26,11 +31,33 @@ public class ExcelExportServiceTests
DataSheetPassword = "TestDataPass"
});
- var cache = new OutputColumnCache();
- var tableWriter = new AttributeTableWriter(cache);
+ var registry = CreateTestRegistry();
+ var tableWriter = new FluentTableWriter(registry);
var criteriaGenerator = new CriteriaSheetGenerator(_options, tableWriter);
- _service = new ExcelExportService(_logger, _options, criteriaGenerator, tableWriter);
+ _service = new ExcelExportService(_logger, _options, criteriaGenerator, tableWriter, registry);
+ }
+
+ private static ExcelMapRegistry CreateTestRegistry()
+ {
+ var registry = new ExcelMapRegistry();
+
+ // Search result maps
+ registry.Register(new SearchResultMap());
+ registry.Register(new MisSearchResultMap());
+ registry.Register(new MisNonMatchSearchResultMap());
+
+ // Filter entry maps
+ registry.Register(new TimespanFilterMap());
+ registry.Register(new WorkOrderFilterEntryMap());
+ registry.Register(new ItemNumberFilterEntryMap());
+ registry.Register(new ProfitCenterFilterEntryMap());
+ registry.Register(new WorkCenterFilterEntryMap());
+ registry.Register(new OperatorFilterEntryMap());
+ registry.Register(new ComponentLotFilterEntryMap());
+ registry.Register(new ItemOperationMisFilterEntryMap());
+
+ return registry;
}
[Fact]
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/InclusionReasonTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/InclusionReasonTests.cs
index 5e39e93..c35007e 100644
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/InclusionReasonTests.cs
+++ b/NEW/tests/JdeScoping.ExcelIO.Tests/InclusionReasonTests.cs
@@ -1,4 +1,4 @@
-using JdeScoping.ExcelIO.Models.Reporting;
+using JdeScoping.Core.Models.SearchResults;
using Shouldly;
using Xunit;
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/LegacyComparisonTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/LegacyComparisonTests.cs
index 368abb0..17b9619 100644
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/LegacyComparisonTests.cs
+++ b/NEW/tests/JdeScoping.ExcelIO.Tests/LegacyComparisonTests.cs
@@ -1,8 +1,8 @@
using ClosedXML.Excel;
using JdeScoping.ExcelIO.Options;
-using JdeScoping.ExcelIO.Formatting;
using JdeScoping.ExcelIO.Generators;
-using JdeScoping.ExcelIO.Helpers;
+using JdeScoping.ExcelIO.Mapping;
+using JdeScoping.ExcelIO.Mapping.Maps;
using JdeScoping.ExcelIO.Models.Reporting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -10,6 +10,11 @@ using NSubstitute;
using Shouldly;
using Xunit;
+using ExcelFormats = JdeScoping.ExcelIO.Formatting.ExcelFormats;
+using SearchResult = JdeScoping.Core.Models.SearchResults.SearchResult;
+using MisSearchResult = JdeScoping.Core.Models.SearchResults.MisSearchResult;
+using MisNonMatchSearchResult = JdeScoping.Core.Models.SearchResults.MisNonMatchSearchResult;
+
namespace JdeScoping.ExcelIO.Tests;
///
@@ -30,11 +35,33 @@ public class LegacyComparisonTests
DataSheetPassword = "JDESCOPINGTOOL"
});
- var cache = new OutputColumnCache();
- var tableWriter = new AttributeTableWriter(cache);
+ var registry = CreateTestRegistry();
+ var tableWriter = new FluentTableWriter(registry);
var criteriaGenerator = new CriteriaSheetGenerator(options, tableWriter);
- _service = new ExcelExportService(logger, options, criteriaGenerator, tableWriter);
+ _service = new ExcelExportService(logger, options, criteriaGenerator, tableWriter, registry);
+ }
+
+ private static ExcelMapRegistry CreateTestRegistry()
+ {
+ var registry = new ExcelMapRegistry();
+
+ // Search result maps
+ registry.Register(new SearchResultMap());
+ registry.Register(new MisSearchResultMap());
+ registry.Register(new MisNonMatchSearchResultMap());
+
+ // Filter entry maps
+ registry.Register(new TimespanFilterMap());
+ registry.Register(new WorkOrderFilterEntryMap());
+ registry.Register(new ItemNumberFilterEntryMap());
+ registry.Register(new ProfitCenterFilterEntryMap());
+ registry.Register(new WorkCenterFilterEntryMap());
+ registry.Register(new OperatorFilterEntryMap());
+ registry.Register(new ComponentLotFilterEntryMap());
+ registry.Register(new ItemOperationMisFilterEntryMap());
+
+ return registry;
}
#region Search Results Column Order Tests
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/Mapping/ExcelClassMapTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/Mapping/ExcelClassMapTests.cs
index 2ef42c9..c37285b 100644
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/Mapping/ExcelClassMapTests.cs
+++ b/NEW/tests/JdeScoping.ExcelIO.Tests/Mapping/ExcelClassMapTests.cs
@@ -1,3 +1,4 @@
+using JdeScoping.ExcelIO.Formatting;
using JdeScoping.ExcelIO.Mapping;
using Shouldly;
using Xunit;
@@ -23,7 +24,7 @@ public class ExcelClassMapTests
Map(x => x.Id).Order(10).Header("ID Number");
Map(x => x.Name).Order(20).Header("Full Name");
- Map(x => x.CreatedAt).Order(30).Header("Created").Format(ExcelFormats.Timestamp);
+ Map(x => x.CreatedAt).Order(30).Header("Created").Format(ExcelFormats.TimestampFormat);
}
}
@@ -71,7 +72,7 @@ public class ExcelClassMapTests
var map = new TestModelMap();
var columns = map.Columns;
- columns[2].Format.ShouldBe(ExcelFormats.Timestamp);
+ columns[2].Format.ShouldBe(ExcelFormats.TimestampFormat);
}
[Fact]
diff --git a/NEW/tests/JdeScoping.ExcelIO.Tests/OutputColumnCacheTests.cs b/NEW/tests/JdeScoping.ExcelIO.Tests/OutputColumnCacheTests.cs
deleted file mode 100644
index 8685d57..0000000
--- a/NEW/tests/JdeScoping.ExcelIO.Tests/OutputColumnCacheTests.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using JdeScoping.ExcelIO.Attributes;
-using JdeScoping.ExcelIO.Helpers;
-using Shouldly;
-using Xunit;
-
-namespace JdeScoping.ExcelIO.Tests;
-
-public class OutputColumnCacheTests
-{
- private readonly OutputColumnCache _cache = new();
-
- [OutputTable(TabName = "Test Table", TableName = "Test_Table")]
- private class TestModel
- {
- [OutputColumn(Order = 30, HeaderText = "Column C")]
- public string ColumnC { get; set; } = string.Empty;
-
- [OutputColumn(Order = 10, HeaderText = "Column A")]
- public string ColumnA { get; set; } = string.Empty;
-
- [OutputColumn(Order = 20, HeaderText = "Column B")]
- public string ColumnB { get; set; } = string.Empty;
-
- public string NonOutputColumn { get; set; } = string.Empty;
- }
-
- private class TieBreakModel
- {
- [OutputColumn(Order = 10, HeaderText = "Zebra")]
- public string Zebra { get; set; } = string.Empty;
-
- [OutputColumn(Order = 10, HeaderText = "Apple")]
- public string Apple { get; set; } = string.Empty;
-
- [OutputColumn(Order = 10, HeaderText = "Mango")]
- public string Mango { get; set; } = string.Empty;
- }
-
- private class EmptyModel
- {
- public string NoAttributes { get; set; } = string.Empty;
- }
-
- [Fact]
- public void GetColumns_ReturnsColumnsOrderedByOrderProperty()
- {
- var columns = _cache.GetColumns();
-
- columns.Count.ShouldBe(3);
- columns[0].Attribute.HeaderText.ShouldBe("Column A");
- columns[1].Attribute.HeaderText.ShouldBe("Column B");
- columns[2].Attribute.HeaderText.ShouldBe("Column C");
- }
-
- [Fact]
- public void GetColumns_TieBreaksAlphabeticallyByPropertyName()
- {
- var columns = _cache.GetColumns();
-
- columns.Count.ShouldBe(3);
- // All have Order=10, so should be sorted by property name
- columns[0].Name.ShouldBe("Apple");
- columns[1].Name.ShouldBe("Mango");
- columns[2].Name.ShouldBe("Zebra");
- }
-
- [Fact]
- public void GetColumns_ExcludesPropertiesWithoutAttribute()
- {
- var columns = _cache.GetColumns();
-
- columns.Count.ShouldBe(3);
- columns.ShouldNotContain(c => c.Name == "NonOutputColumn");
- }
-
- [Fact]
- public void GetColumns_ReturnsEmptyForEmptyModel()
- {
- var columns = _cache.GetColumns();
-
- columns.Count.ShouldBe(0);
- }
-
- [Fact]
- public void GetColumns_CachesResults()
- {
- var columns1 = _cache.GetColumns();
- var columns2 = _cache.GetColumns();
-
- ReferenceEquals(columns1, columns2).ShouldBeTrue();
- }
-
- [Fact]
- public void GetColumns_ByType_ReturnsCorrectColumns()
- {
- var columns = _cache.GetColumns(typeof(TestModel));
-
- columns.Count.ShouldBe(3);
- }
-}