The AR Aging, Invoice Summary by Customer, Homeowner Summary, and
Delinquency reports computed open A/R as total - paid_amount across all
invoices, which counted (1) voided invoices and (2) ledger-synced "paid"
invoices whose paid_amount was left at 0. Both showed huge phantom
past-due balances even when everything was paid.
Add a shared invoiceOpen() helper that treats void/paid/draft invoices as
zero open (status is the source of truth, since paid_amount is unreliable
on synced invoices) and apply it to all A/R computation sites plus the
reconciliation control. Also drop voided invoices from the flat Invoice
Summary list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The monthly P&L was bound to the page Period, which defaults to the
current month — so 'Monthly columns' showed only a single column. When the
selected period is a single month, widen the start to the fiscal year
containing the end date (per company fiscal_year_start) so every month of
the FY-to-date gets a column with none missing. A multi-month selected
range is still respected as-is.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The page-level exporter wasn't reliably producing the Reconciliation
Checks PDF. Add a dedicated 'PDF' button inside the report card that
generates it directly from the checks (Check/Assertion/Residual/Status,
failing rows in red), independent of the toolbar export path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Apply the grey gradient + vertical borders to the Actual/Budget/Variance/
% of Budget columns in the PDF export (generateBudgetVsActualPdf), and
revert the on-screen table to plain styling.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extracted the check computation into buildReconChecks() and exposed it
to the report exporter (exportFlat), so the Reconciliation Checks report
now downloads as a branded PDF/CSV (Check · Residual · Status) like the
other reports.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
B/S line items now render as '3011 SIRS Reserves - 3066 Painting/
Waterproofing' — leaf code+name prefixed by parent code+name when the
account has a parent, sorted so siblings group under their parent. Adds
parent_account_id to the reports accounts fetch. Codes always show
(baked into the label). Budget vs Actuals already shows codes + parent
hierarchy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Budget vs Actuals: shade the Budget / Actual / Variance / Variance % columns
in a light→dark grey gradient with left vertical borders so they're easy to
tell apart (shared BVA_COL styles applied to header, group-total and detail
rows; variance text bumped to emerald/red-700 for contrast on the darker fills).
Reconciliation R2: reconcile() classified GL lines via the active-only account
list and dropped lines on archived accounts, so the "Assets = Liabilities +
Equity (incl. net income)" check went out of balance by the archived balance
(e.g. VW's archived 4016 Renters Insurance Income, -$75). Feed reconcile any
account referenced by glCumulative but missing from the active list (joined
metadata), matching the Balance Sheet builder; once every line is typed, R2
reduces to R1 and passes whenever the ledger balances. Also tightens R3/R4.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Budget column overlap-weighted partial months, so a YTD range
ending mid-month showed a fractional budget. Now include each budget
period's full amount whenever the selected window touches it, for both
the main and comparison windows — exactly as entered on the budget.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The accounting Budget vs. Actuals report computed actuals from
operational tables (bill_items + payment transactions + a
budget-weighted paid-invoice plug), which double-counted (a bill
counted as its line item AND its payment, plus redundant imported
bills) and diverged from the posted books — especially for Buildium
GL-import / import-mode associations whose activity lives only in
journal entries.
Now fetch GL lines via fetchAllGLLines and net per account
(income = credit - debit, expense = debit - credit), matching the
Income Statement. Budget side was already correct (reads active
accounting.budgets + budget_entries).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An archived COA account that still carried a GL balance was dropped from the
Balance Sheet (fetchAllGLLines filtered is_archived=false), so the report went
out of balance by exactly that amount. Now the financial-report GL fetches
include archived accounts (those without activity never appear, since this
queries journal lines), and buildBalanceSheet surfaces archived asset/liability
/equity accounts that carry a balance as line items; archived income/expense
flow into Net Income. Fixes the Village Woods $170.30 out-of-balance and the
same latent issue in Bent Oak and Casuarina.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expense Summary kept billed-date recognition but counted bills the
association hasn't paid yet. Back out the unpaid (prorated) portion of
period bills per expense account, so the report reflects amounts actually
paid. Direct payments are unaffected (cash already out). Bent Oak's open
5/27 City of Titusville water bill ($136) now drops out: Water/Sewer
757.25 -> 621.25.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Income Statement was a duplicate of the P&L, so removed it from the report
menu. The P&L now has a 'Monthly columns' toggle that renders the same
multi-period (by month/quarter/year) breakdown the income statement provided —
relabeled 'Profit & Loss'. Default P&L view is unchanged (single period).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Prior-reconciliation 'View Report' PDF was hard-coding empty uncleared lists,
so outstanding items never appeared. It now reconstructs the items outstanding
as of that statement (dated on/before the statement date, not voided, and not
cleared in that or an earlier reconciliation) and includes them, with the book
balance reflecting them.
- Balance Sheet equity folding matched any name containing 'retained earnings'
(or 'current year earnings'), so a distinct account like 'Retained Earnings
Savings' was swallowed into the calculated line and never shown. Now only the
exact standard accounts fold; other equity accounts render on their own line.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. Reconciliation now shows ALL outstanding (unreconciled) items on/before the
statement date, including ones from prior periods — removed the prior-recon
date floor. Finalized items still drop off (they carry a reconciliation_id).
2. Void transactions in Banking and Reconciliation. New accounting.transactions
.voided flag (+ voided_at/by); voided rows stay visible (strikethrough + VOID
badge) but are excluded from the running balance, register totals, cached
account balance, and reconciliation. post_transaction_gl reverses the GL for
gl_managed companies; un-void supported from Banking.
3. Unified report filters: the single Period bar on the Reports page now drives
every report. General Ledger, Trial Balance, AR Aging (Property), Pre-Paid
Homeowners, Cash Disbursement, and Reserve Fund no longer have their own date
pickers — they consume the shared from/to (range) or to (as-of).
4. Accrual only: removed the cash-basis toggle from Trial Balance and General
Ledger (the data was always accrual GL anyway; the cash label was misleading).
All income/expense reports recognize on billed/issue date.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause of filters conflicting between pages: many accounting pages shared
the same React Query keys (['accounts',cid], ['bank-accounts',cid],
['deposit-accounts',cid]) while running DIFFERENT queries, so whichever page
loaded first poisoned the others' cache (e.g. bill payment picker showing
banks-only with no equity; archived accounts leaking from the CoA list).
- Give every account read query a unique key discriminator per page/purpose;
['accounts',cid] / ['bank-accounts',cid] / ['deposit-accounts',cid] stay as
invalidation prefixes (React Query partial match) so cross-page refresh still works
- Bill line-item category picker now includes expense + asset + equity + liability
(was expense-only) — fixes 11 bills/13 lines categorized to equity (reserve-funded)
that showed blank/—; and lets you assign an equity account to a bill
- Payment account picker (bills + expenses) reliably shows banks + equity now that
it no longer collides with the banks-only deposit/receive-payment pickers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- accounting.report_batches (name + ordered report_ids per company, member RLS)
- batchReports.ts engine: cover page + each report on a fresh page + one global
Page X/Y footer. Financial four reuse the page's fetchReportData/buildFinancial
(injected to avoid an import cycle); Trial Balance, General Ledger, Cash
Disbursement, AR Aging, Pre-Paid, Reserve Fund built from the same source data
- Reports page: Report Batches dialog (name, ordered report checklist, saved
batches load/delete, Save, Generate PDF); page now defaults to This Month
- reportPdf.appendStructuredReportPdf used for the financial sections
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- fetchAllGLLines filters accounts.is_archived=false, covering P&L, Balance
Sheet, Cash Flow, Movement of Equity and Income Statement in one place
- Trial Balance, Reserve Fund Schedule and Budget vs Actuals account lists
exclude archived; Banking page hides archived accounts from cards/pickers
- General Ledger report intentionally keeps archived accounts (history)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Buildium-style reports built on the owner ledger and GL:
- AR Aging (Property): FIFO-aged buckets (0-30/over 30/60/90) per unit with
charge-type breakdown, collection status, summary + distribution bar
- Pre-Paid Homeowners: units with net credit balances as of a date
- Cash Disbursement: bank-credit GL entries grouped by bank account with
check#/vendor/invoice enrichment from the banking register and GL line detail
All with branded PDF/CSV exports; shared owner-ledger helpers in lib/ownerLedger.ts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Group the multi-period Income Statement by account category (Operating Income,
Administration, Utilities, Reserves Budget, …) with "Total for <category>"
subtotals, matching the Buildium layout, in the on-screen table, PDF, and CSV.
- New accounting.accounts.category column (nullable; null = ungrouped), seeded
from the local chart_of_accounts parent hierarchy.
- Editable in Chart of Accounts: single-edit (with datalist autocomplete) and
bulk-edit (blank = no change, __clear__ to unset).
- buildium-account-categories edge function pulls each account's parent-GL
category from Buildium (matched by code, fallback name) and backfills
accounting.accounts.category; idempotent and re-runnable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New "Income Statement" report with a By Month/Quarter/Year selector that lays
out income/expense accounts in period columns plus a Total column, with Total
Income / Total Expense / Net Income rows. Built from the GL over the selected
range; includes branded PDF and CSV export. Accounts are listed flat under
Income/Expense for now (category subgroups to follow once accounts are
categorized).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PostgREST caps each response at 1000 rows. The P&L and Balance Sheet
fetch every journal_entry_line for the company and aggregate client-side,
so any association with >1000 GL lines (e.g. an imported Buildium GL) only
saw the first 1000 — accounts whose activity fell past that point read as
$0 and were hidden, making reports look empty/out-of-balance. Fetch the GL
in 1000-row pages ordered by a stable key so every line is included.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Journal Entries: add Edit (row + detail drawer) that loads an entry into the
form and saves changes (updates the entry and replaces its lines). Warns when
editing an auto-generated entry (may be overwritten by its source sync).
- Reports: add a Refresh button that re-fetches the underlying data so the
report reflects the latest GL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The auto-provision effect could fire twice and create duplicate "Current Year
Earnings" accounts (seen on Village Grove). Use the idempotent
coa_get_or_create RPC with a once-per-company ref guard, and match existing
name variants (Current Year Income / Net Income / Retained Earnings) so it
won't create redundant accounts. Balance sheet now also folds
"Current Year Income"/"Net Income" equity accounts into the Net Income line.
Removed the existing Village Grove duplicate (zero activity).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auto-provision "Retained Earnings" and "Current Year Earnings" equity accounts
per company so they appear as inputtable rows in the Chart of Accounts Opening
Balances grid. The Balance Sheet folds the posted "Current Year Earnings"
account into the Net Income line (already did this for Retained Earnings), so a
mid-year import can seed both equity figures without entering income/expense
detail, and Total Equity stays balanced.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A real "Retained Earnings" equity account is postable via journal entries, but
the balance sheet listed it separately from the calculated "Retained Earnings
(prior years)" line, so JE adjustments looked like they had no effect there.
Now the posted RE-account balance is added into the "Retained Earnings (prior
years)" line (and removed from the generic equity list). Total Equity is
unchanged — it already included that account.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The equity section already carried a permanent current-year earnings line
(income − expenses for the fiscal year to date); rename it from "Current Year
Earnings" to "Net Income" to match the Movement of Equity report and the
requested terminology. No calc change — still YTD income minus expenses,
included in Total Equity.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add Sales Receipts page (dashboard/accounting/sales-receipts): records a
cash sale (name, address, income account, price, qty) — deposits and books
income in one step via a transaction. New accounting.sales_receipts table.
- Sync chart of accounts to the accounting dashboard: mirror accounting.accounts
into public.chart_of_accounts for platform associations (one-way, same id) so
Bill Approvals and every COA consumer use the dashboard's accounts. Legacy
rows hidden; Bill Approvals made system-aware.
- Vendor-expense recognition: a vendor payment with no bill now books the
expense directly (Dr Expense / Cr Bank) on the payment date instead of going
to A/P; payments against open bills still clear A/P (applied FIFO). Backfill
reclassifies unbilled payments stuck in A/P. Expense Summary report made
GL-driven so it follows the same rule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- P&L and Balance Sheet account rows are now clickable and open the
General Ledger filtered to that account (its transaction list for the COA).
Adds StructuredRow.accountId, threaded from the report builders, with a
clickable row in StructuredTable and an initialAccountId prop on
GeneralLedgerReport.
- Bids/Quotes: PDF upload on the New Bid/Quote dialog (bid-attachments
bucket + document_url/document_name columns), shown as a link on the
bid Details dialog.
Migration applied: bids_quotes_pdf_attachments.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove the Zoho Books integration (edge functions, sync libs, settings,
reports/overview, banking links, fees tab, import dialog); preserve fee
rules as a standalone FeesTab and the COA accounting_system classification.
- Financial Overview/Reports (staff + board) render the Accounting dashboard
and reports; board reports mirror the rich Accounting Reports.
- New Reserve Fund Schedule report + an is_reserve flag on accounts.
- Unify all report exports to a branded format (logo + centered header +
footer): shared ReportSheet (on-screen) and reportHeader (PDF). Budget vs
Actuals and Bank Reconciliation PDFs now match the reference layout.
- Render financial reports inline (no preview pop-up).
- Budget Management mirrors Accounting Budgeting (staff-accessible) with SPA
navigation; editable bills in the Accounting Bills page.
- Negative opening balances flow through to the GL and reports (allow negative
input; keep non-zero on save; signed CSV import).
- Upload a per-account trial balance via CSV on Opening Balances.
- Board members: read-only RLS access to their association's accounting ledger;
editable board-members panel on the association page; share vendor contacts
with the board (toggle + directory section).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Movement of Equity derived net income from sub-ledgers (calcNetIncome over
invoices/expenses/bills), while the P&L and Balance Sheet use the GL. With any
direct bank-categorized income/expense the two disagreed — Ashley Manor's SCE
was off from the Balance Sheet equity by 9,257.44. Rebuild Movement of Equity
from the GL (current-year earnings + GL equity balances) so all three statements
tie by construction.
Complete the §9 reconciliation matrix: R3 (P&L net income == raw-GL period net
income — guards the P&L builder) and R5 (Movement of Equity ending == Balance
Sheet total equity) are now computed by cross-checking the report builders against
the raw GL; checks render in numeric order. R6 (GL == TB/BS, satisfied by
construction) and R9 (direct vs indirect CFO, only indirect built) shown as N/A
for matrix completeness. Adds 5 reconcile unit tests (12 total).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bridgewater's GL was imported as single-sided postings missing its opening fund
balance, leaving the trial balance off by 130,348.76 with an abnormal debit
equity balance. Record the gap as an Opening Fund Balance equity credit (migration
20260602150000); R1 and the Balance Sheet now tie out exactly.
A/R-A/P sub-ledger checks (R7/R8) only apply to platform-managed companies whose
invoices/bills post to the GL. Imported-GL companies (Bent Oak, Bridgewater) keep
their own AR/AP, so scope R7/R8 to gl_managed companies (new arApApplicable flag
on reconcile + gl_auto_post surfaced in useReportData). Every company now passes
the Reconciliation report.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- StructuredTable now renders Comparative + Change + Change % columns when a
comparison period is on (P&L, Cash Flow, Movement of Equity, Balance Sheet).
- Balance Sheet supports an as-of comparison period (prior as-of balances per
account + totals); comparison toggle enabled for it (buildBalanceSheet takes
prior dataset). Current Year Earnings stays independently computed.
- Budget vs Actuals: optional "Compare to" date range adds Compare + Δ-vs-Compare
columns; actuals computation factored into a shared helper for both windows.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Cash Flow Statement now supports a comparison period (prior-period/prior-year/
custom): refactored into computeCashFlow() and renders the comparison column
for Net Income, CFO/CFI/CFF, beginning/ending cash. Previously it ignored the
compare toggle. (P&L and Movement of Equity already had comparison.)
- Budget vs Actuals: budget is now pro-rated to the selected actuals window
(sum each budget period weighted by overlap with the range) instead of always
using the full annual figure — honors monthly/quarterly/annual period_type.
Noted in the on-screen card and the PDF header (B4).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add From/To date inputs to the Budget vs Actuals report (Accounting section
Reports) so actuals can be compared to the budget over any custom range,
independent of the page period preset. Defaults to the report period; drives
the actuals queries and CSV/PDF export labels.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In the Accounting section Reports (AccountingReportsPage):
- Rebuild the Cash Flow Statement as an indirect-method report derived from the
GL: Net Income + working-capital/non-cash movements, classified into
CFO/CFI/CFF, with Beginning/Ending Cash. Ties to the change in Balance Sheet
cash by construction (R4); surfaces an explicit residual row if it ever doesn't.
- Add R4 to the Reconciliation Checks report.
- Extract the reconciliation matrix into a pure, tested library
(lib/reconcile.ts) and route the Reconciliation report through it.
- Add §10 synthetic-ledger vitest suite (lib/reconcile.test.ts): empty, single
balanced entry, full period, partial settlement (open vs gross §1.5), and
fault ledgers (single-sided → R1; payment-not-applied → R7). Verified R4 ties
for Ashley Manor ($35,727.08 = ΔCash).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per the Financial Reports Master Spec:
- §1.5 A/R fix: invoice settlements now post to the GL (Dr Undeposited / Cr A/R
from invoice.paid_amount); payments are the cash sub-ledger only and no longer
separately credit A/R (avoids double-count). A/R control = open balance, so
recon R7 passes for managed companies (Ashley Manor 39,248 -> 0). Bills already
settled (R8 ok). Migration applied + backfilled managed companies.
- §9/§10: add a "Reconciliation Checks" report that surfaces R1/R2/R7/R8
residuals (never plugged) so imbalances are visible — e.g. Bridgewater's
imported GL is unbalanced (R1) and its sub-ledgers don't tie (R7/R8).
Imported companies (Bridgewater/Bent Oak) left untouched per decision; their
residuals now surface in the Reconciliation report.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Opening balances now post a single "Opening Balances" journal entry to the GL
(migration applied to prod), scoped to managed companies (imported-GL
associations already carry theirs). Triggers on opening_balances /
opening_balances_setup keep it in sync; Ashley Manor backfilled.
- Balance Sheet: read balances from the GL only (drop the separate opening add,
which also double-counted imported companies).
- Trial Balance: compute balances from journal_entry_lines as of the report date
(was accounts.balance).
- General Ledger report: read from journal_entry_lines (was transactions); opening
rolls in from the GL.
All four reports now share one source. Verified Ashley Manor TB balances
(debits = credits = $90,073.23) with opening cash (BOA +$47,304.31) flowing through.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Drop the branded cover page from all financial/accounting report exports
(P&L, Balance Sheet, Cash Flow, Movement of Equity, AR/AP flats, Trial
Balance, General Ledger, Budget vs Actuals, and the Zoho/Board financial
reports). The general Report Generator's own cover is unchanged.
- Budget vs Actuals now orders accounts as a parent→child tree with
indentation (on screen and in CSV/PDF) instead of flat by account number.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Budget vs Actuals now exports (CSV + branded PDF); previously the page's
export buttons were disabled for it. Wired into hasOwnExport with its own
buttons in the report.
- Apply the shared branded cover page to the remaining PDF exports so they
match the main scheme: homeowner account Statement (AccountingCustomer
DetailPage), Trial Balance, and General Ledger.
Note: payments already render on the accounting customer ledger/statement
via payments_received (phase 3+4).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extract the general Report Generator's branded cover (cover image/band,
logo, title, prepared-for/by) into shared src/lib/reportCover.ts. Financial
reports now open with the same cover: platform AccountingReportsPage via new
renderReportPdfWithCover(), and the Zoho/Board financial reports
(zohoFinancialReportPdf generators). ReportGeneratorPage refactored to use
the shared module (removes duplicated cover code).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>