Files
Database/CNT/CNT_PAC.SRC
Erik Groener 69b38b5a01 PCHD#55257 Contractbeheer - beperkte autorisatie
svn path=/Database/trunk/; revision=41278
2019-03-04 14:54:54 +00:00

524 lines
21 KiB
Plaintext

#ifdef CNT
/*
* $Revision$
* $Id$
*/
CREATE OR REPLACE PACKAGE cnt AS
PROCEDURE setcontractstatus (pcontractkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER);
FUNCTION cnt_getTermijndatum (pdate IN DATE, ptermijn_key IN NUMBER, prichting IN NUMBER) RETURN DATE;
FUNCTION termijnjaarfactor (ptermijn_key IN NUMBER) RETURN NUMBER;
FUNCTION cnt_getOpzegdatum (pcnt_contract_key IN NUMBER) RETURN DATE;
FUNCTION cnt_getRappeldatum (pcnt_contract_key IN NUMBER) RETURN DATE;
FUNCTION cnt_contract_status (van IN DATE, rappel IN DATE, opzeg IN DATE, tot IN DATE) RETURN NUMBER;
PROCEDURE splitscontract (p_key IN NUMBER, p_datum IN DATE, p_user IN NUMBER, p_amount NUMBER);
PROCEDURE generatefactuurschema (pcontractkey IN NUMBER,ptermijnbedrag IN NUMBER DEFAULT NULL);
FUNCTION getnieuwsteversiekey(p_key IN NUMBER) RETURN NUMBER;
FUNCTION sprintf (ps IN VARCHAR2 , p_contract_key IN NUMBER) RETURN VARCHAR2;
PRAGMA RESTRICT_REFERENCES (cnt_contract_status, WNDS, WNPS);
END cnt;
/
CREATE OR REPLACE PACKAGE BODY cnt AS
-- Geef contractkey, 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 StateDiagramContracten.vsd
PROCEDURE setcontractstatus (pcontractkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER)
AS
currentstatus cnt_contract.cnt_contract_status%TYPE;
newstatus cnt_contract.cnt_contract_status%TYPE;
eventcode fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
BEGIN
SELECT cnt_contract_status
INTO currentstatus
FROM cnt_contract
WHERE cnt_contract_key = pcontractkey;
CASE pstatus
WHEN 0 -- Actief
THEN
IF currentstatus IS NULL
THEN
newstatus := pstatus;
eventcode := 'CNTNEW';
ELSIF currentstatus = 2 OR currentstatus = 3 -- Het kan ook zijn dat er geen fiattering nodig is.
THEN
newstatus := pstatus;
eventcode := 'CNTFIT';
END IF;
WHEN 1 -- Gesloten
THEN
IF currentstatus = 0
THEN
newstatus := pstatus;
eventcode := 'CNTCLO';
END IF;
WHEN 2 -- Nieuw
THEN
IF currentstatus IS NULL
THEN
newstatus := pstatus;
eventcode := 'CNTNEW';
ELSIF currentstatus = 3
THEN
newstatus := pstatus;
eventcode := 'CNTREJ';
END IF;
WHEN 3 -- Ter goedkeuring
THEN
IF currentstatus = 2
THEN
newstatus := pstatus;
eventcode := 'CNTCPT';
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 cnt_contract
SET cnt_contract_status = newstatus
WHERE cnt_contract_key = pcontractkey;
-- We know that trackaction doesnt do tracking if eventcode is null
fac.trackaction (eventcode, pcontractkey, puserkey, NULL, NULL);
END IF;
END;
-- Deze functie bepaalt de datum door het termijn (ptermijn_key) van de datum (pdate) in mindering te brengen.
-- Indien de 29, 30 of 31 datum niet in de betreffende maand voorkomt wordt de eerste van de volgende maand genomen.
-- prichting geeft aan of ten opzichte van pdate achteruit (-1) of vooruit (1, of anders) moet worden gerekend.
FUNCTION cnt_getTermijndatum (pdate IN DATE, ptermijn_key IN NUMBER, prichting IN NUMBER)
RETURN DATE
IS
ptermijn_type VARCHAR2(1);
ptermijn_aantal NUMBER;
lrichting NUMBER;
BEGIN
IF prichting = -1
THEN
lrichting := -1;
ELSE
lrichting := 1;
END IF;
-- Bepaal type en aantal periodes
IF ptermijn_key IS NOT NULL
THEN
SELECT cnt_termijn_type,
cnt_termijn_aantal
INTO ptermijn_type,
ptermijn_aantal
FROM cnt_termijn
WHERE cnt_termijn_key = ptermijn_key;
ELSE
-- Als ptermijn_key leeg/ongedefinieerd, return pdate (ofwel termijn dan impliciet 0 dagen)!
RETURN pdate;
END IF;
IF ptermijn_type = 'D'
THEN
RETURN pdate + (lrichting * ptermijn_aantal);
ELSIF ptermijn_type = 'W'
THEN
RETURN pdate + (lrichting * ptermijn_aantal * 7);
ELSIF ptermijn_type = 'M'
THEN
RETURN fac.addMonths(pdate, lrichting * ptermijn_aantal);
ELSE
-- ptermijn_type = 'Y'
RETURN fac.addMonths(pdate, lrichting * ptermijn_aantal * 12);
END IF;
END;
-- Deze functie benadert de factor om een contracttermijn te normaliseren tot een (1) jaar.
-- Als dat niet kan (ongeldige termijn) wordt nu -1 opgeleverd
-- Vb: 4W -> 13, 2M ->6, 2J-> 0,5
-- Kan geen rekening houden met schrikkeljaren en 53 weken en zo
FUNCTION termijnjaarfactor (ptermijn_key IN NUMBER)
RETURN NUMBER
IS
ptermijn_type VARCHAR2 (1);
ptermijn_aantal NUMBER;
BEGIN
IF ptermijn_key IS NOT NULL
THEN
SELECT cnt_termijn_type, cnt_termijn_aantal
INTO ptermijn_type, ptermijn_aantal
FROM cnt_termijn
WHERE cnt_termijn_key = ptermijn_key;
ELSE
-- Als ptermijn_key leeg/ongedefinieerd, return dan maar 1
RETURN -1;
END IF;
IF ptermijn_aantal = 0
THEN
RETURN -1; -- delen door null mag niet he
END IF;
IF ptermijn_type = 'D'
THEN
RETURN 365 / ptermijn_aantal;
-- soms 366
ELSIF ptermijn_type = 'W'
THEN
RETURN 52 / ptermijn_aantal; -- soms 53
ELSIF ptermijn_type = 'M'
THEN
RETURN 12 / ptermijn_aantal;
ELSE
-- ptermijn_type = 'Y'
RETURN 1 / ptermijn_aantal;
END IF;
END;
FUNCTION cnt_getOpzegdatum (pcnt_contract_key IN NUMBER) RETURN DATE IS
plooptijd_tot DATE;
popzegtermijn NUMBER;
BEGIN
SELECT cnt_contract_looptijd_tot,
cnt_contract_opzegtermijn
INTO plooptijd_tot,
popzegtermijn
FROM cnt_contract
WHERE cnt_contract_key = pcnt_contract_key;
RETURN cnt_getTermijndatum (plooptijd_tot, popzegtermijn, -1);
END;
FUNCTION cnt_getRappeldatum (pcnt_contract_key IN NUMBER)
RETURN DATE
IS
plooptijd_tot DATE;
prappeltermijn NUMBER;
popzegtermijn NUMBER;
BEGIN
SELECT cnt_contract_looptijd_tot,
cnt_contract_rappeltermijn,
cnt_contract_opzegtermijn
INTO plooptijd_tot,
prappeltermijn,
popzegtermijn
FROM cnt_contract
WHERE cnt_contract_key = pcnt_contract_key;
RETURN cnt_getTermijndatum (cnt_getTermijndatum (plooptijd_tot, popzegtermijn, -1), prappeltermijn, -1);
END;
FUNCTION cnt_contract_status (van IN DATE, rappel IN DATE, opzeg IN DATE, tot IN DATE)
RETURN NUMBER
AS
varSysdate DATE;
BEGIN
varSysdate:=SYSDATE;
IF varSysdate < van THEN
RETURN 0;
ELSIF varSysdate <= rappel THEN
RETURN 1;
ELSIF varSysdate <= opzeg THEN
RETURN 2;
ELSIF varSysdate <= tot THEN
RETURN 3;
END IF;
RETURN 4;
END;
PROCEDURE splitscontract (p_key IN NUMBER, p_datum IN DATE, p_user IN NUMBER, p_amount NUMBER)
IS
begin1 DATE;
eind1 DATE;
versie1 cnt_contract.cnt_contract_versie%TYPE;
newkey NUMBER;
nummer1 cnt_contract.cnt_contract_nummer_intern%TYPE;
amount1 cnt_contract.cnt_contract_kosten%TYPE;
srtcontract_type cnt_disc_params.cnt_srtcontract_type%TYPE;
new_status cnt_contract.cnt_contract_status%TYPE;
BEGIN
-- Splits het contract met p_key in twee delen: het oude dat eindigt op p_datum - 1,
-- en een nieuwe kopie die begint op die p_datum
-- p_amount is -optioneel- het bedrag dat bij het oude contract moeten blijven
-- de rest komt bij de nieuwe. Als p_amount NULL is, eindigen beide contracten
-- met het originele bedrag.
IF p_key IS NULL
THEN
RETURN;
END IF;
BEGIN
SELECT c.cnt_contract_looptijd_van,
c.cnt_contract_looptijd_tot,
COALESCE (c.cnt_contract_versie, '0'),
cnt_contract_nummer_intern,
cnt_contract_kosten,
cdp.cnt_srtcontract_type
INTO begin1, eind1, versie1, nummer1, amount1, srtcontract_type
FROM cnt_contract c,
cnt_disc_params cdp
WHERE c.ins_discipline_key = cdp.cnt_ins_discipline_key
AND c.cnt_contract_key = p_key
AND c.cnt_contract_looptijd_van < p_datum
AND c.cnt_contract_looptijd_tot > p_datum;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN;
END;
IF (fac.getsetting('cnt_contract_approval') = 1 AND srtcontract_type != 6)
THEN
new_status := 2; -- altijd op nieuw
ELSE
new_status := 0; -- direct actief
END IF;
-- de datum is een zinvolle splitsdatum, alles in orde
INSERT INTO cnt_contract (cnt_contract_nummer, cnt_contract_omschrijving, cnt_contract_looptijd_tot, cnt_contract_kosten,
cnt_contract_uurloon, cnt_prs_bedrijf_key, cnt_prs_afdeling_key, cnt_prs_perslid_key,
cnt_contract_verwijder, cnt_contract_nummer_intern, cnt_contract_korting, prs_contactpersoon_key,
cnt_contract_contact_persoon, ins_discipline_key, cnt_contract_document,
prs_perslid_key_eig, prs_perslid_key_beh, prs_afdeling_key_eig, cnt_contract_status,
cnt_contract_looptijd_van, prs_kostenplaats_key, cnt_contract_termijnkosten, prs_kostensoort_key,
cnt_contract_opmerking, cnt_contract_mantel_key, cnt_contract_opzegtermijn,
cnt_contract_rappeltermijn, cnt_contract_versie, prs_dienst_key, cnt_contract_termijntermijn
)
SELECT cnt_contract_nummer,
cnt_contract_omschrijving,
cnt_contract_looptijd_tot,
amount1 - COALESCE(p_amount, 0),
cnt_contract_uurloon,
cnt_prs_bedrijf_key,
cnt_prs_afdeling_key,
cnt_prs_perslid_key,
NULL,
cnt_contract_nummer_intern,
cnt_contract_korting,
prs_contactpersoon_key,
cnt_contract_contact_persoon,
ins_discipline_key,
cnt_contract_document,
prs_perslid_key_eig,
prs_perslid_key_beh,
prs_afdeling_key_eig,
new_status,
p_datum,
prs_kostenplaats_key,
cnt_contract_termijnkosten,
prs_kostensoort_key,
cnt_contract_opmerking,
cnt_contract_mantel_key,
cnt_contract_opzegtermijn,
cnt_contract_rappeltermijn,
TO_CHAR (versie1 + 1),
prs_dienst_key,
cnt_contract_termijntermijn
FROM cnt_contract
WHERE cnt_contract_key = p_key;
--- ik wil de nieuwe key weten
SELECT cnt_contract_key
INTO newkey
FROM cnt_contract
WHERE cnt_contract_nummer_intern = nummer1
AND cnt_contract_versie = TO_CHAR (versie1 + 1)
AND cnt_contract_verwijder IS NULL;
--- Een versieloos oud contract krijgt expliciet versie 0
UPDATE cnt_contract
SET cnt_contract_looptijd_tot = p_datum - 1,
cnt_contract_versie = versie1,
cnt_contract_kosten = COALESCE(p_amount, cnt_contract_kosten)
WHERE cnt_contract_key = p_key;
fac.trackaction ('CNTUPD', p_key, p_user, NULL, NULL);
-- de basis is gelegd, nu de aanhang meekopieren
-- flexkenmerken
INSERT INTO cnt_kenmerkcontract (cnt_contract_key, cnt_kenmerk_key, cnt_kenmerkcontract_waarde
)
SELECT newkey, k.cnt_kenmerk_key, k.cnt_kenmerkcontract_waarde
FROM cnt_kenmerkcontract k
WHERE k.cnt_contract_key = p_key AND k.cnt_kenmerkcontract_verwijder IS NULL;
-- cnt_contract_dienst (blind kopieren)
INSERT INTO cnt_contract_dienst (cnt_contract_key, cnt_contract_dienst_contactext, cnt_contract_dienst_contactint, cnt_contract_dienst_materiaal, cnt_contract_dienst_uitvoertd, cnt_contract_dienst_uren, cnt_contract_dienst_uurloon, mld_stdmelding_key, prs_bedrijf_key
)
SELECT newkey,
cd.cnt_contract_dienst_contactext,
cd.cnt_contract_dienst_contactint,
cd.cnt_contract_dienst_materiaal,
cd.cnt_contract_dienst_uitvoertd,
cd.cnt_contract_dienst_uren,
cd.cnt_contract_dienst_uurloon,
cd.mld_stdmelding_key,
cd.prs_bedrijf_key
FROM cnt_contract_dienst cd
WHERE cd.cnt_contract_key = p_key;
-- scope en zo
-- cnt_contract_object
INSERT INTO cnt_contract_object (cnt_contract_key, cnt_ins_srtdeel_key, cnt_ins_deel_key
)
SELECT newkey, cob.cnt_ins_srtdeel_key, cob.cnt_ins_deel_key
FROM cnt_contract_object cob
WHERE cob.cnt_contract_key = p_key AND cob.cnt_contract_object_verwijder IS NULL;
--cnt_contract_plaats
INSERT INTO cnt_contract_plaats (cnt_contract_key, cnt_alg_plaats_code, cnt_alg_plaats_key, cnt_contract_plaats_gewicht
)
SELECT newkey, cop.cnt_alg_plaats_code, cop.cnt_alg_plaats_key, cop.cnt_contract_plaats_gewicht
FROM cnt_contract_plaats cop
WHERE cop.cnt_contract_key = p_key AND cop.cnt_contract_plaats_verwijder IS NULL;
IF p_amount IS NOT NULL AND amount1 <> 0 AND fac.getsetting('cnt_scopeverdeling') = 1
THEN -- gewicht is dan telkens een bedrag en cnt_contract_kosten is het totaal daarvan
UPDATE cnt_contract_plaats
SET cnt_contract_plaats_gewicht = cnt_contract_plaats_gewicht / amount1 * p_amount
WHERE cnt_contract_key = p_key;
UPDATE cnt_contract_plaats
SET cnt_contract_plaats_gewicht = cnt_contract_plaats_gewicht / amount1 * (amount1 - p_amount)
WHERE cnt_contract_key = newkey;
END IF;
--cnt_factuurschema: splitst op dezelfde grensdatum
UPDATE cnt_factuurschema
SET cnt_contract_key = newkey
WHERE cnt_contract_key = p_key
AND cnt_factuurschema_boekmaand >= TO_CHAR(p_datum, 'YYYY-MM');
fac.trackaction ('CNTNEW', newkey, p_user, NULL, NULL);
END splitscontract;
-- Genereer een factuurschema met een gelijk bedrag per maand gedurende
-- de looptijd van het contract
-- Verondersteld dat er nog geen schema was.
PROCEDURE generatefactuurschema (
pcontractkey IN NUMBER,
ptermijnbedrag IN NUMBER DEFAULT NULL)
AS
maanden NUMBER (10);
maand NUMBER (10);
ltermijnbedrag cnt_factuurschema.cnt_factuurschema_bedrag%TYPE;
BEGIN
FOR cnt_rec
IN (SELECT cnt_contract_kosten,
cnt_contract_looptijd_tot,
cnt_contract_looptijd_van
FROM cnt_contract
WHERE cnt_contract_key = pcontractkey)
LOOP
maanden :=
1
+ TRUNC(MONTHS_BETWEEN (cnt_rec.cnt_contract_looptijd_tot,
cnt_rec.cnt_contract_looptijd_van));
ltermijnbedrag :=
COALESCE (ptermijnbedrag, cnt_rec.cnt_contract_kosten / maanden);
FOR maand IN 0 .. maanden - 1
LOOP
INSERT INTO cnt_factuurschema (cnt_contract_key,
cnt_factuurschema_boekmaand,
cnt_factuurschema_bedrag)
VALUES (pcontractkey,
TO_CHAR (
ADD_MONTHS (cnt_rec.cnt_contract_looptijd_van, maand),
'YYYY-MM'),
ltermijnbedrag);
END LOOP;
END LOOP;
END;
-- Zoek de key van de hoogste revisie van het meegegeven contract
-- Beseffende dat _versie een oplopende reeks is en hopende dat
-- nummer_intern hetzelfde blijft over versies en vrij uniek is
-- Voor wat extra zekerheid wordt bedrijf betrokken
FUNCTION getnieuwsteversiekey (p_key IN NUMBER)
RETURN NUMBER
IS
nummer1 cnt_contract.cnt_contract_nummer_intern%TYPE;
versie1 cnt_contract.cnt_contract_versie%TYPE;
bedrijf1 cnt_contract.cnt_prs_bedrijf_key%TYPE;
maxversie NUMBER;
resultkey NUMBER;
BEGIN
resultkey := p_key; -- mocht ik niks vinden, dan is dit em
SELECT cnt_contract_nummer_intern, cnt_contract_versie, cnt_prs_bedrijf_key
INTO nummer1, versie1, bedrijf1
FROM cnt_contract
WHERE cnt_contract_verwijder IS NULL AND cnt_contract_key = p_key;
SELECT MAX (fac.safe_to_number (cnt_contract_versie))
INTO maxversie
FROM cnt_contract
WHERE cnt_contract_nummer_intern = nummer1
AND cnt_prs_bedrijf_key = bedrijf1
AND cnt_contract_verwijder IS NULL;
IF maxversie IS NOT NULL
THEN
SELECT cnt_contract_key
INTO resultkey
FROM cnt_contract
WHERE cnt_contract_nummer_intern = nummer1
AND cnt_prs_bedrijf_key = bedrijf1
AND fac.safe_to_number (cnt_contract_versie) = maxversie
AND cnt_contract_verwijder IS NULL;
END IF;
RETURN resultkey;
END;
FUNCTION sprintf (ps IN VARCHAR2 , p_contract_key IN NUMBER )
RETURN VARCHAR2
IS
s VARCHAR2 (2048 CHAR);
varlev VARCHAR2 (255 CHAR); -- Kan nu ook een samenstelling zijn van prs_perslid gegevens.
varomsch cnt_contract.cnt_contract_omschrijving%TYPE;
varnummer cnt_contract.cnt_contract_nummer_intern%TYPE;
BEGIN
s := ps;
-- We do support substitution of placeholders in the messages
-- ##LEV## = prs_bedrijf_naam
-- ##OMSCH## = cnt_contract_omschrijving
-- ##KEY## = cnt_contract_nummer_intern
IF INSTR (s, '#') > 0
THEN
SELECT COALESCE(prs_bedrijf_naam, fac.getsetting ('prs_pers_string'), fac.getsetting ('prs_dep_string')),
cnt_contract_omschrijving,
cnt_contract_nummer_intern
INTO varlev,
varomsch,
varnummer
FROM cnt_contract c,
prs_bedrijf b,
prs_perslid p,
prs_afdeling a
WHERE c.cnt_prs_bedrijf_key = b.prs_bedrijf_key(+)
AND c.cnt_prs_perslid_key = p.prs_perslid_key(+)
AND c.cnt_prs_afdeling_key = a.prs_afdeling_key(+)
AND c.cnt_contract_key = p_contract_key;
s :=
REPLACE (REPLACE (REPLACE (s, '##LEV##', varlev), '##OMSCH##', varomsch),
'##KEY##',
varnummer
);
END IF;
RETURN s;
END;
END cnt;
/
REGISTERRUN('$Id$')
#endif // CNT