Add Phase A accounting features: AP Aging, Trial Balance, Cash vs Accrual

- AP Aging report (GetApAgingAsync, controller actions, view, PDF export)
  mirrors AR Aging — groups open bills by vendor, buckets by days past due date
- Trial Balance report (GetTrialBalanceAsync, view, PDF export)
  uses Account.CurrentBalance, groups by AccountType, validates debits == credits
- Cash vs Accrual accounting method setting on Company entity
  switchable at any time — report-time only, no GL re-posting on change
  P&L cash: revenue = payments received; expenses = bills/expenses paid in period
  Balance Sheet cash: omits AR and AP lines (no receivables/payables concept)
  AccountingMethod badge shown on P&L and Balance Sheet views
- Migration A (AddAccountingMethod) applied, default = Accrual for all existing companies
- AP Aging and Trial Balance added to Reports Landing page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 23:34:54 -04:00
parent 379b0de885
commit 7e1676cfd7
18 changed files with 10765 additions and 67 deletions
@@ -105,6 +105,13 @@ public class Company : BaseEntity
public bool MarketingEmailOptOut { get; set; } = false;
public string MarketingUnsubscribeToken { get; set; } = Guid.NewGuid().ToString("N");
/// <summary>
/// Determines whether financial reports (P&amp;L, Balance Sheet, Cash Flow) use
/// cash-basis or accrual-basis presentation. Switchable at any time — no GL
/// re-posting occurs. Default is Accrual (standard for most businesses).
/// </summary>
public AccountingMethod AccountingMethod { get; set; } = AccountingMethod.Accrual;
// Settings
public string? TimeZone { get; set; } = "America/New_York";
public byte[]? LogoData { get; set; } // Legacy - kept for backward compatibility
@@ -66,3 +66,16 @@ public enum BillStatus
Paid = 3,
Voided = 4
}
/// <summary>
/// Company-level accounting method preference. Affects how financial reports
/// (P&amp;L, Balance Sheet, Cash Flow) query and present data. Switching this
/// setting never re-posts historical GL entries — it is a report-time choice only.
/// </summary>
public enum AccountingMethod
{
/// <summary>Revenue and expenses recognised when cash changes hands.</summary>
Cash = 0,
/// <summary>Revenue and expenses recognised when earned/incurred (default).</summary>
Accrual = 1
}