diff --git a/ExportDXF/ExportDXF.csproj b/ExportDXF/ExportDXF.csproj
index e617553..9c364fe 100644
--- a/ExportDXF/ExportDXF.csproj
+++ b/ExportDXF/ExportDXF.csproj
@@ -26,7 +26,7 @@
Rogers Engineering
true
publish.htm
- 7
+ 8
1.6.0.%2a
false
true
@@ -70,6 +70,9 @@
+
+
+
False
False
@@ -85,6 +88,7 @@
+
@@ -119,6 +123,7 @@
+
diff --git a/ExportDXF/Program.cs b/ExportDXF/Program.cs
index 5c8cc44..b178bcf 100644
--- a/ExportDXF/Program.cs
+++ b/ExportDXF/Program.cs
@@ -1,6 +1,7 @@
using ExportDXF.Forms;
using ExportDXF.Services;
using System;
+using System.Configuration;
using System.Windows.Forms;
namespace ExportDXF
@@ -39,16 +40,17 @@ namespace ExportDXF
var bomExtractor = new BomExtractor();
var partExporter = new PartExporter();
var drawingExporter = new DrawingExporter();
- var bomExcelExporter = new BomExcelExporter();
+ var baseUrl = ConfigurationManager.AppSettings["CutFab.ApiBaseUrl"] ?? "http://localhost:7027";
+ var apiClient = new CutFabApiClient(baseUrl);
var exportService = new DxfExportService(
solidWorksService,
bomExtractor,
partExporter,
drawingExporter,
- bomExcelExporter);
+ apiClient);
- return new MainForm(solidWorksService, exportService);
+ return new MainForm(solidWorksService, exportService, apiClient);
}
}
-}
\ No newline at end of file
+}
diff --git a/ExportDXF/Services/CutFabApiClient.cs b/ExportDXF/Services/CutFabApiClient.cs
new file mode 100644
index 0000000..ecfe4c4
--- /dev/null
+++ b/ExportDXF/Services/CutFabApiClient.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web.Script.Serialization;
+using static ExportDXF.Services.CutFabApiClient;
+
+namespace ExportDXF.Services
+{
+ public interface ICutFabApiClient
+ {
+ string BaseUrl { get; }
+ Task ResolveDrawingIdAsync(string drawingNumber);
+ Task CreateDrawingAsync(int equipmentId, string drawingNumber);
+ Task> CreateDrawingWithInfoAsync(int equipmentId, string drawingNumber);
+ Task UploadDrawingPdfAsync(string drawingNumber, string pdfPath, string uploadedBy = null, string notes = null);
+ Task UploadDxfZipAsync(int drawingId, string zipPath);
+ Task CreateBomItemAsync(object upsertBomItemDto);
+ Task AutoLinkTemplatesAsync(int drawingId);
+ Task> GetEquipmentAsync();
+ Task> GetDrawingsForEquipmentAsync(int equipmentId);
+ }
+
+ public class CutFabApiClient : ICutFabApiClient, IDisposable
+ {
+ private readonly HttpClient _http;
+ private readonly string _baseUrl;
+ public string BaseUrl => _baseUrl;
+ public class ApiResponse
+ {
+ public bool Success { get; set; }
+ public int StatusCode { get; set; }
+ public T Data { get; set; }
+ public string RawBody { get; set; }
+ public string Error { get; set; }
+ }
+
+ public CutFabApiClient(string baseUrl)
+ {
+ _baseUrl = (baseUrl ?? string.Empty).TrimEnd('/');
+
+ if (string.IsNullOrWhiteSpace(_baseUrl))
+ {
+ // Default to deployed API port from deployment script
+ _baseUrl = "http://localhost:7027";
+ }
+
+ _http = new HttpClient
+ {
+ Timeout = TimeSpan.FromSeconds(100)
+ };
+ }
+
+ public async Task ResolveDrawingIdAsync(string drawingNumber)
+ {
+ try
+ {
+ var url = $"{_baseUrl}/api/Drawings/resolve?drawingNumber={Uri.EscapeDataString(drawingNumber)}";
+ var resp = await _http.GetAsync(url).ConfigureAwait(false);
+ if (!resp.IsSuccessStatusCode) return null;
+ var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var dict = new JavaScriptSerializer().Deserialize>(json);
+ if (dict != null && dict.ContainsKey("ID"))
+ {
+ var idObj = dict["ID"]; // serializer returns int or double depending
+ if (idObj is int i) return i;
+ if (idObj is double d) return (int)d;
+ }
+ return null;
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public async Task CreateDrawingAsync(int equipmentId, string drawingNumber)
+ {
+ var payload = new { DrawingNumber = drawingNumber, Description = (string)null, Qty = 1, EquipmentID = equipmentId };
+ var json = new JavaScriptSerializer().Serialize(payload);
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+ var resp = await _http.PostAsync($"{_baseUrl}/api/Drawings", content).ConfigureAwait(false);
+ if (!resp.IsSuccessStatusCode) return null;
+ var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
+ try
+ {
+ var dict = new JavaScriptSerializer().Deserialize>(body);
+ if (dict != null && dict.ContainsKey("ID"))
+ {
+ var idObj = dict["ID"]; if (idObj is int i) return i; if (idObj is double d) return (int)d;
+ }
+ }
+ catch { }
+ return null;
+ }
+
+ public async Task> CreateDrawingWithInfoAsync(int equipmentId, string drawingNumber)
+ {
+ var result = new ApiResponse { Success = false, StatusCode = 0, Data = null, RawBody = null, Error = null };
+ try
+ {
+ var payload = new { DrawingNumber = drawingNumber, Description = (string)null, Qty = 1, EquipmentID = equipmentId };
+ var json = new JavaScriptSerializer().Serialize(payload);
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+ var resp = await _http.PostAsync($"{_baseUrl}/api/Drawings", content).ConfigureAwait(false);
+ result.StatusCode = (int)resp.StatusCode;
+ result.Success = resp.IsSuccessStatusCode;
+ var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
+ result.RawBody = body;
+ if (!resp.IsSuccessStatusCode)
+ {
+ result.Error = "HTTP " + ((int)resp.StatusCode) + " " + resp.ReasonPhrase;
+ return result;
+ }
+ try
+ {
+ var dict = new JavaScriptSerializer().Deserialize>(body);
+ if (dict != null)
+ {
+ object v;
+ if (TryGetCI(dict, new[] { "ID", "id" }, out v))
+ {
+ if (v is int i) { result.Data = i; return result; }
+ if (v is double d) { result.Data = (int)d; return result; }
+ int parsed; if (int.TryParse(Convert.ToString(v), out parsed)) { result.Data = parsed; return result; }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ result.Error = ex.Message;
+ }
+ return result;
+ }
+ catch (Exception ex)
+ {
+ result.Error = ex.Message;
+ return result;
+ }
+ }
+
+ public async Task UploadDrawingPdfAsync(string drawingNumber, string pdfPath, string uploadedBy = null, string notes = null)
+ {
+ if (!File.Exists(pdfPath)) return false;
+ using (var form = new MultipartFormDataContent())
+ {
+ form.Add(new StringContent(drawingNumber ?? string.Empty), "drawingNumber");
+ if (!string.IsNullOrWhiteSpace(uploadedBy)) form.Add(new StringContent(uploadedBy), "uploadedBy");
+ if (!string.IsNullOrWhiteSpace(notes)) form.Add(new StringContent(notes), "notes");
+
+ var fileContent = new StreamContent(File.OpenRead(pdfPath));
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
+ var fileName = Path.GetFileName(pdfPath);
+ form.Add(fileContent, "file", fileName);
+
+ var resp = await _http.PostAsync($"{_baseUrl}/api/DrawingRevisions/upload", form).ConfigureAwait(false);
+ return resp.IsSuccessStatusCode;
+ }
+ }
+
+ public async Task UploadDxfZipAsync(int drawingId, string zipPath)
+ {
+ if (!File.Exists(zipPath)) return false;
+ using (var form = new MultipartFormDataContent())
+ {
+ var fileContent = new StreamContent(File.OpenRead(zipPath));
+ fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/zip");
+ var fileName = Path.GetFileName(zipPath);
+ form.Add(fileContent, "file", fileName);
+
+ var resp = await _http.PostAsync($"{_baseUrl}/api/Drawings/{drawingId}/upload-dxf-templates", form).ConfigureAwait(false);
+ return resp.IsSuccessStatusCode;
+ }
+ }
+
+ public async Task CreateBomItemAsync(object upsertBomItemDto)
+ {
+ var json = new JavaScriptSerializer().Serialize(upsertBomItemDto);
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+ var resp = await _http.PostAsync($"{_baseUrl}/api/BomItems", content).ConfigureAwait(false);
+ if (!resp.IsSuccessStatusCode) return null;
+ var body = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
+ try
+ {
+ var dict = new JavaScriptSerializer().Deserialize>(body);
+ if (dict != null)
+ {
+ object v;
+ if (TryGetCI(dict, new[] { "ID", "id" }, out v))
+ {
+ if (v is int i) return i;
+ if (v is double d) return (int)d;
+ int parsed; if (int.TryParse(Convert.ToString(v), out parsed)) return parsed;
+ }
+ }
+ }
+ catch { }
+ // Successful HTTP with empty/minimal body: treat as success
+ return 0;
+ }
+
+ public async Task AutoLinkTemplatesAsync(int drawingId)
+ {
+ var url = $"{_baseUrl}/api/Drawings/{drawingId}/auto-link-templates";
+ var resp = await _http.PostAsync(url, new ByteArrayContent(new byte[0])).ConfigureAwait(false);
+ return resp.IsSuccessStatusCode;
+ }
+
+ public void Dispose()
+ {
+ _http?.Dispose();
+ }
+
+ // Lightweight DTOs for UI binding
+ public class ApiEquipment
+ {
+ public int ID { get; set; }
+ public string EquipmentNumber { get; set; }
+ public string Description { get; set; }
+ public override string ToString() => EquipmentNumber ?? base.ToString();
+ }
+
+ public class ApiDrawingSummary
+ {
+ public int ID { get; set; }
+ public string DrawingNumber { get; set; }
+ public string Description { get; set; }
+ public override string ToString() => DrawingNumber ?? base.ToString();
+ }
+
+ public async Task> GetEquipmentAsync()
+ {
+ var url = $"{_baseUrl}/api/Equipment";
+ var req = new HttpRequestMessage(HttpMethod.Get, url);
+ req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ var resp = await _http.SendAsync(req).ConfigureAwait(false);
+ resp.EnsureSuccessStatusCode();
+ var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
+
+ var serializer = new JavaScriptSerializer();
+ var raw = serializer.DeserializeObject(json);
+ var result = new List();
+
+ if (raw is System.Collections.IEnumerable enumerable && !(raw is string))
+ {
+ foreach (var item in enumerable)
+ {
+ var dict = item as Dictionary;
+ if (dict == null) continue;
+ var eq = new ApiEquipment();
+ object v;
+ if (TryGetCI(dict, new[] { "ID", "id" }, out v)) eq.ID = ToInt(v);
+ if (TryGetCI(dict, new[] { "EquipmentNumber", "equipmentNumber", "equipmentNo" }, out v)) eq.EquipmentNumber = v?.ToString();
+ if (TryGetCI(dict, new[] { "Description", "description" }, out v)) eq.Description = v?.ToString();
+ result.Add(eq);
+ }
+ }
+
+ return result;
+ }
+
+ public async Task> GetDrawingsForEquipmentAsync(int equipmentId)
+ {
+ var url = $"{_baseUrl}/api/Equipment/{equipmentId}";
+ var resp = await _http.GetAsync(url).ConfigureAwait(false);
+ if (!resp.IsSuccessStatusCode) return new List();
+ var json = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var serializer = new JavaScriptSerializer();
+ var root = serializer.DeserializeObject(json) as Dictionary;
+ var results = new List();
+ if (root != null)
+ {
+ object dval;
+ if (!TryGetCI(root, new[] { "Drawings", "drawings" }, out dval)) return results;
+ if (dval is System.Collections.IEnumerable arr && !(dval is string))
+ {
+ foreach (var item in arr)
+ {
+ var d = item as Dictionary;
+ if (d == null) continue;
+ var summary = new ApiDrawingSummary();
+ object v;
+ if (TryGetCI(d, new[] { "ID", "id" }, out v)) summary.ID = ToInt(v);
+ if (TryGetCI(d, new[] { "DrawingNumber", "drawingNumber" }, out v)) summary.DrawingNumber = v?.ToString();
+ if (TryGetCI(d, new[] { "Description", "description" }, out v)) summary.Description = v?.ToString();
+ results.Add(summary);
+ }
+ }
+ }
+ return results;
+ }
+
+ private static bool TryGetCI(Dictionary dict, IEnumerable keys, out object value)
+ {
+ foreach (var k in keys)
+ {
+ if (dict.ContainsKey(k)) { value = dict[k]; return true; }
+ foreach (var dk in dict.Keys)
+ {
+ if (string.Equals(dk, k, StringComparison.OrdinalIgnoreCase)) { value = dict[dk]; return true; }
+ }
+ }
+ value = null; return false;
+ }
+
+ private static int ToInt(object v)
+ {
+ if (v == null) return 0;
+ if (v is int i) return i;
+ if (v is long l) return (int)l;
+ if (v is double d) return (int)d;
+ int parsed; if (int.TryParse(v.ToString(), out parsed)) return parsed; return 0;
+ }
+ }
+}
diff --git a/ExportDXF/app.config b/ExportDXF/app.config
index a206db0..8bfc0ef 100644
--- a/ExportDXF/app.config
+++ b/ExportDXF/app.config
@@ -5,5 +5,7 @@
+
+