-- Function: recompute bill status from its approvals CREATE OR REPLACE FUNCTION public.recompute_bill_status_from_approvals() RETURNS TRIGGER LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_bill_id uuid; v_total int; v_approved int; v_denied int; v_current_status text; v_new_status text; BEGIN v_bill_id := COALESCE(NEW.bill_id, OLD.bill_id); IF v_bill_id IS NULL THEN RETURN COALESCE(NEW, OLD); END IF; SELECT COUNT(*), COUNT(*) FILTER (WHERE status = 'approved'), COUNT(*) FILTER (WHERE status = 'denied') INTO v_total, v_approved, v_denied FROM public.bill_approvals WHERE bill_id = v_bill_id; IF v_total = 0 THEN RETURN COALESCE(NEW, OLD); END IF; SELECT status INTO v_current_status FROM public.bills WHERE id = v_bill_id; IF v_denied > 0 THEN v_new_status := 'denied'; ELSIF v_approved = v_total THEN v_new_status := 'approved'; ELSE v_new_status := NULL; END IF; IF v_new_status IS NOT NULL AND v_current_status IS DISTINCT FROM v_new_status AND COALESCE(v_current_status, '') NOT IN ('paid', 'cancelled') THEN UPDATE public.bills SET status = v_new_status, updated_at = now(), approved_date = CASE WHEN v_new_status = 'approved' THEN COALESCE(approved_date, CURRENT_DATE) ELSE approved_date END WHERE id = v_bill_id; END IF; RETURN COALESCE(NEW, OLD); END; $$; DROP TRIGGER IF EXISTS trg_bill_approvals_recompute_status ON public.bill_approvals; CREATE TRIGGER trg_bill_approvals_recompute_status AFTER INSERT OR UPDATE OF status OR DELETE ON public.bill_approvals FOR EACH ROW EXECUTE FUNCTION public.recompute_bill_status_from_approvals(); -- Backfill existing bills whose approval state is already complete UPDATE public.bills b SET status = 'approved', approved_date = COALESCE(b.approved_date, CURRENT_DATE), updated_at = now() WHERE b.status NOT IN ('approved', 'denied', 'paid', 'cancelled') AND EXISTS (SELECT 1 FROM public.bill_approvals ba WHERE ba.bill_id = b.id) AND NOT EXISTS ( SELECT 1 FROM public.bill_approvals ba WHERE ba.bill_id = b.id AND ba.status <> 'approved' ); UPDATE public.bills b SET status = 'denied', updated_at = now() WHERE b.status NOT IN ('denied', 'paid', 'cancelled') AND EXISTS ( SELECT 1 FROM public.bill_approvals ba WHERE ba.bill_id = b.id AND ba.status = 'denied' );