From 99b22d2ad2019ba9f771c459cebbfac96aae9acf Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Wed, 17 Jun 2026 12:21:50 -0400 Subject: [PATCH] Enrich received custom powders from the catalog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a quote uses a powder the company doesn't stock but the master catalog does, receiving it ("Got it") created an inventory record with only the color code/name and cost carried on the quote — cure schedule, SDS/TDS, sample image, color families, etc. were left blank. AddCustomPowderToInventory now matches the platform powder catalog by SKU (the coat's color code, preferring the same manufacturer, then by color name) and fills every blank spec/document field from it, links PowderCatalogItemId, and falls back to standard coverage/efficiency defaults. Only gaps are filled, so anything entered on the receive form is preserved. Co-Authored-By: Claude Opus 4.8 --- .../Controllers/DashboardController.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/PowderCoating.Web/Controllers/DashboardController.cs b/src/PowderCoating.Web/Controllers/DashboardController.cs index 123b9f9..c594152 100644 --- a/src/PowderCoating.Web/Controllers/DashboardController.cs +++ b/src/PowderCoating.Web/Controllers/DashboardController.cs @@ -765,6 +765,12 @@ public class DashboardController : Controller UpdatedAt = DateTime.UtcNow, }; + // Enrich from the platform powder catalog so the new inventory record carries the full + // spec/doc set (cure schedule, SDS/TDS, sample image, color families) rather than just + // the color code/name carried on the quote. Match by the catalog SKU (stored as the + // coat's colorCode), preferring the same manufacturer; fall back to color name. + await EnrichInventoryFromCatalogAsync(inventoryItem, colorCode, colorName, manufacturer); + await _unitOfWork.InventoryItems.AddAsync(inventoryItem); await _unitOfWork.CompleteAsync(); // flush to get inventoryItem.Id @@ -828,6 +834,69 @@ public class DashboardController : Controller } } + /// + /// Fills blank spec/document fields on a newly received custom-powder inventory item from the + /// matching platform powder catalog row — cure schedule, coverage, specific gravity, transfer + /// efficiency, SDS/TDS links, sample image, color families, product page — so the tenant gets a + /// complete record instead of just the color code/name carried on the quote. Matches by catalog + /// SKU (stored as the coat's color code), preferring the same manufacturer, then by color name. + /// Only fills gaps (never overwrites form-entered values) and links the item to the catalog row. + /// + private async Task EnrichInventoryFromCatalogAsync( + InventoryItem item, string? colorCode, string? colorName, string? manufacturer) + { + PowderCatalogItem? catalog = null; + + var code = colorCode?.Trim(); + if (!string.IsNullOrWhiteSpace(code)) + { + var codeLower = code.ToLower(); + var hits = (await _unitOfWork.PowderCatalog.FindAsync(p => p.Sku.ToLower() == codeLower)).ToList(); + var mfr = manufacturer?.Trim().ToLower(); + catalog = (!string.IsNullOrWhiteSpace(mfr) + ? hits.FirstOrDefault(p => p.VendorName.ToLower().Contains(mfr)) + : null) + ?? hits.FirstOrDefault(); + } + + if (catalog == null && !string.IsNullOrWhiteSpace(colorName)) + { + var nameLower = colorName.Trim().ToLower(); + catalog = (await _unitOfWork.PowderCatalog.FindAsync(p => p.ColorName.ToLower() == nameLower)) + .FirstOrDefault(); + } + + if (catalog == null) + return; + + item.PowderCatalogItemId = catalog.Id; + + if (string.IsNullOrWhiteSpace(item.ManufacturerPartNumber)) item.ManufacturerPartNumber = catalog.Sku; + if (string.IsNullOrWhiteSpace(item.Manufacturer)) item.Manufacturer = catalog.VendorName; + if (string.IsNullOrWhiteSpace(item.ColorName)) item.ColorName = catalog.ColorName; + if (string.IsNullOrWhiteSpace(item.Finish)) item.Finish = catalog.Finish; + if (string.IsNullOrWhiteSpace(item.ColorFamilies)) item.ColorFamilies = catalog.ColorFamilies; + if (string.IsNullOrWhiteSpace(item.ImageUrl)) item.ImageUrl = catalog.ImageUrl; + if (string.IsNullOrWhiteSpace(item.SdsUrl)) item.SdsUrl = catalog.SdsUrl; + if (string.IsNullOrWhiteSpace(item.TdsUrl)) item.TdsUrl = catalog.TdsUrl; + if (string.IsNullOrWhiteSpace(item.SpecPageUrl)) item.SpecPageUrl = catalog.ProductUrl; + + item.CureTemperatureF ??= catalog.CureTemperatureF; + item.CureTimeMinutes ??= catalog.CureTimeMinutes; + item.SpecificGravity ??= catalog.SpecificGravity; + item.CoverageSqFtPerLb ??= catalog.CoverageSqFtPerLb ?? 30m; + item.TransferEfficiency ??= catalog.TransferEfficiency ?? 65m; + + if (!item.RequiresClearCoat && catalog.RequiresClearCoat == true) + item.RequiresClearCoat = true; + + if (item.UnitCost <= 0 && catalog.UnitPrice > 0) + { + item.UnitCost = catalog.UnitPrice; + item.LastPurchasePrice = catalog.UnitPrice; + } + } + /// /// Platform-level dashboard visible only to SuperAdmins who are not impersonating a tenant. /// Displays a cross-company overview: total/active/inactive company counts, user count,