Commit Graph

2 Commits

Author SHA1 Message Date
spouliot 7576761b70 Scope GL posting account lookups by CompanyId; cap sales-tax remittance (audit O3, O4)
O3: defense-in-depth on the write/posting path. Finding #7 scoped the report
(read) path; this scopes every GL posting-path account lookup that determines
where money lands, so a SuperAdmin acting in a company context can never post to
another tenant's account:
  - InvoicesController: all account-resolver helpers (checking, customer deposits,
    sales returns, customer credits, AR, bad debt, sales tax, sales discount, GC
    liability) plus the bank-account and write-off expense dropdowns
  - CreditMemosController: Create/Apply/Void GL lookups (scoped via the in-scope
    customer/invoice/memo)
  - GiftCertificatesController: Create/BulkCreate/Void GL lookups + GC liability helper
  - BillsController: AP/expense account resolution that pre-fills APAccountId
DepositsController and JournalEntriesController.SalesTaxPayment were already scoped.

O4: SalesTaxPayment now rejects a remittance greater than the outstanding Sales
Tax Payable balance (0.005 rounding tolerance), so a typo can no longer drive
2200 into an abnormal debit balance.

Remaining pure read-path dropdown lookups (app-wide, lower risk) are documented
in docs/ACCOUNTING_AUDIT.md as a separate follow-up. All audit findings O1-O4 are
now resolved. Build clean; 291 unit tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:48:53 -04:00
spouliot 1005be0c9e Fix Customer Deposits account mislabel and Sales Discounts recalc (audit O1, O2)
O1: account 2300 has always been used by the deposit GL code as the Customer
Deposits liability (resolved by number), but it was seeded/named "Payroll
Liabilities" for tenants the AccountingDepositsGL migration's NOT EXISTS guard
skipped — so the liability was mislabeled on the balance sheet. Rename 2300 to
"Customer Deposits" (IsSystem) and move payroll to a new 2400 account:
  - both seed paths (SeedDataService.Accounts, SeedData)
  - EnsureSystemAccountsAsync self-heal (renames only where still default-named,
    preserving user renames; ensures 2400 exists)
  - migration RenameDepositsAccountAddPayroll for existing tenants
Account number 2300 is unchanged, so the deposit posting code needs no changes.

O2: LedgerService never recomputed 4950 Sales Discounts, so "Recalculate
Balances" wiped it to JE-only and the Balance Reconciliation report showed false
drift. Add a 4950 section to GetAccountLedgerAsync and ComputePriorBalanceAsync
that reproduces the actual postings (invoice discounts DR + credit-memo issuance
DR, less the unapplied remainder of voided memos CR), matching AccountBalanceService.

Adds a LedgerService regression test for 4950. Documents both fixes plus the
remaining open findings (O3, O4) in docs/ACCOUNTING_AUDIT.md so the audit is no
longer lost. Build clean; 291 unit tests pass; migration applied.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:37:57 -04:00