206 Commits

Author SHA1 Message Date
admin f063d05ae0 Reconciliation: set cleared=false on transfer far leg (NOT NULL fix)
The far-account transfer leg omitted cleared, violating the column's
not-null constraint. Default it to false; the near leg stays cleared=true.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 15:57:00 -04:00
admin 59c23dfec1 Reconciliation: add transfers, non-vendor expenses, non-owner deposits
- Transfer button records two transfer_id-linked legs (GL via post_transfer_gl);
  this account's leg auto-clears into the open reconciliation
- Withdrawals: vendor now optional so non-vendor expenses (bank fees, gov) post
  Dr Expense / Cr Bank via the category account
- Deposits: optional Owner field — pick to clear A/R, or leave blank for a
  non-owner deposit (interest, refund) booking income

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 15:00:52 -04:00
admin c94057c433 Reconciliation: allow undoing the most recent reconciliation
Adds an Undo action in the reconciliation History tab. Undo reopens every
item the reconciliation cleared (clears the cleared flag and reconciliation_id)
and deletes the reconciliation record, so the period can be reconciled again.
No transactions are deleted. Only the latest completed reconciliation is
undoable, since reopening an earlier one would invalidate the opening balance
all later periods were built on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:07:54 -04:00
admin c8cb583ec9 Import G/L: use buildium_gl source, name-first matching, keep parent rows
- Post imported entries as external_source "buildium_gl" (matching the nightly
  buildium-gl-sync) so the sync's dedupe recognizes them and won't re-pull the
  same transactions as duplicates. A separate "buildium_gl_csv" source is
  invisible to that dedupe and double-counts on the next sync.
- Match accounts by name first, then code: account numbers can differ between
  Buildium and the platform chart (and a number can mean different things), so
  name is the more reliable key; code is the fallback.
- Keep IsParent rows. In some exports a parent account carries its own real
  postings rather than a rollup duplicate; the per-transaction balance check
  flags genuine double-emits instead of silently dropping lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:45:06 -04:00
admin 1296b9449d Accounting: add Import G/L feature on Journal Entries page
New GLImportDialog imports a Buildium General Ledger / journal export
(CSV or XLSX) into journal entries. Lines are grouped into transactions by
Buildium Id (Amount is signed: + debit / - credit), parent-rollup and
cash-book rows are skipped, and accounts are matched to the association's
chart of accounts by code then name. Shows a preview (counts, date range,
trial balance by type) and blocks import on unmatched accounts or
unbalanced transactions. Keyed on the Buildium Id, so re-importing the same
file skips anything already imported.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:42:11 -04:00
admin 7b1d6a59e9 A/R reports: exclude void/paid/draft invoices from open balances
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>
2026-06-19 11:45:18 -04:00
admin 7eb08ad29f P&L monthly: span the fiscal year so columns aren't limited to one month
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>
2026-06-19 02:36:57 -04:00
admin 2e99a9a7da Chart of Accounts: merge two accounts into one
Adds a Merge action (per row) that folds all of an account's history into
another account of the same type, then deletes the empty source. Backed by
a SECURITY DEFINER accounting.merge_accounts RPC that reassigns every
reference — journal lines, transactions, bill items, deposits, sales
receipts, assessments, checks, expenses, budgets, bank/reconciliation
rows, child accounts — and sums opening balances. Admin/manager only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 02:14:29 -04:00
admin e517b60519 Cash Disbursement: exclude manual journal entries
Only actual payments (bill/check/register payments and Buildium-pulled
payments) are disbursements. Skip manual JEs, reclasses, opening-balance
entries, import adjustments and transfers (external_source null or in the
excluded set) so adjustments no longer appear as cash disbursements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 02:06:32 -04:00
admin ee10f74753 Prepaid Homeowners + AR Aging (Property): roll ledger up to the unit, show current owner
Owner-ledger entries tied only to an old owner_id grouped separately,
so former owners showed big prepaid balances and current owners were
missing. Map each entry to its unit (via the owner's unit when the entry
has no unit_id) so balances net per unit, and label each unit with its
current (active, primary) owner.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 00:55:13 -04:00
admin e11a48e8bf Reconciliation Checks: self-contained PDF button in the report
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>
2026-06-19 00:33:07 -04:00
admin 1f6abf07ae Bills: fix Record Payment dialog overflow
The 'Apply existing payment' candidate list spilled outside the dialog.
Cap the dialog at max-h-[85vh] with overflow-y-auto and drop the list's
nested scroll so the whole dialog scrolls as one and stays contained.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 00:25:53 -04:00
admin ed6b926768 Budget vs Actuals: move grey gradient to the PDF (off the page view)
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>
2026-06-19 00:21:55 -04:00
admin 7b9bc2d4c7 AR Aging (Property): label each unit with its current owner
The per-unit aging picked an arbitrary (often moved-out) owner for the
unit label. Fetch owner status/is_primary and prefer the active, primary
owner per unit so balances are never tagged to a former owner. Aging is
already keyed by unit (funds attach to the unit, not the owner).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 00:17:10 -04:00
admin 4ffe17cd7f Reconciliation Checks: enable PDF/CSV download
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>
2026-06-19 00:01:39 -04:00
admin ad74072061 Transaction dialogs: allow all account types as the category
Banking deposit/payment + bulk-categorize and the reconcile add-transaction
dialog previously limited the category to income (deposits) or expense
(payments). Now every account type is selectable, grouped by Income /
Expense / Assets / Liabilities / Equity (with codes); the direction's
natural type is listed first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 23:18:56 -04:00
admin 3f0c7ba1bb Reserve Workbook: add Reserve Spending tab (auto-imported, real-time)
Wraps the page in tabs: Workbook (assumptions/components/projection) and
a new Reserve Spending tab. The spending tab auto-imports every GL line
on reserve-flagged (is_reserve) expense accounts — total + reserve
balance, spending-by-year, and a full imported-expenditure detail list
(date, account, description, ref, amount). It shares the live GL query
so it feeds the projection's actual expenses in real time; Re-import
button refreshes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 23:04:47 -04:00
admin af9e092cbd Balance Sheet: show account numbers + parent categories (Buildium style)
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>
2026-06-18 22:16:42 -04:00
admin fa4ee3e215 Add Reserves Workbook (capital reserve analysis + 30yr projection)
New /dashboard/reserve-workbook: per-association capital reserve study.
- Manually-entered components with computed total, inflated replacement
  cost, replacement year, fully-funded balance, % funded.
- Autoloads the current reserve fund balance and actual reserve
  expenditures by year from reserve-flagged (is_reserve) GL accounts.
- 30-year Reserve Plan Summary projection (starting balance,
  contribution w/ change %, interest, scheduled+actual expenses, ending
  balance, fully-funded, % funded) with inflation/interest assumptions.
- Certify-as-approved + bold red preliminary disclaimer (same pattern as
  the budget workbook); Save + landscape PDF export.
New accounting.reserve_workbooks / reserve_components tables (RLS mirrors
budget_workbooks). Nav links added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 20:36:07 -04:00
admin 7aedc6d90d Budget Workbook: certify-as-approved + preliminary disclaimer
Add a 'Certify as Approved' toggle (accounting.budget_workbooks.certified
/certified_at/certified_by). Until certified, show a bold red note that
the projections are preliminary and not subject to annual increases or
inflation; once certified, show an approved/certified banner. Both states
render in the PDF export too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 20:03:40 -04:00
admin 422b828cdb Reconcile screen: edit transactions inline
Add an edit (pencil) action to each row in the reconciliation working
list, reusing the add dialog in edit mode. On edit, category/vendor are
optional (so imported GL register rows can be edited without forcing
re-categorization); category/coa are only overwritten when a category
is chosen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 19:17:59 -04:00
admin cfd42a3852 Banking: allow editing reconciled transactions (with warning)
Reconciled items were hard-blocked from editing. Replace the block with
a confirmation warning that editing may unbalance the completed
reconciliation. The edit save preserves reconciliation_id, so the item
stays reconciled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 19:09:33 -04:00
admin f03430f09b Account Statement PDF: list all owners, not just primary
generateLedgerStatement now prints every active owner under
'ACCOUNT HOLDER(S):' (primary first) and flows the property address
and tables below the owner block so it never overlaps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:46:52 -04:00
admin 552dfcfc4e Unit ledger: list all active owners, not just the primary
The Owner card on the unit account dashboard showed only the primary
owner. List every active owner (primary first, tagged), with each
owner's email and account number; label becomes 'Owners' when >1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:38:57 -04:00
admin 66469c541f Bills: apply existing payment + Buildium-style approval detail view
1) AccountingBillsPage: add an 'Apply existing payment' mode to the
   Record Payment dialog. Instead of creating a new withdrawal, pick an
   unmatched outgoing bank transaction already in the register; it links
   to the bill (bill_id + coa cleared => Dr A/P / Cr Bank) and marks it
   paid. Same-vendor / exact-amount candidates surface first.

2) BillDetailPage (also used by the board view): redesign the bill
   detail layout to match Buildium - vendor-name header with status +
   amount/due subline, grey-headed 'Bill details' / 'Item details'
   (with Total row) / 'Approval' cards, and a right-hand 'Bill amount'
   (Remaining) card. All editing/approval/comment functionality intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:08:28 -04:00
admin acd99f04ce Avria Sign: fix PDF not rendering (field placement + signer page)
The pdf.js worker was set via new URL("pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url) — Vite only resolves relative paths there, so a bare
node_modules specifier 404s in production and react-pdf never renders the PDF
(both the field-placement step and the recipient signing page). Switch to a
Vite `?url` import so the worker is emitted as a hashed same-origin asset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:08:08 -04:00
admin 86e8513694 Inspections: apply violations new-vs-old cue to the map + list
Match the violations changes on the Inspections map: add a green "New" badge for
violations recorded in the last 7 days, both in the map pin popups and the unit
list, so new vs old is distinguishable. (Newest-first ordering and
auto-advance-to-next-stage on re-recording a property already existed here.)
Also fixed a misleading stage fallback that showed "New" as a notice level.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:03:51 -04:00
admin b15ed4bff8 Avria Sign: add SHA-256 document hash to certificate of completion
The Certificate of Validation claimed "cryptographic proof ... and integrity"
but showed no hash. Add a real SHA-256 of the original document to the
certificate page so the integrity claim is backed by a verifiable digest.
(Deploy via MCP alongside the base-flow fix.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:58:27 -04:00
admin bebd5bd7cb Violation report: clean up Activity History formatting
The "Violation Updated" entries rendered raw change diffs: a "→" arrow the PDF
font can't draw (showed as "!'"), snake_case field names, "—" for empty, and a
dense single-paragraph wall.

- Render-time (fixes existing reports): normalizeTimelineText now maps "→"→"to"
  and smart quotes/dashes/ellipsis to ASCII, prettifies snake_case field labels
  (violation_type → "Violation Type", etc.), and puts each change on its own
  line for proper spacing.
- Logger (future entries): logViolationUpdated/logBulkUpdate now write
  professional notes — "Description / Notes changed from "X" to "Y".",
  "… set to …", "… cleared." — with Title-Case labels, long values truncated to
  80 chars, and one change per line. No arrows or raw field names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:48:18 -04:00
admin feb0d28c25 Violations: fix auto-escalation on re-record + surface new vs old by date
Auto-escalation was broken: calculateNextNoticeLevel queried unit_id but the
dialog passed the owner id, so it always returned "First Notice." Rewrote it to
advance one step past the property's highest CURRENTLY-OPEN stage (First →
Second → Third & Final, capped), identifying the property by unit, else owner,
else association+address; the dialog now passes all of those and re-runs when
the unit/address changes. So re-recording a violation on the same property
auto-selects the next stage.

New vs old by date: list now loads newest-first, and cards show a "New" badge
for violations recorded in the last 7 days (violation_date was already captured
and shown, plus the timeline group-by-date view).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:32:28 -04:00
admin 71cc71f89f Inbound invoices: recipient-alias routing + parser hardening
parse-invoice: guard oversized PDFs (>18MB → clear "too large, saved for manual
entry" message) and surface the AI gateway's actual error instead of a bare
status code.

inbound-bill-email: route to an association by the recipient alias
(<alias>@bills.avriamail.com, via associations.inbound_alias) in addition to the
sender's vendor mapping; fix extractEmail (bare addresses were mis-split, e.g.
invoices@x → s@x); surface parse-invoice's real error in the inbox. Deployed via
MCP; migration associations_inbound_alias adds + populates the aliases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 22:13:49 -04:00
admin 386ee26a6a Bill summary PDF: itemized line items + total
Render an itemized table (Description / Qty / Unit Price / Amount) from the
linked invoice's line_items, with a Total row (the authoritative bill amount)
and a subtle note if the line items don't sum to it. Falls back to a single
row when no line items exist. Fetch invoices.line_items in the bills query and
pass it through to the generator.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 21:13:50 -04:00
admin fa0f60a7f4 Bill Approvals: download a summarized bill PDF
Add a "Download PDF" action to each bill's row menu that generates a clean
one-page bill summary (vendor, amount, invoice #, bill/due dates, expense
account, description, status, and board approval statuses). New generator
src/pages/accounting/lib/billSummaryPdf.ts (jsPDF), styled like the other
report PDFs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 21:00:27 -04:00
admin fe78c25fd1 Messaging: add explicit Delete button to the conversation header
The list-row trash is always-visible now, but add an unmissable "Delete"
button in the open-conversation header (ChatView) too. Deletes the whole 1:1
conversation for everyone and clears the selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 20:04:50 -04:00
admin 53765e1448 Reconciliation: add accrual bill (expense on bill date + paying withdrawal)
New "Add Bill" action on the bank reconciliation screen: enter a bill (bill
date, payment date, vendor, amount, expense account), and it creates the bill
(accrual expense on the bill date) plus a withdrawal that pays it (Dr A/P /
Cr Bank on the payment date) and clears into the current reconciliation. The
expense lands in the bill's period for reporting; the cash leaves on the
payment date.

Fixes import-mode posting: app-created bills now carry gl_post_override=true
(new accounting.bills column) so post_bill_gl posts their expense even for
import-mode (gl_auto_post=false) companies. The previous external_source-based
gate didn't work because the bill back-sync trigger stamps every app bill with
external_source='acmacc_bill', making it indistinguishable from Buildium
imports; the explicit flag set only by the app's bill creators (Bills page +
reconciliation) is reliable, while Buildium-import/auto-reconcile bills stay
gated and never double-count the GL pull. Migration:
bills_gl_post_override_for_inapp_bills.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 19:56:18 -04:00
admin 9c87777046 Messaging: whole-board from Direct New Message + always-visible delete
- Whole board where users actually look: the Direct "New Message" dialog now
  lists "Whole Board — <Association>" rows for staff (All/Board tabs). Clicking
  one opens the group-topic composer prefilled with that board's members (the
  composer is now reusable: hideTrigger + controlled open + initialSelected,
  wired through MessagesPage).
- Delete discoverability: the trash control on Direct conversations and Topic
  threads is now always visible (subtle, bottom-right) instead of hover-only,
  which read as "no delete option."

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 19:38:15 -04:00
admin 6a6e2306ea Messaging: whole-board topics, delete conversations/threads, dialog overflow + board names
- Whole-board messaging: staff starting a Topic can add an entire association's
  board in one click ("Whole Board — <Association>") in NewTopicThreadDialog;
  create_topic_thread already permits staff to add board members.
- Delete for everyone: trash control on Direct conversations (deletes the 1:1
  both directions) and on Topic threads (deletes the thread for the creator or
  admin/manager — cascade). Backed by new RLS delete policies on direct_messages
  and message_threads (migration allow_delete_conversations_and_threads).
- Fix New Message dialog overflow for real: the grid child needed min-w-0 (+
  overflow-hidden on the card); applied the same guard to the Topic dialog.
- Fix board members showing as "Unknown User": fall back to board_members.member_name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 15:44:39 -04:00
admin bfc758f1f2 Messaging: fix New Message dialog overflow on long recipient names
The recipient row's inner name+badge flex lacked min-w-0, so a long name
(e.g. a full association name) couldn't truncate — it widened the row,
pushed the badge out, and stretched the dialog (and its full-width search
field) past max-w-md. Add min-w-0 so the name truncates and the dialog
stays within bounds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 15:01:23 -04:00
admin d5145e2515 Messaging: board topic threads with management + board
Add a "Topics" tab to the Messages page so board members can start a
topic-scoped group conversation with management and their own-association
board members. Topic = predefined category + free-text subject; recipients
are multi-selected; replies are visible to all participants.

- New public tables message_threads / message_thread_participants /
  thread_messages (migration board_topic_message_threads), added to the
  realtime publication; RLS scopes reads/writes to thread participants via
  is_thread_participant().
- create_topic_thread() RPC (SECURITY DEFINER) enforces recipient
  eligibility server-side: management (admin/manager) or a board member of
  the caller's own association; rejects anyone else.
- Frontend: messageTopics constant, useMessageThreads/useThreadMessages
  hooks (realtime), TopicThreadList/TopicThreadView/NewTopicThreadDialog,
  and a tabbed MessagesPage. Recipients notified via insert_notification
  with a /dashboard/messages?thread= deep link. Existing 1:1 DMs unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 14:58:50 -04:00
admin 56e63edcd6 Violation reports: replace fining stamp with bold red header line
The diagonal semi-transparent "RECOMMENDED FOR FINING" stamp looked poor over
the report content. Remove it (drawRecommendedForFiningStamp + both call sites)
and instead print a bold red "RECOMMENDED FOR FINING" line just beneath the
navy header bar on both the Summary and Timeline reports, shifting the owner
block down to make room. Non-fining reports are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 12:16:16 -04:00
admin 0fadfcd2d2 Accounting reports: BvA column shading + reconciliation archived-account fix
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>
2026-06-17 11:53:07 -04:00
admin 61b9933bea AR Aging (Property): exclude archived owner-ledger entries
fetchOwnerLedger pulled all entries regardless of is_archived, so the
accounting AR Aging / Prepaid / batch reports still counted archived
(voided/duplicate) charges — e.g. 2455-VL showed $4K in violations
instead of $3K. Exclude archived entries at the source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 22:49:52 -04:00
admin 46b0855840 Owner ledger: exclude archived entries from balance/breakdown views
Archived (voided/duplicate) owner_ledger_entries were still counted in
the per-unit account breakdown, Collections, and Outstanding Balances —
inflating totals (e.g. 2455-VL showed $4K in violations vs the real
$3K after a duplicate was archived). Filter out archived entries in all
three, matching the canonical Unit Ledger view.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 21:00:07 -04:00
admin c670ca7e0e Bids & Quotes: PDF attachment upload (board-accessible)
Adds a PDF upload to the bid/quote dialog (stored in the bid-attachments
bucket, saved to document_url/document_name) and shows the attachment in
the detail view. Board members with can_upload can attach PDFs — table
RLS and the storage bucket already permit it; only the UI was missing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 20:53:19 -04:00
admin b18a9b9e78 Status updates: restore staff write RLS policy
The "Staff full access on status_updates" policy was missing from the
live DB (dropped outside migrations), so all inserts/updates failed with
"new row violates row-level security policy". Recreate it (admin/manager).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 20:53:19 -04:00
admin a866160482 Status updates: add "hidden from board" flag
Lets management post internal status updates that don't appear in the
board portal. Adds status_updates.hidden_from_board and re-creates the
association-scoped RLS SELECT policy so board members can't read hidden
rows (staff still see all). Dialog gains a "Hide from board" toggle, the
board view filters hidden updates, and management cards show a badge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 20:28:09 -04:00
admin 03cd7127a2 Budget vs Actuals: show full per-period budget, no proration
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>
2026-06-16 14:26:32 -04:00
admin fe5d897139 Budget vs Actuals: source actuals from the GL
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>
2026-06-16 14:07:10 -04:00
admin d7d53c5022 Merge pull request #14 from renee-png/bs-include-archived-accounts-with-balance
Reports: keep archived accounts with a balance on the financial statements
2026-06-16 13:16:10 -04:00
admin 8404f9b79d Reports: keep archived accounts with a balance on the financial statements
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>
2026-06-16 13:15:34 -04:00