diff --git a/src/PowderCoating.Web/Controllers/PowderCatalogController.cs b/src/PowderCoating.Web/Controllers/PowderCatalogController.cs index 25329c3..32f2148 100644 --- a/src/PowderCoating.Web/Controllers/PowderCatalogController.cs +++ b/src/PowderCoating.Web/Controllers/PowderCatalogController.cs @@ -452,6 +452,60 @@ public class PowderCatalogController : Controller return RedirectToAction(nameof(Index)); } + /// + /// Right-to-delete: removes every catalog record sourced from the Columbia Coatings API + /// (regardless of derived manufacturer, since PPG/KP products were served through that feed) + /// and nulls any inventory links to them across all tenants. The shops' own inventory stock + /// records survive — only the catalog link and discontinued badge are lost. SuperAdmin only. + /// + [HttpPost] + [ValidateAntiForgeryToken] + public async Task PurgeColumbiaData() + { + var sourced = (await _unitOfWork.PowderCatalog.FindAsync( + p => p.Source == ColumbiaIntegrationConstants.SourceName)).ToList(); + + if (sourced.Count == 0) + { + TempData["Error"] = "There is no Columbia Coatings API data to remove."; + return RedirectToAction(nameof(Index)); + } + + var ids = sourced.Select(p => p.Id).ToList(); + + // Null the inventory links across ALL tenants (platform-level purge). A tenant's stock + // record is their data and must survive — it keeps its add-time snapshot, losing only the + // live catalog link. + var linked = (await _unitOfWork.InventoryItems.FindAsync( + i => i.PowderCatalogItemId.HasValue && ids.Contains(i.PowderCatalogItemId.Value), + ignoreQueryFilters: true)).ToList(); + foreach (var inv in linked) + { + inv.PowderCatalogItemId = null; + await _unitOfWork.InventoryItems.UpdateAsync(inv); + } + + foreach (var p in sourced) + await _unitOfWork.PowderCatalog.DeleteAsync(p); + await _unitOfWork.CompleteAsync(); + + // Reset sync tracking so the admin panel reflects the purge. + await _platformSettings.SetAsync(ColumbiaIntegrationConstants.SettingLastSyncedAt, null, "Columbia Purge"); + await _platformSettings.SetAsync( + ColumbiaIntegrationConstants.SettingLastResult, + $"Purged {sourced.Count:N0} records on {DateTime.UtcNow:yyyy-MM-dd}", + "Columbia Purge"); + + _logger.LogWarning( + "Columbia data purge: deleted {Count} catalog records, unlinked {Linked} inventory items.", + sourced.Count, linked.Count); + + TempData["Success"] = + $"Removed {sourced.Count:N0} Columbia Coatings catalog record(s) and unlinked " + + $"{linked.Count:N0} inventory item(s). Inventory stock was preserved."; + return RedirectToAction(nameof(Index)); + } + // Private helpers private async Task ApplyTdsCureFallbackAsync(InventoryAiLookupResult result, string? colorName) diff --git a/src/PowderCoating.Web/Views/PowderCatalog/Index.cshtml b/src/PowderCoating.Web/Views/PowderCatalog/Index.cshtml index 4ceb16d..7a71a0a 100644 --- a/src/PowderCoating.Web/Views/PowderCatalog/Index.cshtml +++ b/src/PowderCoating.Web/Views/PowderCatalog/Index.cshtml @@ -144,6 +144,13 @@ { — @columbiaLastResult } +
+ @Html.AntiForgeryToken() + +