Issue #24653:allow issue of orders on credit hold with 0 balance
[xtuple] / foundation-database / public / functions / issuetoshipping.sql
1 CREATE OR REPLACE FUNCTION issueToShipping(INTEGER, NUMERIC) RETURNS INTEGER 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 BEGIN
5   RETURN issueToShipping('SO', $1, $2, 0, CURRENT_TIMESTAMP);
6 END;
7 $$ LANGUAGE plpgsql;
8
9 CREATE OR REPLACE FUNCTION issueToShipping(INTEGER, NUMERIC, INTEGER) RETURNS INTEGER AS $$
10 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
11 -- See www.xtuple.com/CPAL for the full text of the software license.
12 BEGIN
13   RETURN issueToShipping('SO', $1, $2, $3, CURRENT_TIMESTAMP);
14 END;
15 $$ LANGUAGE plpgsql;
16
17 CREATE OR REPLACE FUNCTION issueToShipping(TEXT, INTEGER, NUMERIC, INTEGER, TIMESTAMP WITH TIME ZONE) RETURNS INTEGER AS $$
18 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
19 -- See www.xtuple.com/CPAL for the full text of the software license.
20 BEGIN
21   RETURN issueToShipping($1, $2, $3, $4, $5, NULL);
22 END;
23 $$ LANGUAGE plpgsql;
24
25 CREATE OR REPLACE FUNCTION issueToShipping(pordertype TEXT,
26                                            pitemid INTEGER,
27                                            pQty NUMERIC,
28                                            pItemlocSeries INTEGER,
29                                            pTimestamp TIMESTAMP WITH TIME ZONE,
30                                            pinvhistid INTEGER) RETURNS INTEGER AS $$
31 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple. 
32 -- See www.xtuple.com/CPAL for the full text of the software license.
33 DECLARE
34   _itemlocSeries        INTEGER;
35   _timestamp            TIMESTAMP WITH TIME ZONE;
36   _coholdtype           TEXT;
37   _balance              NUMERIC;
38   _invhistid            INTEGER;
39   _shipheadid           INTEGER;
40   _shipnumber           INTEGER;
41   _cntctid              INTEGER;
42   _p                    RECORD;
43   _m                    RECORD;
44   _value                NUMERIC;
45   _warehouseid          INTEGER;
46   _shipitemid           INTEGER;
47   _freight              NUMERIC;
48
49 BEGIN
50
51   IF (pTimestamp IS NULL) THEN
52     _timestamp := CURRENT_TIMESTAMP;
53   ELSE
54     _timestamp := pTimestamp;
55   END IF;
56
57   IF (pItemlocSeries = 0) THEN
58     _itemlocSeries := NEXTVAL('itemloc_series_seq');
59   ELSE
60     _itemlocSeries := pItemlocSeries;
61   END IF;
62
63   IF (pordertype = 'SO') THEN
64
65     -- Check site security
66     SELECT warehous_id INTO _warehouseid
67     FROM coitem,itemsite,site()
68     WHERE ((coitem_id=pitemid)
69     AND (itemsite_id=coitem_itemsite_id)
70     AND (warehous_id=itemsite_warehous_id));
71           
72     IF (NOT FOUND) THEN
73       RETURN 0;
74     END IF;
75
76     -- Check for average cost items going negative
77     IF ( SELECT ( (itemsite_costmethod='A') AND
78                   ((itemsite_qtyonhand - round(pQty * coitem_qty_invuomratio, 6)) < 0.0) )
79          FROM coitem JOIN itemsite ON (itemsite_id=coitem_itemsite_id)
80          WHERE (coitem_id=pitemid) ) THEN
81       RETURN -20;
82     END IF;
83
84     -- Check auto registration
85     IF ( SELECT COALESCE(itemsite_autoreg, FALSE)
86          FROM coitem JOIN itemsite ON (itemsite_id=coitem_itemsite_id)
87          WHERE (coitem_id=pitemid) ) THEN
88       SELECT COALESCE(crmacct_cntct_id_1, -1) INTO _cntctid
89       FROM coitem JOIN cohead ON (cohead_id=coitem_cohead_id)
90                   JOIN crmacct ON (crmacct_cust_id=cohead_cust_id)
91       WHERE (coitem_id=pitemid);
92       IF (_cntctid = -1) THEN
93         RETURN -15;
94       END IF;
95     END IF; 
96   
97     -- Check Credit Hold
98     SELECT cohead_holdtype INTO _coholdtype
99     FROM coitem JOIN cohead ON (cohead_id=coitem_cohead_id)
100     WHERE (coitem_id=pitemid);
101
102     SELECT calcSalesOrderAmt(cohead_id) -
103            COALESCE(SUM(currToCurr(aropenalloc_curr_id, cohead_curr_id,
104                                    aropenalloc_amount, cohead_orderdate)),0) INTO _balance
105     FROM coitem JOIN cohead ON (cohead_id=coitem_cohead_id)
106                 LEFT OUTER JOIN aropenalloc ON (aropenalloc_doctype='S' AND
107                                                 aropenalloc_doc_id=cohead_id)
108     WHERE (coitem_id=pitemid)
109     GROUP BY cohead_id;
110
111     --RAISE NOTICE 'issueToShipping - order balance is %', _balance;
112     IF ( (_coholdtype = 'C') AND (_balance > 0.0) ) THEN
113       RETURN -12;
114     ELSIF (_coholdtype = 'P') THEN
115       RETURN -13;
116     ELSIF (_coholdtype = 'R') THEN
117       RETURN -14;
118     END IF;
119
120     SELECT shiphead_id INTO _shipheadid
121     FROM shiphead, coitem JOIN itemsite ON (itemsite_id=coitem_itemsite_id)
122     WHERE ( (coitem_id=pitemid)
123       AND   (shiphead_number=getOpenShipment(pordertype, coitem_cohead_id, itemsite_warehous_id)) );
124     IF (NOT FOUND) THEN
125       SELECT NEXTVAL('shiphead_shiphead_id_seq') INTO _shipheadid;
126
127       _shipnumber := fetchShipmentNumber();
128       IF (_shipnumber < 0) THEN
129         RETURN -10;
130       END IF;
131
132       INSERT INTO shiphead
133       ( shiphead_id, shiphead_number, shiphead_order_id, shiphead_order_type,
134         shiphead_shipped,
135         shiphead_sfstatus, shiphead_shipvia, shiphead_shipchrg_id,
136         shiphead_freight, shiphead_freight_curr_id,
137         shiphead_shipdate, shiphead_notes, shiphead_shipform_id )
138       SELECT _shipheadid, _shipnumber, coitem_cohead_id, pordertype,
139              FALSE,
140              'N', cohead_shipvia,
141              CASE WHEN (cohead_shipchrg_id <= 0) THEN NULL
142                   ELSE cohead_shipchrg_id
143              END,
144              cohead_freight, cohead_curr_id,
145              _timestamp::DATE, cohead_shipcomments,
146              CASE WHEN cohead_shipform_id = -1 THEN NULL
147                   ELSE cohead_shipform_id
148              END
149       FROM cohead, coitem
150       WHERE ((coitem_cohead_id=cohead_id)
151          AND (coitem_id=pitemid) );
152
153       UPDATE pack
154       SET pack_shiphead_id = _shipheadid,
155           pack_printed = FALSE
156       FROM coitem
157       WHERE ((pack_head_id=coitem_cohead_id)
158         AND  (pack_shiphead_id IS NULL)
159         AND  (pack_head_type='SO')
160         AND  (coitem_id=pitemid));
161
162     ELSE
163       UPDATE pack
164       SET pack_printed = FALSE
165       FROM coitem
166       WHERE ((pack_head_id=coitem_cohead_id)
167         AND  (pack_shiphead_id=_shipheadid)
168         AND  (pack_head_type='SO')
169         AND  (coitem_id=pitemid));
170     END IF;
171
172     -- Handle g/l transaction
173     SELECT postInvTrans( itemsite_id, 'SH', (pQty * coitem_qty_invuomratio),
174                            'S/R', porderType,
175                            formatSoNumber(coitem_id), shiphead_number,
176                            ('Issue ' || item_number || ' to Shipping for customer ' || cohead_billtoname),
177                            getPrjAccntId(cohead_prj_id, costcat_shipasset_accnt_id), costcat_asset_accnt_id,
178                            _itemlocSeries, _timestamp, NULL, pinvhistid ) INTO _invhistid
179     FROM coitem, cohead, itemsite, item, costcat, shiphead
180     WHERE ( (coitem_cohead_id=cohead_id)
181      AND (coitem_itemsite_id=itemsite_id)
182      AND (itemsite_item_id=item_id)
183      AND (itemsite_costcat_id=costcat_id)
184      AND (coitem_id=pitemid)
185      AND (shiphead_id=_shipheadid) );
186
187     SELECT (invhist_unitcost * invhist_invqty) INTO _value
188     FROM invhist
189     WHERE (invhist_id=_invhistid);
190
191     _shipitemid := nextval('shipitem_shipitem_id_seq');
192     INSERT INTO shipitem
193     ( shipitem_id, shipitem_shiphead_id, shipitem_orderitem_id, shipitem_qty,
194       shipitem_transdate, shipitem_trans_username, shipitem_invoiced,
195       shipitem_value, shipitem_invhist_id )
196     VALUES
197     ( _shipitemid, _shipheadid, pitemid, pQty,
198       _timestamp, getEffectiveXtUser(), FALSE,
199       _value, 
200       CASE WHEN _invhistid = -1 THEN
201         NULL
202       ELSE 
203         _invhistid
204       END );
205
206     -- Handle reservation
207     IF (fetchmetricbool('EnableSOReservations')) THEN
208       -- Remember what was reserved so we can re-reserve if this issue is returned
209       INSERT INTO shipitemrsrv 
210         (shipitemrsrv_shipitem_id, shipitemrsrv_qty)
211       SELECT _shipitemid, least(pQty,coitem_qtyreserved)
212       FROM coitem
213       WHERE ((coitem_id=pitemid)
214       AND (coitem_qtyreserved > 0));
215
216       -- Update sales order
217       UPDATE coitem
218         SET coitem_qtyreserved = noNeg(coitem_qtyreserved - pQty)
219       WHERE(coitem_id=pitemid);
220     END IF;
221
222     -- Calculate shipment freight
223     SELECT calcShipFreight(_shipheadid) INTO _freight;
224     UPDATE shiphead SET shiphead_freight=_freight
225     WHERE (shiphead_id=_shipheadid);
226
227   ELSEIF (pordertype = 'TO') THEN
228
229     -- Check site security
230     IF (fetchMetricBool('MultiWhs')) THEN
231       SELECT warehous_id INTO _warehouseid
232       FROM toitem, tohead, site()
233       WHERE ( (toitem_id=pitemid)
234         AND   (tohead_id=toitem_tohead_id)
235         AND   (warehous_id=tohead_src_warehous_id) );
236           
237       IF (NOT FOUND) THEN
238         RETURN 0;
239       END IF;
240     END IF;
241
242     SELECT postInvTrans( itemsite_id, 'SH', pQty, 'S/R',
243                          pordertype, formatToNumber(toitem_id), '', 'Issue to Shipping',
244                          costcat_shipasset_accnt_id, costcat_asset_accnt_id,
245                          _itemlocSeries, _timestamp) INTO _invhistid
246     FROM tohead, toitem, itemsite, costcat
247     WHERE ((tohead_id=toitem_tohead_id)
248       AND  (itemsite_item_id=toitem_item_id)
249       AND  (itemsite_warehous_id=tohead_src_warehous_id)
250       AND  (itemsite_costcat_id=costcat_id)
251       AND  (toitem_id=pitemid) );
252
253     SELECT (invhist_unitcost * invhist_invqty) INTO _value
254     FROM invhist
255     WHERE (invhist_id=_invhistid);
256
257     SELECT shiphead_id INTO _shipheadid
258     FROM shiphead, toitem JOIN tohead ON (tohead_id=toitem_tohead_id)
259     WHERE ( (toitem_id=pitemid)
260       AND   (shiphead_number=getOpenShipment(pordertype, tohead_id, tohead_src_warehous_id)) );
261
262     IF (NOT FOUND) THEN
263       _shipheadid := NEXTVAL('shiphead_shiphead_id_seq');
264
265       _shipnumber := fetchShipmentNumber();
266       IF (_shipnumber < 0) THEN
267         RETURN -10;
268       END IF;
269
270       INSERT INTO shiphead
271       ( shiphead_id, shiphead_number, shiphead_order_id, shiphead_order_type,
272         shiphead_shipped,
273         shiphead_sfstatus, shiphead_shipvia, shiphead_shipchrg_id,
274         shiphead_freight, shiphead_freight_curr_id,
275         shiphead_shipdate, shiphead_notes, shiphead_shipform_id )
276       SELECT _shipheadid, _shipnumber, tohead_id, pordertype,
277              FALSE,
278              'N', tohead_shipvia, tohead_shipchrg_id,
279              tohead_freight + SUM(toitem_freight), tohead_freight_curr_id,
280              _timestamp::DATE, tohead_shipcomments, tohead_shipform_id
281       FROM tohead, toitem
282       WHERE ((toitem_tohead_id=tohead_id)
283          AND (tohead_id IN (SELECT toitem_tohead_id
284                             FROM toitem
285                             WHERE (toitem_id=pitemid))) )
286       GROUP BY tohead_id, tohead_shipvia, tohead_shipchrg_id, tohead_freight,
287                tohead_freight_curr_id, tohead_shipcomments, tohead_shipform_id;
288     END IF;
289
290     INSERT INTO shipitem
291     ( shipitem_shiphead_id, shipitem_orderitem_id, shipitem_qty,
292       shipitem_transdate, shipitem_trans_username, shipitem_invoiced,
293       shipitem_value, shipitem_invhist_id )
294     VALUES
295     ( _shipheadid, pitemid, pQty,
296       _timestamp, getEffectiveXtUser(), FALSE,
297       _value, 
298       CASE WHEN _invhistid = -1 THEN NULL
299            ELSE _invhistid
300       END
301     );
302
303   ELSE
304     RETURN -11;
305   END IF;
306
307   RETURN _itemlocSeries;
308
309 END;
310 $$ LANGUAGE plpgsql;