Accounting audit fixes: revenue default IsActive + deposit account guard

Audit of this session's accounting changes (sub-type→type dropdowns,
deposit account picker, default GL accounts) found no ledger-drift bugs.
Two fixes applied:

- Default revenue account now requires IsActive (mirrors the 4000
  fallback), so a deactivated default isn't silently posted to.
- DepositsController.Record blocks recording when the 2300 Customer
  Deposits liability exists but no deposit/bank account resolves — that
  would post a one-sided entry. When 2300 doesn't exist (no accounting),
  nothing posts, so the deposit is still allowed.

ACCOUNTING_AUDIT.md updated: O9 footgun surface widened by the default-
accounts feature (now mitigated/documented), plus the 2026-06-20 review
notes and the resolved deposit-imbalance item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 10:23:47 -04:00
parent 58a0010ae8
commit 74d529f7d2
3 changed files with 51 additions and 3 deletions
@@ -413,10 +413,13 @@ public class InvoicesController : Controller
: new Dictionary<int, CatalogItem>();
// Fall back to the company's configured default revenue account when a catalog item
// has no specific account; if none is configured, fall back to the seeded 4000 account.
// has no specific account; if none is configured (or it has since been deactivated),
// fall back to the seeded 4000 account. The IsActive check mirrors the 4000 lookup so a
// deactivated default doesn't keep being posted to.
Account? defaultRevenueAccount = null;
if (prefs?.DefaultRevenueAccountId != null)
defaultRevenueAccount = await _unitOfWork.Accounts.GetByIdAsync(prefs.DefaultRevenueAccountId.Value);
defaultRevenueAccount = await _unitOfWork.Accounts.FirstOrDefaultAsync(
a => a.Id == prefs.DefaultRevenueAccountId.Value && a.IsActive);
defaultRevenueAccount ??= await _unitOfWork.Accounts
.FirstOrDefaultAsync(a => a.AccountNumber == "4000" && a.IsActive);