using System; using System.Collections.Generic; using System.Linq; namespace rgbc_sds.services.Models { /// /// Raw data from an Excel row during import /// public class ExcelRowData { /// /// Row number in the Excel file (1-based) /// public int RowNumber { get; set; } /// /// Dictionary of column values by header name /// public Dictionary ColumnValues { get; set; } = new Dictionary(); /// /// Whether this row has any data /// public bool HasData => ColumnValues.Values.Any(v => !string.IsNullOrWhiteSpace(v)); /// /// Gets a column value by header name /// /// Column header name /// Column value or empty string if not found public string GetValue(string headerName) { return ColumnValues.TryGetValue(headerName, out var value) ? value : string.Empty; } /// /// Gets a column value by header name with fallback /// /// Column header name /// Fallback value if column not found /// Column value or fallback value public string GetValue(string headerName, string fallbackValue) { return ColumnValues.TryGetValue(headerName, out var value) ? value : fallbackValue; } /// /// Checks if a column exists and has a value /// /// Column header name /// True if column exists and has non-empty value public bool HasValue(string headerName) { return ColumnValues.TryGetValue(headerName, out var value) && !string.IsNullOrWhiteSpace(value); } } /// /// Column mapping information for Excel import /// public class ColumnMapping { /// /// Expected column headers in the Excel file /// public static readonly string[] ExpectedHeaders = new[] { "Supplier", "Indent Number", "Shipshape Number", "Mother Vessel", "E.T.A", "Bill of Entry Number", "Container Number", "Offloading Port", "Container Received", "No of Flatcases", "Voyage", "M/BL Number", "Redirect to SACD" }; /// /// Maps Excel column headers to entity property names /// public static readonly Dictionary HeaderToPropertyMap = new() { { "Supplier", "SupplierName" }, { "Indent Number", "IndentNumber" }, { "Shipshape Number", "ShipshapeNumber" }, { "Mother Vessel", "MotherVessel" }, { "E.T.A", "ETA" }, { "Bill of Entry Number", "BillOfEntryNumber" }, { "Container Number", "ContainerNumber" }, { "Offloading Port", "OffloadingPort" }, { "Container Received", "ContainerReceived" }, { "No of Flatcases", "NoOfFlatcases" }, { "Voyage", "Voyage" }, { "M/BL Number", "MBLNumber" }, { "Redirect to SACD", "RedirectToSACD" } }; /// /// Required columns that must be present /// public static readonly string[] RequiredColumns = new[] { "Supplier", "Indent Number", "Shipshape Number", "Mother Vessel", "E.T.A", "Bill of Entry Number", "Container Number", "Offloading Port", "Container Received", "No of Flatcases", "Voyage", "M/BL Number", "Redirect to SACD" }; /// /// Date columns that need special parsing /// public static readonly string[] DateColumns = new[] { "E.T.A", "Container Received", "Redirect to SACD" }; /// /// Validates that all required columns are present /// /// Headers found in the Excel file /// Validation result with missing columns public static ColumnValidationResult ValidateHeaders(IEnumerable foundHeaders) { var foundHeadersSet = foundHeaders.Select(h => h.Trim()).ToHashSet(StringComparer.OrdinalIgnoreCase); var missingColumns = RequiredColumns .Where(required => !foundHeadersSet.Contains(required)) .ToList(); return new ColumnValidationResult { IsValid = missingColumns.Count == 0, MissingColumns = missingColumns, FoundHeaders = foundHeadersSet.ToList() }; } } /// /// Result of column validation /// public class ColumnValidationResult { public bool IsValid { get; set; } public List MissingColumns { get; set; } = new List(); public List FoundHeaders { get; set; } = new List(); public string ErrorMessage => MissingColumns.Count > 0 ? $"Missing required columns: {string.Join(", ", MissingColumns)}" : string.Empty; } /// /// Import configuration options /// public class ImportConfiguration { /// /// Maximum number of records allowed per import /// public const int MaxRecordsPerImport = 200; /// /// Maximum file size in bytes (10MB) /// public const long MaxFileSizeBytes = 10 * 1024 * 1024; /// /// Allowed file extensions /// public static readonly string[] AllowedExtensions = { ".xlsx", ".xls" }; /// /// Whether to allow updates to existing records /// public bool AllowUpdates { get; set; } = true; /// /// Whether to create new suppliers if they don't exist /// public bool CreateMissingSuppliers { get; set; } = false; /// /// Whether to create new ports if they don't exist /// public bool CreateMissingPorts { get; set; } = false; /// /// Default import mode /// public string DefaultImportMode { get; set; } = "UpdateExisting"; } }