Enforce quarterly run limit on AI price check

- GET: sets ViewBag.NextRunAvailable if last run was within 90 days;
  view disables the button and shows the next eligible date
- POST: returns early with a warning if called before the 90-day window

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 22:48:39 -04:00
parent 03c10a3d77
commit 37c95192ca
2 changed files with 41 additions and 8 deletions
@@ -941,6 +941,13 @@ namespace PowderCoating.Web.Controllers
var pricedItems = await _unitOfWork.CatalogItems.FindAsync(ci => ci.IsActive && ci.DefaultPrice > 0);
ViewBag.ActiveItemCount = pricedItems.Count();
if (report != null)
{
var nextRun = report.RunAt.AddDays(90);
if (nextRun > DateTime.UtcNow)
ViewBag.NextRunAvailable = nextRun.ToLocalTime().ToString("MMMM d, yyyy");
}
CatalogPriceCheckReportDto? dto = null;
if (report != null)
{
@@ -988,6 +995,20 @@ namespace PowderCoating.Web.Controllers
var currentUser = await _userManager.GetUserAsync(User);
if (currentUser == null) return Forbid();
// Enforce quarterly run limit — check the most recent report for this company.
var lastReport = (await _unitOfWork.CatalogPriceCheckReports.FindAsync(
r => r.CompanyId == currentUser.CompanyId))
.OrderByDescending(r => r.RunAt).FirstOrDefault();
if (lastReport != null)
{
var nextRun = lastReport.RunAt.AddDays(90);
if (nextRun > DateTime.UtcNow)
{
TempData["Warning"] = $"Price check can only be run once per quarter. Next run available: {nextRun.ToLocalTime():MMMM d, yyyy}.";
return RedirectToAction(nameof(AiPriceCheck));
}
}
try
{
// Load active catalog items with a real price — skip $0 items (placeholders,
@@ -94,14 +94,26 @@
<a asp-action="Index" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left me-1"></i> Back to Catalog
</a>
<form asp-action="RunAiPriceCheck" method="post" id="runForm" class="run-btn-wrap">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-primary" id="runBtn"
data-item-count="@(ViewBag.ActiveItemCount ?? 0)">
<i class="bi bi-robot me-2"></i>
@(Model == null ? "Run Price Check" : "Re-run Price Check")
</button>
</form>
@if (ViewBag.NextRunAvailable != null)
{
<div class="text-end">
<button class="btn btn-primary" disabled>
<i class="bi bi-robot me-2"></i>Re-run Price Check
</button>
<div class="small text-muted mt-1">Next run available: @ViewBag.NextRunAvailable</div>
</div>
}
else
{
<form asp-action="RunAiPriceCheck" method="post" id="runForm" class="run-btn-wrap">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-primary" id="runBtn"
data-item-count="@(ViewBag.ActiveItemCount ?? 0)">
<i class="bi bi-robot me-2"></i>
@(Model == null ? "Run Price Check" : "Re-run Price Check")
</button>
</form>
}
</div>
@if (TempData["Success"] != null)