diff --git a/src/PowderCoating.Web/Controllers/InventoryController.cs b/src/PowderCoating.Web/Controllers/InventoryController.cs index 0cadef0..34305e0 100644 --- a/src/PowderCoating.Web/Controllers/InventoryController.cs +++ b/src/PowderCoating.Web/Controllers/InventoryController.cs @@ -679,6 +679,7 @@ public class InventoryController : Controller return Json(new { success = false, errorMessage = "AI Inventory Assist is not enabled for your account. Contact your administrator." }); var result = await _aiLookupService.LookupAsync(manufacturer, colorName, colorCode, partNumber); + if (result.Success) await ApplyTdsCureFallbackAsync(result, colorName); return Json(result); } @@ -701,9 +702,31 @@ public class InventoryController : Controller return Json(new { success = false, errorMessage = "No product URL provided." }); var result = await _aiLookupService.LookupByUrlAsync(productUrl, colorName); + if (result.Success) await ApplyTdsCureFallbackAsync(result, colorName); return Json(result); } + /// + /// If cure temperature or cure time is still missing after the primary lookup but a TDS URL + /// was returned, fetches that page and asks Claude to extract only the cure schedule. + /// Mutates in place; silently no-ops on failure so callers + /// can always return the result even if the TDS fetch does not help. + /// + private async Task ApplyTdsCureFallbackAsync(InventoryAiLookupResult result, string? colorName) + { + if ((result.CureTemperatureF == null || result.CureTimeMinutes == null) + && !string.IsNullOrEmpty(result.TdsUrl)) + { + _logger.LogInformation("Cure specs missing after lookup; trying TDS at {Url}", result.TdsUrl); + var tds = await _aiLookupService.FetchTdsCureSpecsAsync(result.TdsUrl, colorName); + if (tds.Success) + { + if (result.CureTemperatureF == null) result.CureTemperatureF = tds.CureTemperatureF; + if (result.CureTimeMinutes == null) result.CureTimeMinutes = tds.CureTimeMinutes; + } + } + } + /// /// Accepts a base64 label photo or a decoded QR URL from the in-browser label scanner, /// runs it through Claude (vision for photos, URL-fetch for QR), searches the platform @@ -834,22 +857,14 @@ public class InventoryController : Controller } } - // If cure specs are still missing but we have a TDS URL, fetch it and try to extract - // cure temperature and cure time. Most TDS pages are HTML; PDFs fail silently. - var resolvedCureTemp = catalogMatch?.CureTemperatureF ?? aiResult.CureTemperatureF; - var resolvedCureTime = catalogMatch?.CureTimeMinutes ?? aiResult.CureTimeMinutes; - var resolvedTdsUrl = catalogMatch?.TdsUrl ?? aiResult.TdsUrl; - - if ((resolvedCureTemp == null || resolvedCureTime == null) && !string.IsNullOrEmpty(resolvedTdsUrl)) - { - _logger.LogInformation("Cure specs missing after main lookup; trying TDS at {Url}", resolvedTdsUrl); - var tdsResult = await _aiLookupService.FetchTdsCureSpecsAsync(resolvedTdsUrl, colorName); - if (tdsResult.Success) - { - if (resolvedCureTemp == null) aiResult.CureTemperatureF = tdsResult.CureTemperatureF; - if (resolvedCureTime == null) aiResult.CureTimeMinutes = tdsResult.CureTimeMinutes; - } - } + // If cure specs are still missing but we have a TDS URL, try reading it. + // Prefer the catalog's TDS URL if present; the catalog record is more reliable. + // Temporarily merge the catalog TDS URL into aiResult so ApplyTdsCureFallbackAsync + // sees the best available URL and writes the result back into aiResult. + if (catalogMatch?.CureTemperatureF != null) aiResult.CureTemperatureF = catalogMatch.CureTemperatureF; + if (catalogMatch?.CureTimeMinutes != null) aiResult.CureTimeMinutes = catalogMatch.CureTimeMinutes; + aiResult.TdsUrl ??= catalogMatch?.TdsUrl; + await ApplyTdsCureFallbackAsync(aiResult, colorName); // Check if this product already exists in the tenant's inventory. // Match by ManufacturerPartNumber first (most precise); fall back to color name + manufacturer. diff --git a/src/PowderCoating.Web/Views/Inventory/_InventoryColorFamilyScripts.cshtml b/src/PowderCoating.Web/Views/Inventory/_InventoryColorFamilyScripts.cshtml index 7b968d4..4dba788 100644 --- a/src/PowderCoating.Web/Views/Inventory/_InventoryColorFamilyScripts.cshtml +++ b/src/PowderCoating.Web/Views/Inventory/_InventoryColorFamilyScripts.cshtml @@ -450,6 +450,21 @@ aiFilledImage = true; } + // SDS / TDS document URLs — fill inputs and show open-link buttons + const fillDocUrl = (fieldId, linkId, url, label) => { + if (!url) return; + const el = document.getElementById(fieldId); + const link = document.getElementById(linkId); + if (el && (forceRefill || !el.value.trim())) { + el.value = url; + filled.push(label); + if (!aiFilledFields.includes(fieldId)) aiFilledFields.push(fieldId); + } + if (link) { link.href = url; link.classList.remove('d-none'); } + }; + fillDocUrl('field-sdsurl', 'field-sdsurl-link', data.sdsUrl, 'SDS'); + fillDocUrl('field-tdsurl', 'field-tdsurl-link', data.tdsUrl, 'TDS'); + // Build a persistent "needs more info" tip if key identity fields are still unknown const missingHints = []; if (!data.manufacturer && !document.getElementById('field-manufacturer')?.value?.trim())