1 CREATE OR REPLACE FUNCTION voidApopenVoucher(INTEGER) 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.
5 pApopenid ALIAS FOR $1;
7 RETURN voidApopenVoucher(pApopenid, fetchJournalNumber('AP-VO'));
11 CREATE OR REPLACE FUNCTION voidApopenVoucher(INTEGER, INTEGER) RETURNS INTEGER AS $$
12 -- Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
13 -- See www.xtuple.com/CPAL for the full text of the software license.
15 pApopenid ALIAS FOR $1;
16 pJournalNumber ALIAS FOR $2;
18 _apcreditapplyid INTEGER;
22 _totalAmount_base NUMERIC;
24 _itemAmount_base NUMERIC;
36 _exchGainFreight NUMERIC;
37 _firstExchDateFreight DATE;
43 _totalAmount_base := 0;
45 SELECT fetchGLSequence() INTO _sequence;
47 -- Cache APOpen Information
48 SELECT apopen.* INTO _n
50 WHERE ( (apopen_doctype='V')
51 AND (apopen_id=pApopenid) );
53 RAISE EXCEPTION 'Cannot Void Voucher #% as apopen not found', pApopenid;
56 -- Cache Voucher Infomation
58 vend_number || '-' || vend_name || ' ' || vohead_reference
60 COALESCE(pohead_orderdate, vohead_docdate) AS pohead_orderdate,
61 COALESCE(pohead_curr_id, vohead_curr_id) AS pohead_curr_id INTO _p
62 FROM vohead JOIN vendinfo ON (vend_id=vohead_vend_id)
63 LEFT OUTER JOIN pohead ON (vohead_pohead_id = pohead_id)
64 WHERE (vohead_number=_n.apopen_docnumber);
66 RAISE EXCEPTION 'Cannot Void Voucher #% as vohead not found', _n.apopen_docnumber;
69 _glDate := COALESCE(_p.vohead_gldistdate, _p.vohead_distdate);
71 -- there is no currency gain/loss on items, see issue 3892,
72 -- but there might be on freight, which is first encountered at p/o receipt
73 SELECT recv_date::DATE INTO _firstExchDateFreight
75 WHERE (recv_vohead_id = _p.vohead_id);
77 -- Start by handling taxes
78 FOR _r IN SELECT tax_sales_accnt_id,
79 round(sum(taxdetail_tax),2) AS tax,
80 currToBase(_p.vohead_curr_id, round(sum(taxdetail_tax),2), _p.vohead_docdate) AS taxbasevalue
82 JOIN calculateTaxDetailSummary('VO', _p.vohead_id, 'T') ON (taxdetail_tax_id=tax_id)
83 GROUP BY tax_id, tax_sales_accnt_id LOOP
85 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', _p.vohead_number,
86 _r.tax_sales_accnt_id,
87 (_r.taxbasevalue * -1),
88 _glDate, _p.glnotes );
90 _totalAmount_base := (_totalAmount_base - _r.taxbasevalue);
91 _totalAmount := (_totalAmount - _r.tax);
95 -- Loop through the vodist records for the passed vohead that
96 -- are posted against a P/O Item
97 FOR _g IN SELECT DISTINCT poitem_id, voitem_qty, poitem_expcat_id,
98 poitem_invvenduomratio,
99 COALESCE(itemsite_id, -1) AS itemsiteid,
100 COALESCE(itemsite_costcat_id, -1) AS costcatid,
101 COALESCE(itemsite_item_id, -1) AS itemsite_item_id,
104 SELECT SUM(recv_value) AS value
106 WHERE (recv_voitem_id=voitem_id)
108 SELECT SUM(poreject_value)*-1 AS value
110 WHERE (poreject_voitem_id=voitem_id)) as data)
112 (poitem_freight_vouchered / poitem_qty_vouchered) * voitem_qty AS vouchered_freight,
113 currToBase(_p.pohead_curr_id, (poitem_freight_vouchered / poitem_qty_vouchered) * voitem_qty, _firstExchDateFreight ) AS vouchered_freight_base,
115 currToBase(_p.vohead_curr_id, voitem_freight,
116 _p.vohead_distdate) AS voitem_freight_base
118 poitem LEFT OUTER JOIN itemsite ON (poitem_itemsite_id=itemsite_id)
119 WHERE ( (vodist_poitem_id=poitem_id)
120 AND (voitem_poitem_id=poitem_id)
121 AND (voitem_vohead_id=vodist_vohead_id)
122 AND (vodist_vohead_id=_p.vohead_id)) LOOP
124 -- Grab the G/L Accounts
125 IF (_g.costcatid = -1) THEN
126 SELECT pp.accnt_id AS pp_accnt_id,
127 lb.accnt_id AS lb_accnt_id INTO _a
128 FROM expcat, accnt AS pp, accnt AS lb
129 WHERE ( (expcat_purchprice_accnt_id=pp.accnt_id)
130 AND (expcat_liability_accnt_id=lb.accnt_id)
131 AND (expcat_id=_g.poitem_expcat_id) );
133 RAISE EXCEPTION 'Cannot Void Voucher #% due to unassigned G/L Accounts.', _p.vohead_number;
136 SELECT pp.accnt_id AS pp_accnt_id,
137 lb.accnt_id AS lb_accnt_id INTO _a
138 FROM costcat, accnt AS pp, accnt AS lb
139 WHERE ( (costcat_purchprice_accnt_id=pp.accnt_id)
140 AND (costcat_liability_accnt_id=lb.accnt_id)
141 AND (costcat_id=_g.costcatid) );
143 RAISE EXCEPTION 'Cannot Void Voucher #% due to unassigned G/L Accounts.', _p.vohead_number;
147 -- Clear the Item Amount accumulator
148 _itemAmount_base := 0;
151 -- Figure out the total posted value for this line item
152 FOR _d IN SELECT vodist_id, vodist_amount,
153 _p.vohead_curr_id, vodist_costelem_id,
154 currToBase(_p.vohead_curr_id, vodist_amount,
155 _p.vohead_distdate) AS vodist_amount_base
157 WHERE ( (vodist_vohead_id=_p.vohead_id)
158 AND (vodist_poitem_id=_g.poitem_id) ) LOOP
163 WHERE ( (itemcost_item_id = _g.itemsite_item_id)
164 AND (itemcost_costelem_id = _d.vodist_costelem_id) );
167 _pExplain := _costx.itemcost_lowlevel;
170 -- Add the Distribution Amount to the Item Amount
171 _itemAmount_base := _itemAmount_base + ROUND(_d.vodist_amount_base, 2);
172 _itemAmount := _itemAmount + _d.vodist_amount;
176 -- Distribute from the clearing account
177 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
179 round(_g.value_base + _g.vouchered_freight_base, 2),
180 _glDate, _p.glnotes );
182 -- Attribute the correct portion to currency gain/loss
183 _exchGainFreight := 0;
184 SELECT currGain(_p.pohead_curr_id, _g.vouchered_freight,
185 _firstExchDateFreight, _p.vohead_distdate )
186 INTO _exchGainFreight;
187 IF (round(_exchGainFreight, 2) <> 0) THEN
188 PERFORM insertIntoGLSeries(_sequence, 'A/P', 'VO',
189 text(_p.vohead_number),
190 getGainLossAccntId(_a.lb_accnt_id), round(_exchGainFreight, 2) * -1,
191 _glDate, _p.glnotes);
194 -- Distribute the remaining variance to the Purchase Price Variance account
195 IF (round(_itemAmount_base, 2) <> round(_g.value_base, 2)) THEN
196 _tmpTotal := round(_itemAmount_base, 2) - round(_g.value_base, 2);
197 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
200 _glDate, _p.glnotes );
203 -- Distribute the remaining freight variance to the Purchase Price Variance account
204 IF (round(_g.voitem_freight_base + _exchGainFreight, 2) <> round(_g.vouchered_freight_base, 2)) THEN
205 _tmpTotal := round(_g.voitem_freight_base + _exchGainFreight, 2) - round(_g.vouchered_freight_base, 2);
206 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
209 _glDate, _p.glnotes );
212 -- Add the distribution amount to the total amount to distribute
213 _totalAmount_base := (_totalAmount_base + _itemAmount_base + _g.voitem_freight_base);
214 _totalAmount := (_totalAmount + _itemAmount + _g.voitem_freight);
216 -- Reverse the posting for all the Tagged Receivings for this P/O Item
218 SET recv_invoiced=FALSE,
219 recv_recvcost_curr_id=basecurrid(),
224 WHERE ( (recv_orderitem_id=poitem_id)
225 AND (recv_order_type='PO')
226 AND (recv_orderitem_id=_g.poitem_id)
227 AND (recv_vohead_id=_p.vohead_id) );
229 -- Reverse the posting for all the Tagged Rejections for this P/O Item
231 SET poreject_invoiced=FALSE,
232 poreject_vohead_id=NULL,
233 poreject_voitem_id=NULL
234 WHERE ( (poreject_poitem_id=_g.poitem_id)
235 AND (poreject_vohead_id=_p.vohead_id) );
237 -- Update the qty and freight vouchered fields
239 SET poitem_qty_vouchered = (poitem_qty_vouchered - _g.voitem_qty),
240 poitem_freight_vouchered = (poitem_freight_vouchered - _g.voitem_freight)
241 WHERE (poitem_id=_g.poitem_id);
245 -- Loop through the vodist records for the passed vohead that
246 -- are not posted against a P/O Item
247 -- Skip the tax distributions
248 FOR _d IN SELECT vodist_id,
249 currToBase(_p.vohead_curr_id, vodist_amount,
250 _p.vohead_distdate) AS vodist_amount_base,
252 vodist_accnt_id, vodist_expcat_id
254 WHERE ( (vodist_vohead_id=_p.vohead_id)
255 AND (vodist_poitem_id=-1)
256 AND (vodist_tax_id=-1) ) LOOP
258 -- Distribute from the misc. account
259 IF (_d.vodist_accnt_id = -1) THEN
260 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
262 round(_d.vodist_amount_base, 2),
263 _glDate, _p.glnotes )
265 WHERE (expcat_id=_d.vodist_expcat_id);
267 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
269 round(_d.vodist_amount_base, 2),
270 _glDate, _p.glnotes );
273 -- Add the Distribution Amount to the Total Amount
274 _totalAmount_base := _totalAmount_base + ROUND(_d.vodist_amount_base, 2);
275 _totalAmount := _totalAmount + _d.vodist_amount;
279 SELECT insertIntoGLSeries( _sequence, 'A/P', 'VO', text(vohead_number),
280 accnt_id, round(_totalAmount_base, 2) * -1,
281 _glDate, _p.glnotes ) INTO _test
282 FROM vohead LEFT OUTER JOIN accnt ON (accnt_id=findAPAccount(vohead_vend_id))
283 WHERE ( (findAPAccount(vohead_vend_id)=0 OR accnt_id > 0) -- G/L interface might be disabled
284 AND (vohead_id=_p.vohead_id) );
286 RAISE EXCEPTION 'Cannot Void Voucher #% due to an unassigned A/P Account.', _p.vohead_number;
289 PERFORM postGLSeries(_sequence, pJournalNumber);
291 -- Create the A/P Open Item
292 SELECT NEXTVAL('apopen_apopen_id_seq') INTO _apopenid;
293 _reference := ('Void Voucher #' || _n.apopen_docnumber);
295 ( apopen_id, apopen_username, apopen_journalnumber,
296 apopen_vend_id, apopen_docnumber, apopen_doctype, apopen_ponumber,
297 apopen_docdate, apopen_duedate, apopen_distdate, apopen_terms_id, apopen_curr_id,
298 apopen_amount, apopen_paid, apopen_open, apopen_notes, apopen_discount, apopen_curr_rate )
299 SELECT _apopenid, getEffectiveXtUser(), pJournalnumber,
300 apopen_vend_id, apopen_docnumber, 'C', apopen_ponumber,
301 _glDate, _glDate, _glDate, -1, apopen_curr_id,
302 apopen_amount - apopen_paid, 0, TRUE, _reference, TRUE, apopen_curr_rate
304 WHERE (apopen_id=_n.apopen_id);
306 SELECT apcreditapply_id INTO _apcreditapplyid
308 WHERE ( (apcreditapply_source_apopen_id=_apopenid)
309 AND (apcreditapply_target_apopen_id=_n.apopen_id) );
312 SET apcreditapply_amount=_n.apopen_amount-_n.apopen_paid
313 WHERE (apcreditapply_id=_apcreditapplyid);
315 SELECT nextval('apcreditapply_apcreditapply_id_seq') INTO _apcreditapplyid;
316 INSERT INTO apcreditapply
317 ( apcreditapply_id, apcreditapply_source_apopen_id,
318 apcreditapply_target_apopen_id, apcreditapply_amount,
319 apcreditapply_curr_id )
320 VALUES ( _apcreditapplyid, _apopenid, _n.apopen_id, _n.apopen_amount-_n.apopen_paid, _n.apopen_curr_id );
323 SELECT postAPCreditMemoApplication(_apopenid) INTO _result;
325 IF (_result < 0) THEN
326 RAISE EXCEPTION 'Credit application failed with result %.', _result;
329 -- Reopen all of the P/O Items that were closed by this Voucher
331 SET poitem_status='O'
333 WHERE ( (voitem_poitem_id=poitem_id)
335 AND (voitem_vohead_id=_p.vohead_id) );
339 SET pohead_status='O'
340 WHERE (pohead_id=_p.vohead_pohead_id);
345 WHERE (apopen_id=_n.apopen_id);
347 RETURN pJournalNumber;
350 $$ LANGUAGE 'plpgsql';