diff --git a/ExportDXF/Models/ExportContext.cs b/ExportDXF/Models/ExportContext.cs index fb4dae7..66a8abb 100644 --- a/ExportDXF/Models/ExportContext.cs +++ b/ExportDXF/Models/ExportContext.cs @@ -32,6 +32,11 @@ namespace ExportDXF.Services /// public string FilePrefix { get; set; } + /// + /// Selected Equipment ID for API operations (optional). + /// + public int? EquipmentId { get; set; } + /// /// Cancellation token for canceling the export operation. /// @@ -127,4 +132,4 @@ namespace ExportDXF.Services return SolidWorksApp?.NewDocument(templatePath, paperSize, width, height) as ModelDoc2; } } -} \ No newline at end of file +} diff --git a/ExportDXF/Services/DxfExportService.cs b/ExportDXF/Services/DxfExportService.cs index b89786f..7f481e6 100644 --- a/ExportDXF/Services/DxfExportService.cs +++ b/ExportDXF/Services/DxfExportService.cs @@ -1,13 +1,17 @@ -using ExportDXF.Extensions; +using ExportDXF.Extensions; using ExportDXF.ItemExtractors; using ExportDXF.Models; +using ExportDXF; using SolidWorks.Interop.sldworks; using SolidWorks.Interop.swconst; using System; using System.Collections.Generic; +using System.Linq; using System.Drawing; using System.IO; using System.Windows.Forms; +using Environment = System.Environment; +using System.IO.Compression; namespace ExportDXF.Services { @@ -29,20 +33,20 @@ namespace ExportDXF.Services private readonly IBomExtractor _bomExtractor; private readonly IPartExporter _partExporter; private readonly IDrawingExporter _drawingExporter; - private readonly IBomExcelExporter _bomExcelExporter; + private readonly ICutFabApiClient _apiClient; public DxfExportService( ISolidWorksService solidWorksService, IBomExtractor bomExtractor, IPartExporter partExporter, IDrawingExporter drawingExporter, - IBomExcelExporter bomExcelExporter) + ICutFabApiClient apiClient) { _solidWorksService = solidWorksService ?? throw new ArgumentNullException(nameof(solidWorksService)); _bomExtractor = bomExtractor ?? throw new ArgumentNullException(nameof(bomExtractor)); _partExporter = partExporter ?? throw new ArgumentNullException(nameof(partExporter)); _drawingExporter = drawingExporter ?? throw new ArgumentNullException(nameof(drawingExporter)); - _bomExcelExporter = bomExcelExporter ?? throw new ArgumentNullException(nameof(bomExcelExporter)); + _apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient)); } /// @@ -104,14 +108,8 @@ namespace ExportDXF.Services return; } - var saveDirectory = PromptUserForDirectory(context); - if (saveDirectory == null) - { - LogProgress(context, "Canceled", Color.Red); - return; - } - - _partExporter.ExportSinglePart(part, saveDirectory, context); + var tempDir = CreateTempWorkDir(); + _partExporter.ExportSinglePart(part, tempDir, context); } private void ExportAssembly(ExportContext context) @@ -136,14 +134,8 @@ namespace ExportDXF.Services LogProgress(context, $"Found {items.Count} item(s).", null); - var saveDirectory = PromptUserForDirectory(context); - if (saveDirectory == null) - { - LogProgress(context, "Canceled", Color.Red); - return; - } - - ExportItems(items, saveDirectory, context); + var tempDir = CreateTempWorkDir(); + ExportItems(items, tempDir, context, drawingId: null); } private void ExportDrawing(ExportContext context) @@ -168,18 +160,120 @@ namespace ExportDXF.Services LogProgress(context, $"Found {items.Count} component(s)", null); - var saveDirectory = PromptUserForDirectory(context); - if (saveDirectory == null) + var tempDir = CreateTempWorkDir(); + + // Determine drawing number + var drawingNumber = ParseDrawingNumber(context); + if (string.IsNullOrWhiteSpace(drawingNumber)) { - LogProgress(context, "Canceled", Color.Red); - return; + LogProgress(context, "Warning: Could not determine drawing number for API upload.", Color.DarkBlue); } - // Export drawing to PDF first - _drawingExporter.ExportToPdf(drawing, saveDirectory, context); + // Resolve drawing ID if possible + int? drawingId = null; + if (!string.IsNullOrWhiteSpace(drawingNumber)) + { + drawingId = _apiClient.ResolveDrawingIdAsync(drawingNumber).GetAwaiter().GetResult(); + // Fallback: if resolve endpoint not available or failed, search equipment details + if (drawingId == null && context.EquipmentId.HasValue) + { + try + { + var drawings = _apiClient.GetDrawingsForEquipmentAsync(context.EquipmentId.Value).GetAwaiter().GetResult(); + if (drawings != null) + { + // Match by exact DrawingNumber (case-insensitive, trimmed) + var match = drawings.FirstOrDefault(d => string.Equals(d.DrawingNumber?.Trim(), drawingNumber.Trim(), StringComparison.OrdinalIgnoreCase)); + if (match != null) drawingId = match.ID; + } + } + catch { } + } + if (drawingId == null) + { + // If equipment is provided, create the drawing on the API + if (context.EquipmentId.HasValue) + { + var create = _apiClient.CreateDrawingWithInfoAsync(context.EquipmentId.Value, drawingNumber).GetAwaiter().GetResult(); + if (create != null && create.Success && create.Data.HasValue) + { + drawingId = create.Data; + LogProgress(context, "Created drawing '" + drawingNumber + "' (ID " + drawingId + ") for equipment " + context.EquipmentId, Color.Green); + } + else + { + var code = create != null ? create.StatusCode.ToString() : "?"; + var err = create != null ? (create.Error ?? create.RawBody) : null; + if (!string.IsNullOrWhiteSpace(err) && err.Length > 180) err = err.Substring(0, 180) + "..."; + LogProgress(context, "Warning: Could not create drawing '" + drawingNumber + "' on API (status " + code + "). " + (err ?? string.Empty), Color.DarkBlue); + } + } + else + { + LogProgress(context, $"Warning: Drawing '{drawingNumber}' not found in API; uploads will be skipped.", Color.DarkBlue); + } + } - // Then export parts to DXF - ExportItems(items, saveDirectory, context); + // Export drawing to PDF first + _drawingExporter.ExportToPdf(drawing, tempDir, context); + + // Upload PDF if we have a drawing number + try + { + if (!string.IsNullOrWhiteSpace(drawingNumber)) + { + var pdfs = Directory.GetFiles(tempDir, "*.pdf"); + var pdfName = pdfs.Length > 0 ? pdfs[0] : null; + if (pdfName != null) + { + var uploadedBy = Environment.UserName; + var ok = _apiClient.UploadDrawingPdfAsync(drawingNumber, pdfName, uploadedBy, null).GetAwaiter().GetResult(); + LogProgress(context, ok ? $"Uploaded PDF for '{drawingNumber}'" : $"Failed to upload PDF for '{drawingNumber}'", ok ? Color.Green : Color.Red); + } + } + } + catch (Exception ex) + { + LogProgress(context, $"PDF upload error: {ex.Message}", Color.Red); + } + + // If we still don't have an ID, resolve again after PDF upload (server may create on upload) + if (!drawingId.HasValue && !string.IsNullOrWhiteSpace(drawingNumber)) + { + var resolved = _apiClient.ResolveDrawingIdAsync(drawingNumber).GetAwaiter().GetResult(); + if (!resolved.HasValue && context.EquipmentId.HasValue) + { + try + { + var drawings = _apiClient.GetDrawingsForEquipmentAsync(context.EquipmentId.Value).GetAwaiter().GetResult(); + if (drawings != null) + { + var match = drawings.FirstOrDefault(d => string.Equals(d.DrawingNumber?.Trim(), drawingNumber.Trim(), StringComparison.OrdinalIgnoreCase)); + if (match != null) resolved = match.ID; + } + } + catch { } + } + if (resolved.HasValue) + { + drawingId = resolved; + LogProgress(context, $"Resolved drawing ID after PDF upload: {drawingId}", Color.Green); + } + } + + // Then export parts to DXF and upload per-file + ExportItems(items, tempDir, context, drawingId); + + // Attempt to auto-link templates at the end + try + { + if (drawingId.HasValue) + { + _apiClient.AutoLinkTemplatesAsync(drawingId.Value).GetAwaiter().GetResult(); + } + } + catch { } + } } #endregion @@ -238,7 +332,7 @@ namespace ExportDXF.Services } } - private void ExportItems(List items, string saveDirectory, ExportContext context) + private void ExportItems(List items, string saveDirectory, ExportContext context, int? drawingId) { LogProgress(context, "", null); @@ -259,9 +353,51 @@ namespace ExportDXF.Services _partExporter.ExportItem(item, saveDirectory, context); if (!string.IsNullOrEmpty(item.FileName)) + { successCount++; + + // If we know the drawing, upload DXF and BOM row immediately + if (drawingId.HasValue) + { + var dxfPath = Path.Combine(saveDirectory, item.FileName + ".dxf"); + if (File.Exists(dxfPath)) + { + // Zip just this file + string zipPath = CreateZipWithSingleFile(dxfPath); + try + { + var okZip = _apiClient.UploadDxfZipAsync(drawingId.Value, zipPath).GetAwaiter().GetResult(); + LogProgress(context, okZip ? $"Uploaded DXF: {Path.GetFileName(dxfPath)}" : $"Failed to upload DXF: {Path.GetFileName(dxfPath)}", okZip ? Color.Green : Color.Red); + } + finally + { + try { if (File.Exists(zipPath)) File.Delete(zipPath); } catch { } + } + + // Create BOM item + var dto = new + { + DrawingID = drawingId.Value, + ItemNo = item.ItemNo, + PartNo = item.FileName, + Qty = (int?)item.Quantity, + Description = string.IsNullOrWhiteSpace(item.Description) ? null : item.Description, + PartName = string.IsNullOrWhiteSpace(item.PartName) ? null : item.PartName, + ConfigurationName = string.IsNullOrWhiteSpace(item.Configuration) ? null : item.Configuration, + Material = string.IsNullOrWhiteSpace(item.Material) ? null : item.Material, + SortOrder = 0, + CutTemplateID = (int?)null, + FormProgramID = (int?)null + }; + var bomId = _apiClient.CreateBomItemAsync(dto).GetAwaiter().GetResult(); + LogProgress(context, bomId.HasValue ? $"Created BOM item for {item.ItemNo ?? item.PartName}" : $"Failed to create BOM item for {item.ItemNo ?? item.PartName}", bomId.HasValue ? Color.Green : Color.Red); + } + } + } else + { failureCount++; + } } catch (Exception ex) { @@ -274,79 +410,41 @@ namespace ExportDXF.Services LogProgress(context, $"Export complete: {successCount} succeeded, {failureCount} failed", failureCount > 0 ? Color.DarkBlue : Color.Green); - - // Create BOM Excel file - CreateBomExcelFile(items, saveDirectory, context); } #endregion - #region BOM Excel Creation + #region Temp + Upload Helpers - private void CreateBomExcelFile(List items, string saveDirectory, ExportContext context) + private string CreateTempWorkDir() { - try - { - var bomFileName = GetBomFileName(context.FilePrefix); - var bomFilePath = Path.Combine(saveDirectory, bomFileName + ".xlsx"); - - _bomExcelExporter.CreateBOMExcelFile(bomFilePath, items); - - LogProgress(context, $"Created BOM Excel file: {bomFileName}.xlsx", Color.Green); - } - catch (Exception ex) - { - LogProgress(context, $"Failed to create BOM Excel: {ex.Message}", Color.Red); - } + var path = Path.Combine(Path.GetTempPath(), "ExportDXF-" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(path); + return path; } - private string GetBomFileName(string prefix) + private string ParseDrawingNumber(ExportContext context) { - if (string.IsNullOrWhiteSpace(prefix)) - return "BOM"; - - var drawingInfo = DrawingInfo.Parse(prefix); - - if (drawingInfo != null) + // Prefer prefix (e.g., "5007 A02 PT"), fallback to active document title + var candidate = context?.FilePrefix; + var info = string.IsNullOrWhiteSpace(candidate) ? null : DrawingInfo.Parse(candidate); + if (info == null) { - return $"{drawingInfo.JobNo} {drawingInfo.DrawingNo} BOM"; + var title = context?.ActiveDocument?.Title; + info = string.IsNullOrWhiteSpace(title) ? null : DrawingInfo.Parse(title); } - - return prefix.Trim() + " BOM"; + return info != null ? ($"{info.EquipmentNo} {info.DrawingNo}") : null; } - #endregion - - #region User Interaction - - private string PromptUserForDirectory(ExportContext context) + private string CreateZipWithSingleFile(string filePath) { - // Check if already canceled - if (context.CancellationToken.IsCancellationRequested) - return null; - - string selectedPath = null; - - // Must run on STA thread for FolderBrowserDialog - var thread = new System.Threading.Thread(() => + var zipPath = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + ".zip"); + if (File.Exists(zipPath)) File.Delete(zipPath); + using (var zip = System.IO.Compression.ZipFile.Open(zipPath, System.IO.Compression.ZipArchiveMode.Create)) { - using (var dialog = new FolderBrowserDialog()) - { - dialog.Description = "Where do you want to save the DXF files?"; - dialog.ShowNewFolderButton = true; - - if (dialog.ShowDialog() == DialogResult.OK) - { - selectedPath = dialog.SelectedPath; - } - } - }); - - thread.SetApartmentState(System.Threading.ApartmentState.STA); - thread.Start(); - thread.Join(); - - return selectedPath; + zip.CreateEntryFromFile(filePath, Path.GetFileName(filePath)); + } + return zipPath; } #endregion @@ -371,4 +469,6 @@ namespace ExportDXF.Services #endregion } -} \ No newline at end of file +} + +