1 -- updted to match svn version.
2 --- added checkhead_voided
4 ALTER TABLE checkhead add column checkhead_voided DATE;
6 CREATE OR REPLACE FUNCTION voidPostedCheck(INTEGER, INTEGER, DATE) RETURNS INTEGER AS $$
7 -- Copyright (c) 1999-2012 by OpenMFG LLC, d/b/a xTuple.
8 -- See www.xtuple.com/CPAL for the full text of the software license.
10 pCheckid ALIAS FOR $1;
11 pJournalNumber ALIAS FOR $2;
12 pVoidDate ALIAS FOR $3;
13 _amount_base NUMERIC := 0;
16 _credit_glaccnt INTEGER;
18 _exchGain NUMERIC := 0;
19 _exchGainTmp NUMERIC := 0;
24 _amount_check NUMERIC := 0;
28 SELECT fetchGLSequence() INTO _sequence;
31 checkhead_amount / checkhead_curr_rate AS checkhead_amount_base,
32 bankaccnt_accnt_id AS bankaccntid,
33 findPrepaidAccount(checkhead_recip_id) AS prepaidaccntid,
35 FROM bankaccnt, checkhead LEFT OUTER JOIN
36 checkrecip ON ((checkrecip_type=checkhead_recip_type)
37 AND (checkrecip_id=checkhead_recip_id))
38 WHERE ((checkhead_bankaccnt_id=bankaccnt_id)
39 AND (checkhead_id=pCheckid));
41 IF (NOT _p.checkhead_posted) THEN
45 IF (_p.checkrecip_id IS NULL) THEN -- outer join failed
49 -- Cannot void if already reconciled
50 SELECT trans_id INTO _result
51 FROM ( SELECT gltrans_id AS trans_id
53 WHERE ((gltrans_doctype='CK')
54 AND (gltrans_misc_id=_p.checkhead_id)
57 SELECT sltrans_id AS trans_id
59 WHERE ((sltrans_doctype='CK')
60 AND (sltrans_misc_id=_p.checkhead_id)
61 AND (sltrans_rec)) ) AS data;
66 _gltransNote := 'Void Posted Check #' || _p.checkhead_number || ' ' ||
67 _p.checkrecip_number || '-' || _p.checkrecip_name;
69 IF (_p.checkhead_misc) THEN
70 IF (COALESCE(_p.checkhead_expcat_id, -1) < 0) THEN
71 IF (_p.checkhead_recip_type = 'V') THEN
72 PERFORM createAPDebitMemo(_p.checkhead_recip_id, pJournalNumber,
73 CAST(fetchAPMemoNumber() AS text), '',
74 pVoidDate, _p.checkhead_amount,
75 _gltransNote || ' '|| _p.checkhead_notes,
76 -1, pVoidDate, -1, _p.checkhead_curr_id );
77 _credit_glaccnt := findAPPrepaidAccount(_p.checkhead_recip_id);
79 ELSIF (_p.checkhead_recip_type = 'C') THEN
80 PERFORM createARCreditMemo(NULL, _p.checkhead_recip_id,
81 fetchARMemoNumber(), '',
82 pVoidDate, _p.checkhead_amount,
83 _gltransNote || ' '|| _p.checkhead_notes,
84 -1, -1, -1, pVoidDate, -1, NULL, 0.0,
85 pJournalNumber, _p.checkhead_curr_id );
86 _credit_glaccnt := _p.prepaidaccntid;
88 ELSIF (_p.checkhead_recip_type = 'T') THEN
89 -- TODO: should we create a debit memo for the tax authority? how?
90 _credit_glaccnt := _p.checkrecip_accnt_id;
95 SELECT expcat_exp_accnt_id INTO _credit_glaccnt
97 WHERE (expcat_id=_p.checkhead_expcat_id);
103 IF (COALESCE(_credit_glaccnt, -1) < 0) THEN
107 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source, 'CK',
108 text(_p.checkhead_number),
110 round(_p.checkhead_amount_base, 2),
111 pVoidDate, _gltransNote, pCheckid);
113 _amount_base := _p.checkhead_amount_base;
116 FOR _r IN SELECT checkitem_amount, checkitem_discount,
117 CASE WHEN (checkitem_apopen_id IS NOT NULL) THEN
118 checkitem_amount / apopen_curr_rate
120 currToBase(checkitem_curr_id,
122 COALESCE(checkitem_docdate, _p.checkhead_checkdate))
123 END AS checkitem_amount_base,
124 checkitem_amount / checkitem_curr_rate AS amount_check,
125 apopen_id, apopen_doctype, apopen_docnumber, apopen_curr_rate, apopen_docdate,
126 aropen_id, aropen_doctype, aropen_docnumber,
127 checkitem_curr_id, checkitem_curr_rate,
128 COALESCE(checkitem_docdate, _p.checkhead_checkdate) AS docdate
129 FROM (checkitem LEFT OUTER JOIN
130 apopen ON (checkitem_apopen_id=apopen_id)) LEFT OUTER JOIN
131 aropen ON (checkitem_aropen_id=aropen_id)
132 WHERE (checkitem_checkhead_id=pcheckid) LOOP
135 IF (_r.apopen_id IS NOT NULL) THEN
136 -- undo the APDiscount Credit Memo if a discount was taken
137 IF(_r.checkitem_discount > 0) THEN
138 SELECT NEXTVAL('apopen_apopen_id_seq') INTO _apopenid;
139 SELECT fetchAPMemoNumber() INTO _docnumber;
141 ( apopen_id, apopen_username, apopen_journalnumber,
142 apopen_vend_id, apopen_docnumber, apopen_doctype, apopen_ponumber,
143 apopen_docdate, apopen_duedate, apopen_distdate, apopen_terms_id,
144 apopen_amount, apopen_paid, apopen_open,
146 apopen_accnt_id, apopen_curr_id, apopen_discount, apopen_curr_rate,
149 ( _apopenid, getEffectiveXtUser(), pJournalNumber,
150 _p.checkhead_recip_id, _docnumber, 'D', '',
151 pVoidDate, pVoidDate, pVoidDate, -1,
152 _r.checkitem_discount, _r.checkitem_discount, FALSE,
153 ('Reverse Posted Discount ' || _r.apopen_doctype || ' ' ||
154 _r.apopen_docnumber),
155 -1, _p.checkhead_curr_id, TRUE, _r.apopen_curr_rate,
159 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source,
160 'DS', _r.apopen_docnumber,
161 findAPDiscountAccount(_p.checkhead_recip_id),
162 round(_r.checkitem_discount / _r.apopen_curr_rate, 2) * -1,
163 pVoidDate, _gltransNote, pCheckid);
165 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source,
166 'DS', _r.apopen_docnumber,
167 findAPAccount(_p.checkhead_recip_id),
168 round(_r.checkitem_discount / _r.apopen_curr_rate, 2),
169 pVoidDate, _gltransNote, pCheckid);
171 -- Post the application
173 ( apapply_vend_id, apapply_postdate, apapply_username,
174 apapply_source_apopen_id, apapply_source_doctype, apapply_source_docnumber,
175 apapply_target_apopen_id, apapply_target_doctype, apapply_target_docnumber,
176 apapply_journalnumber, apapply_amount, apapply_curr_id )
178 ( _p.checkhead_recip_id, pVoidDate, getEffectiveXtUser(),
179 _apopenid, 'D', _docnumber,
180 _r.apopen_id, _r.apopen_doctype, _r.apopen_docnumber,
181 pJournalNumber, (_r.checkitem_discount * -1), _r.checkitem_curr_id );
182 END IF; -- discount was taken
185 SET apopen_paid = round(apopen_paid -
186 (_r.checkitem_amount + noNeg(_r.checkitem_discount)), 2),
187 apopen_open = round(apopen_amount, 2) >
189 (_r.checkitem_amount + noNeg(_r.checkitem_discount)), 2),
190 apopen_closedate = CASE WHEN (round(apopen_amount, 2) >
192 (_r.checkitem_amount + noNeg(_r.checkitem_discount)))) THEN NULL ELSE apopen_closedate END
193 WHERE (apopen_id=_r.apopen_id);
195 -- Post the application
197 ( apapply_vend_id, apapply_postdate, apapply_username,
198 apapply_source_apopen_id, apapply_source_doctype, apapply_source_docnumber,
199 apapply_target_apopen_id, apapply_target_doctype, apapply_target_docnumber,
200 apapply_journalnumber, apapply_amount, apapply_curr_id )
202 ( _p.checkhead_recip_id, pVoidDate, getEffectiveXtUser(),
203 -1, 'K', _p.checkhead_number,
204 _r.apopen_id, _r.apopen_doctype, _r.apopen_docnumber,
205 pJournalNumber, (_r.checkitem_amount * -1), _r.checkitem_curr_id );
206 END IF; -- if check item's apopen_id is not null
208 IF (_r.aropen_id IS NOT NULL) THEN
210 SET aropen_paid = round(aropen_paid -_r.checkitem_amount, 2),
211 aropen_open = round(aropen_amount, 2) >
212 round(aropen_paid - _r.checkitem_amount, 2)
213 WHERE (aropen_id=_r.aropen_id);
215 -- Post the application
217 ( arapply_cust_id, arapply_postdate, arapply_distdate, arapply_username,
218 arapply_source_aropen_id, arapply_source_doctype, arapply_source_docnumber,
219 arapply_target_aropen_id, arapply_target_doctype, arapply_target_docnumber,
220 arapply_journalnumber, arapply_applied, arapply_curr_id )
222 ( _p.checkhead_recip_id, pVoidDate, pVoidDate, getEffectiveXtUser(),
223 -1, 'K', _p.checkhead_number,
224 _r.aropen_id, _r.aropen_doctype, _r.aropen_docnumber,
225 pJournalNumber, (_r.checkitem_amount * -1), _r.checkitem_curr_id );
227 END IF; -- if check item's aropen_id is not null
229 -- calculate currency gain/loss
230 IF (_r.apopen_id IS NOT NULL) THEN
231 IF (_p.checkhead_curr_id = _r.checkitem_curr_id) THEN
232 IF (_r.apopen_docdate > _p.checkhead_checkdate) THEN
233 _exchGainTmp := ((_r.checkitem_amount/_p.checkhead_curr_rate) - (_r.checkitem_amount / _r.apopen_curr_rate)) * -1;
235 _exchGainTmp := ((_r.checkitem_amount / _r.apopen_curr_rate) - (_r.checkitem_amount/_p.checkhead_curr_rate));
238 -- unusual condition where bank overridden and different currency from voucher
239 IF (_r.apopen_docdate > _p.checkhead_checkdate) THEN
240 _exchGainTmp := ((_r.checkitem_amount/_r.checkitem_curr_rate) - (_r.checkitem_amount / _r.apopen_curr_rate)) * -1;
242 _exchGainTmp := ((_r.checkitem_amount / _r.apopen_curr_rate) - (_r.checkitem_amount/_r.checkitem_curr_rate));
246 SELECT arCurrGain(_r.aropen_id,_r.checkitem_curr_id, _r.checkitem_amount,
247 _p.checkhead_checkdate)
250 _exchGain := _exchGain + _exchGainTmp;
252 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source,
253 'CK', text(_p.checkhead_number),
254 _p.checkrecip_accnt_id,
255 round(_r.checkitem_amount_base, 2),
256 pVoidDate, _gltransNote, pCheckid);
257 IF (_exchGainTmp <> 0) THEN
258 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source,
259 'CK', text(_p.checkhead_number),
260 getGainLossAccntId(_p.checkrecip_accnt_id),
261 round(_exchGainTmp, 2) * -1,
262 pVoidDate, _gltransNote, pCheckid);
265 _amount_check := (_amount_check + _r.amount_check);
266 _amount_base := (_amount_base + _r.checkitem_amount_base);
270 IF( (_amount_check - _p.checkhead_amount) <> 0.0 ) THEN
271 _exchGainTmp := (_amount_check - _p.checkhead_amount) / _p.checkhead_curr_rate;
272 _exchGain := _exchGain + _exchGainTmp;
275 -- ensure that the check balances, attribute rounding errors to gain/loss
276 IF round(_amount_base, 2) - round(_exchGain, 2) <> round(_p.checkhead_amount_base, 2) THEN
277 IF round(_amount_base - _exchGain, 2) = round(_p.checkhead_amount_base, 2) THEN
278 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source,
280 text(_p.checkhead_number), getGainLossAccntId(_p.bankaccntid),
281 (round(_amount_base, 2) -
282 round(_exchGain, 2) -
283 round(_p.checkhead_amount_base, 2)) * -1,
284 pVoidDate, _gltransNote, pCheckid);
286 RAISE EXCEPTION 'checkhead_id % does not balance (% - % <> %)', pCheckid,
287 _amount_base, _exchGain, _p.checkhead_amount_base;
292 PERFORM insertIntoGLSeries( _sequence, _p.checkrecip_gltrans_source, 'CK',
293 text(_p.checkhead_number),
295 round(_p.checkhead_amount_base, 2) * -1,
296 pVoidDate, _gltransNote, pCheckid);
298 PERFORM postGLSeries(_sequence, pJournalNumber);
301 SET gltrans_misc_id=pCheckid
302 WHERE gltrans_sequence=_sequence;
305 SET checkhead_posted=false,
307 checkhead_voided=pVoidDate,
308 checkhead_journalnumber=pJournalNumber
309 WHERE (checkhead_id=pCheckid);
311 RETURN pJournalNumber;
314 $$ LANGUAGE 'plpgsql';