FSN#23620 Vervolmaking datumplusuitvoertijd/datumplusuitvoertijd

svn path=/Database/trunk/; revision=22829
This commit is contained in:
Maarten van der Heide
2014-10-07 16:55:33 +00:00
parent 3bf3db0830
commit 322dcf242a
2 changed files with 185 additions and 108 deletions

View File

@@ -60,10 +60,10 @@ CREATE OR REPLACE PACKAGE fac AS
FUNCTION count_Work_Days_InclTime ( pdate1 IN DATE , pdate2 IN DATE ) RETURN NUMBER;
FUNCTION datumtijdplusuitvoertijd (begindatum IN DATE, uitvoertijd IN NUMBER, uitvoertijdtype IN VARCHAR2) RETURN DATE;
FUNCTION datumtijdplusuitvoertijd (begindatum IN DATE, uitvoertijd IN NUMBER, uitvoertijdtype IN VARCHAR2,
pBeginWerkUur IN NUMBER, pEindWerkUur IN NUMBER, palleenWerkdagen IN NUMBER) RETURN DATE;
pBeginWerkUur IN NUMBER, pEindWerkUur IN NUMBER, pMode IN NUMBER) RETURN DATE;
FUNCTION datumtijdnaaruitvoertijd (begindatum IN DATE, einddatum IN DATE, uitvoertijdtype IN VARCHAR2) RETURN NUMBER;
FUNCTION datumtijdnaaruitvoertijd (begindatum IN DATE, einddatum IN DATE, uitvoertijdtype IN VARCHAR2,
pBeginWerkUur IN NUMBER, pEindWerkUur IN NUMBER, palleenWerkdagen IN NUMBER) RETURN NUMBER;
pBeginWerkUur IN NUMBER, pEindWerkUur IN NUMBER, pMode IN NUMBER) RETURN NUMBER;
FUNCTION getdatemillisec (i_date IN DATE) RETURN NUMBER;
FUNCTION usrrap_query (p_tabelnaam IN VARCHAR2) RETURN VARCHAR2;
FUNCTION usrrap_orderby (p_tabelnaam IN VARCHAR2) RETURN VARCHAR2;
@@ -502,32 +502,45 @@ CREATE OR REPLACE PACKAGE BODY fac AS
DBMS_OUTPUT.put_line ('Recaching Werkuren ' || BeginWerkUur||'..'||EindWerkUur);
END IF;
RETURN datumtijdplusuitvoertijd (begindatum, uitvoertijd, uitvoertijdtype,
BeginWerkUur, EindWerkUur, 1); // altijd alleen werkdagen
BeginWerkUur, EindWerkUur, 1); // 1=alleen werkdagen excl. vrije dagen
END;
FUNCTION datumtijdplusuitvoertijd (begindatum IN DATE, uitvoertijd IN NUMBER, uitvoertijdtype IN VARCHAR2,
pBeginWerkUur IN NUMBER, pEindWerkUur IN NUMBER, palleenWerkdagen IN NUMBER) -- uur-parameters zijn 7.5 voor half acht (en niet 7.3)
-- Bereken de einddatum gegeven de begindatum en uitvoertijd. De mode bepaalt
-- hoe dagen/tijden meetellen als volgt:
-- 0 => alle dagen van de week excl. vrije dagen en uren tussen begin- en eindtijd
-- 1 => alleen werkdagen excl. vrije dagen en uren tussen begin- en eindtijd
-- 2 => 24/7 => alle 7 dagen van de week incl. vrije dagen en alle 24 uren per dag
FUNCTION datumtijdplusuitvoertijd (begindatum IN DATE,
uitvoertijd IN NUMBER,
uitvoertijdtype IN VARCHAR2,
pBeginWerkUur IN NUMBER,
pEindWerkUur IN NUMBER,
pMode IN NUMBER)
RETURN DATE
IS
eikdag NUMBER;
returnval DATE;
eikdag NUMBER;
vrijedag NUMBER;
datumbegin DATE;
dagenperweek NUMBER;
weekdagbegin NUMBER;
olddatumgereed DATE;
newdatumgereed DATE;
weekdaggereed NUMBER;
delta NUMBER;
aantalwerkweken NUMBER;
aantaldagenover NUMBER;
werkuren NUMBER (7, 4); -- 4 decimalen i.v.m. afrondingsfouten
weekdaggereed NUMBER;
urenperdag NUMBER (7, 4); -- 4 decimalen i.v.m. afrondingsfouten
aantalwerkdagen NUMBER;
aantalurenover NUMBER;
beginuur NUMBER (7, 4);
gereeduur NUMBER (7, 4);
beginuur NUMBER (7, 4); -- 4 decimalen i.v.m. afrondingsfouten
gereeduur NUMBER (7, 4); -- 4 decimalen i.v.m. afrondingsfouten
BEGIN
returnval := NULL;
-- Dit is een maandag, is dat volgens de huidige territory dag 2?
eikdag := TO_NUMBER (TO_CHAR (TO_DATE ('01-01-2007', 'DD-MM-YYYY'), 'D'));
eikdag :=
TO_NUMBER (TO_CHAR (TO_DATE ('01-01-2007', 'DD-MM-YYYY'), 'D'));
IF eikdag <> 2
THEN -- We MOETEN met zo=1 werken (geen nieuwe eis, wel duidelijker probleem).
@@ -538,15 +551,11 @@ CREATE OR REPLACE PACKAGE BODY fac AS
IF begindatum IS NOT NULL
AND uitvoertijd IS NOT NULL
AND pBeginWerkUur BETWEEN 0 AND 24
AND pEindWerkUur BETWEEN 0 AND 24
AND pEindWerkUur > pBeginWerkUur
AND pMode BETWEEN 0 AND 2
THEN
IF palleenWerkdagen = 0
IF pMode = 2
THEN
-- Zo simpel kan het zijn (als alle dagen meetellen)!
-- Geen verschuiving als gereedtijd buiten de meegegeven uren valt, wat in
-- theorie kan igv. Openingstijden-regime!?
-- Zo simpel kan het zijn (igv. 24/7)!
IF uitvoertijdtype IN ('D', 'DAGEN')
THEN
returnval := begindatum + uitvoertijd;
@@ -556,12 +565,12 @@ CREATE OR REPLACE PACKAGE BODY fac AS
ELSE
returnval := NULL;
END IF;
ELSIF palleenWerkdagen = 1
ELSIF pBeginWerkUur BETWEEN 0 AND 24
AND pEindWerkUur BETWEEN 0 AND 24
AND pEindWerkUur > pBeginWerkUur
THEN
-- Verschuif begindatum als deze valt [a] buiten de meegegeven uren, [b] op
-- een vrije dag of [c] in het weekend!
-- LET OP: Volgorde hier van belang, want vrijdag na eindtijd wordt eerst
-- verschoven naar zaterdag-begintijd en vervolgens naar maandag-begintijd.
-- Verschuif begindatum als deze valt [a] buiten de meegegeven uren of [b] op
-- een vrije dag. Dit geldt Kantoortijden- of Openingstijden-regime!
SELECT COUNT ( * )
INTO vrijedag
FROM mld_vrije_dagen
@@ -582,16 +591,28 @@ CREATE OR REPLACE PACKAGE BODY fac AS
datumbegin := begindatum;
END IF;
-- Verschuif (gewijzigde) datumbegin als deze in het weekend valt.
weekdagbegin := fac.getweekdaynum (datumbegin); -- zo=1 t/m za=7
IF weekdagbegin = 1
IF pMode = 0
THEN
-- Als zo=1, dan schuif 1 dag door naar maandag 'pBeginWerkUur'.
datumbegin := TRUNC (datumbegin + 1) + (pBeginWerkUur / 24);
ELSIF weekdagbegin = 7
THEN
-- Als za=7, dan schuif 2 dagen door naar maandag 'pBeginWerkUur'.
datumbegin := TRUNC (datumbegin + 2) + (pBeginWerkUur / 24);
-- Alle dagen van de week excl. vrije dagen (= alle dagen-variant van
-- Openingstijden-regime)!
dagenperweek := 7;
ELSE -- pMode = 1
-- Alleen werkdagen excl. vrije dagen (= Kantoortijden-regime en alleen
-- werkdagen-variant van Openingstijden-regime)!
dagenperweek := 5;
-- Verschuif (gewijzigde) datumbegin als deze in het weekend valt.
weekdagbegin := fac.getweekdaynum (datumbegin); -- zo=1 t/m za=7
IF weekdagbegin = 1
THEN
-- Als zo=1, dan schuif 1 dag door naar maandag 'pBeginWerkUur'.
datumbegin := TRUNC (datumbegin + 1) + (pBeginWerkUur / 24);
ELSIF weekdagbegin = 7
THEN
-- Als za=7, dan schuif 2 dagen door naar maandag 'pBeginWerkUur'.
datumbegin := TRUNC (datumbegin + 2) + (pBeginWerkUur / 24);
END IF;
END IF;
IF uitvoertijdtype IN ('D', 'DAGEN')
@@ -605,9 +626,9 @@ CREATE OR REPLACE PACKAGE BODY fac AS
LOOP
olddatumgereed := newdatumgereed;
weekdagbegin := fac.getweekdaynum (olddatumgereed); -- ma=2 t/m vr=6
aantalwerkweken := TRUNC (delta / 5);
aantaldagenover := delta MOD 5;
-- Een werkweek van 5 dagen zorgt voor een doorlooptijd van 7 kalenderdagen.
aantalwerkweken := TRUNC (delta / dagenperweek);
aantaldagenover := delta MOD dagenperweek;
-- Een/elke werkweek zorgt voor een doorlooptijd van 7 kalenderdagen.
newdatumgereed := olddatumgereed + (aantalwerkweken * 7) + aantaldagenover;
-- Verschuif newdatumgereed als gereedtijd buiten de meegegeven uren valt.
@@ -624,7 +645,10 @@ CREATE OR REPLACE PACKAGE BODY fac AS
-- Compenseer eventueel (eind)weekend afhankelijk van 'aantaldagenover'.
weekdaggereed := fac.getweekdaynum (newdatumgereed); -- zo=1 t/m za=7
IF (weekdaggereed = 7 OR weekdagbegin > weekdaggereed) AND delta <> 0
IF pMode = 1
AND (weekdaggereed = 7 OR weekdagbegin > weekdaggereed)
AND delta <> 0
THEN
-- Als za=7 of weekdagbegin > weekdaggereed, dan 2 dagen optellen!
newdatumgereed := newdatumgereed + 2;
@@ -633,9 +657,11 @@ CREATE OR REPLACE PACKAGE BODY fac AS
-- Bepaal nieuwe delta.
SELECT COUNT ( * )
INTO delta
FROM mld_vrije_dagen
WHERE fac.getweekdaynum (mld_vrije_dagen_datum) NOT IN (1, 7) -- nodig!
AND mld_vrije_dagen_datum BETWEEN TRUNC (olddatumgereed) AND newdatumgereed;
FROM (SELECT * FROM mld_vrije_dagen
MINUS -- Igv. pMode=1 za+zo niet meetellen; deze worden sowieso geskipt!
SELECT * FROM mld_vrije_dagen
WHERE pMode = 1 AND fac.getweekdaynum (mld_vrije_dagen_datum) IN (1,7))
WHERE mld_vrije_dagen_datum BETWEEN TRUNC (olddatumgereed) AND newdatumgereed;
EXIT WHEN delta = 0;
END LOOP;
@@ -644,9 +670,9 @@ CREATE OR REPLACE PACKAGE BODY fac AS
ELSIF uitvoertijdtype IN ('U', 'UREN')
THEN
-- Bepaal gereedtijd, dan hoeft daarna alleen nog maar in werkdagen te worden geschoven!
werkuren := pEindWerkUur - pBeginWerkUur;
aantalwerkdagen := TRUNC (uitvoertijd / werkuren); -- werkdagen
aantalurenover := uitvoertijd MOD werkuren; -- rest uren
urenperdag := pEindWerkUur - pBeginWerkUur;
aantalwerkdagen := TRUNC (uitvoertijd / urenperdag); -- werkdagen
aantalurenover := uitvoertijd MOD urenperdag; -- rest uren
beginuur := (datumbegin - TRUNC (datumbegin)) * 24;
gereeduur := beginuur + aantalurenover;
@@ -657,18 +683,12 @@ CREATE OR REPLACE PACKAGE BODY fac AS
aantalwerkdagen := aantalwerkdagen + 1; -- inclusief extra dag
END IF;
newdatumgereed := datumtijdplusuitvoertijd (datumbegin, aantalwerkdagen, 'DAGEN', pBeginWerkUur, pEindWerkUur, palleenWerkdagen);
newdatumgereed := datumtijdplusuitvoertijd (datumbegin, aantalwerkdagen, 'DAGEN', pBeginWerkUur, pEindWerkUur, pMode);
--Belangrijk: nu nog de eerder bepaalde gereedtijd zetten!
returnval := TRUNC (newdatumgereed) + (gereeduur / 24);
ELSE
returnval := NULL; -- uitvoertijdtype ongedefinieerd
END IF;
ELSE
returnval := NULL; -- palleenWerkdagen ongedefinieerd
END IF;
ELSE
returnval := NULL; -- andere parameters ongedefinieerd
END IF;
RETURN returnval;
@@ -689,28 +709,26 @@ CREATE OR REPLACE PACKAGE BODY fac AS
DBMS_OUTPUT.put_line ('Recaching Werkuren ' || BeginWerkUur||'..'||EindWerkUur);
END IF;
RETURN datumtijdnaaruitvoertijd (begindatum, einddatum, uitvoertijdtype,
BeginWerkUur, EindWerkUur, 1); // altijd alleen werkdagen
BeginWerkUur, EindWerkUur, 1); // 1=alleen werkdagen excl. vrije dagen
END datumtijdnaaruitvoertijd;
FUNCTION datumtijdnaaruitvoertijd (
begindatum IN DATE,
einddatum IN DATE,
uitvoertijdtype IN VARCHAR2,
pBeginWerkUur IN NUMBER,
pEindWerkUur IN NUMBER,
palleenWerkdagen IN NUMBER)
FUNCTION datumtijdnaaruitvoertijd (begindatum IN DATE,
einddatum IN DATE,
uitvoertijdtype IN VARCHAR2,
pBeginWerkUur IN NUMBER,
pEindWerkUur IN NUMBER,
pMode IN NUMBER)
RETURN NUMBER
AS
urenperdag NUMBER (10, 3);
eerstedag NUMBER (10, 3);
laatstedag NUMBER (10, 3);
heledagen NUMBER (10);
vrijedagen NUMBER;
BEGIN
IF begindatum IS NOT NULL
AND einddatum IS NOT NULL
AND pBeginWerkUur BETWEEN 0 AND 24
AND pEindWerkUur BETWEEN 0 AND 24
AND pEindWerkUur > pBeginWerkUur
AND pMode BETWEEN 0 AND 2
THEN
IF begindatum > einddatum
THEN
@@ -719,35 +737,96 @@ CREATE OR REPLACE PACKAGE BODY fac AS
uitvoertijdtype,
pBeginWerkUur,
pEindWerkUur,
palleenWerkdagen);
pMode);
END IF;
urenperdag := pEindWerkUur - pBeginWerkUur;
--Waarom niet gewoon? eerstedag := pEindWerkUur - ((begindatum - TRUNC (begindatum)) * 24);
eerstedag := pEindWerkUur - (TRUNC (begindatum, 'MI') - TRUNC (begindatum)) * 24;
eerstedag := LEAST (GREATEST (0, eerstedag), urenperdag);
--Waarom niet gewoon? laatstedag := ((einddatum - TRUNC (einddatum)) * 24) - pBeginWerkUur;
laatstedag := (TRUNC (einddatum, 'MI') - TRUNC (einddatum)) * 24 - pBeginWerkUur;
laatstedag := LEAST (GREATEST (0, laatstedag), urenperdag);
IF palleenWerkdagen = 0
IF pMode = 2
THEN
heledagen := TRUNC (einddatum) - TRUNC (begindatum) - 1;
ELSE -- default/palleenWerkdagen = 1
-- Oppassen als begin/eind in het weekend of zo valt,
-- dan moeten eerste/laatste dag gewoon 0 uur zijn.
IF iswerkdag (begindatum) = 0
-- Zo simpel kan het zijn (igv. 24/7)!
IF uitvoertijdtype IN ('D', 'DAGEN')
THEN
eerstedag := 0;
-- Per 5.4.3 kunnen hier gebroken dagen worden teruggegeven!
RETURN einddatum - begindatum;
ELSE -- default/uitvoertijdtype IN ('U', 'UREN')
RETURN (einddatum - begindatum) * 24;
END IF;
ELSIF pBeginWerkUur BETWEEN 0 AND 24
AND pEindWerkUur BETWEEN 0 AND 24
AND pEindWerkUur > pBeginWerkUur
THEN
urenperdag := pEindWerkUur - pBeginWerkUur;
eerstedag := pEindWerkUur - (TRUNC (begindatum, 'MI') - TRUNC (begindatum)) * 24;
eerstedag := LEAST (GREATEST (0, eerstedag), urenperdag);
laatstedag := (TRUNC (einddatum, 'MI') - TRUNC (einddatum)) * 24 - pBeginWerkUur;
laatstedag := LEAST (GREATEST (0, laatstedag), urenperdag);
IF iswerkdag (einddatum) = 0
IF pMode = 0
THEN
laatstedag := 0;
heledagen := fac.count_Work_Days (TRUNC (begindatum), TRUNC (einddatum));
ELSE
heledagen := fac.count_Work_Days (TRUNC (begindatum), TRUNC (einddatum)) - 1;
-- Oppassen als begin/eind op een vrije dag valt,
-- dan moeten eerste/laatste dag gewoon 0 uur zijn.
SELECT COUNT ( * )
INTO vrijedagen
FROM mld_vrije_dagen
WHERE mld_vrije_dagen_datum = TRUNC (begindatum);
IF vrijedagen = 1
THEN
eerstedag := 0;
END IF;
SELECT COUNT ( * )
INTO vrijedagen
FROM mld_vrije_dagen
WHERE mld_vrije_dagen_datum = TRUNC (einddatum);
IF vrijedagen = 1
THEN
laatstedag := 0;
END IF;
IF TRUNC (begindatum) = TRUNC (einddatum)
THEN
IF eerstedag + laatstedag > 0 -- geen vrije dag!
THEN
-- Als begindatum=einddatum <20>n werkdag, dan 1 dag corrigeren!
heledagen := -1;
ELSE
-- Als begindatum=einddatum <20>n vrije dag, dan geen correctie!
heledagen := 0;
END IF;
ELSE
-- Als begindatum<>einddatum, dan alleen nog vrije dagen tussen
-- begin+1 en eind-1 corrigeren (en altijd 0 als begin+1=eind)!
SELECT COUNT ( * )
INTO vrijedagen
FROM mld_vrije_dagen
WHERE mld_vrije_dagen_datum BETWEEN TRUNC (begindatum + 1) AND einddatum - 1;
IF TRUNC (begindatum+1) = TRUNC (einddatum)
THEN
heledagen := 0;
ELSE
heledagen := TRUNC (begindatum + 1) - TRUNC (einddatum - 1) - vrijedagen;
END IF;
END IF;
ELSE -- pMode = 1
-- Oppassen als begin/eind in het weekend of zo valt,
-- dan moeten eerste/laatste dag gewoon 0 uur zijn.
IF iswerkdag (begindatum) = 0
THEN
eerstedag := 0;
END IF;
IF iswerkdag (einddatum) = 0
THEN
laatstedag := 0;
heledagen := fac.count_Work_Days (TRUNC (begindatum), TRUNC (einddatum));
ELSE
heledagen := fac.count_Work_Days (TRUNC (begindatum), TRUNC (einddatum)) - 1;
END IF;
END IF;
ELSE
RETURN NULL;
END IF;
DBMS_OUTPUT.put_line ('Eerstedag ' || TO_CHAR (eerstedag));
@@ -758,7 +837,7 @@ CREATE OR REPLACE PACKAGE BODY fac AS
THEN
-- Per 5.4.3 kunnen hier gebroken dagen worden teruggegeven!
RETURN (eerstedag + laatstedag + heledagen * urenperdag) / urenperdag;
ELSE -- default/uitvoertijdtype IN ('U', 'UREN')
ELSE -- default/uitvoertijdtype IN ('U', 'UREN')
RETURN eerstedag + laatstedag + heledagen * urenperdag;
END IF;
ELSE