Add company default GL accounts; move QB sign-fix to platform

Default accounts: companies can now set a default Revenue, COGS, and
Inventory account (Chart of Accounts -> "Default Accounts" card). Stored
on CompanyPreferences (3 nullable FKs + migration). Used as the fallback
when an item or invoice line leaves its account blank:
 - Invoice lines fall back to the default Revenue account, then to 4000.
 - New inventory/catalog items are pre-filled with the COGS/Inventory
   defaults, so the value is stored on the item and both live posting and
   the balance-recompute path stay consistent.
Blank defaults = unchanged behavior, so nothing changes until a company
opts in. Setting both COGS + Inventory enables perpetual-inventory COGS
posting (warned in the UI and help docs). Help KB + Settings article
updated.

Also moves the "Fix QB Import Signs" tool off the company Chart of
Accounts page (was CompanyAdmin-visible) to the SuperAdmin-only platform
Company Details page, operating on the target company.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 10:03:11 -04:00
parent 687aedf7a4
commit ee86d7aaf6
14 changed files with 11913 additions and 44 deletions
@@ -412,8 +412,12 @@ public class InvoicesController : Controller
.ToDictionary(ci => ci.Id)
: new Dictionary<int, CatalogItem>();
// Fall back to the default revenue account (4000) if a catalog item has no specific account
var defaultRevenueAccount = await _unitOfWork.Accounts
// 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.
Account? defaultRevenueAccount = null;
if (prefs?.DefaultRevenueAccountId != null)
defaultRevenueAccount = await _unitOfWork.Accounts.GetByIdAsync(prefs.DefaultRevenueAccountId.Value);
defaultRevenueAccount ??= await _unitOfWork.Accounts
.FirstOrDefaultAsync(a => a.AccountNumber == "4000" && a.IsActive);
// Deserialize the job's pricing snapshot up front — it is authoritative for discount,