renderReportPdf now matches the on-screen comparison: when a comparison period
is active it renders Amount | Comparative | Change | Change % columns (was
Previous | Amount), switches to landscape for room, and underlines each numeric
column on totals. Applies to P&L, Cash Flow, Movement of Equity, and Balance
Sheet exports.
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>
- post_transaction_gl counter priority fixed: customer->A/R, then coa->that
account (direct categorized expense/income), then uncategorized vendor->A/P.
Previously any vendor payment went to A/P, driving A/P negative and hiding the
real expense account. The 38 direct vendor payments now post to their expense
accounts; A/P went from -5,895.79 to +3,099.29 (real open payables).
- sync_public_bill now maps the public bill's expense_account_id to the matching
accounting expense account (by name) on the bill line item, so synced bills
stop defaulting to "Administrative". Expenses now spread across Attorneys Fees,
Electric, Lawn Service, Management Fees, Water, etc.
- Verified managed companies: R1=0, R7=0. R8 surfaces a real $1,029.17 residual
(bills marked paid whose payments were entered as direct expenses, not A/P
settlements) — surfaced in the Reconciliation report, not plugged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: accounting.transactions (deposits, transfers, bank payments) never
posted to the GL, and the GL's cash came only from synthesized legs that
hard-coded Undeposited Funds. So the balance sheet ignored transfers (#1) and
showed directly-deposited funds as Undeposited (#2), with banks going negative.
- Post the bank register to the GL: customer receipt -> Dr bank/Cr A/R, vendor
payment -> Dr A/P/Cr bank, categorized -> Dr/Cr bank+COA, transfer -> Dr dest/
Cr source, deposit -> Dr bank/Cr Undeposited; payments_received -> Undeposited.
Retire the synthesized invoice/bill cash legs (acmacc_invpay/billpay) so cash is
sourced once, from the register. Triggers on transactions/deposits keep it live.
- Fix gl_managed: make it an explicit accounting.companies.gl_auto_post flag
instead of inferring from null-source journal entries (a single manual journal
entry had silently disabled all automation for Ashley Manor).
Verified (Ashley Manor): transfer reflected (Cogent +47,127 vs prior -3,521),
deposits land in BOA (Undeposited cleared), R1=0, R7=0, no negative banks.
Imported companies (Bridgewater/Bent Oak) untouched; their residuals stay
surfaced in the Reconciliation report.
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>
Add a "Allow document & bid/quote uploads" toggle on board member profiles
(board_members.can_upload). When enabled, that board member can upload
association documents and create/manage bids & quotes for their association(s);
otherwise the board portal stays read-only for them.
- Migration (prod): board_members.can_upload column; tighten the documents
insert + storage 'files' upload policies to require can_upload; add a
bids_quotes board policy gated on can_upload.
- BoardMembersPage: permission switch (load/save).
- BoardAssociationContext: expose canUpload for the selected association.
- DocumentsPage: board upload gated by the flag (was always-on for board).
- BidsQuotesPage: permitted board members can add/manage bids (was hidden);
board inserts target the board's association.
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>
The P&L and Balance Sheet are GL-driven, but invoices/payments/bills never
posted to journal_entries (the referenced syncBillsInvoicesToLedger was never
built), so accounts with no GL activity showed $0 and were hidden.
Adds an idempotent GL posting engine (migration applied to prod), scoped to
companies whose GL is "managed" (no imported/foreign journal entries) to avoid
double-counting Bridgewater/Bent Oak:
- invoice -> Dr Accounts Receivable / Cr income (keyword-mapped, default Assessment Fees)
- payment -> Dr Undeposited Funds / Cr Accounts Receivable
- bill -> Dr expense (bill_items) / Cr Accounts Payable (+ paid leg to bank)
Auto-creates AR (1100) / AP (2000) where missing. AFTER triggers on
invoices/payments_received/bills keep the GL in sync; existing docs backfilled.
Verified debits=credits and the balance-sheet invariant holds.
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>
- Homeowner "Export/Email Statement" now uses the same generateLedgerStatement
layout as the main-app account statement (account holder, amounts-due
breakdown, categorized columns incl. Pay (AR), no cover page) instead of the
branded-cover table.
- Ledger view: default the "To" date to the latest entry when it's beyond
today, so a payment dated when an invoice was marked paid (updated_at) is no
longer filtered out of the rows / Total Paid.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The customer Ledger tab + statement defaulted to the current calendar year,
so older payments looked missing and didn't line up with the main-app owner
ledger (all-time). Default the "From" date to the earliest transaction
(user can still narrow), so the accounting ledger/statement matches the
main owner ledger.
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>
Migration applied to prod: approved/paid public.bills mirror into
accounting.bills (Payables) with find-or-create vendor + line item
(external_source='acmacc_bill'/'acmacc_vendor'). When an accounting bill is
marked paid (paid_amount>=total), the linked public.bills is set status=paid
(+paid_date, amount_paid) and its bill_approvals marked paid. Loop-guarded
with is-distinct-from. Backfilled 370 bills/45 vendors; totals reconcile.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1: gate the Accounting sidebar item and /dashboard/accounting route
behind isAdmin via a RequireAdmin guard; Financial Reports stay visible.
Phase 2: platform associations now read the Chart of Accounts from
accounting.accounts (single source) instead of public.chart_of_accounts.
Shared fetchChartOfAccounts() normalizes both sources; central COA hooks
and ChartOfAccountsDropdown route through it (reads only, no migration).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mergeHomeownersByAddress reassigned invoices/transactions/work_orders/
estimates but missed payments_received, orphaning payment references on
the deleted duplicate. Add it to the FK reassignment list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds DB triggers + backfill so accounting.customers is driven by the
public units/owners roster: one customer per unit, all owners combined,
Units/Owners as source of truth for contact fields. Balances and ledger
links (invoices, payments_received, transactions, work_orders, estimates)
are always preserved. Scoped to associations with an accounting company.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>