Accounting platform: remove Zoho, unify reports, board access, vendor sharing

- 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>
This commit is contained in:
2026-06-02 18:29:31 -04:00
parent db20226d62
commit e302fb91f0
63 changed files with 2406 additions and 9514 deletions
+6 -3
View File
@@ -12,7 +12,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
type ReportType = "trial_balance" | "income_statement" | "balance_sheet" | "aging" | "delinquency";
export default function AccountingReportsPage() {
export default function AccountingReportsPage({ associationIds }: { associationIds?: string[] } = {}) {
const { toast } = useToast();
const [associations, setAssociations] = useState<any[]>([]);
const [selectedAssocId, setSelectedAssocId] = useState("");
@@ -28,11 +28,14 @@ export default function AccountingReportsPage() {
const [loading, setLoading] = useState(false);
useEffect(() => {
supabase.from("associations").select("id, name").eq("status", "active").order("name").then(({ data }) => {
let q = supabase.from("associations").select("id, name").eq("status", "active").order("name");
// When scoped (e.g. board members), limit the picker to the given associations.
if (associationIds?.length) q = q.in("id", associationIds);
q.then(({ data }) => {
setAssociations(data || []);
if (data?.length) setSelectedAssocId(data[0].id);
});
}, []);
}, [associationIds?.join(",")]);
const generateReport = async () => {
if (!selectedAssocId) return;