1 -- based on the latest code in subversion.
5 CREATE OR REPLACE FUNCTION voidApopenVoucher(INTEGER) RETURNS INTEGER AS $$
6 -- Copyright (c) 1999-2012 by OpenMFG LLC, d/b/a xTuple.
7 -- See www.xtuple.com/CPAL for the full text of the software license.
9 pApopenid ALIAS FOR $1;
11 RETURN voidApopenVoucher(pApopenid, fetchJournalNumber('AP-VO'));
13 $$ LANGUAGE 'plpgsql';
15 CREATE OR REPLACE FUNCTION voidApopenVoucher(INTEGER, INTEGER) RETURNS INTEGER AS $$
16 -- Copyright (c) 1999-2012 by OpenMFG LLC, d/b/a xTuple.
17 -- See www.xtuple.com/CPAL for the full text of the software license.
19 pApopenid ALIAS FOR $1;
20 pJournalNumber ALIAS FOR $2;
22 _apcreditapplyid INTEGER;
26 _totalAmount_base NUMERIC;
28 _itemAmount_base NUMERIC;
40 _exchGainFreight NUMERIC;
41 _firstExchDateFreight DATE;
47 _totalAmount_base := 0;
49 SELECT fetchGLSequence() INTO _sequence;
51 -- Cache APOpen Information
52 SELECT apopen.* INTO _n
54 WHERE ( (apopen_doctype='V')
55 AND (apopen_id=pApopenid) );
57 RAISE EXCEPTION 'Cannot Void Voucher #% as apopen not found', pApopenid;
60 -- Cache Voucher Infomation
62 vend_number || '-' || vend_name || ' ' || vohead_reference
64 COALESCE(pohead_orderdate, vohead_docdate) AS pohead_orderdate,
65 COALESCE(pohead_curr_id, vohead_curr_id) AS pohead_curr_id INTO _p
66 FROM vohead JOIN vendinfo ON (vend_id=vohead_vend_id)
67 LEFT OUTER JOIN pohead ON (vohead_pohead_id = pohead_id)
68 WHERE (vohead_number=_n.apopen_docnumber);
70 RAISE EXCEPTION 'Cannot Void Voucher #% as vohead not found', _n.apopen_docnumber;
73 _glDate := COALESCE(_p.vohead_gldistdate, _p.vohead_distdate);
75 -- there is no currency gain/loss on items, see issue 3892,
76 -- but there might be on freight, which is first encountered at p/o receipt
77 SELECT recv_date::DATE INTO _firstExchDateFreight
79 WHERE (recv_vohead_id = _p.vohead_id);
81 -- Start by handling taxes
82 FOR _r IN SELECT tax_sales_accnt_id,
83 round(sum(taxdetail_tax),2) AS tax,
84 currToBase(_p.vohead_curr_id, round(sum(taxdetail_tax),2), _p.vohead_docdate) AS taxbasevalue
86 JOIN calculateTaxDetailSummary('VO', _p.vohead_id, 'T') ON (taxdetail_tax_id=tax_id)
87 GROUP BY tax_id, tax_sales_accnt_id LOOP
89 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', _p.vohead_number,
90 _r.tax_sales_accnt_id,
91 (_r.taxbasevalue * -1),
92 _glDate, _p.glnotes );
94 _totalAmount_base := (_totalAmount_base - _r.taxbasevalue);
95 _totalAmount := (_totalAmount - _r.tax);
99 -- Loop through the vodist records for the passed vohead that
100 -- are posted against a P/O Item
101 FOR _g IN SELECT DISTINCT poitem_id, voitem_qty, poitem_expcat_id,
102 poitem_invvenduomratio,
103 COALESCE(itemsite_id, -1) AS itemsiteid,
104 COALESCE(itemsite_costcat_id, -1) AS costcatid,
105 COALESCE(itemsite_item_id, -1) AS itemsite_item_id,
108 SELECT SUM(recv_value) AS value
110 WHERE (recv_voitem_id=voitem_id)
112 SELECT SUM(poreject_value)*-1 AS value
114 WHERE (poreject_voitem_id=voitem_id)) as data)
116 (poitem_freight_vouchered / poitem_qty_vouchered) * voitem_qty AS vouchered_freight,
117 currToBase(_p.pohead_curr_id, (poitem_freight_vouchered / poitem_qty_vouchered) * voitem_qty, _firstExchDateFreight ) AS vouchered_freight_base,
119 currToBase(_p.vohead_curr_id, voitem_freight,
120 _p.vohead_distdate) AS voitem_freight_base
122 poitem LEFT OUTER JOIN itemsite ON (poitem_itemsite_id=itemsite_id)
123 WHERE ( (vodist_poitem_id=poitem_id)
124 AND (voitem_poitem_id=poitem_id)
125 AND (voitem_vohead_id=vodist_vohead_id)
126 AND (vodist_vohead_id=_p.vohead_id)) LOOP
128 -- Grab the G/L Accounts
129 IF (_g.costcatid = -1) THEN
130 SELECT pp.accnt_id AS pp_accnt_id,
131 lb.accnt_id AS lb_accnt_id INTO _a
132 FROM expcat, accnt AS pp, accnt AS lb
133 WHERE ( (expcat_purchprice_accnt_id=pp.accnt_id)
134 AND (expcat_liability_accnt_id=lb.accnt_id)
135 AND (expcat_id=_g.poitem_expcat_id) );
137 RAISE EXCEPTION 'Cannot Void Voucher #% due to unassigned G/L Accounts.', _p.vohead_number;
140 SELECT pp.accnt_id AS pp_accnt_id,
141 lb.accnt_id AS lb_accnt_id INTO _a
142 FROM costcat, accnt AS pp, accnt AS lb
143 WHERE ( (costcat_purchprice_accnt_id=pp.accnt_id)
144 AND (costcat_liability_accnt_id=lb.accnt_id)
145 AND (costcat_id=_g.costcatid) );
147 RAISE EXCEPTION 'Cannot Void Voucher #% due to unassigned G/L Accounts.', _p.vohead_number;
151 -- Clear the Item Amount accumulator
152 _itemAmount_base := 0;
155 -- Figure out the total posted value for this line item
156 FOR _d IN SELECT vodist_id, vodist_amount,
157 _p.vohead_curr_id, vodist_costelem_id,
158 currToBase(_p.vohead_curr_id, vodist_amount,
159 _p.vohead_distdate) AS vodist_amount_base
161 WHERE ( (vodist_vohead_id=_p.vohead_id)
162 AND (vodist_poitem_id=_g.poitem_id) ) LOOP
167 WHERE ( (itemcost_item_id = _g.itemsite_item_id)
168 AND (itemcost_costelem_id = _d.vodist_costelem_id) );
171 _pExplain := _costx.itemcost_lowlevel;
174 -- Add the Distribution Amount to the Item Amount
175 _itemAmount_base := _itemAmount_base + ROUND(_d.vodist_amount_base, 2);
176 _itemAmount := _itemAmount + _d.vodist_amount;
180 -- Distribute from the clearing account
181 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
183 round(_g.value_base + _g.vouchered_freight_base, 2),
184 _glDate, _p.glnotes );
186 -- Attribute the correct portion to currency gain/loss
187 _exchGainFreight := 0;
188 SELECT currGain(_p.pohead_curr_id, _g.vouchered_freight,
189 _firstExchDateFreight, _p.vohead_distdate )
190 INTO _exchGainFreight;
191 IF (round(_exchGainFreight, 2) <> 0) THEN
192 PERFORM insertIntoGLSeries(_sequence, 'A/P', 'VO',
193 text(_p.vohead_number),
194 getGainLossAccntId(_a.lb_accnt_id), round(_exchGainFreight, 2) * -1,
195 _glDate, _p.glnotes);
198 -- Distribute the remaining variance to the Purchase Price Variance account
199 IF (round(_itemAmount_base, 2) <> round(_g.value_base, 2)) THEN
200 _tmpTotal := round(_itemAmount_base, 2) - round(_g.value_base, 2);
201 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
204 _glDate, _p.glnotes );
207 -- Distribute the remaining freight variance to the Purchase Price Variance account
208 IF (round(_g.voitem_freight_base + _exchGainFreight, 2) <> round(_g.vouchered_freight_base, 2)) THEN
209 _tmpTotal := round(_g.voitem_freight_base + _exchGainFreight, 2) - round(_g.vouchered_freight_base, 2);
210 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
213 _glDate, _p.glnotes );
216 -- Add the distribution amount to the total amount to distribute
217 _totalAmount_base := (_totalAmount_base + _itemAmount_base + _g.voitem_freight_base);
218 _totalAmount := (_totalAmount + _itemAmount + _g.voitem_freight);
220 -- Reverse the posting for all the Tagged Receivings for this P/O Item
222 SET recv_invoiced=FALSE,
223 recv_recvcost_curr_id=basecurrid(),
228 WHERE ( (recv_orderitem_id=poitem_id)
229 AND (recv_order_type='PO')
230 AND (recv_orderitem_id=_g.poitem_id)
231 AND (recv_vohead_id=_p.vohead_id) );
233 -- Reverse the posting for all the Tagged Rejections for this P/O Item
235 SET poreject_invoiced=FALSE,
236 poreject_vohead_id=NULL,
237 poreject_voitem_id=NULL
238 WHERE ( (poreject_poitem_id=_g.poitem_id)
239 AND (poreject_vohead_id=_p.vohead_id) );
241 -- Update the qty and freight vouchered fields
243 SET poitem_qty_vouchered = (poitem_qty_vouchered - _g.voitem_qty),
244 poitem_freight_vouchered = (poitem_freight_vouchered - _g.voitem_freight)
245 WHERE (poitem_id=_g.poitem_id);
249 -- Loop through the vodist records for the passed vohead that
250 -- are not posted against a P/O Item
251 -- Skip the tax distributions
252 FOR _d IN SELECT vodist_id,
253 currToBase(_p.vohead_curr_id, vodist_amount,
254 _p.vohead_distdate) AS vodist_amount_base,
256 vodist_accnt_id, vodist_expcat_id
258 WHERE ( (vodist_vohead_id=_p.vohead_id)
259 AND (vodist_poitem_id=-1)
260 AND (vodist_tax_id=-1) ) LOOP
262 -- Distribute from the misc. account
263 IF (_d.vodist_accnt_id = -1) THEN
264 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
266 round(_d.vodist_amount_base, 2),
267 _glDate, _p.glnotes )
269 WHERE (expcat_id=_d.vodist_expcat_id);
271 PERFORM insertIntoGLSeries( _sequence, 'A/P', 'VO', text(_p.vohead_number),
273 round(_d.vodist_amount_base, 2),
274 _glDate, _p.glnotes );
277 -- Add the Distribution Amount to the Total Amount
278 _totalAmount_base := _totalAmount_base + ROUND(_d.vodist_amount_base, 2);
279 _totalAmount := _totalAmount + _d.vodist_amount;
283 SELECT insertIntoGLSeries( _sequence, 'A/P', 'VO', text(vohead_number),
284 accnt_id, round(_totalAmount_base, 2) * -1,
285 _glDate, _p.glnotes ) INTO _test
286 FROM vohead LEFT OUTER JOIN accnt ON (accnt_id=findAPAccount(vohead_vend_id))
287 WHERE ( (findAPAccount(vohead_vend_id)=0 OR accnt_id > 0) -- G/L interface might be disabled
288 AND (vohead_id=_p.vohead_id) );
290 RAISE EXCEPTION 'Cannot Void Voucher #% due to an unassigned A/P Account.', _p.vohead_number;
293 PERFORM postGLSeries(_sequence, pJournalNumber);
295 -- Create the A/P Open Item
296 SELECT NEXTVAL('apopen_apopen_id_seq') INTO _apopenid;
297 _reference := ('Void Voucher #' || _n.apopen_docnumber);
299 ( apopen_id, apopen_username, apopen_journalnumber,
300 apopen_vend_id, apopen_docnumber, apopen_doctype, apopen_ponumber,
301 apopen_docdate, apopen_duedate, apopen_distdate, apopen_terms_id, apopen_curr_id,
302 apopen_amount, apopen_paid, apopen_open, apopen_notes, apopen_discount, apopen_curr_rate )
303 SELECT _apopenid, getEffectiveXtUser(), pJournalnumber,
304 apopen_vend_id, apopen_docnumber, 'C', apopen_ponumber,
305 CURRENT_DATE, CURRENT_DATE, CURRENT_DATE, -1, apopen_curr_id,
306 apopen_amount - apopen_paid, 0, TRUE, _reference, TRUE, apopen_curr_rate
308 WHERE (apopen_id=_n.apopen_id);
310 SELECT apcreditapply_id INTO _apcreditapplyid
312 WHERE ( (apcreditapply_source_apopen_id=_apopenid)
313 AND (apcreditapply_target_apopen_id=_n.apopen_id) );
316 SET apcreditapply_amount=_n.apopen_amount-_n.apopen_paid
317 WHERE (apcreditapply_id=_apcreditapplyid);
319 SELECT nextval('apcreditapply_apcreditapply_id_seq') INTO _apcreditapplyid;
320 INSERT INTO apcreditapply
321 ( apcreditapply_id, apcreditapply_source_apopen_id,
322 apcreditapply_target_apopen_id, apcreditapply_amount,
323 apcreditapply_curr_id )
324 VALUES ( _apcreditapplyid, _apopenid, _n.apopen_id, _n.apopen_amount-_n.apopen_paid, _n.apopen_curr_id );
327 SELECT postAPCreditMemoApplication(_apopenid) INTO _result;
329 IF (_result < 0) THEN
330 RAISE EXCEPTION 'Credit application failed with result %.', _result;
333 -- Reopen all of the P/O Items that were closed by this Voucher
335 SET poitem_status='O'
337 WHERE ( (voitem_poitem_id=poitem_id)
339 AND (voitem_vohead_id=_p.vohead_id) );
343 SET pohead_status='O'
344 WHERE (pohead_id=_p.vohead_pohead_id);
349 WHERE (apopen_id=_n.apopen_id);
351 RETURN pJournalNumber;
354 $$ LANGUAGE 'plpgsql';