Demo reset + dev banner suppression for DEMO company

- DemoController: company-code-gated reset action (DEMO only, CSRF protected)
- SeedDataService.Remove: FK-safe topological pre-sweep, all deletes scoped to companyId
- SeedDataService: clock entries, extra seed data, updated customer/worker/job-status seeders
- CompanySettingsController + Index.cshtml: Reset Demo Data button for DEMO company users
- ReportsController + FinancialReportService: supporting report fixes
- _Layout.cshtml: suppress env banner when current company is DEMO (all auth paths)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 09:26:40 -04:00
parent 7735fe3cce
commit 6eb7be0193
13 changed files with 963 additions and 221 deletions
@@ -2679,6 +2679,34 @@
</div>
</div>
@if (ViewBag.IsDemoCompany == true)
{
<div class="container-fluid mt-4">
<div class="card border-warning">
<div class="card-header bg-warning bg-opacity-10 d-flex align-items-center gap-2">
<i class="bi bi-arrow-clockwise text-warning fs-5"></i>
<strong>Demo Environment</strong>
</div>
<div class="card-body">
<p class="mb-2">
This is the <strong>DEMO</strong> company. Use the button below to wipe and re-seed all
demo data with fresh dates. Workers and system configuration are preserved.
</p>
<p class="text-muted small mb-3">
Reset takes 10&ndash;30 seconds. You will be redirected here when complete.
</p>
<form asp-controller="Demo" asp-action="ResetDemoData" method="post"
onsubmit="this.querySelector('button').disabled=true; this.querySelector('button').innerHTML='<span class=\'spinner-border spinner-border-sm me-2\'></span>Resetting&hellip;';">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-warning">
<i class="bi bi-arrow-clockwise me-1"></i>Reset Demo Data
</button>
</form>
</div>
</div>
</div>
}
@section Scripts {
<script>
$(document).ready(function () {
@@ -22,9 +22,10 @@
var _bsTheme = (_pclSurface == "ink") ? "dark" : "light";
var hasProfilePic = User.FindFirst("HasProfilePicture")?.Value == "true";
var _envName = _hostEnv.EnvironmentName; // Development, Staging, Production, etc.
var _isNonProd = !_hostEnv.IsProduction();
var _envColor = _envName.ToLower() switch
var _envName = _hostEnv.EnvironmentName; // Development, Staging, Production, etc.
var _isNonProd = !_hostEnv.IsProduction();
bool _isDemoCompany = false; // suppresses env banner for the demo tenant
var _envColor = _envName.ToLower() switch
{
"development" => "#b45309", // amber-700
"staging" => "#7c3aed", // violet-700
@@ -53,8 +54,9 @@
var company = await UnitOfWork.Companies.GetByIdAsync(impersonatedId.Value, ignoreQueryFilters: true);
if (company != null)
{
companyHasLogo = !string.IsNullOrEmpty(company.LogoFilePath) || (company.LogoData?.Length > 0);
logoVersion = (company.UpdatedAt ?? DateTime.UtcNow).Ticks;
companyHasLogo = !string.IsNullOrEmpty(company.LogoFilePath) || (company.LogoData?.Length > 0);
logoVersion = (company.UpdatedAt ?? DateTime.UtcNow).Ticks;
_isDemoCompany = company.CompanyCode == "DEMO";
}
}
}
@@ -71,10 +73,14 @@
if (companyId.HasValue && companyId.Value > 0)
{
var company = await UnitOfWork.Companies.GetByIdAsync(companyId.Value, ignoreQueryFilters: true);
if (company != null && (!string.IsNullOrEmpty(company.LogoFilePath) || (company.LogoData != null && company.LogoData.Length > 0)))
if (company != null)
{
companyHasLogo = true;
logoVersion = (company.UpdatedAt ?? DateTime.UtcNow).Ticks;
_isDemoCompany = company.CompanyCode == "DEMO";
if (!string.IsNullOrEmpty(company.LogoFilePath) || (company.LogoData != null && company.LogoData.Length > 0))
{
companyHasLogo = true;
logoVersion = (company.UpdatedAt ?? DateTime.UtcNow).Ticks;
}
}
}
}
@@ -86,9 +92,10 @@
var company = await UnitOfWork.Companies.GetByIdAsync(companyId.Value, ignoreQueryFilters: true);
if (company != null)
{
companyName = company.CompanyName;
companyName = company.CompanyName;
companyHasLogo = !string.IsNullOrEmpty(company.LogoFilePath) || (company.LogoData != null && company.LogoData.Length > 0);
logoVersion = (company.UpdatedAt ?? DateTime.UtcNow).Ticks;
logoVersion = (company.UpdatedAt ?? DateTime.UtcNow).Ticks;
_isDemoCompany = company.CompanyCode == "DEMO";
}
else
{
@@ -153,7 +160,7 @@
--sidebar-hover: rgba(255,255,255,0.07);
--primary-color: #4f46e5;
--primary-hover: #4338ca;
--env-banner-height: @(_isNonProd ? "32px" : "0px");
--env-banner-height: @((_isNonProd && !_isDemoCompany) ? "32px" : "0px");
}
* {
@@ -942,7 +949,7 @@
<script>
(function(){var s='@_serverNavMode',p=localStorage.getItem('pcl-nav-mode')||'ops';document.documentElement.dataset.navMode=s==='fin'?'fin':p;})();
</script>
@if (_isNonProd)
@if (_isNonProd && !_isDemoCompany)
{
<div style="position:fixed;top:0;left:0;width:100%;height:var(--env-banner-height);z-index:2000;
background:@_envColor;color:#fff;