Add explicit CompanyId to tenant-scoped FindAsync queries (partial sweep)

Multi-tenant defense-in-depth sweep, FindAsync/FirstOrDefaultAsync vector.
Adds explicit CompanyId predicates to list/index/validation queries that
previously relied only on the global tenant filter (exposure: raw
platform-admin sessions where the filter is bypassed).

Done this pass:
- Financial: Budgets, CreditMemos, FixedAssets, GiftCertificates,
  TaxRates, PricingTiers, VendorCredits, Accounts (year-end close),
  Invoices (tax-rate default, merchandise).
- Operational: Inventory (bin/sample-panels/vendors/usage-edit),
  OvenScheduler (ovens/batches/queue), Customers (pricing tiers),
  InAppNotifications (mark-all-read), CatalogItems (by-category /
  merchandise / price-check lists).
- AI: AiQuickQuote and Quotes (powder cost, predictions, walk-in
  customer, benchmark), Reports (budgets, 1099 vendors).

Child-by-parent-FK and by-PK queries were left as-is (already scoped via
the verified parent). Builds clean; 293 unit tests pass.

REMAINING (next session): ReportsController.Analytics powder-usage query
(line ~593) and the ~20 CompanySettings delete-protection Count/Any +
dup-code checks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 16:53:29 -04:00
parent 7c0357b4c5
commit c0d3a30176
17 changed files with 62 additions and 43 deletions
@@ -474,7 +474,7 @@ public class AccountsController : Controller
public async Task<IActionResult> YearEndClose()
{
var companyId = _tenantContext.GetCurrentCompanyId() ?? 0;
var history = (await _unitOfWork.YearEndCloses.FindAsync(y => true, false, y => y.JournalEntry))
var history = (await _unitOfWork.YearEndCloses.FindAsync(y => y.CompanyId == companyId, false, y => y.JournalEntry))
.OrderByDescending(y => y.ClosedYear)
.ToList();
@@ -499,7 +499,7 @@ public class AccountsController : Controller
var companyId = _tenantContext.GetCurrentCompanyId() ?? 0;
// Idempotency check
var existing = (await _unitOfWork.YearEndCloses.FindAsync(y => y.ClosedYear == year)).FirstOrDefault();
var existing = (await _unitOfWork.YearEndCloses.FindAsync(y => y.CompanyId == companyId && y.ClosedYear == year)).FirstOrDefault();
if (existing != null)
{
TempData["Error"] = $"{year} has already been closed (JE {existing.JournalEntryId}).";