Skip to content

Budget-Comparison Reports — Account Variance & Budget

Date: 2026-07-01

Problem / motivation

Peachtree's General Ledger and Financial-Statement sections compare actuals to a budget: Account Variance ("actual amount, budget amount, variance amount, and variance percent … by selected accounts"), the Budget report ("budget amounts for the period and year-to-date"), and the Income/Budget statement family. We ship Budgets (budgets + budget_lines, per account per period) and posted ledger actuals, so this joins the two into a variance report and surfaces the budget itself. Phase 3 of the Peachtree Report Parity tracker.

In scope

  • account_variance(budget_id, date_filter, start_period, end_period, account_types?, generate_csv) — per account: budgeted amount (sum of budget lines in the period range), actual (posted ledger activity in the account's natural balance direction over the date range), variance, and variance %. Optional account_types filter makes it serve the Income/Budget view (filter to revenue/expense).
  • budget_report(budget_id, generate_csv) — the budget's amounts per account per period (a flat listing the frontend can pivot to period + YTD).
  • Posted actuals only. Path.REPORTS. CSV-exportable.

Out of scope

  • Account Variance – Dual Budgets and the multi-column Income/Budget-YTD statement layouts — the underlying actual-vs-budget data is delivered here; the dual-budget/statement presentation is deferred.
  • Balance Sheet/Budget layout (same data restricted to balance-sheet accounts via account_types).

Data model changes

None. Reads budgets / budget_lines (account_id, period_number, amount) and posted ledger_entries / ledger_entry_lines joined to accounts. No migration, no new Path/Resource.

What's being implemented

  • Responsesapp/graphql/reports/strawberry/budget/budget_report_response.py (AccountVarianceLineResponse, BudgetLineReportResponse).
  • Repositoryapp/graphql/reports/repositories/budget/budget_report_repository.py (budget_by_account, actuals_by_account, budget_lines).
  • Serviceapp/graphql/reports/services/budget/budget_report_service.py (merges + natural-signs).
  • Queriesapp/graphql/reports/queries/budget/budget_report_queries.py.
  • Teststests/graphql/reports/test_budget_reports.py.

GraphQL surface

accountVariance(budgetId: UUID!, dateFilter: DateRangeFilter!, startPeriod: Int! = 1, endPeriod: Int! = 12, accountTypes: [AccountType!], generateCsv: Boolean! = false): GenericReportPage!
budgetReport(budgetId: UUID!, generateCsv: Boolean! = false): GenericReportPage!

type AccountVarianceLine { accountCode: Int!, accountName: String, accountType: AccountType!, budgetAmount: Decimal!, actualAmount: Decimal!, varianceAmount: Decimal!, variancePct: Decimal! }
type BudgetLineReport { accountCode: Int!, accountName: String, periodNumber: Int!, amount: Decimal! }

Frontend contract

  • Account Variance: pass a budget id, an actuals date range, and the fiscal period range for the budget columns; optional accountTypes to scope (e.g. revenue+expense for an Income/Budget view). actualAmount is already in each account's natural sign; varianceAmount = actual − budget.
  • Budget: flat BudgetLineReport rows (account × period); pivot client-side for period + YTD totals.
  • generateCsv: truecsvUrl.

Future additions

  • Dual-budget comparison and the multi-column Income/Budget-YTD statement layouts.