#ifdef FIN /* FIN_PAC.SRC * $Revision$ * $Id$ */ /* Formatted on 16-7-2010 17:57:48 (QP5 v5.136.908.31019) */ CREATE OR REPLACE PACKAGE fin AS PROCEDURE setfactuurstatus (pfactuurkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER); FUNCTION tolerantiematch (pdisckey IN NUMBER, pftype IN VARCHAR2, pfactbedrag IN NUMBER, pbestelbedrag IN NUMBER) RETURN NUMBER; FUNCTION matchfactuur (pfactuur_key IN NUMBER) RETURN NUMBER; PROCEDURE matchandsetfactuur (pfactuur_key IN NUMBER, prejecttoo IN BOOLEAN); PROCEDURE autoapprovefactuur (pfactuur_key IN NUMBER); FUNCTION getdefaultbtwtabelkey RETURN NUMBER; FUNCTION getbtwtabelkey(p_bkey IN NUMBER, p_ckey IN NUMBER, p_okey IN NUMBER, p_otherwise_default IN BOOLEAN) RETURN NUMBER; FUNCTION getbtwtabelwaardekey_perc (pperc IN NUMBER, pbtwtabelkey IN NUMBER, pbtwverlegd IN NUMBER) RETURN NUMBER; FUNCTION getbtwtabelwaardekey(pbedragexc IN NUMBER, pbtwbedrag IN NUMBER, pbtwtabelkey IN NUMBER, pbtwverlegd IN NUMBER) RETURN NUMBER; FUNCTION getbtw_bedrag_percentage (pbedragexc IN NUMBER, pperc IN NUMBER) RETURN NUMBER; FUNCTION getbtw_bedrag (pbedragexc IN NUMBER, pbtwtabelwaardekey IN NUMBER) RETURN NUMBER; FUNCTION getfactuurkostenplaats (pfactuur_key IN NUMBER) RETURN NUMBER; FUNCTION getfiatteur (pfactuur_key IN NUMBER, pexcludekey IN NUMBER DEFAULT NULL) RETURN NUMBER; FUNCTION sprintf (ps IN VARCHAR2 , p_factuur_key IN NUMBER) RETURN VARCHAR2; PROCEDURE remove(p_factuur_key IN NUMBER); END fin; / /* Formatted on 12-7-2011 14:49:08 (QP5 v5.136.908.31019) */ CREATE OR REPLACE PACKAGE BODY fin AS -- Geef meldingkey, gewenste status en userkey, en de status wortdt -- gezet, waarbij zonodig (indien verandering) een trackrecord wordt gemaakt -- Als de status niet wijzigt, wordt ook geen trackrecord gemaakt -- ZIE schema StateDiagramOpdrachten.vsd PROCEDURE setfactuurstatus (pfactuurkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER) AS currentstatus fin_factuur.fin_factuur_statuses_key%TYPE; newstatus fin_factuur.fin_factuur_statuses_key%TYPE; eventcode fac_srtnotificatie.fac_srtnotificatie_code%TYPE; BEGIN SELECT fin_factuur_statuses_key INTO currentstatus FROM fin_factuur WHERE fin_factuur_key = pfactuurkey; CASE pstatus WHEN 1 -- Afgewezen THEN IF currentstatus IS NULL OR currentstatus = 2 OR currentstatus = 5 THEN newstatus := pstatus; IF currentstatus = 5 THEN eventcode := 'FINGNO'; ELSE eventcode := 'FINFNO'; END IF; END IF; WHEN 2 -- Ingevoerd THEN IF currentstatus IS NULL THEN newstatus := pstatus; eventcode := 'FINNEW'; ELSIF currentstatus = 1 OR currentstatus = 5 THEN newstatus := pstatus; eventcode := 'FINFUN'; ELSIF currentstatus = 6 THEN newstatus := pstatus; eventcode := 'FINGUN'; END IF; WHEN 5 -- Ter goedkeuring THEN IF currentstatus = 2 THEN newstatus := pstatus; eventcode := 'FINFOK'; END IF; WHEN 6 -- Verwerkt THEN IF currentstatus = 2 OR currentstatus = 5 THEN newstatus := pstatus; eventcode := 'FINGOE'; END IF; WHEN 7 -- Uitgegeven THEN IF currentstatus = 6 THEN newstatus := pstatus; eventcode := 'FINVER'; END IF; ELSE -- Invalid statuschange or no change newstatus := NULL; END CASE; IF newstatus IS NOT NULL THEN -- vooralsnog lopen de notificaties 1-op-1 met de tracking -- noticode := eventcode; UPDATE fin_factuur SET fin_factuur_statuses_key = newstatus WHERE fin_factuur_key = pfactuurkey; -- We know that trackaction doesnt do tracking if eventcode is null fac.trackaction (eventcode, pfactuurkey, puserkey, NULL, NULL); END IF; END; -- Gegeven de 2 referentiekeys, lever het type 'B', 'O' of 'C' op -- Interne functie in de package vooralsnog FUNCTION getreferentietype (po_key IN NUMBER, pc_key IN NUMBER, pb_key IN NUMBER) RETURN VARCHAR2 IS rtype VARCHAR2 (1) := '?'; BEGIN IF po_key IS NOT NULL THEN rtype := 'O'; DBMS_OUTPUT.put_line ('opdrachtkey: ' || po_key); ELSIF pc_key IS NOT NULL THEN rtype := 'C'; DBMS_OUTPUT.put_line ('contractkey: ' || pc_key); ELSIF pb_key IS NOT NULL THEN rtype := 'B'; DBMS_OUTPUT.put_line ('besteloprachtkey: ' || pb_key); END IF; RETURN rtype; END; -- Geef 2 of 3 terug voor tweeweg of drieweg factuurmatchingsmode FUNCTION getfactmatchmode (pdisckey IN NUMBER, pftype IN VARCHAR2) RETURN NUMBER IS mmode VARCHAR2 (1) := '?'; BEGIN CASE WHEN pftype = 'B' THEN SELECT p.bes_disc_params_factmatchmode INTO mmode FROM bes_disc_params p WHERE p.bes_ins_discipline_key = pdisckey; WHEN pftype = 'C' THEN mmode := 2; WHEN pftype = 'O' THEN SELECT p.mld_disc_params_factmatchmode INTO mmode FROM mld_disc_params p WHERE p.mld_ins_discipline_key = pdisckey; ELSE mmode := 2; END CASE; IF mmode IS NULL THEN mmode := 2; -- default END IF; DBMS_OUTPUT.put_line ('>matchm(eth)ode: ' || mmode); RETURN mmode; END; -- Functie kan nu ook van buitenaf worden aangeroepen, en dan is BOOLEAN niet meer mogelijk -- true=match=1, false=geen match=0 FUNCTION tolerantiematch (pdisckey IN NUMBER, pftype IN VARCHAR2, pfactbedrag IN NUMBER, pbestelbedrag IN NUMBER) RETURN NUMBER IS discpct NUMBER; discmarge NUMBER; upperlimit NUMBER; lowerlimit NUMBER; match_lowerlimit fac_setting.fac_setting_default%TYPE; franchise NUMBER; BEGIN CASE WHEN pftype = 'B' THEN SELECT p.bes_disc_params_factuurpct, p.bes_disc_params_factuurmarge, p.bes_disc_params_factuurgrens INTO discpct, discmarge, franchise FROM bes_disc_params p WHERE p.bes_ins_discipline_key = pdisckey; WHEN pftype = 'C' THEN SELECT p.cnt_disc_params_factuurpct, p.cnt_disc_params_factuurmarge, p.cnt_disc_params_factuurgrens INTO discpct, discmarge, franchise FROM cnt_disc_params p WHERE p.cnt_ins_discipline_key = pdisckey; WHEN pftype = 'O' THEN SELECT p.mld_disc_params_factuurpct, p.mld_disc_params_factuurmarge, p.mld_disc_params_factuurgrens INTO discpct, discmarge, franchise FROM mld_disc_params p WHERE p.mld_ins_discipline_key = pdisckey; ELSE discpct := 0; discmarge := 0; END CASE; IF franchise IS NOT NULL AND pfactbedrag <= franchise THEN RETURN 1; -- klaar END IF; -- TODO Nagaan of je hiervoor toch nog iets met eerder gefactureerd moet? -- Je wilt het gedrag alsof alle deelfacturen in 1 keer waren gestuurd -- maar dat regelt de aanroeper al. Wat doet dit bij CNT? IF pbestelbedrag IS NULL -- niks van te zeggen verder THEN RETURN 0; END IF; IF discpct IS NULL AND discmarge IS NULL THEN upperlimit := pbestelbedrag; lowerlimit := pbestelbedrag; ELSIF discpct IS NULL THEN upperlimit := pbestelbedrag + discmarge; lowerlimit := pbestelbedrag - discmarge; ELSE upperlimit := pbestelbedrag * (100 + discpct) / 100; lowerlimit := pbestelbedrag * (100 - discpct) / 100; END IF; match_lowerlimit := fac.getSetting('fin_match_lowerlimit'); DBMS_OUTPUT.put_line ('discipline: ' || pdisckey); DBMS_OUTPUT.put_line ('tolerantie%: ' || discpct); DBMS_OUTPUT.put_line ('tolerantie-abs: ' || discmarge); DBMS_OUTPUT.put_line ('bestel/opdracht/contactbedrag: ' || pbestelbedrag); DBMS_OUTPUT.put_line ('bovengrens: ' || upperlimit); IF match_lowerlimit = 1 THEN DBMS_OUTPUT.put_line ('ondergrens: ' || lowerlimit); END IF; DBMS_OUTPUT.put_line ('vrijstelling: ' || franchise); DBMS_OUTPUT.put_line ('factuurbedrag: ' || pfactbedrag); IF pfactbedrag <= upperlimit THEN -- niet te hoog IF match_lowerlimit = 1 AND pfactbedrag < lowerlimit THEN -- ondergrens doet er toe en het is te laag = nok RETURN 0; ELSE -- ondergrens doet er niet toe of het is hoger dan de ondergrens = ok RETURN 1; END IF; ELSE -- te hoog = nok RETURN 0; END IF; END; FUNCTION matchfactuur (pfactuur_key IN NUMBER) RETURN NUMBER IS -- controleert deze nieuwe factuur, en levert een oordeel op: -- -1 factuur niet (automatisch) goed -- 0 niks van te zeggen of reeds goed-/afgekeurd/verwerkt -- 1 factuur okay ftype VARCHAR2 (1); c_key fin_factuur.cnt_contract_key%TYPE; b_key fin_factuur.bes_bestelopdr_key%TYPE; o_key fin_factuur.mld_opdr_key%TYPE; factuurstatus fin_factuur.fin_factuur_statuses_key%TYPE; factuurdatum fin_factuur.fin_factuur_datum%TYPE; factuurboekmaand fin_factuur.fin_factuur_boekmaand%TYPE; discipline ins_tab_discipline.ins_discipline_key%TYPE; factmatchmode mld_disc_params.mld_disc_params_factmatchmode%TYPE; korting bes_bestelopdr.bes_bestelopdr_korting%TYPE; levkosten bes_bestelopdr.bes_bestelopdr_levkosten%TYPE; contracttermijnkosten cnt_contract.cnt_contract_termijnkosten%TYPE; factuurschemabedrag cnt_factuurschema.cnt_factuurschema_bedrag%TYPE; contractkosten cnt_contract.cnt_contract_kosten%TYPE; opdrachtkosten mld_opdr.mld_opdr_kosten%TYPE; typeopdr_factuur mld_typeopdr.mld_typeopdr_factuur%TYPE; factuurbedrag NUMBER (12, 2); bestelbedrag NUMBER (12, 2); -- van de opdracht waar deze factuur over gaat totaalgefactureerd NUMBER (12, 2); -- met deze factuur erbij eerder gefactureerd van dezelfde B(R)OC totaaltermijngefactureerd NUMBER (12, 2); -- met deze factuur erbij eerder gefactureerd van dezelfde C igv factuurschema-gebruik totaaltermijngefactureerdbtw NUMBER (12, 2); -- met deze factuur erbij eerder gefactureerd van dezelfde C igv factuurschema-gebruik totaalgefactureerdbtw NUMBER (12, 2); aantalgefactureerd NUMBER := 0; opdrstatus mld_opdr.mld_statusopdr_key%TYPE; retval NUMBER := 0; inclbtw NUMBER := 0; -- Bepaal te tolerantie van de vakgroep -- waarschijnlijk in procenten of zo? -- of geven we de factuurwaarde mee en leveren we true/false op? BEGIN -------------------------------------------- ------------ START MAIN ROUTINE ------------ -------------------------------------------- --- --- Over wat voor soort factuur hebben we het? --- IF pfactuur_key IS NULL THEN DBMS_OUTPUT.put_line ('STOP, factuurkey: NULL'); RETURN 0; END IF; DBMS_OUTPUT.put_line ('\nfactuurkey: ' || pfactuur_key); SELECT mld_opdr_key, cnt_contract_key, bes_bestelopdr_key, fin_factuur_totaal, fin_factuur_statuses_key, fin_factuur_datum, fin_factuur_boekmaand INTO o_key, c_key, b_key, factuurbedrag, factuurstatus, factuurdatum, factuurboekmaand FROM fin_factuur WHERE fin_factuur_key = pfactuur_key; IF factuurstatus <> 2 -- is al verwerkt, matching zinloos THEN DBMS_OUTPUT.put_line ('STOP, factuurstatus: ' || factuurstatus); RETURN 0; END IF; ftype := fin.getreferentietype (o_key, c_key, b_key); DBMS_OUTPUT.put_line ('>opdrachttype: ' || ftype); -- -- Ga maar eens matchen -- CASE -- -- BESTELLING -- WHEN ftype = 'B' THEN -- Factuur ok als binnen de toleranties van de bestelcatalogus -- en het totaal met de eerder bestellingfacturen ook, -- waarbij afhankelijk van 2-weg/3-weg wordt geteld. -- Dat moeten we dus eerst bepalen SELECT MAX (isg.ins_discipline_key) INTO discipline FROM bes_bestelopdr_item boi, bes_bestelling_item bbi, bes_srtdeel isd, bes_srtgroep isg WHERE isd.bes_srtgroep_key = isg.bes_srtgroep_key AND bbi.bes_srtdeel_key = isd.bes_srtdeel_key AND boi.bes_bestelopdr_item_key = bbi.bes_bestelopdr_item_key AND boi.bes_bestelopdr_key = b_key; factmatchmode := fin.getfactmatchmode (discipline, 'B'); -- Zijn de bestelbedragen incl. of excl. BTW. SELECT MAX( (SELECT ks.prs_kostensoort_btw FROM prs_kostensoort ks WHERE ks.prs_kostensoort_key = COALESCE (bsg.prs_kostensoort_key, bd.prs_kostensoort_key))) INTO inclbtw FROM bes_discipline bd, bes_srtgroep bsg WHERE bd.ins_discipline_key = bsg.ins_discipline_key AND bd.ins_discipline_key = discipline; -- Bereken dan nu de voor de matching relevante bedragen -- Voor bestellingen nemen we de INKOOPPRIJS (het is immers een factuur die wij ontvangen) -- Maar als die niet gevuld is (ook bv bij punchout), dan de enige andere prijs die we weten -- de verkoopprijs CASE WHEN factmatchmode = 2 THEN SELECT SUM(boi.bes_bestelopdr_item_aantal * COALESCE (boi.bes_bestelopdr_item_inkprijs, boi.bes_bestelopdr_item_prijs)), MAX (COALESCE (bo.bes_bestelopdr_korting, 0)), MAX (COALESCE (bo.bes_bestelopdr_levkosten, 0)) INTO bestelbedrag, korting, levkosten FROM bes_bestelopdr_item boi, bes_bestelling_item bbi, bes_bestelopdr bo WHERE boi.bes_bestelopdr_item_key = bbi.bes_bestelopdr_item_key AND bo.bes_bestelopdr_key = boi.bes_bestelopdr_key AND bo.bes_bestelopdr_status NOT IN (1, 3, 8) -- als die maar niet afgewezen/geannuleerd is AND boi.bes_bestelopdr_key = b_key; WHEN factmatchmode = 3 THEN SELECT SUM(boi.bes_bestelopdr_item_aantal * COALESCE (boi.bes_bestelopdr_item_inkprijs, boi.bes_bestelopdr_item_prijs)), MAX (COALESCE (bo.bes_bestelopdr_korting, 0)), MAX (COALESCE (bo.bes_bestelopdr_levkosten, 0)) INTO bestelbedrag, korting, levkosten FROM bes_bestelopdr_item boi, bes_bestelling_item bbi, bes_bestelopdr bo WHERE boi.bes_bestelopdr_item_key = bbi.bes_bestelopdr_item_key AND bo.bes_bestelopdr_key = boi.bes_bestelopdr_key AND boi.bes_bestelopdr_item_status IN (6, 7) -- alleen de geleverde regels meetellen AND boi.bes_bestelopdr_key = b_key; END CASE; bestelbedrag := bestelbedrag - korting + levkosten; -- Bedragen zijn excl. BTW? SELECT SUM (fin_factuur_totaal), SUM (fin_factuur_totaal_btw) INTO totaalgefactureerd, totaalgefactureerdbtw FROM fin_factuur WHERE bes_bestelopdr_key = b_key AND fin_factuur_statuses_key <> 1 AND fin_factuur_verwijder IS NULL AND (fin_factuur_datum <= factuurdatum OR fin_factuur_statuses_key IN (6, 7)); -- Akkoord(6) en Verwerkt(7) IF inclbtw = 1 -- Artikelen zijn al inclusief, dan ook maar factuur inclusief matchen THEN DBMS_OUTPUT.put_line ('Inclusief BTW'); totaalgefactureerd := totaalgefactureerd + totaalgefactureerdbtw; END IF; IF fin.tolerantiematch (discipline, ftype, totaalgefactureerd, bestelbedrag) = 1 THEN retval := 1; ELSE retval := -1; END IF; -- -- CONTRACT -- WHEN ftype = 'C' THEN -- om te beginnen zit deze factuur per definitie in deze termijn (welke dan ook) totaaltermijngefactureerd := factuurbedrag; -- Zijn deze contractbedragen incl. of excl. BTW. SELECT MAX( (SELECT ks.prs_kostensoort_btw FROM prs_kostensoort ks WHERE ks.prs_kostensoort_key = COALESCE (c.prs_kostensoort_key, cd.prs_kostensoort_key))) INTO inclbtw FROM cnt_discipline cd, cnt_contract c WHERE cd.ins_discipline_key = c.ins_discipline_key AND c.cnt_contract_key = c_key; -- Controle op termijn bedrag en totaal, je kunt discussieren of _verwijder moet worden gecontroleerd. BEGIN SELECT c.cnt_contract_termijnkosten, c.cnt_contract_kosten, c.ins_discipline_key INTO contracttermijnkosten, contractkosten, discipline FROM cnt_contract c WHERE cnt_contract_status = 0 -- actief AND cnt_contract_key = c_key; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.put_line ('Bijbehorend contract(status?) is ongeldig: ' || c_key); RETURN -1; END; -- Er kan ook gebruik gemaakt worden van een factuurschema, dan moet het termijnbedrag anders bepaald worden BEGIN SELECT s.cnt_factuurschema_bedrag INTO factuurschemabedrag FROM cnt_factuurschema s WHERE s.cnt_factuurschema_boekmaand = factuurboekmaand AND s.cnt_contract_key = c_key; -- Ok, er is dus een factuurschema-bedrag voor deze periode: dan controleren: EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.put_line( 'Geen factuurschema van toepassing voor contract ' || c_key || ' in periode ' || factuurboekmaand); -- factuurschemabedrag is nu null END; -- waren er niet al facturen voor dezelfde periode en komt het totaal er met deze dan niet overheen? SELECT SUM (fin_factuur_totaal), SUM (fin_factuur_totaal_btw) INTO totaaltermijngefactureerd, totaaltermijngefactureerdbtw FROM fin_factuur WHERE cnt_contract_key = c_key AND fin_factuur_statuses_key <> 1 AND fin_factuur_verwijder IS NULL AND fin_factuur_datum <= factuurdatum AND fin_factuur_boekmaand = factuurboekmaand; -- totaaltermijngefactureerd(btw) is dus voor deze periode inclusief deze nieuwe, dus -- dus mogelijk hoger dan deze ene factuur -- We doen er toch niks mee: factmatchmode := fin.getfactmatchmode (discipline, 'C'); -- hoeveel is er *met deze factuur erbij* totaal voor dit contract gefactureerd SELECT SUM (fin_factuur_totaal), SUM (fin_factuur_totaal_btw) INTO totaalgefactureerd, totaalgefactureerdbtw FROM fin_factuur WHERE cnt_contract_key = c_key AND fin_factuur_statuses_key <> 1 AND fin_factuur_verwijder IS NULL AND fin_factuur_datum <= factuurdatum; DBMS_OUTPUT.put_line ('Totaal gefactureerd: ' || totaalgefactureerd); DBMS_OUTPUT.put_line ('Totaal gefactureerd periode: ' || totaaltermijngefactureerd); IF inclbtw = 1 -- Contractbedragen zijn al inclusief, dan ook factuur inclusief matchen THEN DBMS_OUTPUT.put_line ('Inclusief BTW'); totaalgefactureerd := totaalgefactureerd + totaalgefactureerdbtw; -- inclusief BTW totaaltermijngefactureerd := totaaltermijngefactureerd + totaaltermijngefactureerdbtw; -- deze periode(maand) incl. BTW DBMS_OUTPUT.put_line ('Totaal gefactureerd: ' || totaalgefactureerd); DBMS_OUTPUT.put_line ('Totaal gefactureerd periode: ' || totaaltermijngefactureerd); END IF; IF ( totaalgefactureerd <= contractkosten + fac.safe_to_number (fac.getsetting ('cnt_factuur_totaalmarge')) OR contractkosten IS NULL) AND fin.tolerantiematch (discipline, ftype, totaaltermijngefactureerd, COALESCE (factuurschemabedrag, contracttermijnkosten)) = 1 THEN retval := 1; ELSE retval := -1; END IF; -- -- OPDRACHT -- WHEN ftype = 'O' THEN -- controleer op basis van mld_typeopdr_factuur BEGIN SELECT o.mld_opdr_kosten, o.mld_opdr_discipline_key, top.mld_typeopdr_factuur, o.mld_statusopdr_key INTO opdrachtkosten, discipline, typeopdr_factuur, opdrstatus FROM mld_opdr o, mld_melding m, mld_typeopdr top WHERE o.mld_melding_key = m.mld_melding_key AND o.mld_typeopdr_key = top.mld_typeopdr_key --AND top.mld_typeopdr_uren NOT IN (3, 4, 5) -- bij interne uren geen facturen AND top.mld_typeopdr_factuur <> 0 -- dan willen we ook geen factuur AND top.mld_typeopdr_kosten = 1 -- daar mag een factuur bij AND mld_statusopdr_key NOT IN (1, 2, 3, 10) -- dat zijn (nog) ongeldige opdrachten AND mld_opdr_key = o_key; EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.put_line ( 'Bijbehorende opdracht(status/kosten/type) is ongeldig: ' || o_key); RETURN -1; END; DBMS_OUTPUT.put_line ('opdrachtkosten: ' || opdrachtkosten); DBMS_OUTPUT.put_line ('typeopdr_factuur: ' || typeopdr_factuur); DBMS_OUTPUT.put_line ('opdrstatus: ' || opdrstatus); SELECT MAX( (SELECT ks.prs_kostensoort_btw FROM prs_kostensoort ks WHERE ks.prs_kostensoort_key = COALESCE (o.prs_kostensoort_key, stdm.prs_kostensoort_key, md.prs_kostensoort_key))) INTO inclbtw FROM mld_discipline md, mld_opdr o, mld_stdmelding stdm, mld_melding m WHERE md.ins_discipline_key = o.mld_opdr_discipline_key AND o.mld_melding_key = m.mld_melding_key AND m.mld_stdmelding_key = stdm.mld_stdmelding_key AND mld_opdr_key = o_key; factmatchmode := fin.getfactmatchmode (discipline, 'O'); -- Een opdracht is maar 1 ding, dus die status bepaalt al veel bij 3-weg -- De opdracht moet nl. so wie so afgemeld zijn. IF factmatchmode = 3 AND opdrstatus NOT IN (6, 7, 9) THEN RETURN -1; END IF; SELECT SUM (fin_factuur_totaal), SUM (fin_factuur_totaal_btw), COUNT(*) INTO totaalgefactureerd, totaalgefactureerdbtw, aantalgefactureerd FROM fin_factuur WHERE mld_opdr_key = o_key AND fin_factuur_statuses_key <> 1 AND fin_factuur_verwijder IS NULL AND fin_factuur_datum <= factuurdatum; -- Hier kunnen we iets met de deels nieuwe opties -- '0;Geen facturen;1;Eén factuur (vaste prijs);2;Eén factuur (nacalculatie);3;Meerdere facturen;4;Contracttermijnen', -- 0 hebben we direct al afgevangen -- 1 en 2 verdragen geen eerdere factuur IF typeopdr_factuur IN (1,2) AND aantalgefactureerd>1 THEN -- er is al een eerdere factuur, dan is de rest fout retval := -1; ELSE -- dan is dit 3 of de eerste van 1 of 2 IF inclbtw = 1 -- Opdrachtbedragen zijn dus inclusief, dan ook factuur inclusief matchen THEN DBMS_OUTPUT.put_line ('Inclusief BTW'); totaalgefactureerd := totaalgefactureerd + totaalgefactureerdbtw; END IF; IF typeopdr_factuur = 2 THEN retval := 1; ELSE IF fin.tolerantiematch (discipline, ftype, totaalgefactureerd, opdrachtkosten) = 1 THEN retval := 1; ELSE retval := -1; END IF; END IF; END IF; ELSE retval := 0; END CASE; RETURN retval; END; -- Keurt een ingevoerde factuur (onvoorwaardelijk) goed of (als rejecttoo) af op basis van de matchingscriteria PROCEDURE matchandsetfactuur (pfactuur_key IN NUMBER, prejecttoo IN BOOLEAN) IS lgoedkeurder fin_factuur.prs_perslid_key_goedkeur%TYPE; BEGIN CASE fin.matchfactuur (pfactuur_key) WHEN 1 THEN IF fac.getsetting('fin_enable_goedkeuren') = 0 -- validation unavailable THEN fin.setfactuurstatus (pfactuur_key, 6, NULL); ELSIF fac.getsetting('fin_enable_goedkeuren') = 2 -- validation required THEN fin.setfactuurstatus (pfactuur_key, 5, NULL); ELSE -- validation optional (fin_enable_goedkeuren = 1) SELECT f.prs_perslid_key_goedkeur INTO lgoedkeurder FROM fin_factuur f WHERE fin_factuur_key = pfactuur_key; IF lgoedkeurder IS NULL THEN fin.setfactuurstatus (pfactuur_key, 6, NULL); ELSE fin.setfactuurstatus (pfactuur_key, 5, NULL); END IF; END IF; WHEN -1 THEN IF prejecttoo THEN fin.setfactuurstatus (pfactuur_key, 1, NULL); END IF; ELSE NULL; END CASE; END; -- Behandelt een ingevoerde factuur conform settings en matchingscriteria PROCEDURE autoapprovefactuur (pfactuur_key IN NUMBER) IS ftype VARCHAR2 (1); c_key fin_factuur.cnt_contract_key%TYPE; b_key fin_factuur.bes_bestelopdr_key%TYPE; o_key fin_factuur.mld_opdr_key%TYPE; factuurappr bes_disc_params.bes_disc_params_factuurappr%TYPE; BEGIN SELECT mld_opdr_key, cnt_contract_key, bes_bestelopdr_key INTO o_key, c_key, b_key FROM fin_factuur WHERE fin_factuur_key = pfactuur_key; ftype := fin.getreferentietype (o_key, c_key, b_key); -- Jammer dat ik ook hier nog eens de discipline moet bepalen CASE WHEN ftype = 'B' THEN SELECT p.bes_disc_params_factuurappr INTO factuurappr FROM bes_disc_params p WHERE p.bes_ins_discipline_key = (SELECT MAX (isg.ins_discipline_key) FROM bes_bestelopdr_item boi, bes_bestelling_item bbi, bes_srtdeel isd, bes_srtgroep isg WHERE boi.bes_bestelopdr_item_key = bbi.bes_bestelopdr_item_key AND bbi.bes_srtdeel_key = isd.bes_srtdeel_key AND isd.bes_srtgroep_key = isg.bes_srtgroep_key AND boi.bes_bestelopdr_key = b_key); WHEN ftype = 'C' THEN SELECT p.cnt_disc_params_factuurappr INTO factuurappr FROM cnt_disc_params p WHERE p.cnt_ins_discipline_key = (SELECT c.ins_discipline_key FROM cnt_contract c WHERE cnt_contract_key = c_key); WHEN ftype = 'O' THEN SELECT p.mld_disc_params_factuurappr INTO factuurappr FROM mld_disc_params p WHERE p.mld_ins_discipline_key = (SELECT o.mld_opdr_discipline_key FROM mld_opdr o WHERE mld_opdr_key = o_key); ELSE factuurappr := 0; END CASE; IF factuurappr = 1 THEN matchandsetfactuur (pfactuur_key, FALSE); END IF; END; -- Bepaalt de key van de DEFAULT btw-tabel FUNCTION getdefaultbtwtabelkey RETURN NUMBER IS lkey fin_btwtabel.fin_btwtabel_key%TYPE; BEGIN BEGIN SELECT fin_btwtabel_key INTO lkey FROM fin_btwtabel WHERE fin_btwtabel_default = 1 AND fin_btwtabel_verwijder IS NULL; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; END; RETURN lkey; END; -- Bepaalt de key van de overeenkomstige btw-tabel, gegeven de key van (XOR) of contract, of meldingopdracht, of bestelopdracht -- Wanneer geen p_bkey, p_ckey, p_okey wordt meegegeven (allemaal NULL), dan wordt de default btw-tabel opgeleverd indien p_otherwise_default = TRUE, -- en anders (als p_otherwise_default = FALSE) dan wordt NULL opgeleverd. -- PF: en ik constateer dat ook als er bij de gevonden entititeit geen table is, ook de default wordt gegegeven, dus FUNCTION getbtwtabelkey (p_bkey IN NUMBER, p_ckey IN NUMBER, p_okey IN NUMBER, p_otherwise_default IN BOOLEAN) RETURN NUMBER IS lkey fin_btwtabel.fin_btwtabel_key%TYPE; CURSOR bes_btwtabel IS SELECT DISTINCT COALESCE (btw.fin_btwtabel_key, fin.getdefaultbtwtabelkey ()) btwtabel_key FROM bes_bestelling_item bi, bes_srtdeel isd, bes_bestelopdr_item boi, bes_bestelopdr bo, prs_bedrijf bd, fin_btwtabel btw WHERE btw.fin_btwtabel_key(+) = bd.fin_btwtabel_key AND bd.prs_bedrijf_key = isd.prs_bedrijf_key AND isd.bes_srtdeel_key = bi.bes_srtdeel_key AND bi.bes_bestelopdr_item_key = boi.bes_bestelopdr_item_key AND boi.bes_bestelopdr_key = bo.bes_bestelopdr_key AND bo.bes_bestelopdr_key = p_bkey; CURSOR cnt_btwtabel IS SELECT DISTINCT COALESCE (btw.fin_btwtabel_key, fin.getdefaultbtwtabelkey ()) btwtabel_key FROM cnt_contract c, prs_bedrijf bd, fin_btwtabel btw WHERE btw.fin_btwtabel_key(+) = bd.fin_btwtabel_key AND bd.prs_bedrijf_key(+) = c.cnt_prs_bedrijf_key AND c.cnt_contract_key = p_ckey; CURSOR mld_btwtabel IS SELECT DISTINCT COALESCE (btw.fin_btwtabel_key, fin.getdefaultbtwtabelkey ()) btwtabel_key FROM mld_opdr o, prs_bedrijf bd, fin_btwtabel btw WHERE btw.fin_btwtabel_key(+) = bd.fin_btwtabel_key AND bd.prs_bedrijf_key(+) = o.mld_uitvoerende_keys AND o.mld_opdr_key = p_okey; BEGIN lkey := NULL; IF p_bkey IS NOT NULL THEN -- BTW-tabel is te zoeken vanaf de bestelopdracht FOR rc IN bes_btwtabel LOOP lkey := rc.btwtabel_key; EXIT WHEN lkey IS NOT NULL; END LOOP; ELSIF p_ckey IS NOT NULL THEN -- BTW-tabel is te zoeken bij contract FOR rc IN cnt_btwtabel LOOP lkey := rc.btwtabel_key; EXIT WHEN lkey IS NOT NULL; END LOOP; ELSIF p_okey IS NOT NULL THEN -- BTW-tabel is te zoeken bij de meldingopdracht FOR rc IN mld_btwtabel LOOP lkey := rc.btwtabel_key; EXIT WHEN lkey IS NOT NULL; END LOOP; ELSIF p_otherwise_default THEN lkey := fin.getdefaultbtwtabelkey (); END IF; RETURN lkey; END; -- Zoekt de key van het overeenkomstige btwpercentage op, gegeven het percentage 'pperc' en de btwtabel 'pbtwtabelkey' -- Geeft NULL indien het percentage niet voorkomt. FUNCTION getbtwtabelwaardekey_perc (pperc IN NUMBER, pbtwtabelkey IN NUMBER, pbtwverlegd IN NUMBER) RETURN NUMBER IS lkey fin_btwtabelwaarde.fin_btwtabelwaarde_key%TYPE; BEGIN BEGIN SELECT fin_btwtabelwaarde_key INTO lkey FROM fin_btwtabelwaarde WHERE fin_btwtabel_key = pbtwtabelkey AND fin_btwtabelwaarde_perc = pperc AND COALESCE (fin_btwtabelwaarde_verlegd, 0) = pbtwverlegd AND fin_btwtabelwaarde_verwijder IS NULL; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; END; RETURN lkey; END; -- Zoekt de key van het overeenkomstige btwpercentage op, gegeven het excl bedrag, btwbedrag en tabel -- Geeft NULL indien het percentage niet voorkomt. FUNCTION getbtwtabelwaardekey (pbedragexc IN NUMBER, pbtwbedrag IN NUMBER, pbtwtabelkey IN NUMBER, pbtwverlegd IN NUMBER) RETURN NUMBER IS lpercentage NUMBER; lkey fin_btwtabelwaarde.fin_btwtabelwaarde_key%TYPE; BEGIN IF pbedragexc <> 0 THEN lpercentage := ROUND (100 * pbtwbedrag / pbedragexc); lkey := getbtwtabelwaardekey_perc (lpercentage, pbtwtabelkey, pbtwverlegd); END IF; RETURN lkey; END; -- Berekent het BTW-bedrag, gegeven het bedrag 'pbedragexc' en het percentage 'pperc' FUNCTION getbtw_bedrag_percentage (pbedragexc IN NUMBER, pperc IN NUMBER) RETURN NUMBER IS lbtwbedrag NUMBER; BEGIN RETURN ROUND (pbedragexc * pperc / 100, 2); END; -- Berekent het BTW-bedrag, gegeven het bedrag 'pbedragexc', de btwtabelwaarde 'pbtwtabelwaardekey' FUNCTION getbtw_bedrag (pbedragexc IN NUMBER, pbtwtabelwaardekey IN NUMBER) RETURN NUMBER IS lperc fin_btwtabelwaarde.fin_btwtabelwaarde_perc%TYPE; lverlegd fin_btwtabelwaarde.fin_btwtabelwaarde_verlegd%TYPE; lbtwbedrag NUMBER; BEGIN BEGIN SELECT fin_btwtabelwaarde_perc, COALESCE(fin_btwtabelwaarde_verlegd, 0) INTO lperc, lverlegd FROM fin_btwtabelwaarde WHERE fin_btwtabelwaarde_key = pbtwtabelwaardekey; IF lverlegd = 1 THEN lbtwbedrag := 0; ELSE lbtwbedrag := getbtw_bedrag_percentage (pbedragexc, lperc); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; END; RETURN lbtwbedrag; END; -- zoek de kostenplaats van een (gekoppelde) factuur op -- Bij voorkeur niet meer gebruiken sinds v2017.2 FUNCTION getfactuurkostenplaats (pfactuur_key IN NUMBER) RETURN NUMBER IS ftype VARCHAR2 (1); c_key fin_factuur.cnt_contract_key%TYPE; b_key fin_factuur.bes_bestelopdr_key%TYPE; o_key fin_factuur.mld_opdr_key%TYPE; kpkey prs_kostenplaats.prs_kostenplaats_key%TYPE; BEGIN SELECT mld_opdr_key, cnt_contract_key, bes_bestelopdr_key INTO o_key, c_key, b_key FROM fin_factuur WHERE fin_factuur_key = pfactuur_key; ftype := fin.getreferentietype (o_key, c_key, b_key); CASE WHEN ftype = 'B' THEN SELECT MAX (b.prs_kostenplaats_key) INTO kpkey FROM bes_bestelopdr_item boi, bes_bestelling_item bbi, bes_bestelopdr bo, bes_bestelling b WHERE bbi.bes_bestelling_key = b.bes_bestelling_key AND boi.bes_bestelopdr_item_key = bbi.bes_bestelopdr_item_key AND bo.bes_bestelopdr_key = boi.bes_bestelopdr_key AND boi.bes_bestelopdr_key = b_key; WHEN ftype = 'C' THEN SELECT c.prs_kostenplaats_key INTO kpkey FROM cnt_contract c WHERE cnt_contract_key = c_key; WHEN ftype = 'O' THEN SELECT COALESCE (o.prs_kostenplaats_key, m.prs_kostenplaats_key) INTO kpkey FROM mld_opdr o, mld_melding m WHERE o.mld_melding_key = m.mld_melding_key AND mld_opdr_key = o_key; ELSE kpkey := -1; END CASE; RETURN kpkey; END; -- zoek de fiatteur van een (gekoppelde) factuur op -- -1 als niet gevonden FUNCTION getfiatteur (pfactuur_key IN NUMBER, pexcludekey IN NUMBER DEFAULT NULL) RETURN NUMBER IS c_key fin_factuur.cnt_contract_key%TYPE; b_key fin_factuur.bes_bestelopdr_key%TYPE; o_key fin_factuur.mld_opdr_key%TYPE; ftot fin_factuur.fin_factuur_totaal%TYPE; ftotb fin_factuur.fin_factuur_totaal_btw%TYPE; kpkey prs_kostenplaats.prs_kostenplaats_key%TYPE; ldisckey ins_tab_discipline.ins_discipline_key%TYPE; kskey prs_kostensoort.prs_kostensoort_key%TYPE; linclbtw prs_kostensoort.prs_kostensoort_btw%TYPE; lbedrag fin_factuur.fin_factuur_totaal%TYPE; BEGIN SELECT mld_opdr_key, cnt_contract_key, bes_bestelopdr_key, fin_factuur_totaal, fin_factuur_totaal_btw INTO o_key, c_key, b_key, ftot, ftotb FROM fin_factuur WHERE fin_factuur_key = pfactuur_key; CASE WHEN b_key IS NOT NULL THEN SELECT MAX (b.prs_kostenplaats_key) INTO kpkey FROM bes_bestelopdr_item boi, bes_bestelling_item bbi, bes_bestelopdr bo, bes_bestelling b WHERE bbi.bes_bestelling_key = b.bes_bestelling_key AND boi.bes_bestelopdr_item_key = bbi.bes_bestelopdr_item_key AND bo.bes_bestelopdr_key = boi.bes_bestelopdr_key AND boi.bes_bestelopdr_key = b_key; WHEN c_key IS NOT NULL THEN SELECT c.prs_kostenplaats_key INTO kpkey FROM cnt_contract c WHERE cnt_contract_key = c_key; WHEN o_key IS NOT NULL THEN SELECT COALESCE (o.prs_kostenplaats_key, m.prs_kostenplaats_key) INTO kpkey FROM mld_opdr o, mld_melding m WHERE o.mld_melding_key = m.mld_melding_key AND mld_opdr_key = o_key; ELSE RETURN -1; END CASE; IF linclbtw = 1 THEN lbedrag := ftot + ftotb; ELSE lbedrag := ftot; END IF; RETURN prs.getfiatteur(kpkey, pexcludekey, lbedrag, ldisckey); END; FUNCTION sprintf (ps IN VARCHAR2 , p_factuur_key IN NUMBER) RETURN VARCHAR2 IS s VARCHAR2 (2048 CHAR); BEGIN s := ps; -- We do support substitution of placeholders in the messages -- ##KEY## = fin_factuur_key IF INSTR (s, '#') > 0 THEN s := REPLACE (s, '##KEY##', p_factuur_key); END IF; RETURN s; END; PROCEDURE remove(p_factuur_key IN NUMBER) IS CURSOR c_bijlagen(p_refkey IN NUMBER) IS SELECT fac_bijlagen_key FROM fac_bijlagen b , fin_factuur r , fin_kenmerk k WHERE b.fac_bijlagen_kenmerk_key = k.fin_kenmerk_key AND b.fac_bijlagen_refkey = r.fin_factuur_key AND b.fac_bijlagen_module = 'FIN' AND k.fin_kenmerk_type = 'F' AND b.fac_bijlagen_refkey = p_refkey; BEGIN -- Bijlagen van factuurregels verwijderen. -- Zoek alle factuurregels bij deze factuur. -- Garandeer dat de bijlage bij de factuurregel hoort en niet bij een factuur met dezelfde refkey als de factuurregel, -- door alleen kenmerken te gebruiken die alleen voor factuurregels zijn. FOR ref_bijlagen IN (SELECT fac_bijlagen_key FROM fac_bijlagen b , fin_factuurregel r , fin_kenmerk k WHERE b.fac_bijlagen_kenmerk_key = k.fin_kenmerk_key AND b.fac_bijlagen_refkey = r.fin_factuurregel_key AND b.fac_bijlagen_module = 'FIN' AND k.fin_kenmerk_type = 'R' AND r.fin_factuur_key = p_factuur_key ) LOOP flx.deleteflexbijlage (ref_bijlagen.fac_bijlagen_key); END LOOP; FOR ref_bijlagen IN c_bijlagen(p_factuur_key) LOOP flx.deleteflexbijlage (ref_bijlagen.fac_bijlagen_key); END LOOP; DELETE FROM fin_factuur WHERE fin_factuur_key = p_factuur_key; -- Van de volgende tabellen worden de records die naar deze p_afspraak_key -- verwijzen met ON DELETE CASCADE ook verwijderd: -- fin_factuur_note -- fin_kenmerkfactuur -- Hierdoor worden de afhankelijkheden in de volgende tabellen ook verwijderd: -- fin_factuurregel -- fin_kenmerkfactregel fac.remove_tracking('factuur', p_factuur_key); END; END fin; / REGISTERRUN('$Id$') #endif // FIN