let's get build_app running on a masterref database
[xtuple] / foundation-database / public / trigger_functions / aropen.sql
1 CREATE OR REPLACE FUNCTION _aropenTrigger() RETURNS TRIGGER AS $$
2 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
3 -- See www.xtuple.com/CPAL for the full text of the software license.
4 DECLARE
5   _openAmount NUMERIC;
6   _p RECORD;
7   _lateCount INTEGER := 0;
8   _graceDays INTEGER;
9   _checkLate BOOLEAN := false;
10   _checkLimit BOOLEAN := false;
11   _id INTEGER;
12   _currRate NUMERIC;
13 BEGIN
14   -- Checks
15   -- Start with privileges
16   IF ( (NOT checkPrivilege('MaintainARMemos')) AND
17        (NOT checkPrivilege('PostMiscInvoices')) AND
18        (NOT checkPrivilege('PostARDocuments')) ) THEN
19     RAISE EXCEPTION 'You do not have privileges to maintain A/R Memos.';
20   END IF;
21
22   IF ( (NEW.aropen_docnumber IS NULL) OR (LENGTH(NEW.aropen_docnumber) = 0) ) THEN
23     RAISE EXCEPTION 'You must enter a valid Document # for this A/R Memo.';
24   END IF;
25
26   IF ( (NEW.aropen_amount IS NOT NULL) AND (NEW.aropen_amount < 0) ) THEN
27     RAISE EXCEPTION 'You must enter a positive Amount for this A/R Memo.';
28   END IF;
29
30   IF (TG_OP IN ('INSERT', 'UPDATE') AND NEW.aropen_cust_id < 0) THEN
31     RAISE NOTICE 'Fixing deprecated use of negative aropen_cust_id';
32     NEW.aropen_cust_id := NULL;
33   END IF;
34
35   IF (TG_OP IN ('INSERT', 'UPDATE') AND NEW.aropen_salesrep_id < 0) THEN
36     RAISE NOTICE 'Fixing deprecated use of negative aropen_salesrep_id';
37     NEW.aropen_salesrep_id := NULL;
38   END IF;
39
40   IF (TG_OP = 'INSERT') THEN
41     SELECT aropen_id INTO _id
42     FROM aropen
43     WHERE ( (aropen_doctype=NEW.aropen_doctype)
44       AND   (aropen_docnumber=NEW.aropen_docnumber) )
45     LIMIT 1;
46     IF (FOUND) THEN
47       RAISE EXCEPTION 'This Document Type/Number already exists. You may not enter a duplicate A/R Memo.';
48     END IF;
49
50     --- clear the number from the issue cache if applicable
51     PERFORM clearNumberIssue('ARMemoNumber', NEW.aropen_docnumber);
52   END IF;
53
54 -- Determine the number of late invoices
55   IF ( SELECT (metric_value='t')
56          FROM metric
57         WHERE(metric_name='AutoCreditWarnLateCustomers')) THEN
58     _checkLate := true;
59
60     SELECT COALESCE(metric_value::integer, _graceDays)
61       INTO _graceDays
62       FROM metric
63      WHERE(metric_name='DefaultAutoCreditWarnGraceDays');
64     IF (NOT FOUND) THEN
65       _graceDays := 30;
66     END IF;
67     SELECT COALESCE(cust_gracedays, _graceDays)
68       INTO _graceDays
69       FROM custinfo
70      WHERE(cust_id=NEW.aropen_cust_id);
71     IF (NOT FOUND) THEN
72       _graceDays := 30;
73     END IF;
74
75     SELECT count(aropen_id)
76       INTO _lateCount
77       FROM aropen
78      WHERE((NEW.aropen_cust_id = aropen_cust_id)
79        AND (aropen_open)
80        AND (aropen_amount > aropen_paid)
81        AND (aropen_doctype IN ('I', 'D'))
82        AND (aropen_duedate < (CURRENT_DATE - _graceDays)));
83
84   --  Adjust _lateCount if late invoice being paid
85     IF ( (NEW.aropen_paid = NEW.aropen_amount)
86      AND (NEW.aropen_doctype IN ('I', 'D'))
87      AND (NEW.aropen_duedate < (CURRENT_DATE - _graceDays))) THEN
88       _lateCount := _lateCount - 1;
89     END IF;
90   END IF;
91
92 -- get the base exchange rate for the doc date
93   IF (TG_OP = 'INSERT' AND NEW.aropen_curr_rate IS NULL) THEN
94     SELECT curr_rate INTO _currrate
95       FROM curr_rate
96     WHERE ( (NEW.aropen_curr_id=curr_id)
97       AND ( NEW.aropen_docdate BETWEEN curr_effective
98                                    AND curr_expires) );
99     IF (FOUND) THEN
100       NEW.aropen_curr_rate := _currrate;
101     ELSE
102       RAISE EXCEPTION 'Currency exchange rate not found';
103     END IF;
104   END IF;
105
106 --  Close this aropen if it is paid
107   IF (NEW.aropen_paid = NEW.aropen_amount) THEN
108     NEW.aropen_open=FALSE;
109
110 --  Remove any aropenalloc regards that reference this aropen item
111     DELETE FROM aropenalloc WHERE (aropenalloc_aropen_id=NEW.aropen_id);
112   END IF;
113
114   IF (TG_OP = 'INSERT') THEN
115     IF (NEW.aropen_open=FALSE)
116     AND (NEW.aropen_closedate IS NULL) THEN
117       NEW.aropen_closedate=current_date;
118     END IF;
119   END IF;
120
121   IF (TG_OP = 'UPDATE') THEN
122     IF ((OLD.aropen_open=TRUE)
123     AND (NEW.aropen_open=FALSE)
124     AND (NEW.aropen_closedate IS NULL)) THEN
125       NEW.aropen_closedate=current_date;
126     END IF;
127   END IF;
128
129 --  Only check if the customer in question has a non-zero Credit Limit
130   SELECT cust_id, cust_creditlmt, cust_creditstatus,
131          cust_autoupdatestatus, cust_autoholdorders INTO _p
132   FROM custinfo
133   WHERE (cust_id=NEW.aropen_cust_id);
134   IF (_p.cust_creditlmt > 0) THEN
135     _checkLimit := true;
136
137     SELECT COALESCE(SUM( CASE WHEN (aropen_doctype IN ('I', 'D')) THEN (aropen_amount - aropen_paid)
138                      ELSE ((aropen_amount - aropen_paid) * -1)
139                 END ), 0.0) INTO _openAmount
140     FROM aropen AS current
141     WHERE ( (current.aropen_cust_id=NEW.aropen_cust_id)
142      AND (current.aropen_open)
143      AND (current.aropen_id <> NEW.aropen_id) );
144
145 --  Add in the value of the current aropen item
146     IF (NEW.aropen_doctype IN ('I', 'D')) THEN
147       _openAmount := (_openAmount + (NEW.aropen_amount - NEW.aropen_paid));
148     ELSE
149       _openAmount := (_openAmount - (NEW.aropen_amount - NEW.aropen_paid));
150     END IF;
151   ELSE
152     _openAmount := 0;
153   END IF;
154
155   IF (_checkLimit OR _checkLate) THEN
156 --  Handle a Customer that is going under its credit limit
157     IF ((_p.cust_creditlmt >= _openAmount) AND (_lateCount <= 0)) THEN
158
159 --  Handle the Customer Status
160       IF ( (_p.cust_autoupdatestatus) AND (_p.cust_creditstatus='W') ) THEN
161         UPDATE custinfo
162         SET cust_creditstatus='G'
163         WHERE (cust_id=NEW.aropen_cust_id);
164       END IF;
165
166 --  Handle the open Sales Orders
167       IF (_p.cust_autoholdorders) THEN
168         UPDATE cohead
169         SET cohead_holdtype='N'
170         FROM coitem
171         WHERE ( (coitem_cohead_id=cohead_id)
172          AND (cohead_holdtype='C')
173          AND (coitem_status='O')
174          AND (cohead_cust_id=_p.cust_id) );
175       END IF;
176
177 --  Handle a Customer that is going over its credit limit
178     ELSIF ((_p.cust_creditlmt < _openAmount) OR (_lateCount > 0)) THEN
179
180 --  Handle the Customer Status
181       IF ( (_p.cust_autoupdatestatus) AND (_p.cust_creditstatus = 'G') ) THEN
182         UPDATE custinfo
183         SET cust_creditstatus='W'
184         WHERE (cust_id=NEW.aropen_cust_id);
185       END IF;
186
187 --  Handle the open Sales Orders
188       IF (_p.cust_autoholdorders) THEN
189         UPDATE cohead
190         SET cohead_holdtype='C'
191         FROM coitem
192         WHERE ( (coitem_cohead_id=cohead_id)
193          AND (cohead_holdtype='N')
194          AND (coitem_status='O')
195          AND (cohead_cust_id=_p.cust_id) );
196       END IF;
197
198     END IF;
199
200   END IF;
201
202   RETURN NEW;
203
204 END;
205 $$
206  LANGUAGE 'plpgsql';
207
208 DROP TRIGGER IF EXISTS aropenTrigger ON aropen;
209 CREATE TRIGGER aropenTrigger BEFORE INSERT OR UPDATE ON aropen FOR EACH ROW EXECUTE PROCEDURE _aropenTrigger();
210
211 CREATE OR REPLACE FUNCTION _aropenAfterTrigger() RETURNS TRIGGER AS $$
212 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
213 -- See www.xtuple.com/CPAL for the full text of the software license.
214 DECLARE
215   _openAmount NUMERIC;
216   _lateCount INTEGER := 0;
217   _graceDays INTEGER;
218   _checkLate BOOLEAN := false;
219   _checkLimit BOOLEAN := false;
220   _id INTEGER;
221 BEGIN
222
223   IF (TG_OP = 'INSERT') THEN
224     _id := NEW.aropen_id;
225   ELSE
226     _id := OLD.aropen_id;
227   END IF;
228 -- If metric is set then auto close any associated incidents when AR is closed
229   IF (fetchMetricBool('AutoCloseARIncident')) THEN
230     IF (NEW.aropen_open = FALSE) THEN
231       UPDATE incdt SET incdt_status='L' WHERE (incdt_aropen_id=_id);
232     END IF;
233   END IF;
234
235   RETURN NEW;
236
237 END;
238 $$
239  LANGUAGE 'plpgsql';
240
241 SELECT dropIfExists('TRIGGER', 'aropenAfterTrigger');
242 CREATE TRIGGER aropenAfterTrigger AFTER INSERT OR UPDATE ON aropen FOR EACH ROW EXECUTE PROCEDURE _aropenAfterTrigger();
243