refactor: extract CutTemplate from BomItem for all-item BOM tracking
BomItems are now created for every BOM item regardless of whether they produce a DXF. Sheet metal cut data (thickness, k-factor, bend radius, DXF path, content hash) moved to a new CutTemplate entity with a 1:1 optional relationship. Non-sheet-metal items are counted as "skipped" instead of "failed" in the export summary. Added Cut Templates tab to the UI with a DataGridView for viewing cut template records. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ namespace ExportDXF.Data
|
||||
{
|
||||
public DbSet<ExportRecord> ExportRecords { get; set; }
|
||||
public DbSet<BomItem> BomItems { get; set; }
|
||||
public DbSet<CutTemplate> CutTemplates { get; set; }
|
||||
|
||||
public ExportDxfDbContext() : base()
|
||||
{
|
||||
@@ -38,6 +39,7 @@ namespace ExportDXF.Data
|
||||
entity.Property(e => e.SourceFilePath).HasMaxLength(500);
|
||||
entity.Property(e => e.OutputFolder).HasMaxLength(500);
|
||||
entity.Property(e => e.ExportedBy).HasMaxLength(100);
|
||||
entity.Property(e => e.PdfContentHash).HasMaxLength(64);
|
||||
|
||||
entity.HasMany(e => e.BomItems)
|
||||
.WithOne(b => b.ExportRecord)
|
||||
@@ -54,7 +56,18 @@ namespace ExportDXF.Data
|
||||
entity.Property(e => e.PartName).HasMaxLength(200);
|
||||
entity.Property(e => e.ConfigurationName).HasMaxLength(100);
|
||||
entity.Property(e => e.Material).HasMaxLength(100);
|
||||
|
||||
entity.HasOne(e => e.CutTemplate)
|
||||
.WithOne(ct => ct.BomItem)
|
||||
.HasForeignKey<CutTemplate>(ct => ct.BomItemId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<CutTemplate>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.Property(e => e.CutTemplateName).HasMaxLength(100);
|
||||
entity.Property(e => e.ContentHash).HasMaxLength(64);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
56
ExportDXF/Forms/MainForm.Designer.cs
generated
56
ExportDXF/Forms/MainForm.Designer.cs
generated
@@ -36,6 +36,8 @@ namespace ExportDXF.Forms
|
||||
logEventsDataGrid = new System.Windows.Forms.DataGridView();
|
||||
bomTab = new System.Windows.Forms.TabPage();
|
||||
bomDataGrid = new System.Windows.Forms.DataGridView();
|
||||
cutTemplatesTab = new System.Windows.Forms.TabPage();
|
||||
cutTemplatesDataGrid = new System.Windows.Forms.DataGridView();
|
||||
equipmentBox = new System.Windows.Forms.ComboBox();
|
||||
label1 = new System.Windows.Forms.Label();
|
||||
label2 = new System.Windows.Forms.Label();
|
||||
@@ -45,12 +47,14 @@ namespace ExportDXF.Forms
|
||||
((System.ComponentModel.ISupportInitialize)logEventsDataGrid).BeginInit();
|
||||
bomTab.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)bomDataGrid).BeginInit();
|
||||
cutTemplatesTab.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)cutTemplatesDataGrid).BeginInit();
|
||||
SuspendLayout();
|
||||
//
|
||||
// runButton
|
||||
//
|
||||
runButton.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right;
|
||||
runButton.Location = new System.Drawing.Point(656, 13);
|
||||
runButton.Location = new System.Drawing.Point(514, 13);
|
||||
runButton.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
runButton.Name = "runButton";
|
||||
runButton.Size = new System.Drawing.Size(100, 30);
|
||||
@@ -74,7 +78,7 @@ namespace ExportDXF.Forms
|
||||
viewFlipDeciderBox.FormattingEnabled = true;
|
||||
viewFlipDeciderBox.Location = new System.Drawing.Point(137, 43);
|
||||
viewFlipDeciderBox.Name = "viewFlipDeciderBox";
|
||||
viewFlipDeciderBox.Size = new System.Drawing.Size(502, 25);
|
||||
viewFlipDeciderBox.Size = new System.Drawing.Size(365, 25);
|
||||
viewFlipDeciderBox.TabIndex = 3;
|
||||
//
|
||||
// mainTabControl
|
||||
@@ -82,11 +86,12 @@ namespace ExportDXF.Forms
|
||||
mainTabControl.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
mainTabControl.Controls.Add(logEventsTab);
|
||||
mainTabControl.Controls.Add(bomTab);
|
||||
mainTabControl.Controls.Add(cutTemplatesTab);
|
||||
mainTabControl.Location = new System.Drawing.Point(15, 74);
|
||||
mainTabControl.Name = "mainTabControl";
|
||||
mainTabControl.Padding = new System.Drawing.Point(20, 5);
|
||||
mainTabControl.SelectedIndex = 0;
|
||||
mainTabControl.Size = new System.Drawing.Size(741, 586);
|
||||
mainTabControl.Size = new System.Drawing.Size(599, 330);
|
||||
mainTabControl.TabIndex = 12;
|
||||
//
|
||||
// logEventsTab
|
||||
@@ -95,7 +100,7 @@ namespace ExportDXF.Forms
|
||||
logEventsTab.Location = new System.Drawing.Point(4, 30);
|
||||
logEventsTab.Name = "logEventsTab";
|
||||
logEventsTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
logEventsTab.Size = new System.Drawing.Size(733, 552);
|
||||
logEventsTab.Size = new System.Drawing.Size(591, 296);
|
||||
logEventsTab.TabIndex = 0;
|
||||
logEventsTab.Text = "Log Events";
|
||||
logEventsTab.UseVisualStyleBackColor = true;
|
||||
@@ -107,7 +112,7 @@ namespace ExportDXF.Forms
|
||||
logEventsDataGrid.GridColor = System.Drawing.Color.WhiteSmoke;
|
||||
logEventsDataGrid.Location = new System.Drawing.Point(6, 6);
|
||||
logEventsDataGrid.Name = "logEventsDataGrid";
|
||||
logEventsDataGrid.Size = new System.Drawing.Size(721, 540);
|
||||
logEventsDataGrid.Size = new System.Drawing.Size(579, 282);
|
||||
logEventsDataGrid.TabIndex = 0;
|
||||
//
|
||||
// bomTab
|
||||
@@ -116,7 +121,7 @@ namespace ExportDXF.Forms
|
||||
bomTab.Location = new System.Drawing.Point(4, 30);
|
||||
bomTab.Name = "bomTab";
|
||||
bomTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
bomTab.Size = new System.Drawing.Size(733, 552);
|
||||
bomTab.Size = new System.Drawing.Size(982, 549);
|
||||
bomTab.TabIndex = 1;
|
||||
bomTab.Text = "Bill Of Materials";
|
||||
bomTab.UseVisualStyleBackColor = true;
|
||||
@@ -128,9 +133,30 @@ namespace ExportDXF.Forms
|
||||
bomDataGrid.GridColor = System.Drawing.Color.WhiteSmoke;
|
||||
bomDataGrid.Location = new System.Drawing.Point(6, 6);
|
||||
bomDataGrid.Name = "bomDataGrid";
|
||||
bomDataGrid.Size = new System.Drawing.Size(721, 540);
|
||||
bomDataGrid.Size = new System.Drawing.Size(970, 535);
|
||||
bomDataGrid.TabIndex = 1;
|
||||
//
|
||||
//
|
||||
// cutTemplatesTab
|
||||
//
|
||||
cutTemplatesTab.Controls.Add(cutTemplatesDataGrid);
|
||||
cutTemplatesTab.Location = new System.Drawing.Point(4, 30);
|
||||
cutTemplatesTab.Name = "cutTemplatesTab";
|
||||
cutTemplatesTab.Padding = new System.Windows.Forms.Padding(3);
|
||||
cutTemplatesTab.Size = new System.Drawing.Size(982, 549);
|
||||
cutTemplatesTab.TabIndex = 2;
|
||||
cutTemplatesTab.Text = "Cut Templates";
|
||||
cutTemplatesTab.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// cutTemplatesDataGrid
|
||||
//
|
||||
cutTemplatesDataGrid.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
cutTemplatesDataGrid.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||
cutTemplatesDataGrid.GridColor = System.Drawing.Color.WhiteSmoke;
|
||||
cutTemplatesDataGrid.Location = new System.Drawing.Point(6, 6);
|
||||
cutTemplatesDataGrid.Name = "cutTemplatesDataGrid";
|
||||
cutTemplatesDataGrid.Size = new System.Drawing.Size(970, 535);
|
||||
cutTemplatesDataGrid.TabIndex = 2;
|
||||
//
|
||||
// equipmentBox
|
||||
//
|
||||
equipmentBox.FormattingEnabled = true;
|
||||
@@ -151,7 +177,7 @@ namespace ExportDXF.Forms
|
||||
// label2
|
||||
//
|
||||
label2.AutoSize = true;
|
||||
label2.Location = new System.Drawing.Point(354, 15);
|
||||
label2.Location = new System.Drawing.Point(321, 15);
|
||||
label2.Name = "label2";
|
||||
label2.Size = new System.Drawing.Size(56, 17);
|
||||
label2.TabIndex = 2;
|
||||
@@ -160,15 +186,15 @@ namespace ExportDXF.Forms
|
||||
// drawingNoBox
|
||||
//
|
||||
drawingNoBox.FormattingEnabled = true;
|
||||
drawingNoBox.Location = new System.Drawing.Point(416, 12);
|
||||
drawingNoBox.Location = new System.Drawing.Point(383, 12);
|
||||
drawingNoBox.Name = "drawingNoBox";
|
||||
drawingNoBox.Size = new System.Drawing.Size(223, 25);
|
||||
drawingNoBox.Size = new System.Drawing.Size(119, 25);
|
||||
drawingNoBox.TabIndex = 13;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
|
||||
ClientSize = new System.Drawing.Size(768, 672);
|
||||
ClientSize = new System.Drawing.Size(626, 416);
|
||||
Controls.Add(drawingNoBox);
|
||||
Controls.Add(equipmentBox);
|
||||
Controls.Add(mainTabControl);
|
||||
@@ -180,7 +206,7 @@ namespace ExportDXF.Forms
|
||||
Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0);
|
||||
Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||
MaximizeBox = false;
|
||||
MinimumSize = new System.Drawing.Size(643, 355);
|
||||
MinimumSize = new System.Drawing.Size(642, 455);
|
||||
Name = "MainForm";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
Text = "ExportDXF";
|
||||
@@ -189,6 +215,8 @@ namespace ExportDXF.Forms
|
||||
((System.ComponentModel.ISupportInitialize)logEventsDataGrid).EndInit();
|
||||
bomTab.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)bomDataGrid).EndInit();
|
||||
cutTemplatesTab.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)cutTemplatesDataGrid).EndInit();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
@@ -203,6 +231,8 @@ namespace ExportDXF.Forms
|
||||
private System.Windows.Forms.TabPage bomTab;
|
||||
private System.Windows.Forms.DataGridView logEventsDataGrid;
|
||||
private System.Windows.Forms.DataGridView bomDataGrid;
|
||||
private System.Windows.Forms.TabPage cutTemplatesTab;
|
||||
private System.Windows.Forms.DataGridView cutTemplatesDataGrid;
|
||||
private System.Windows.Forms.ComboBox equipmentBox;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.Label label2;
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace ExportDXF.Forms
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
private readonly BindingList<LogEvent> _logEvents;
|
||||
private readonly BindingList<BomItem> _bomItems;
|
||||
private readonly BindingList<CutTemplate> _cutTemplates;
|
||||
private List<DrawingInfo> _allDrawings;
|
||||
|
||||
public MainForm(ISolidWorksService solidWorksService, IDxfExportService exportService, IFileExportService fileExportService, Func<ExportDxfDbContext> dbContextFactory = null)
|
||||
@@ -38,10 +39,12 @@ namespace ExportDXF.Forms
|
||||
_dbContextFactory = dbContextFactory ?? (() => new ExportDxfDbContext());
|
||||
_logEvents = new BindingList<LogEvent>();
|
||||
_bomItems = new BindingList<BomItem>();
|
||||
_cutTemplates = new BindingList<CutTemplate>();
|
||||
_allDrawings = new List<DrawingInfo>();
|
||||
InitializeViewFlipDeciders();
|
||||
InitializeLogEventsGrid();
|
||||
InitializeBomGrid();
|
||||
InitializeCutTemplatesGrid();
|
||||
InitializeDrawingDropdowns();
|
||||
}
|
||||
|
||||
@@ -215,6 +218,61 @@ namespace ExportDXF.Forms
|
||||
bomDataGrid.DataSource = _bomItems;
|
||||
}
|
||||
|
||||
private void InitializeCutTemplatesGrid()
|
||||
{
|
||||
cutTemplatesDataGrid.Columns.Clear();
|
||||
|
||||
cutTemplatesDataGrid.AutoGenerateColumns = false;
|
||||
cutTemplatesDataGrid.AllowUserToAddRows = false;
|
||||
cutTemplatesDataGrid.AllowUserToDeleteRows = false;
|
||||
cutTemplatesDataGrid.ReadOnly = true;
|
||||
cutTemplatesDataGrid.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutTemplate.CutTemplateName),
|
||||
HeaderText = "Template Name",
|
||||
Width = 150
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutTemplate.DxfFilePath),
|
||||
HeaderText = "DXF File",
|
||||
Width = 250
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutTemplate.Thickness),
|
||||
HeaderText = "Thickness",
|
||||
Width = 80
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutTemplate.KFactor),
|
||||
HeaderText = "K-Factor",
|
||||
Width = 80
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutTemplate.DefaultBendRadius),
|
||||
HeaderText = "Bend Radius",
|
||||
Width = 90
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
DataPropertyName = nameof(CutTemplate.ContentHash),
|
||||
HeaderText = "Content Hash",
|
||||
Width = 150
|
||||
});
|
||||
|
||||
cutTemplatesDataGrid.DataSource = _cutTemplates;
|
||||
}
|
||||
|
||||
private void InitializeDrawingDropdowns()
|
||||
{
|
||||
try
|
||||
@@ -319,9 +377,12 @@ namespace ExportDXF.Forms
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse drawing number from active document title
|
||||
var drawingInfo = DrawingInfo.Parse(activeDoc.Title);
|
||||
var filePrefix = drawingInfo != null ? $"{drawingInfo.EquipmentNo} {drawingInfo.DrawingNo}" : activeDoc.Title;
|
||||
// Use equipment/drawing values from the UI dropdowns
|
||||
var equipment = equipmentBox.Text?.Trim();
|
||||
var drawingNo = drawingNoBox.Text?.Trim();
|
||||
var filePrefix = !string.IsNullOrEmpty(equipment) && !string.IsNullOrEmpty(drawingNo)
|
||||
? $"{equipment} {drawingNo}"
|
||||
: activeDoc.Title;
|
||||
|
||||
var viewFlipDecider = GetSelectedViewFlipDecider();
|
||||
var exportContext = new ExportContext
|
||||
@@ -335,8 +396,9 @@ namespace ExportDXF.Forms
|
||||
BomItemCallback = AddBomItem
|
||||
};
|
||||
|
||||
// Clear previous BOM items
|
||||
// Clear previous BOM items and cut templates
|
||||
_bomItems.Clear();
|
||||
_cutTemplates.Clear();
|
||||
|
||||
LogMessage($"Started at {DateTime.Now:t}");
|
||||
LogMessage($"Exporting to: {_fileExportService.OutputFolder}");
|
||||
@@ -405,6 +467,22 @@ namespace ExportDXF.Forms
|
||||
var activeDoc = _solidWorksService.GetActiveDocument();
|
||||
var docTitle = activeDoc?.Title ?? "No Document Open";
|
||||
this.Text = $"ExportDXF - {docTitle}";
|
||||
|
||||
// Parse the file name and fill Equipment/Drawing dropdowns
|
||||
if (activeDoc != null)
|
||||
{
|
||||
var drawingInfo = DrawingInfo.Parse(activeDoc.Title);
|
||||
if (drawingInfo != null)
|
||||
{
|
||||
if (!equipmentBox.Items.Contains(drawingInfo.EquipmentNo))
|
||||
equipmentBox.Items.Add(drawingInfo.EquipmentNo);
|
||||
equipmentBox.Text = drawingInfo.EquipmentNo;
|
||||
|
||||
if (!drawingNoBox.Items.Contains(drawingInfo.DrawingNo))
|
||||
drawingNoBox.Items.Add(drawingInfo.DrawingNo);
|
||||
drawingNoBox.Text = drawingInfo.DrawingNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LogMessage(string message, LogLevel level = LogLevel.Info, string file = null)
|
||||
@@ -451,6 +529,11 @@ namespace ExportDXF.Forms
|
||||
return;
|
||||
}
|
||||
_bomItems.Add(item);
|
||||
|
||||
if (item.CutTemplate != null)
|
||||
{
|
||||
_cutTemplates.Add(item.CutTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogEventsDataGrid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
|
||||
|
||||
188
ExportDXF/Migrations/20260214195856_ExtractCutTemplate.Designer.cs
generated
Normal file
188
ExportDXF/Migrations/20260214195856_ExtractCutTemplate.Designer.cs
generated
Normal file
@@ -0,0 +1,188 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using ExportDXF.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ExportDXF.Migrations
|
||||
{
|
||||
[DbContext(typeof(ExportDxfDbContext))]
|
||||
[Migration("20260214195856_ExtractCutTemplate")]
|
||||
partial class ExtractCutTemplate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.11")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.BomItem", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string>("ConfigurationName")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("ExportRecordId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ItemNo")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Material")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("PartName")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("PartNo")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int?>("Qty")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("TotalQty")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("ExportRecordId");
|
||||
|
||||
b.ToTable("BomItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.CutTemplate", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BomItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ContentHash")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("CutTemplateName")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<double?>("DefaultBendRadius")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<string>("DxfFilePath")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<double?>("KFactor")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<double?>("Thickness")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BomItemId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CutTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.ExportRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DrawingNumber")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime>("ExportedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ExportedBy")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("OutputFolder")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("PdfContentHash")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("SourceFilePath")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ExportRecords");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.BomItem", b =>
|
||||
{
|
||||
b.HasOne("ExportDXF.Models.ExportRecord", "ExportRecord")
|
||||
.WithMany("BomItems")
|
||||
.HasForeignKey("ExportRecordId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ExportRecord");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.CutTemplate", b =>
|
||||
{
|
||||
b.HasOne("ExportDXF.Models.BomItem", "BomItem")
|
||||
.WithOne("CutTemplate")
|
||||
.HasForeignKey("ExportDXF.Models.CutTemplate", "BomItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("BomItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.BomItem", b =>
|
||||
{
|
||||
b.Navigation("CutTemplate");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.ExportRecord", b =>
|
||||
{
|
||||
b.Navigation("BomItems");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
114
ExportDXF/Migrations/20260214195856_ExtractCutTemplate.cs
Normal file
114
ExportDXF/Migrations/20260214195856_ExtractCutTemplate.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ExportDXF.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ExtractCutTemplate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ContentHash",
|
||||
table: "BomItems");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CutTemplateName",
|
||||
table: "BomItems");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DefaultBendRadius",
|
||||
table: "BomItems");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DxfFilePath",
|
||||
table: "BomItems");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "KFactor",
|
||||
table: "BomItems");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Thickness",
|
||||
table: "BomItems");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CutTemplates",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
DxfFilePath = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ContentHash = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
||||
CutTemplateName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: true),
|
||||
Thickness = table.Column<double>(type: "float", nullable: true),
|
||||
KFactor = table.Column<double>(type: "float", nullable: true),
|
||||
DefaultBendRadius = table.Column<double>(type: "float", nullable: true),
|
||||
BomItemId = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CutTemplates", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CutTemplates_BomItems_BomItemId",
|
||||
column: x => x.BomItemId,
|
||||
principalTable: "BomItems",
|
||||
principalColumn: "ID",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CutTemplates_BomItemId",
|
||||
table: "CutTemplates",
|
||||
column: "BomItemId",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CutTemplates");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ContentHash",
|
||||
table: "BomItems",
|
||||
type: "nvarchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "CutTemplateName",
|
||||
table: "BomItems",
|
||||
type: "nvarchar(100)",
|
||||
maxLength: 100,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "DefaultBendRadius",
|
||||
table: "BomItems",
|
||||
type: "float",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "DxfFilePath",
|
||||
table: "BomItems",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "KFactor",
|
||||
table: "BomItems",
|
||||
type: "float",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "Thickness",
|
||||
table: "BomItems",
|
||||
type: "float",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
185
ExportDXF/Migrations/ExportDxfDbContextModelSnapshot.cs
Normal file
185
ExportDXF/Migrations/ExportDxfDbContextModelSnapshot.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using ExportDXF.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ExportDXF.Migrations
|
||||
{
|
||||
[DbContext(typeof(ExportDxfDbContext))]
|
||||
partial class ExportDxfDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.11")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.BomItem", b =>
|
||||
{
|
||||
b.Property<int>("ID")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
|
||||
|
||||
b.Property<string>("ConfigurationName")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("ExportRecordId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ItemNo")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Material")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("PartName")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<string>("PartNo")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int?>("Qty")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("TotalQty")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("ID");
|
||||
|
||||
b.HasIndex("ExportRecordId");
|
||||
|
||||
b.ToTable("BomItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.CutTemplate", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BomItemId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ContentHash")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("CutTemplateName")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<double?>("DefaultBendRadius")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<string>("DxfFilePath")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<double?>("KFactor")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<double?>("Thickness")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("BomItemId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("CutTemplates");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.ExportRecord", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("DrawingNumber")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime>("ExportedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ExportedBy")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("OutputFolder")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<string>("PdfContentHash")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("SourceFilePath")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ExportRecords");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.BomItem", b =>
|
||||
{
|
||||
b.HasOne("ExportDXF.Models.ExportRecord", "ExportRecord")
|
||||
.WithMany("BomItems")
|
||||
.HasForeignKey("ExportRecordId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ExportRecord");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.CutTemplate", b =>
|
||||
{
|
||||
b.HasOne("ExportDXF.Models.BomItem", "BomItem")
|
||||
.WithOne("CutTemplate")
|
||||
.HasForeignKey("ExportDXF.Models.CutTemplate", "BomItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("BomItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.BomItem", b =>
|
||||
{
|
||||
b.Navigation("CutTemplate");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ExportDXF.Models.ExportRecord", b =>
|
||||
{
|
||||
b.Navigation("BomItems");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace ExportDXF.Models
|
||||
{
|
||||
public class BomItem
|
||||
@@ -14,29 +12,13 @@ namespace ExportDXF.Models
|
||||
public string PartName { get; set; } = "";
|
||||
public string ConfigurationName { get; set; } = "";
|
||||
public string Material { get; set; } = "";
|
||||
public string CutTemplateName { get; set; } = "";
|
||||
public string DxfFilePath { get; set; } = "";
|
||||
|
||||
// Sheet metal properties
|
||||
private double? _thickness;
|
||||
public double? Thickness
|
||||
{
|
||||
get => _thickness;
|
||||
set => _thickness = value.HasValue ? Math.Round(value.Value, 8) : null;
|
||||
}
|
||||
|
||||
public double? KFactor { get; set; }
|
||||
|
||||
private double? _defaultBendRadius;
|
||||
public double? DefaultBendRadius
|
||||
{
|
||||
get => _defaultBendRadius;
|
||||
set => _defaultBendRadius = value.HasValue ? Math.Round(value.Value, 8) : null;
|
||||
}
|
||||
|
||||
// EF Core relationship to ExportRecord
|
||||
public int ExportRecordId { get; set; }
|
||||
public virtual ExportRecord ExportRecord { get; set; }
|
||||
|
||||
// Optional 1:1 relationship to CutTemplate (only for sheet metal parts)
|
||||
public virtual CutTemplate CutTemplate { get; set; }
|
||||
}
|
||||
|
||||
public struct Size
|
||||
|
||||
33
ExportDXF/Models/CutTemplate.cs
Normal file
33
ExportDXF/Models/CutTemplate.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace ExportDXF.Models
|
||||
{
|
||||
public class CutTemplate
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string DxfFilePath { get; set; } = "";
|
||||
public string ContentHash { get; set; }
|
||||
public string CutTemplateName { get; set; } = "";
|
||||
|
||||
// Sheet metal properties (moved from BomItem)
|
||||
private double? _thickness;
|
||||
public double? Thickness
|
||||
{
|
||||
get => _thickness;
|
||||
set => _thickness = value.HasValue ? Math.Round(value.Value, 8) : null;
|
||||
}
|
||||
|
||||
public double? KFactor { get; set; }
|
||||
|
||||
private double? _defaultBendRadius;
|
||||
public double? DefaultBendRadius
|
||||
{
|
||||
get => _defaultBendRadius;
|
||||
set => _defaultBendRadius = value.HasValue ? Math.Round(value.Value, 8) : null;
|
||||
}
|
||||
|
||||
// FK back to BomItem
|
||||
public int BomItemId { get; set; }
|
||||
public virtual BomItem BomItem { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,14 @@ using ExportDXF.Data;
|
||||
using ExportDXF.Extensions;
|
||||
using ExportDXF.ItemExtractors;
|
||||
using ExportDXF.Models;
|
||||
using ExportDXF.Utilities;
|
||||
using ExportDXF;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SolidWorks.Interop.sldworks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace ExportDXF.Services
|
||||
{
|
||||
@@ -161,18 +164,29 @@ namespace ExportDXF.Services
|
||||
// Determine drawing number for file naming
|
||||
var drawingNumber = ParseDrawingNumber(context);
|
||||
|
||||
// Resolve output folder: /{outputDir}/{equipmentNo}/{drawingNo}/ or flat fallback
|
||||
var drawingOutputFolder = _fileExportService.GetDrawingOutputFolder(drawingNumber);
|
||||
|
||||
// Export drawing to PDF
|
||||
var tempDir = CreateTempWorkDir();
|
||||
_drawingExporter.ExportToPdf(drawing, tempDir, context);
|
||||
|
||||
// Copy PDF to output folder
|
||||
// Copy PDF to output folder with versioning
|
||||
string pdfStashPath = null;
|
||||
string savedPdfPath = null;
|
||||
try
|
||||
{
|
||||
var pdfs = Directory.GetFiles(tempDir, "*.pdf");
|
||||
if (pdfs.Length > 0)
|
||||
{
|
||||
var savedPath = _fileExportService.SavePdfFile(pdfs[0], drawingNumber);
|
||||
LogProgress(context, $"Saved PDF: {Path.GetFileName(savedPath)}", LogLevel.Info);
|
||||
// Determine the destination path to stash the existing file
|
||||
var pdfFileName = !string.IsNullOrEmpty(drawingNumber)
|
||||
? $"{drawingNumber}.pdf"
|
||||
: Path.GetFileName(pdfs[0]);
|
||||
var pdfDestPath = Path.Combine(drawingOutputFolder, pdfFileName);
|
||||
|
||||
pdfStashPath = _fileExportService.StashFile(pdfDestPath);
|
||||
savedPdfPath = _fileExportService.SavePdfFile(pdfs[0], drawingNumber, drawingOutputFolder);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -186,15 +200,40 @@ namespace ExportDXF.Services
|
||||
{
|
||||
using (var db = _dbContextFactory())
|
||||
{
|
||||
db.Database.EnsureCreated();
|
||||
db.Database.Migrate();
|
||||
exportRecord = new ExportRecord
|
||||
{
|
||||
DrawingNumber = drawingNumber ?? context.ActiveDocument.Title,
|
||||
SourceFilePath = context.ActiveDocument.FilePath,
|
||||
OutputFolder = _fileExportService.OutputFolder,
|
||||
OutputFolder = drawingOutputFolder,
|
||||
ExportedAt = DateTime.Now,
|
||||
ExportedBy = System.Environment.UserName
|
||||
};
|
||||
|
||||
// Handle PDF versioning - compute hash and compare with previous
|
||||
if (savedPdfPath != null)
|
||||
{
|
||||
HandlePdfVersioning(savedPdfPath, exportRecord.DrawingNumber, exportRecord, context);
|
||||
|
||||
// Archive or discard old PDF based on hash comparison
|
||||
if (pdfStashPath != null)
|
||||
{
|
||||
var previousRecord = db.ExportRecords
|
||||
.Where(r => r.DrawingNumber == exportRecord.DrawingNumber && r.PdfContentHash != null)
|
||||
.OrderByDescending(r => r.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (previousRecord != null && previousRecord.PdfContentHash == exportRecord.PdfContentHash)
|
||||
{
|
||||
_fileExportService.DiscardStash(pdfStashPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileExportService.ArchiveFile(pdfStashPath, savedPdfPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.ExportRecords.Add(exportRecord);
|
||||
db.SaveChanges();
|
||||
LogProgress(context, $"Created export record (ID: {exportRecord.Id})", LogLevel.Info);
|
||||
@@ -202,11 +241,13 @@ namespace ExportDXF.Services
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Clean up stash on error
|
||||
_fileExportService.DiscardStash(pdfStashPath);
|
||||
LogProgress(context, $"Database error creating export record: {ex.Message}", LogLevel.Error);
|
||||
}
|
||||
|
||||
// Export parts to DXF (directly to output folder) and save BOM items
|
||||
ExportItems(items, _fileExportService.OutputFolder, context, exportRecord?.Id);
|
||||
// Export parts to DXF and save BOM items
|
||||
ExportItems(items, drawingOutputFolder, context, exportRecord?.Id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -268,6 +309,7 @@ namespace ExportDXF.Services
|
||||
private void ExportItems(List<Item> items, string saveDirectory, ExportContext context, int? exportRecordId = null)
|
||||
{
|
||||
int successCount = 0;
|
||||
int skippedCount = 0;
|
||||
int failureCount = 0;
|
||||
int sortOrder = 0;
|
||||
|
||||
@@ -284,54 +326,62 @@ namespace ExportDXF.Services
|
||||
// PartExporter will handle template drawing creation through context
|
||||
_partExporter.ExportItem(item, saveDirectory, context);
|
||||
|
||||
// Always create BomItem for every item (sheet metal or not)
|
||||
var bomItem = new BomItem
|
||||
{
|
||||
ExportRecordId = exportRecordId ?? 0,
|
||||
ItemNo = item.ItemNo ?? "",
|
||||
PartNo = item.FileName ?? item.PartName ?? "",
|
||||
SortOrder = sortOrder++,
|
||||
Qty = item.Quantity,
|
||||
TotalQty = item.Quantity,
|
||||
Description = item.Description ?? "",
|
||||
PartName = item.PartName ?? "",
|
||||
ConfigurationName = item.Configuration ?? "",
|
||||
Material = item.Material ?? ""
|
||||
};
|
||||
|
||||
// Only create CutTemplate if DXF was exported successfully
|
||||
if (!string.IsNullOrEmpty(item.FileName))
|
||||
{
|
||||
successCount++;
|
||||
LogProgress(context, $"Exported: {item.FileName}.dxf", LogLevel.Info);
|
||||
|
||||
// Create BOM item
|
||||
var dxfPath = Path.Combine(saveDirectory, item.FileName + ".dxf");
|
||||
var bomItem = new BomItem
|
||||
bomItem.CutTemplate = new CutTemplate
|
||||
{
|
||||
ExportRecordId = exportRecordId ?? 0,
|
||||
ItemNo = item.ItemNo ?? "",
|
||||
PartNo = item.FileName ?? item.PartName ?? "",
|
||||
SortOrder = sortOrder++,
|
||||
Qty = item.Quantity,
|
||||
TotalQty = item.Quantity,
|
||||
Description = item.Description ?? "",
|
||||
PartName = item.PartName ?? "",
|
||||
ConfigurationName = item.Configuration ?? "",
|
||||
Material = item.Material ?? "",
|
||||
DxfFilePath = dxfPath,
|
||||
ContentHash = item.ContentHash,
|
||||
Thickness = item.Thickness > 0 ? item.Thickness : null,
|
||||
KFactor = item.KFactor > 0 ? item.KFactor : null,
|
||||
DefaultBendRadius = item.BendRadius > 0 ? item.BendRadius : null,
|
||||
DxfFilePath = dxfPath
|
||||
DefaultBendRadius = item.BendRadius > 0 ? item.BendRadius : null
|
||||
};
|
||||
|
||||
// Add to UI
|
||||
context.BomItemCallback?.Invoke(bomItem);
|
||||
|
||||
// Save BOM item to database if we have an export record
|
||||
if (exportRecordId.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var db = _dbContextFactory())
|
||||
{
|
||||
db.BomItems.Add(bomItem);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
catch (Exception dbEx)
|
||||
{
|
||||
LogProgress(context, $"Database error saving BOM item: {dbEx.Message}", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
// Compare hash with previous export to decide archive/discard
|
||||
HandleDxfVersioning(item, dxfPath, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
failureCount++;
|
||||
skippedCount++;
|
||||
}
|
||||
|
||||
// Add to UI
|
||||
context.BomItemCallback?.Invoke(bomItem);
|
||||
|
||||
// Save BOM item to database if we have an export record
|
||||
if (exportRecordId.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var db = _dbContextFactory())
|
||||
{
|
||||
db.BomItems.Add(bomItem);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
catch (Exception dbEx)
|
||||
{
|
||||
LogProgress(context, $"Database error saving BOM item: {dbEx.Message}", LogLevel.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -341,8 +391,10 @@ namespace ExportDXF.Services
|
||||
}
|
||||
}
|
||||
|
||||
LogProgress(context, $"Export complete: {successCount} succeeded, {failureCount} failed",
|
||||
failureCount > 0 ? LogLevel.Warning : LogLevel.Info);
|
||||
var summary = $"Export complete: {successCount} exported, {skippedCount} skipped";
|
||||
if (failureCount > 0)
|
||||
summary += $", {failureCount} failed";
|
||||
LogProgress(context, summary, failureCount > 0 ? LogLevel.Warning : LogLevel.Info);
|
||||
|
||||
if (exportRecordId.HasValue)
|
||||
{
|
||||
@@ -352,6 +404,85 @@ namespace ExportDXF.Services
|
||||
|
||||
#endregion
|
||||
|
||||
#region Versioning
|
||||
|
||||
private void HandleDxfVersioning(Item item, string dxfPath, ExportContext context)
|
||||
{
|
||||
if (string.IsNullOrEmpty(item.ContentHash))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
using (var db = _dbContextFactory())
|
||||
{
|
||||
var previousCutTemplate = db.CutTemplates
|
||||
.Where(ct => ct.DxfFilePath == dxfPath && ct.ContentHash != null)
|
||||
.OrderByDescending(ct => ct.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (previousCutTemplate != null && previousCutTemplate.ContentHash == item.ContentHash)
|
||||
{
|
||||
// Content unchanged - discard the stashed file
|
||||
_fileExportService.DiscardStash(item.StashedFilePath);
|
||||
LogProgress(context, $"DXF unchanged: {item.FileName}.dxf", LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Content changed or first export - archive the old file
|
||||
if (!string.IsNullOrEmpty(item.StashedFilePath))
|
||||
{
|
||||
_fileExportService.ArchiveFile(item.StashedFilePath, dxfPath);
|
||||
LogProgress(context, $"DXF updated, previous version archived: {item.FileName}.dxf", LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogProgress(context, $"Exported: {item.FileName}.dxf", LogLevel.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Don't fail the export if versioning fails - just discard the stash
|
||||
_fileExportService.DiscardStash(item.StashedFilePath);
|
||||
LogProgress(context, $"Versioning check failed for {item.FileName}: {ex.Message}", LogLevel.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePdfVersioning(string pdfPath, string drawingNumber, ExportRecord exportRecord, ExportContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newHash = ContentHasher.ComputeFileHash(pdfPath);
|
||||
|
||||
using (var db = _dbContextFactory())
|
||||
{
|
||||
var previousRecord = db.ExportRecords
|
||||
.Where(r => r.DrawingNumber == drawingNumber && r.PdfContentHash != null)
|
||||
.OrderByDescending(r => r.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (previousRecord != null && previousRecord.PdfContentHash == newHash)
|
||||
{
|
||||
LogProgress(context, $"PDF unchanged: {Path.GetFileName(pdfPath)}", LogLevel.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogProgress(context, $"Saved PDF: {Path.GetFileName(pdfPath)}", LogLevel.Info);
|
||||
}
|
||||
}
|
||||
|
||||
if (exportRecord != null)
|
||||
exportRecord.PdfContentHash = newHash;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogProgress(context, $"PDF versioning check failed: {ex.Message}", LogLevel.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper Methods
|
||||
|
||||
private string CreateTempWorkDir()
|
||||
|
||||
Reference in New Issue
Block a user