DatabaseProgramming: 04 Payment financial sync trigger.sql

File 04 Payment financial sync trigger.sql, 2.8 KB (added by 231139, 10 days ago)
Line 
1CREATE OR REPLACE FUNCTION public.fn_recalculate_account_balance(p_account_id bigint)
2RETURNS void
3LANGUAGE sql
4AS $$
5 UPDATE public.accounts a
6 SET current_balance = GREATEST(COALESCE((
7 SELECT SUM(i.total_amount - COALESCE((
8 SELECT SUM(p.amount)
9 FROM public.payments p
10 WHERE p.invoice_id = i.invoice_id AND p.status = 'completed'
11 ), 0))
12 FROM public.invoices i
13 WHERE i.account_id = p_account_id AND i.status <> 'cancelled'
14 ), 0), 0)
15 WHERE a.account_id = p_account_id;
16$$;
17
18CREATE OR REPLACE FUNCTION public.fn_recalculate_invoice_status(p_invoice_id bigint)
19RETURNS void
20LANGUAGE plpgsql
21AS $$
22DECLARE
23 v_total numeric;
24 v_paid numeric;
25 v_due_date date;
26 v_status text;
27BEGIN
28 SELECT total_amount, due_date, status
29 INTO v_total, v_due_date, v_status
30 FROM public.invoices
31 WHERE invoice_id = p_invoice_id;
32
33 IF NOT FOUND OR v_status = 'cancelled' THEN
34 RETURN;
35 END IF;
36
37 SELECT COALESCE(SUM(amount), 0)
38 INTO v_paid
39 FROM public.payments
40 WHERE invoice_id = p_invoice_id AND status = 'completed';
41
42 UPDATE public.invoices
43 SET status = CASE
44 WHEN v_paid >= v_total - 0.01 THEN 'paid'
45 WHEN v_due_date < CURRENT_DATE AND v_paid < v_total - 0.01 THEN 'overdue'
46 WHEN v_paid > 0 THEN 'partially_paid'
47 ELSE 'issued'
48 END
49 WHERE invoice_id = p_invoice_id;
50END;
51$$;
52
53DROP TRIGGER IF EXISTS trg_sync_financials_on_payment ON public.payments;
54CREATE OR REPLACE FUNCTION public.trg_fn_sync_financials_on_payment()
55RETURNS trigger
56LANGUAGE plpgsql
57AS $$
58DECLARE
59 v_new_invoice_id bigint;
60 v_old_invoice_id bigint;
61 v_new_account_id bigint;
62 v_old_account_id bigint;
63BEGIN
64 IF TG_OP <> 'DELETE' THEN
65 v_new_invoice_id := NEW.invoice_id;
66 v_new_account_id := NEW.account_id;
67 END IF;
68 IF TG_OP <> 'INSERT' THEN
69 v_old_invoice_id := OLD.invoice_id;
70 v_old_account_id := OLD.account_id;
71 END IF;
72
73 IF v_new_invoice_id IS NOT NULL THEN
74 PERFORM public.fn_recalculate_invoice_status(v_new_invoice_id);
75 END IF;
76 IF v_old_invoice_id IS NOT NULL AND v_old_invoice_id IS DISTINCT FROM v_new_invoice_id THEN
77 PERFORM public.fn_recalculate_invoice_status(v_old_invoice_id);
78 END IF;
79 IF v_new_account_id IS NOT NULL THEN
80 PERFORM public.fn_recalculate_account_balance(v_new_account_id);
81 END IF;
82 IF v_old_account_id IS NOT NULL AND v_old_account_id IS DISTINCT FROM v_new_account_id THEN
83 PERFORM public.fn_recalculate_account_balance(v_old_account_id);
84 END IF;
85
86 IF TG_OP = 'DELETE' THEN RETURN OLD; END IF;
87 RETURN NEW;
88END;
89$$;
90
91CREATE TRIGGER trg_sync_financials_on_payment
92AFTER INSERT OR UPDATE OR DELETE ON public.payments
93FOR EACH ROW
94EXECUTE FUNCTION public.trg_fn_sync_financials_on_payment();