refactor: remove Excel export functionality

Removed BomExcelExporter service, BomExcelSettings class, BomTemplate.xlsx template, and EPPlus package dependency. This functionality is being replaced with direct API integration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-03 06:45:58 -05:00
parent 5cf7e1f1e5
commit 84f0196c97
4 changed files with 30 additions and 483 deletions

View File

@@ -103,6 +103,12 @@
<Compile Include="Extensions\TimeSpanExtensions.cs" />
<Compile Include="Extensions\UIExtensions.cs" />
<Compile Include="Extensions\UnitConversionExtensions.cs" />
<Compile Include="Forms\DrawingSelectionForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\DrawingSelectionForm.Designer.cs">
<DependentUpon>DrawingSelectionForm.cs</DependentUpon>
</Compile>
<Compile Include="Forms\MainForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -116,11 +122,11 @@
<Compile Include="Forms\ViewFlipDeciderComboboxItem.cs" />
<Compile Include="Models\DocumentType.cs" />
<Compile Include="Models\ExportContext.cs" />
<Compile Include="Models\BomItem.cs" />
<Compile Include="Models\Item.cs" />
<Compile Include="Models\LogEvent.cs" />
<Compile Include="Models\SolidWorksDocument.cs" />
<Compile Include="Services\BomExcelExporter.cs" />
<Compile Include="Services\BomExtractor.cs" />
<Compile Include="Services\BomExcelSettings.cs" />
<Compile Include="Services\DrawingExporter.cs" />
<Compile Include="Services\DxfExportService.cs" />
<Compile Include="Services\CutFabApiClient.cs" />
@@ -137,6 +143,9 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewFlipDeciders\PreferUpViewFlipDecider.cs" />
<Compile Include="ViewFlipDeciders\ViewFlipDeciderFactory.cs" />
<EmbeddedResource Include="Forms\DrawingSelectionForm.resx">
<DependentUpon>DrawingSelectionForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
@@ -163,9 +172,6 @@
<Content Include="Templates\Blank.drwdot">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Templates\BomTemplate.xlsx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="Resources\edit_alt.png" />
@@ -193,18 +199,31 @@
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<PackageReference Include="EPPlus">
<Version>4.5.3.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EtchBendLines\EtchBendLines\EtchBendLines.csproj">
<Project>{229c2fb9-6ad6-4a5d-b83a-d1146573d6f9}</Project>
<Name>EtchBendLines</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<COMReference Include="AcroPDFLib">
<Guid>{05BFD3F1-6319-4F30-B752-C7A22889BCC4}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="AxAcroPDFLib">
<Guid>{05BFD3F1-6319-4F30-B752-C7A22889BCC4}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>aximp</WrapperTool>
<Isolated>False</Isolated>
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -1,408 +0,0 @@
using ExportDXF.Utilities;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
namespace ExportDXF.Services
{
/// <summary>
/// Service for creating BOM Excel files.
/// </summary>
public interface IBomExcelExporter
{
/// <summary>
/// Creates an Excel file containing the Bill of Materials.
/// </summary>
/// <param name="filepath">The full path where the Excel file will be saved.</param>
/// <param name="items">The list of items to include in the BOM.</param>
void CreateBOMExcelFile(string filepath, IList<Item> items);
}
/// <summary>
/// Service for creating Excel files containing Bill of Materials data.
/// </summary>
public class BomExcelExporter : IBomExcelExporter
{
private const string DEFAULT_TEMPLATE_FILENAME = "BomTemplate.xlsx";
private const string DEFAULT_SHEET_NAME = "Parts";
private const int HEADER_ROW = 1;
private const int DATA_START_ROW = 2;
private const double COLUMN_PADDING = 2.0;
private const int MAX_COLUMN_WIDTH = 50;
private readonly string _templatePath;
private readonly BomExcelSettings _settings;
public BomExcelExporter() : this(GetDefaultTemplatePath(), new BomExcelSettings())
{
}
public BomExcelExporter(string templatePath) : this(templatePath, new BomExcelSettings())
{
}
public BomExcelExporter(string templatePath, BomExcelSettings settings)
{
if (string.IsNullOrWhiteSpace(templatePath))
throw new ArgumentException("Template path cannot be null or empty.", nameof(templatePath));
_templatePath = templatePath;
_settings = settings ?? new BomExcelSettings();
// Set EPPlus license context (required for newer versions)
//ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
}
/// <summary>
/// Creates an Excel file containing the Bill of Materials.
/// </summary>
public void CreateBOMExcelFile(string filepath, IList<Item> items)
{
if (string.IsNullOrWhiteSpace(filepath))
throw new ArgumentException("Filepath cannot be null or empty.", nameof(filepath));
if (items == null)
throw new ArgumentNullException(nameof(items));
ValidateAndPrepareFile(filepath);
using (var package = new ExcelPackage(new FileInfo(filepath)))
{
var worksheet = GetOrCreateWorksheet(package);
PopulateWorksheet(worksheet, items);
FormatWorksheet(worksheet);
package.Save();
}
}
#region Worksheet Management
private ExcelWorksheet GetOrCreateWorksheet(ExcelPackage package)
{
var worksheet = package.Workbook.Worksheets[DEFAULT_SHEET_NAME];
if (worksheet == null)
{
if (_settings.CreateWorksheetIfMissing)
{
worksheet = package.Workbook.Worksheets.Add(DEFAULT_SHEET_NAME);
CreateDefaultHeaders(worksheet);
}
else
{
var availableSheets = string.Join(", ",
package.Workbook.Worksheets.Select(ws => ws.Name));
throw new InvalidOperationException(
$"Worksheet '{DEFAULT_SHEET_NAME}' not found in template. " +
$"Available sheets: {availableSheets}");
}
}
return worksheet;
}
private void CreateDefaultHeaders(ExcelWorksheet worksheet)
{
var headers = new[]
{
"Item No", "File Name", "Qty", "Description", "Part Name",
"Configuration", "Thickness", "Material", "K-Factor", "Bend Radius"
};
for (int i = 0; i < headers.Length; i++)
{
var cell = worksheet.Cells[HEADER_ROW, i + 1];
cell.Value = headers[i];
if (_settings.FormatHeaders)
{
cell.Style.Font.Bold = true;
cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
cell.Style.Fill.BackgroundColor.SetColor(Color.LightGray);
}
}
}
#endregion
#region Data Population
private void PopulateWorksheet(ExcelWorksheet worksheet, IList<Item> items)
{
var filteredItems = _settings.SkipItemsWithoutFiles
? items.Where(i => !string.IsNullOrEmpty(i.FileName)).ToList()
: items.ToList();
for (int i = 0; i < filteredItems.Count; i++)
{
var item = filteredItems[i];
var row = DATA_START_ROW + i;
WriteItemToRow(worksheet, row, item);
}
// Add summary information if enabled
if (_settings.AddSummary && filteredItems.Count > 0)
{
AddSummarySection(worksheet, filteredItems, DATA_START_ROW + filteredItems.Count + 2);
}
}
private void WriteItemToRow(ExcelWorksheet worksheet, int row, Item item)
{
int col = 1;
// Item No
worksheet.Cells[row, col++].Value = FormatItemNumber(item.ItemNo);
// File Name
worksheet.Cells[row, col++].Value = item.FileName;
// Quantity
worksheet.Cells[row, col++].Value = item.Quantity;
// Description
worksheet.Cells[row, col++].Value = CleanDescription(item.Description);
// Part Name
worksheet.Cells[row, col++].Value = item.PartName;
// Configuration
worksheet.Cells[row, col++].Value = item.Configuration;
// Thickness (only if > 0)
worksheet.Cells[row, col++].Value = GetFormattedNumericValue(item.Thickness, _settings.ThicknessDecimalPlaces);
// Material
worksheet.Cells[row, col++].Value = item.Material;
// K-Factor (only if > 0)
worksheet.Cells[row, col++].Value = GetFormattedNumericValue(item.KFactor, _settings.KFactorDecimalPlaces);
// Bend Radius (only if > 0)
worksheet.Cells[row, col++].Value = GetFormattedNumericValue(item.BendRadius, _settings.BendRadiusDecimalPlaces);
// Apply row formatting
if (_settings.AlternateRowColors && row % 2 == 0)
{
var rowRange = worksheet.Cells[row, 1, row, col - 1];
rowRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
rowRange.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(240, 240, 240));
}
}
private void AddSummarySection(ExcelWorksheet worksheet, IList<Item> items, int startRow)
{
worksheet.Cells[startRow, 1].Value = "SUMMARY";
worksheet.Cells[startRow, 1].Style.Font.Bold = true;
worksheet.Cells[startRow, 1].Style.Font.Size = 12;
startRow += 2;
// Total items
worksheet.Cells[startRow, 1].Value = "Total Items:";
worksheet.Cells[startRow, 2].Value = items.Count;
// Total quantity
var totalQty = items.Sum(i => i.Quantity);
worksheet.Cells[startRow + 1, 1].Value = "Total Quantity:";
worksheet.Cells[startRow + 1, 2].Value = totalQty;
// Unique materials
var uniqueMaterials = items.Where(i => !string.IsNullOrEmpty(i.Material))
.Select(i => i.Material)
.Distinct()
.Count();
worksheet.Cells[startRow + 2, 1].Value = "Unique Materials:";
worksheet.Cells[startRow + 2, 2].Value = uniqueMaterials;
// Thickness range
var thicknesses = items.Where(i => i.Thickness > 0).Select(i => i.Thickness).ToList();
if (thicknesses.Any())
{
worksheet.Cells[startRow + 3, 1].Value = "Thickness Range:";
worksheet.Cells[startRow + 3, 2].Value = $"{thicknesses.Min():F1} - {thicknesses.Max():F1} mm";
}
}
#endregion
#region Data Formatting
private string FormatItemNumber(string itemNo)
{
if (string.IsNullOrWhiteSpace(itemNo))
return string.Empty;
// Try to parse as number and pad with zeros if it's a simple number
if (int.TryParse(itemNo, out int number))
{
return number.ToString().PadLeft(_settings.ItemNumberPadding, '0');
}
return itemNo;
}
private string CleanDescription(string description)
{
if (string.IsNullOrWhiteSpace(description))
return string.Empty;
// Remove any remaining XML tags that might have been missed
description = TextHelper.RemoveXmlTags(description);
// Trim and normalize whitespace
return System.Text.RegularExpressions.Regex.Replace(description.Trim(), @"\s+", " ");
}
private object GetFormattedNumericValue(double value, int decimalPlaces)
{
if (value <= 0)
return null;
return Math.Round(value, decimalPlaces);
}
#endregion
#region Worksheet Formatting
private void FormatWorksheet(ExcelWorksheet worksheet)
{
if (worksheet.Dimension == null)
return;
// Auto-fit columns with limits
for (int col = 1; col <= worksheet.Dimension.Columns; col++)
{
worksheet.Column(col).AutoFit();
// Special handling for Description column (assuming it's column 4)
if (col == 4) // Description column
{
worksheet.Column(col).Width = Math.Max(worksheet.Column(col).Width, 30); // Minimum 30 units
if (worksheet.Column(col).Width > 50) // Maximum 50 units
worksheet.Column(col).Width = 50;
}
else if (worksheet.Column(col).Width > MAX_COLUMN_WIDTH)
{
worksheet.Column(col).Width = MAX_COLUMN_WIDTH;
}
else
{
worksheet.Column(col).Width += COLUMN_PADDING;
}
}
// Add borders if enabled
if (_settings.AddBorders)
{
var dataRange = worksheet.Cells[HEADER_ROW, 1, worksheet.Dimension.End.Row, worksheet.Dimension.End.Column];
dataRange.Style.Border.Top.Style = ExcelBorderStyle.Thin;
dataRange.Style.Border.Left.Style = ExcelBorderStyle.Thin;
dataRange.Style.Border.Right.Style = ExcelBorderStyle.Thin;
dataRange.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
}
// Format numeric columns
FormatNumericColumns(worksheet);
// Freeze header row if enabled
if (_settings.FreezeHeaderRow)
{
worksheet.View.FreezePanes(DATA_START_ROW, 1);
}
}
private void FormatNumericColumns(ExcelWorksheet worksheet)
{
if (worksheet.Dimension == null)
return;
var lastRow = worksheet.Dimension.End.Row;
// Format quantity column (assuming it's column 3)
if (worksheet.Dimension.Columns >= 3)
{
var qtyRange = worksheet.Cells[DATA_START_ROW, 3, lastRow, 3];
qtyRange.Style.Numberformat.Format = "0";
qtyRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
}
// Format thickness column (assuming it's column 7)
if (worksheet.Dimension.Columns >= 7)
{
var thicknessRange = worksheet.Cells[DATA_START_ROW, 7, lastRow, 7];
thicknessRange.Style.Numberformat.Format = $"0.{new string('0', _settings.ThicknessDecimalPlaces)}";
thicknessRange.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;
}
}
#endregion
#region File Management
private void ValidateAndPrepareFile(string filepath)
{
var directory = Path.GetDirectoryName(filepath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (UseTemplate())
{
CopyTemplateToDestination(filepath);
}
else if (File.Exists(filepath))
{
File.Delete(filepath); // Remove existing file to start fresh
}
}
private bool UseTemplate()
{
return !string.IsNullOrEmpty(_templatePath) && File.Exists(_templatePath);
}
private void CopyTemplateToDestination(string filepath)
{
if (!File.Exists(_templatePath))
{
throw new FileNotFoundException(
$"BOM template file not found at: {_templatePath}. " +
"Either provide a valid template or enable CreateWorksheetIfMissing.",
_templatePath);
}
try
{
File.Copy(_templatePath, filepath, overwrite: true);
}
catch (Exception ex)
{
throw new IOException($"Failed to copy template to {filepath}: {ex.Message}", ex);
}
}
private static string GetDefaultTemplatePath()
{
return Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Templates",
DEFAULT_TEMPLATE_FILENAME);
}
#endregion
}
}

View File

@@ -1,64 +0,0 @@
namespace ExportDXF.Services
{
/// <summary>
/// Configuration settings for BOM Excel export.
/// </summary>
public class BomExcelSettings
{
/// <summary>
/// Create the worksheet if it doesn't exist in the template.
/// </summary>
public bool CreateWorksheetIfMissing { get; set; } = true;
/// <summary>
/// Skip items that don't have an associated DXF file.
/// </summary>
public bool SkipItemsWithoutFiles { get; set; } = false;
/// <summary>
/// Add summary section with totals and statistics.
/// </summary>
public bool AddSummary { get; set; } = false;
/// <summary>
/// Format header row with bold text and background color.
/// </summary>
public bool FormatHeaders { get; set; } = false;
/// <summary>
/// Add borders around all cells.
/// </summary>
public bool AddBorders { get; set; } = false;
/// <summary>
/// Freeze the header row for easier scrolling.
/// </summary>
public bool FreezeHeaderRow { get; set; } = true;
/// <summary>
/// Alternate row background colors for easier reading.
/// </summary>
public bool AlternateRowColors { get; set; } = true;
/// <summary>
/// Number of decimal places for thickness values.
/// </summary>
public int ThicknessDecimalPlaces { get; set; } = 4;
/// <summary>
/// Number of decimal places for K-Factor values.
/// </summary>
public int KFactorDecimalPlaces { get; set; } = 3;
/// <summary>
/// Number of decimal places for bend radius values.
/// </summary>
public int BendRadiusDecimalPlaces { get; set; } = 3;
/// <summary>
/// Minimum number of digits for item numbers (pad with zeros).
/// </summary>
public int ItemNumberPadding { get; set; } = 2;
}
}

Binary file not shown.