-- Zoho account mappings (local COA -> Zoho account) CREATE TABLE public.zoho_account_mappings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), association_id UUID NOT NULL REFERENCES public.associations(id) ON DELETE CASCADE, chart_of_account_id UUID NOT NULL REFERENCES public.chart_of_accounts(id) ON DELETE CASCADE, zoho_account_id TEXT NOT NULL, zoho_account_name TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE(association_id, chart_of_account_id) ); ALTER TABLE public.zoho_account_mappings ENABLE ROW LEVEL SECURITY; CREATE POLICY "Staff full access on zoho_account_mappings" ON public.zoho_account_mappings FOR ALL TO authenticated USING (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)) WITH CHECK (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)); -- Zoho customer mappings (owner/unit -> Zoho customer) CREATE TABLE public.zoho_customer_mappings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), association_id UUID NOT NULL REFERENCES public.associations(id) ON DELETE CASCADE, owner_id UUID REFERENCES public.owners(id) ON DELETE CASCADE, unit_id UUID REFERENCES public.units(id) ON DELETE CASCADE, zoho_customer_id TEXT NOT NULL, zoho_customer_name TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), UNIQUE(association_id, owner_id) ); ALTER TABLE public.zoho_customer_mappings ENABLE ROW LEVEL SECURITY; CREATE POLICY "Staff full access on zoho_customer_mappings" ON public.zoho_customer_mappings FOR ALL TO authenticated USING (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)) WITH CHECK (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)); -- Zoho sync settings per association (toggle which entry types sync) CREATE TABLE public.zoho_sync_settings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), association_id UUID NOT NULL REFERENCES public.associations(id) ON DELETE CASCADE UNIQUE, sync_invoices BOOLEAN NOT NULL DEFAULT true, sync_payments BOOLEAN NOT NULL DEFAULT true, sync_contacts BOOLEAN NOT NULL DEFAULT true, sync_bills BOOLEAN NOT NULL DEFAULT false, sync_journal_entries BOOLEAN NOT NULL DEFAULT false, auto_sync_enabled BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ALTER TABLE public.zoho_sync_settings ENABLE ROW LEVEL SECURITY; CREATE POLICY "Staff full access on zoho_sync_settings" ON public.zoho_sync_settings FOR ALL TO authenticated USING (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)) WITH CHECK (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)); -- Zoho sync log for tracking sync history and errors CREATE TABLE public.zoho_sync_log ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), association_id UUID NOT NULL REFERENCES public.associations(id) ON DELETE CASCADE, sync_type TEXT NOT NULL, -- 'invoice', 'payment', 'contact', 'bill', etc. direction TEXT NOT NULL DEFAULT 'push', -- 'push' or 'pull' status TEXT NOT NULL DEFAULT 'success', -- 'success', 'error', 'partial' record_count INTEGER DEFAULT 0, error_message TEXT, details JSONB, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ALTER TABLE public.zoho_sync_log ENABLE ROW LEVEL SECURITY; CREATE POLICY "Staff full access on zoho_sync_log" ON public.zoho_sync_log FOR ALL TO authenticated USING (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)) WITH CHECK (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)); -- Association fee rules (interest & late fee configuration per association) CREATE TABLE public.association_fee_rules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), association_id UUID NOT NULL REFERENCES public.associations(id) ON DELETE CASCADE UNIQUE, -- Interest settings interest_enabled BOOLEAN NOT NULL DEFAULT false, interest_rate NUMERIC NOT NULL DEFAULT 0, -- APR percentage e.g. 18.0 interest_grace_days INTEGER NOT NULL DEFAULT 30, interest_compound TEXT NOT NULL DEFAULT 'monthly', -- 'monthly', 'daily', 'quarterly' interest_apply_to TEXT NOT NULL DEFAULT 'assessments', -- 'assessments', 'all_charges', 'assessments_and_fees' -- Late fee settings late_fee_enabled BOOLEAN NOT NULL DEFAULT false, late_fee_type TEXT NOT NULL DEFAULT 'flat', -- 'flat' or 'percentage' late_fee_amount NUMERIC NOT NULL DEFAULT 0, -- dollar amount or percentage late_fee_trigger_days INTEGER NOT NULL DEFAULT 15, -- days past due before late fee applies late_fee_max NUMERIC, -- optional max cap for percentage-based fees late_fee_recurring BOOLEAN NOT NULL DEFAULT false, -- apply every month? -- Schedule auto_apply_enabled BOOLEAN NOT NULL DEFAULT false, auto_apply_schedule TEXT NOT NULL DEFAULT 'monthly', -- 'monthly', 'quarterly' auto_apply_day INTEGER NOT NULL DEFAULT 1, -- day of month -- Push to Zoho push_to_zoho BOOLEAN NOT NULL DEFAULT true, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); ALTER TABLE public.association_fee_rules ENABLE ROW LEVEL SECURITY; CREATE POLICY "Staff full access on association_fee_rules" ON public.association_fee_rules FOR ALL TO authenticated USING (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)) WITH CHECK (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role));