CREATE OR REPLACE FUNCTION public.sync_owner_balance_from_ledger() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$ DECLARE affected_owner_id uuid; BEGIN affected_owner_id := COALESCE(NEW.owner_id, OLD.owner_id); IF affected_owner_id IS NOT NULL THEN UPDATE public.owners o SET balance = COALESCE(( SELECT ROUND(SUM(COALESCE(ole.debit, 0) - COALESCE(ole.credit, 0))::numeric, 2) FROM public.owner_ledger_entries ole WHERE ole.owner_id = affected_owner_id ), 0) WHERE o.id = affected_owner_id; END IF; IF TG_OP = 'UPDATE' AND OLD.owner_id IS DISTINCT FROM NEW.owner_id AND OLD.owner_id IS NOT NULL THEN UPDATE public.owners o SET balance = COALESCE(( SELECT ROUND(SUM(COALESCE(ole.debit, 0) - COALESCE(ole.credit, 0))::numeric, 2) FROM public.owner_ledger_entries ole WHERE ole.owner_id = OLD.owner_id ), 0) WHERE o.id = OLD.owner_id; END IF; RETURN COALESCE(NEW, OLD); END; $$; DROP TRIGGER IF EXISTS sync_owner_balance_after_ledger_change ON public.owner_ledger_entries; CREATE TRIGGER sync_owner_balance_after_ledger_change AFTER INSERT OR UPDATE OR DELETE ON public.owner_ledger_entries FOR EACH ROW EXECUTE FUNCTION public.sync_owner_balance_from_ledger();