From 90f333c8f328e6af6dc8a317bc87454bfb1a390b Mon Sep 17 00:00:00 2001 From: Scott Pouliot Date: Sun, 3 May 2026 11:02:25 -0400 Subject: [PATCH] Fix SMS Agreements version display and auto-remove stale templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix Razor rendering of TermsVersion — property chains after a literal character need @() parentheses or Razor misparses the expression. Also adds cleanup to EnsureNotificationTemplatesSeededAsync to remove stale template rows (no longer canonical, never customised) on next settings visit, so retired types like JobReadyForPickup SMS disappear automatically. Co-Authored-By: Claude Sonnet 4.6 --- .../Controllers/CompanySettingsController.cs | 19 ++++++++++++++++--- .../Views/SmsAgreements/Index.cshtml | 6 +++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/PowderCoating.Web/Controllers/CompanySettingsController.cs b/src/PowderCoating.Web/Controllers/CompanySettingsController.cs index 0472378..61643c3 100644 --- a/src/PowderCoating.Web/Controllers/CompanySettingsController.cs +++ b/src/PowderCoating.Web/Controllers/CompanySettingsController.cs @@ -2557,24 +2557,37 @@ public class CompanySettingsController : Controller /// company. Called on every visit to the Settings Index and NotificationTemplates pages so new /// notification types added to SeedData.BuildDefaultNotificationTemplates are automatically /// provisioned without requiring a migration or a manual "Seed Data" action by the platform admin. - /// Returns the count of newly added templates so the caller can decide whether to reload from the DB. + /// Also removes stale rows (no longer in the canonical list) that have never been customised + /// (UpdatedAt == null), so retired notification types disappear from the UI automatically. + /// Returns the count of changes so the caller can decide whether to reload from the DB. /// private async Task EnsureNotificationTemplatesSeededAsync( int companyId, List existing) { var allDefaults = SeedData.BuildDefaultNotificationTemplates(companyId); + var toAdd = allDefaults .Where(d => !existing.Any(e => e.NotificationType == d.NotificationType && e.Channel == d.Channel)) .ToList(); + // Remove rows that are no longer canonical and have never been customised. + var toRemove = existing + .Where(e => !allDefaults.Any(d => + d.NotificationType == e.NotificationType && d.Channel == e.Channel) + && e.UpdatedAt == null) + .ToList(); + foreach (var t in toAdd) await _unitOfWork.NotificationTemplates.AddAsync(t); - if (toAdd.Count > 0) + foreach (var t in toRemove) + await _unitOfWork.NotificationTemplates.DeleteAsync(t); + + if (toAdd.Count > 0 || toRemove.Count > 0) await _unitOfWork.CompleteAsync(); - return toAdd.Count; + return toAdd.Count + toRemove.Count; } /// diff --git a/src/PowderCoating.Web/Views/SmsAgreements/Index.cshtml b/src/PowderCoating.Web/Views/SmsAgreements/Index.cshtml index b0fd7fe..b420cbe 100644 --- a/src/PowderCoating.Web/Views/SmsAgreements/Index.cshtml +++ b/src/PowderCoating.Web/Views/SmsAgreements/Index.cshtml @@ -155,12 +155,12 @@ @if (row.CurrentAgreement != null) { - v@row.CurrentAgreement.TermsVersion + v@(row.CurrentAgreement.TermsVersion) } else if (row.LatestAgreement != null) { - - Stale (v@row.LatestAgreement.TermsVersion) + + Stale (v@(row.LatestAgreement.TermsVersion)) } else