diff --git a/.gitignore b/.gitignore index 00902a3..38233a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +# Stray Windows redirect artifact +/nul + # User-specific files *.suo *.user diff --git a/ExportDXF/ExportDXF.csproj b/ExportDXF/ExportDXF.csproj index 405ba86..0d6545a 100644 --- a/ExportDXF/ExportDXF.csproj +++ b/ExportDXF/ExportDXF.csproj @@ -37,6 +37,9 @@ Always + + Always + diff --git a/ExportDXF/Services/DxfExportService.cs b/ExportDXF/Services/DxfExportService.cs index b7615b3..aab8a6c 100644 --- a/ExportDXF/Services/DxfExportService.cs +++ b/ExportDXF/Services/DxfExportService.cs @@ -130,7 +130,7 @@ namespace ExportDXF.Services ExportContext context, string tempDir, string outputFolder, - Dictionary existingTemplates, + Dictionary existingTemplates, List bomItems) { LogProgress(context, "Active document is a Part"); @@ -159,7 +159,7 @@ namespace ExportDXF.Services ExportContext context, string tempDir, string outputFolder, - Dictionary existingTemplates, + Dictionary existingTemplates, List bomItems) { LogProgress(context, "Active document is an Assembly"); @@ -200,7 +200,7 @@ namespace ExportDXF.Services ExportContext context, string tempDir, string outputFolder, - Dictionary existingTemplates, + Dictionary existingTemplates, List bomItems) { LogProgress(context, "Active document is a Drawing"); @@ -294,7 +294,7 @@ namespace ExportDXF.Services string tempDir, string outputFolder, ExportContext context, - Dictionary existingTemplates, + Dictionary existingTemplates, List bomItems) { int successCount = 0; @@ -362,7 +362,7 @@ namespace ExportDXF.Services Item item, ExportContext context, string outputFolder, - Dictionary existingTemplates, + Dictionary existingTemplates, BomItem bomItem) { var baseName = FilenameTemplateParser.Evaluate(context.FilenameTemplate, item); @@ -377,15 +377,15 @@ namespace ExportDXF.Services if (existing.ContentHash == contentHash) { // Unchanged — skip file write, keep existing - dxfFileName = existing.FileName; revision = existing.Revision; + dxfFileName = GetRevisionFileName(baseName, revision); LogProgress(context, $"Unchanged: {dxfFileName}", LogLevel.Info, item.PartName); _logFileService.LogInfo($"Unchanged: {dxfFileName}"); bomItem.CutTemplate = new CutTemplate { - DxfFilePath = dxfFileName, + DxfFilePath = Path.GetFileNameWithoutExtension(dxfFileName), ContentHash = contentHash, Revision = revision, Thickness = item.Thickness > 0 ? item.Thickness : (double?)null, @@ -402,7 +402,7 @@ namespace ExportDXF.Services dxfFileName = GetRevisionFileName(baseName, revision); LogProgress(context, $"Updated: {dxfFileName} (Rev{revision})", LogLevel.Info, item.PartName); - _logFileService.LogInfo($"Updated: {dxfFileName} (was {existing.FileName})"); + _logFileService.LogInfo($"Updated: {dxfFileName}"); } } else diff --git a/ExportDXF/Services/ExcelExportService.cs b/ExportDXF/Services/ExcelExportService.cs index d097b49..29cf599 100644 --- a/ExportDXF/Services/ExcelExportService.cs +++ b/ExportDXF/Services/ExcelExportService.cs @@ -1,6 +1,8 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using ClosedXML.Excel; using ExportDXF.Models; @@ -8,14 +10,18 @@ namespace ExportDXF.Services { public class ExcelExportService { + private static readonly string TemplatePath = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "Templates", + "BOM Template.xlsx"); /// /// Reads existing Cut Templates from an xlsx file to compare content hashes. /// Returns empty dictionary if file doesn't exist or has no Cut Templates sheet. - /// Key = Item #, Value = (ContentHash, Revision, FileName) + /// Key = Item #, Value = (ContentHash, Revision) /// - public Dictionary ReadExistingCutTemplates(string xlsxPath) + public Dictionary ReadExistingCutTemplates(string xlsxPath) { - var result = new Dictionary(); + var result = new Dictionary(); if (!File.Exists(xlsxPath)) return result; @@ -49,12 +55,9 @@ namespace ExportDXF.Services var revision = headers.ContainsKey("Revision") ? ws.Cell(row, headers["Revision"]).GetValue() : 1; - var fileName = headers.ContainsKey("File Name") - ? ws.Cell(row, headers["File Name"]).GetString() - : ""; if (!string.IsNullOrEmpty(itemNo)) - result[itemNo] = (hash, revision, fileName); + result[itemNo] = (hash, revision); } } @@ -71,9 +74,12 @@ namespace ExportDXF.Services List> rawBomTable, List bomItems) { - using (var workbook = File.Exists(xlsxPath) - ? new XLWorkbook(xlsxPath) - : new XLWorkbook()) + if (!File.Exists(TemplatePath)) + throw new FileNotFoundException("Excel template not found.", TemplatePath); + + File.Copy(TemplatePath, xlsxPath, overwrite: true); + + using (var workbook = new XLWorkbook(xlsxPath)) { WriteBomSheet(workbook, rawBomTable); WriteCutTemplatesSheet(workbook, bomItems); @@ -86,10 +92,9 @@ namespace ExportDXF.Services if (rawBomTable == null || rawBomTable.Count == 0) return; - if (workbook.TryGetWorksheet("BOM", out _)) - workbook.Worksheets.Delete("BOM"); + var sheet = GetOrCreateSheet(workbook, "BOM"); + sheet.Clear(); - var sheet = workbook.Worksheets.Add("BOM"); var columns = rawBomTable[0].Keys.ToList(); for (int col = 0; col < columns.Count; col++) @@ -110,30 +115,34 @@ namespace ExportDXF.Services private void WriteCutTemplatesSheet(XLWorkbook workbook, List bomItems) { - if (workbook.TryGetWorksheet("Cut Templates", out _)) - workbook.Worksheets.Delete("Cut Templates"); + var sheet = GetOrCreateSheet(workbook, "Cut Templates"); - var sheet = workbook.Worksheets.Add("Cut Templates"); - - var headers = new[] { "Item #", "File Name", "Revision", "Thickness", "K-Factor", "Bend Radius", "Content Hash" }; - for (int col = 0; col < headers.Length; col++) - sheet.Cell(1, col + 1).Value = headers[col]; + // Clear data rows only (preserve template headers/formatting in row 1) + var lastRow = sheet.LastRowUsed()?.RowNumber() ?? 1; + if (lastRow > 1) + sheet.Range(2, 1, lastRow, sheet.LastColumnUsed()?.ColumnNumber() ?? 1).Clear(); int row = 2; foreach (var item in bomItems.Where(b => b.CutTemplate != null).OrderBy(b => b.ItemNo)) { var ct = item.CutTemplate; sheet.Cell(row, 1).Value = item.ItemNo; - sheet.Cell(row, 2).Value = ct.DxfFilePath; - sheet.Cell(row, 3).Value = ct.Revision; - sheet.Cell(row, 4).Value = ct.Thickness ?? 0; - sheet.Cell(row, 5).Value = ct.KFactor ?? 0; - sheet.Cell(row, 6).Value = ct.DefaultBendRadius ?? 0; - sheet.Cell(row, 7).Value = ct.ContentHash ?? ""; + sheet.Cell(row, 2).Value = ct.Revision; + sheet.Cell(row, 3).Value = ct.Thickness ?? 0; + sheet.Cell(row, 4).Value = ct.KFactor ?? 0; + sheet.Cell(row, 5).Value = ct.DefaultBendRadius ?? 0; + sheet.Cell(row, 6).Value = ct.ContentHash ?? ""; row++; } sheet.Columns().AdjustToContents(); } + + private IXLWorksheet GetOrCreateSheet(XLWorkbook workbook, string name) + { + if (workbook.TryGetWorksheet(name, out var sheet)) + return sheet; + return workbook.Worksheets.Add(name); + } } } diff --git a/ExportDXF/Templates/BOM Template.xlsx b/ExportDXF/Templates/BOM Template.xlsx new file mode 100644 index 0000000..105d730 Binary files /dev/null and b/ExportDXF/Templates/BOM Template.xlsx differ