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>
Add a Payee / Payor column to the bank register (Banking), the reconciliation
list, and the Deposits 'awaiting deposit' list — showing the vendor (payee) for
money out or the customer/homeowner (payor) for money in. Expenses already shows
Vendor and Receive Payments shows Homeowner, so those were left as-is.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Editing a paid bill now updates the linked payment along with the bill: when the
amount changes and the bill has a single bill payment, the bank transaction, the
check, and the paid amount are all updated to the new total. The whole save is
wrapped in error handling and the bill_items insert is now error-checked, so any
failure surfaces a clear toast instead of silently appearing to 'not save'.
Also refreshes the transactions/accounts caches after a bill edit.
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>
Import-mode companies pull their GL from Buildium, so transactions entered
directly in Banking/Reconciliation never reached the GL — they reconciled but
were missing from GL-based reports (P&L etc.). This is why Bent Oak's May P&L
was missing Bank Interest and understated expenses.
- post_transaction_gl no longer gates on gl_managed; it posts any transaction
that isn't voided, Buildium-sourced (journal_entry_line_id set), frozen
(exclude_from_gl), a transfer/deposit leg, or missing an account/counter
- New accounting.transactions.exclude_from_gl flag freezes pre-existing manual /
duplicate register rows on already-tied books so they can't double-post
- One-time data ops: linked all Buildium-sourced register rows to their GL bank
line; froze remaining pre-existing manual rows for Bridgewater/Casuarina/
Village Grove (ambiguous, would risk double-count); posted Bent Oak's 4
verified-missing operating items. Bent Oak GL stays balanced.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Top-level grouping is now by vendor (name as the section header) with a
per-vendor subtotal, instead of by bank account. The bank account each payment
was drawn from moves to a column on the row. Vendor is resolved from the
reliable payment→vendor / payment→bill→vendor linkage; disbursements with no
vendor on record (e.g. Buildium GL-pull entries) collect under a 'No vendor on
record' group sorted last rather than being guessed. PDF + CSV updated to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Show outstanding items dated on/before the statement_end_date (prior periods
included), but hide anything dated after it — e.g. a 2/28/2026 statement shows
2/28 and earlier, nothing later.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A transaction's billed date no longer gates which reconciliation it can clear
in — items billed in one period frequently clear the bank in another. The
reconcile list now shows every uncleared, non-voided item for the account
(reconciliation_id is null), dropping the date <= statement_end_date ceiling.
Finalized items still carry a reconciliation_id and drop off.
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 'syncs stop at 5/31': the nightly buildium-gl-sync writes journal
entries (so reports stay current) but never created the matching bank-register
transactions for import-mode companies (gl_auto_post=false). Those registers were
materialized once at import, so the reconciliation/register views froze ~5/31
while the GL kept advancing.
- Add accounting.transactions.journal_entry_line_id (FK + unique index) to link
register rows to their source GL line, making materialization idempotent
- buildium-gl-sync now materializes a register transaction for each bank line it
inserts, for import-mode companies only (bank debit -> deposit/credit,
bank credit -> withdrawal/debit; category/coa from the single offset account),
upserting on journal_entry_line_id so re-runs never double-insert
- One-time backfill (run against prod) filled the existing gap: 231 register
rows across Bridgewater/Casuarina/Village Grove/Bent Oak, skipping 3 near-miss
rows that share a day with an existing register row (incl. a Casuarina transfer)
for manual review
gl_managed companies are unaffected — their register drives the GL via
post_transaction_gl, not the other way around.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Add Deposit/Withdrawal dialog on the reconciliation screen now shows a
required vendor dropdown for withdrawals (debits) and stores vendor_id on the
transaction, matching the vendor-required rule on Bills/Expenses/Banking.
Deposits (credits) are unaffected.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bill Approvals Create/Edit dialogs redesigned to the same professional
two-column Buildium layout used on the accounting Bills page: left
attachment panel (drag-drop + live image/PDF preview), right grouped form,
prominent blue total bar, primary-action-first footer
- Accounting backend payments now require a vendor chosen from the dropdown:
- Expenses: vendor is required; removed the free-text vendor fallback
- Bills: must pick a 'Pay to' vendor before saving
- Banking payments already enforced this
(Reconciliation bank adjustments — interest/service charges — intentionally
still allow no vendor, as they are not vendor payments)
- Board members remain locked to approving/denying their own assigned rows
plus commenting and submitting invoices (per request); all bill edits, GL,
line items, status, and deletes stay read-only for board users
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>
- Record/Edit dialog redesigned to a two-column layout: large attachment panel
(drop/preview/replace) on the left; Bill Details + Item Details table on the
right; prominent total bar; Save / Save & add another / Cancel footer.
Keeps AI parse, field highlighting, vendor mapping
- New read-only bill detail view (click a bill #/vendor): header with vendor +
status + Pay/Duplicate/Delete/Edit, Bill details card, item-details table,
and a Bill amount sidebar (Total / Paid / Remaining)
- duplicateBill clones a bill into a fresh create form
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Deposit / Withdrawal buttons in the statement-transactions header open a
dialog (date, amount, description, income/expense category, reference)
- New transaction posts to the bank account, is marked cleared, and is
auto-checked into the current reconciliation; category picker excludes bank
and archived accounts. gl-managed companies post the offset via the existing
transaction GL trigger; import-mode books add register-only (consistent with
Banking), so imported GL isn't double-counted
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Transactions on/before the last completed reconciliation's statement date no
longer reappear in a new reconciliation (date floor). Imported GL registers
were inserted cleared-but-unreconciled, flooding the list with prior-period
rows; reconciling now works period-by-period
- Sortable headers (Date / Description / Ref # / Deposit / Withdrawal) with
asc/desc toggle indicators
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>
- Shared PeriodPicker (default This Month); wired into General Ledger report,
Journal Entries page, and bank registers (Banking shows a Balance forward
row carrying the running balance at period start)
- Financial reports are now logo-free: drawBrandedHeader/reportPdf skip the
logo block; ReportSheet drops the on-screen logo
- reportPdf: appendStructuredReportPdf + skipFooter scaffolding for upcoming
report batches (not yet wired)
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>
- accounting.accounts.is_archived; COA mirror sets public is_active accordingly
so association-side pickers hide archived accounts
- COA page: archive/restore per row + bulk, show-archived toggle, delete
confirm dialog with 'Archive instead'; FK-blocked deletes (posted activity)
get a friendly message + one-click archive; bulk delete skips blocked
accounts per-id instead of failing the batch
- fetchChartOfAccounts excludes archived platform accounts from pickers;
parent dropdowns and Opening Balances only offer active accounts
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/v1/glaccounts omits some inactive accounts (e.g. prior-management bank
accounts) whose ledgers still hold one side of historical transactions,
making checks/deposits come back unbalanced on backfills (found during the
Casuarina Club GL import).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /v1/vendors 403s on keys without the Vendors scope; import bills without
vendor links instead of failing the pull, and surface it in results.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Anything on/before buildium_gl.last_synced_date is already in the books as
buildium_gl entries; ap_cutover_date freezes that boundary so direct
buildium_bill/billpay postings never double-count history.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- public.bills.line_items + line-aware accounting mirror (one bill_item per
Buildium line with its mapped platform account)
- buildium-sync bills: strict per-line resolution through
buildium_gl_account_links (unmapped -> bill held + flagged); pulls
/bills/{id}/payments (check#, bank, date) and /bankaccounts/{id}/checks
(one-off checks become paid bill+payment pairs)
- import-mode companies get direct JEs (buildium_bill Dr expense/Cr AP,
buildium_billpay Dr AP/Cr mapped bank) + cleared register rows; sets
buildium_gl.exclude_ap so the nightly GL pull skips Bill/Bill Payment/Check
- buildium-gl-sync: exclude_ap transaction-type filter; preserve buildium_gl
config keys when advancing the watermark
- Settings: Pull Bills & Expenses card with held/unmapped reporting
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- gl_accounts fetched without includeAll (active Buildium accounts only)
- replaced per-account row grid (370+ selects) with a single add row:
Buildium dropdown -> system account dropdown -> Add
- mappings list is plain rows with remove + push-target radio; changes save
immediately (no bulk Save); flagged sync-blockers are click-to-select chips
- Auto-map exact matches button inserts code/name-identical pairs
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>
- Buildium API exposes no ARC comment threads or member votes (verified live);
surface the final decision instead: vote row dated to the actual decision,
decision_notes 'Approved by X on date (via Buildium)'
- record_buildium_arc_vote RPC bypasses the finalized-ARC write lock that was
silently swallowing import votes; 69 existing imports backfilled
- Application Record PDF: paragraph break between comments and decision notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After the build check passes, SSH to the VPS with a forced-command key
(can only run deploy.sh) which pulls main, builds, and rsyncs dist/ to
public_html. Replaces the manual `ssh myvps ... deploy.sh` step.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add missing indexes on journal_entry_lines (journal_entry_id, account_id)
and journal_entries (company_id, date): Bridgewater's ledger query took
7.5s, blew the 8s statement timeout, and rendered the JE/GL pages empty
- Paginate JE/GL page fetches past the 1000-row PostgREST cap (shared
fetchJournalEntries helper) and surface query errors instead of
swallowing them into an empty list
- New buildium-gl-sync edge function (scheduled nightly via pg_cron):
incrementally pulls new Buildium GL activity into accounting journal
entries via GET /v1/generalledger, reconstructing double-entry JEs by
grouping per-account entries by transaction id; watermark + 14-day
overlap window, dedupe on (company_id, external_source, external_id),
account mapping by external_id/code/name with auto-create for new
Buildium accounts
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>
Add prev/next buttons and a "Client N of M" indicator around the association
picker so a budget can be built for every client in turn. Cycles in name order
and wraps; direct dropdown selection still works.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a PDF button that generates a board-ready proposed budget: income and
expense tables (monthly/annual per account with totals), a summary, and a
headline banner for the per-unit monthly assessment. Uses the workbook's
projected figures (overrides/inflation/unit override) via jsPDF + autotable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The per-unit assessment (annual expenses / 12 / units) used the live association
unit count only. Add an override so the rate can use weighted/excluded units,
persisted on accounting.budget_workbooks.unit_override (null = live count). New
"# Units" control with a reset link; summary card and CSV use the effective count.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Banking-page deposit form required a homeowner, blocking general/cash
deposits. Drop that requirement: a deposit still needs an income account, and
post_transaction_gl already books Dr Bank / Cr income when no customer is set
(vs. Dr Bank / Cr A/R with one). The Homeowner field is now optional with an
explicit "No homeowner (general deposit)" choice.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/dashboard/budget-management now renders a Budget Workbook that pulls YTD
actuals (from the accounting GL, through a chosen month), derives a monthly
average (YTD/N), takes a per-line inflation %, and projects an annual budget
(avg x 12 x (1+infl)). Footer rolls up annual budget / 12 / # units = per-unit
monthly assessment. Income + expense sections; all imported fields editable.
- Standalone saved worksheet (accounting.budget_workbooks/_lines, RLS like accounts)
- "Push to Budget" writes projected/12 into accounting.budgets + budget_entries
- Uses accounting.accounts (synced with the Accounting dashboard COA) and paginates
the GL fetch (1000-row cap). Nav relabeled Budget Management -> Budget Workbook.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The bank register fetched transactions in a single request, which
PostgREST caps at 1000 rows. An imported bank account with a longer
register (e.g. Bridgewater Checking, ~1,500 rows) truncated, throwing
off the displayed running balance. Page through all rows ordered by a
stable key (date, created_at, id).
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>
Manual journal entries post straight to the GL, but saving/deleting one
only invalidated the journal-entries list — so the Reports data (P&L /
Balance Sheet) and the General Ledger tab kept showing stale figures
until a manual refresh. Invalidate reports-data and gl-journal-entries
on save and delete too.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Buildium-style GL grouped by account type with date-range filter,
account filter, beginning/ending balances, per-line running balance,
and grand totals. Reads posted journal entries.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a "Recent Deposits" list to the Deposits page with Edit (date, bank
account, memo — GL re-posts via the deposit trigger) and Delete (releases the
deposited transactions/payments back to "awaiting deposit" and reverses the GL).
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>
The blanket rule stripped expense from direct-expense checks that have no bill,
leaving the P&L showing only a couple of accounts. Restore original
post_transaction_gl precedence (coded account before vendor). Re-posted affected
transactions to restore expense recognition. Double-count needs a bill-linkage fix.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- post_transaction_gl: a vendor money-out (check) now posts Dr A/P / Cr Bank
instead of re-debiting the coded expense account. Fixes double-counted expense
and checks showing as P&L debits (bill already recognized the expense).
- post_payment_gl: Village Grove owner payments post straight to HOLII COGENT
Checking instead of Undeposited Funds (scoped; others unchanged).
Both applied to the live DB; Ashley Manor's affected transactions re-posted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>