From 4506c1f64159c66c2efc83fa5f9e788ee7c8daf1 Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Wed, 17 Jun 2026 11:18:15 -0400 Subject: [PATCH] Link inventory to powder catalog and flag discontinued items MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 5 (part): the inventory tie-in. - Set InventoryItem.PowderCatalogItemId on the catalog-sourced create paths: directly in CreateIncomingFromCatalog, and via a new FindCatalogMatchAsync (Manufacturer + ManufacturerPartNumber) helper in Create. - Inventory Details loads the linked catalog row (falling back to an identity match for items created before linking) and shows a "Discontinued by manufacturer — cannot reorder" badge + banner when it's discontinued. Deliberately distinct from the shop's own Active/Inactive status: existing stock can still be used and quoted, it just can't be reordered. Co-Authored-By: Claude Opus 4.8 --- .../Controllers/InventoryController.cs | 36 +++++++++++++++++++ .../Views/Inventory/Details.cshtml | 20 +++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/PowderCoating.Web/Controllers/InventoryController.cs b/src/PowderCoating.Web/Controllers/InventoryController.cs index 9437e25..ca23974 100644 --- a/src/PowderCoating.Web/Controllers/InventoryController.cs +++ b/src/PowderCoating.Web/Controllers/InventoryController.cs @@ -240,6 +240,17 @@ public class InventoryController : Controller var useMetric = await _tenantContext.UseMetricSystemAsync(); ViewBag.CoverageUnit = _measurementService.GetCoverageUnitLabel(useMetric); + // Manufacturer-level catalog status: prefer the linked catalog row, fall back to an + // identity match for items added before they were linked. Drives the "discontinued by + // manufacturer — cannot reorder" warning. This is distinct from the shop's own + // IsActive/DiscontinuedDate (whether the shop still stocks it). + var catalogItem = item.PowderCatalogItemId.HasValue + ? await _unitOfWork.PowderCatalog.GetByIdAsync(item.PowderCatalogItemId.Value) + : await FindCatalogMatchAsync(item.Manufacturer, item.ManufacturerPartNumber); + ViewBag.CatalogDiscontinued = catalogItem?.IsDiscontinued ?? false; + ViewBag.CatalogVendorName = catalogItem?.VendorName; + ViewBag.CatalogProductUrl = catalogItem?.ProductUrl; + return View(itemDto); } catch (Exception ex) @@ -302,6 +313,12 @@ public class InventoryController : Controller item.Category = category.DisplayName; } + // Link to the platform catalog row when this item's identity matches one, so the detail + // screen can show manufacturer-level status (discontinued / cannot reorder). + var catalogMatch = await FindCatalogMatchAsync(item.Manufacturer, item.ManufacturerPartNumber); + if (catalogMatch != null) + item.PowderCatalogItemId = catalogMatch.Id; + await _unitOfWork.InventoryItems.AddAsync(item); await _unitOfWork.SaveChangesAsync(); @@ -763,6 +780,24 @@ public class InventoryController : Controller /// Returns (wasInCatalog, addedToCatalog) so callers can surface UI badges. /// Mutates in place. /// + /// + /// Finds the platform powder catalog row matching an inventory item's identity + /// (Manufacturer + ManufacturerPartNumber), or null. Used to set + /// and to surface manufacturer-level status + /// (e.g. discontinued / cannot reorder) on the detail screen. + /// + private async Task FindCatalogMatchAsync(string? manufacturer, string? sku) + { + if (string.IsNullOrWhiteSpace(manufacturer) || string.IsNullOrWhiteSpace(sku)) + return null; + + var skuLower = sku.Trim().ToLower(); + var mfrLower = manufacturer.Trim().ToLower(); + var hits = await _unitOfWork.PowderCatalog.FindAsync(p => + p.Sku.ToLower() == skuLower && p.VendorName.ToLower().Contains(mfrLower)); + return hits.FirstOrDefault(); + } + private async Task<(bool wasInCatalog, bool addedToCatalog)> EnrichFromCatalogAsync( InventoryAiLookupResult result, bool autoContribute) { @@ -1257,6 +1292,7 @@ public class InventoryController : Controller ColorName = catalogItem.ColorName, Manufacturer = catalogItem.VendorName, ManufacturerPartNumber= catalogItem.Sku, + PowderCatalogItemId = catalogItem.Id, Finish = catalogItem.Finish, ColorFamilies = catalogItem.ColorFamilies, RequiresClearCoat = catalogItem.RequiresClearCoat ?? false, diff --git a/src/PowderCoating.Web/Views/Inventory/Details.cshtml b/src/PowderCoating.Web/Views/Inventory/Details.cshtml index 5399c1b..f448310 100644 --- a/src/PowderCoating.Web/Views/Inventory/Details.cshtml +++ b/src/PowderCoating.Web/Views/Inventory/Details.cshtml @@ -69,6 +69,12 @@ { Inactive } + @if ((bool?)ViewBag.CatalogDiscontinued == true) + { + + Discontinued by manufacturer + + }
@@ -103,6 +109,20 @@
Status: This item is inactive
} + @if ((bool?)ViewBag.CatalogDiscontinued == true) + { +
+ +
+ Discontinued by @(ViewBag.CatalogVendorName ?? "manufacturer"): + this powder has been discontinued and cannot be reordered. Existing stock can still be used and quoted. + @if (!string.IsNullOrEmpty(ViewBag.CatalogProductUrl as string)) + { + View product page + } +
+
+ }