diff --git a/src/PowderCoating.Web/Controllers/SeedDataController.cs b/src/PowderCoating.Web/Controllers/SeedDataController.cs index 24dcd42..351f900 100644 --- a/src/PowderCoating.Web/Controllers/SeedDataController.cs +++ b/src/PowderCoating.Web/Controllers/SeedDataController.cs @@ -106,6 +106,75 @@ public class SeedDataController : Controller return RedirectToAction(nameof(Index)); } + /// + /// Wipes all seeded data from the DEMO company and immediately re-seeds it with fresh demo data + /// so all dates are current. Intended for tutorial recording resets — one click returns the demo + /// company to a clean, realistic state without touching any other tenant. + /// + [HttpPost] + [ValidateAntiForgeryToken] + public async Task ResetDemoCompany() + { + try + { + var companies = await _seedDataService.GetCompaniesAsync(); + var demo = companies.FirstOrDefault(c => c.CompanyCode == "DEMO"); + if (demo == null) + { + TempData["ErrorMessage"] = "Demo company (code: DEMO) not found. Run Seed System Data first."; + return RedirectToAction(nameof(Index)); + } + + // Remove all seed data categories + var removeOptions = new RemoveSeedDataOptions + { + Customers = true, + InventoryItems = true, + Equipment = true, + Catalog = true, + PricingTiers = true, + OperatingCosts = true, + }; + + var removeResult = await _seedDataService.RemoveSeedDataAsync(demo.Id, removeOptions); + if (!removeResult.Success) + { + TempData["ErrorMessage"] = $"Wipe step failed: {removeResult.Message}"; + return RedirectToAction(nameof(Index)); + } + + // Re-seed with today's dates + var seedResult = await _seedDataService.SeedCompanyDataAsync(demo.Id); + + if (seedResult.Success) + { + TempData["SuccessMessage"] = $"Demo company reset complete. {seedResult.ItemsSeeded} records re-seeded with today's dates."; + TempData["SeedDetails"] = string.Join("|", seedResult.Details); + TempData["ItemsSeeded"] = seedResult.ItemsSeeded; + + if (seedResult.Warnings.Any()) + { + TempData["WarningMessage"] = $"{seedResult.ItemsSkipped} item(s) were skipped"; + var displayWarnings = seedResult.Warnings.Take(30).ToList(); + if (seedResult.Warnings.Count > 30) + displayWarnings.Add($"… and {seedResult.Warnings.Count - 30} more (see logs)"); + TempData["SeedWarnings"] = string.Join("|", displayWarnings); + } + } + else + { + TempData["ErrorMessage"] = $"Wipe succeeded but re-seed failed: {seedResult.Message}"; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error resetting demo company"); + TempData["ErrorMessage"] = $"An error occurred during demo reset: {ex.Message}"; + } + + return RedirectToAction(nameof(Index)); + } + /// /// Removes previously seeded demo data from a company according to the supplied options (e.g., jobs only, or all data). Used during QA/demo resets to return a company to a clean state without a full database drop. /// diff --git a/src/PowderCoating.Web/Views/SeedData/Index.cshtml b/src/PowderCoating.Web/Views/SeedData/Index.cshtml index a5dadae..d208e7b 100644 --- a/src/PowderCoating.Web/Views/SeedData/Index.cshtml +++ b/src/PowderCoating.Web/Views/SeedData/Index.cshtml @@ -98,6 +98,44 @@ } + + @{ + var demoCompany = Model?.FirstOrDefault(c => c.CompanyCode == "DEMO"); + } + @if (demoCompany != null) + { +
+
+ +
Reset Demo Company
+ Tutorial Prep +
+
+

+ Wipes all seeded data from the Demo Company and immediately re-seeds it with + fresh records dated relative to today. Use this before every recording session + so jobs, quotes, invoices, and AR aging always look current. +

+
    +
  • Removes: customers, jobs, quotes, invoices, inventory, equipment, catalog, pricing tiers, operating costs
  • +
  • Re-seeds: 100 customers, 50 jobs across all statuses, quotes, invoices, inventory transactions, vendor bills, appointments — all dated from today
  • +
  • Preserves: user accounts, company settings, lookup tables (job statuses, priorities, etc.)
  • +
+
+ + This permanently deletes and recreates all demo data. Any manual edits made to the demo company will be lost. +
+
+ @Html.AntiForgeryToken() + +
+
+
+ } +