Files
Mareon/sql/mareon_plan.sql
Marcel Bourseau 399f578c86 MARX#83495 AiAi in rapport "Mijn Mareon Premium": ORA-01427
svn path=/Mareon/trunk/; revision=64397
2024-04-24 17:41:31 +00:00

1924 lines
87 KiB
MySQL

--
-- $Id$
--
-- Script containing customer specific sql statements for the FACILITOR database
-- Voor dbuser invullen: - indien script voor 1 klant is: 'MARX' (de klantcode, zoals vermeld in fac_version_cust)
-- - script is voor meerdere klanten: 'AAXX' (de groepcode, zoals vermeld in fac_version_group)
-- - script is voor meerdere klanten met naam volgens een bepaald patroon: '^AA|^ASMS|^GULU|^NMMS|^RABO|^ZKHM'
-- Ook als het script gedraaid wordt voor de verkeerde cust wordt er een logfile gemaakt.
-- (dit in tegenstelling tot sample_xxxx.sql)
DEFINE thisfile = 'MAREON_PLAN.SQL'
DEFINE dbuser = '^MARX'
SET ECHO ON
SET DEFINE ON
COLUMN fcltlogfile NEW_VALUE fcltlogfile NOPRINT;
COLUMN fcltcusttxt NEW_VALUE fcltcusttxt NOPRINT;
WHENEVER SQLERROR CONTINUE;
SELECT adm.getscriptspoolfile('&thisfile') AS fcltlogfile FROM DUAL;
SPOOL &fcltlogfile
WHENEVER SQLERROR EXIT;
SELECT adm.checkscriptcust('&dbuser') AS fcltcusttxt FROM DUAL;
WHENEVER SQLERROR CONTINUE;
---------------------------------------
PROMPT &fcltcusttxt
---------------------------------------
SET DEFINE OFF
------ payload begin ------
--------------------- MAREON PLANNING --------------------- MAREON PLANNING --------------------- MAREON PLANNING --------------------- MAREON PLANNING --------------------- MAREON PLANNING ------------------
-- MARX#66773 Module Mareon Planning
-- Check of leverancier de module Mareon Planning heeft afgenomen, dus of deze geautoriseerd is voor planningen, oftewel: staat prs_kenmerk_key 61 AAN (of UIT).
-- Waarde 0: nee, niet geautoriseerd voor module Planbord
-- Waarde 1: ja, wel geautoriseerd voor module Planbord
-- Waarde 2: ja, wel geautoriseerd voor module Planbord EN geautoriseerd voor Mareon Premium Groene Planning
CREATE OR REPLACE FUNCTION marx_bedrijf_auth_4_plan (v_prs_bedrijf_key IN NUMBER)
RETURN NUMBER
AS
v_geautoriseerd NUMBER(10);
BEGIN
SELECT COALESCE (MAX (prs_kenmerklink_waarde), '0')
INTO v_geautoriseerd
FROM prs_kenmerklink
WHERE prs_kenmerk_key = 61 AND prs_kenmerklink_niveau = 'B' AND prs_link_key = v_prs_bedrijf_key;
RETURN v_geautoriseerd;
END;
/
CREATE OR REPLACE FUNCTION marx_bedrijf_auth_4_planbord (v_prs_bedrijf_key IN NUMBER)
RETURN NUMBER
AS
BEGIN
IF marx_bedrijf_auth_4_plan(v_prs_bedrijf_key) = 1 OR marx_bedrijf_auth_4_plan(v_prs_bedrijf_key) = 2
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
/
-- MARX#73599 Planningsberichten: vertaling van vaardigheid(code) van opdrachtgever
-- Extra check: heeft leverancier wel Planning Premium ingetsteld?
-- Dit bepalen we ahdv technisch adres, staat deze voor v_prs_bedrijf_key wel ingesteld
CREATE OR REPLACE FUNCTION marx_bedrijf_auth_4premiumplan (v_prs_bedrijf_key IN NUMBER)
RETURN NUMBER
AS
v_geautoriseerd NUMBER(10);
BEGIN
SELECT COALESCE (MAX (prs_kenmerklink_waarde), '0')
INTO v_geautoriseerd
FROM prs_kenmerklink
WHERE prs_kenmerk_key = 61 AND prs_kenmerklink_niveau = 'B' AND prs_link_key = v_prs_bedrijf_key;
SELECT DECODE(count(*),0,0,1)
INTO v_geautoriseerd
FROM prs_bedrijfadres ba
WHERE ba.prs_bedrijfadres_type = 'V'
AND ba.prs_bedrijf_key = v_prs_bedrijf_key
AND ba.prs_bedrijfadres_startdatum = (SELECT MAX(ba2.prs_bedrijfadres_startdatum)
FROM prs_bedrijfadres ba2
WHERE ba2.prs_bedrijf_key = ba.prs_bedrijf_key AND ba2.prs_bedrijfadres_type = 'V' AND ba2.prs_bedrijfadres_startdatum <= SYSDATE);
RETURN v_geautoriseerd;
END;
/
-- MARX#70053 Mareon Premium Groene Planningen: plannen met geografische optimalisatie
-- Waarde 0: geen autorisatie voor Groene Planning, waarde 1 wel autorisatie.
CREATE OR REPLACE FUNCTION marx_bedrijf_auth_4_greenplan (v_prs_bedrijf_key IN NUMBER)
RETURN NUMBER
AS
BEGIN
IF marx_bedrijf_auth_4_plan(v_prs_bedrijf_key) = 2
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
/
-- MARX#66773 Module Mareon Planning
-- View met name bedoeld voor de LEV bedrijven, die default geen afdeling hebben (is verder ook niet nodig / interessant),
-- Alleen wel nodig wanneer LEV gebruik wil maken van het Mareon planbord, dan moeten de perslid's van de contactpersonen ff in een aparte afdeling i.v.m. WEB_RESFOF scope die op/per BEDRIJF is, zodat de andere users onzichtbaar blijven.
-- Deze view wordt gebuikt bij de initplanning en aanmaak nieuwe personen (beheer contactpersoon).
CREATE OR REPLACE VIEW marx_v_bedrijf_afdeling
(
prs_bedrijf_key,
prs_bedrijf_naam,
prs_afdeling_key
)
AS SELECT b.prs_bedrijf_key, b.prs_bedrijf_naam, COALESCE(a.prs_afdeling_key, 1)
FROM prs_afdeling a, prs_bedrijf b
WHERE b.prs_bedrijf_key = a.prs_bedrijf_key(+);
-- Aanmaken van nieuwe (aparte) API user voor het (alleen) kunnen opvragen van planvoorstellen en inschieten van plankeuze bij (eigen) leveranciers
CREATE OR REPLACE PROCEDURE marx_create_woco_planner
(p_prs_bedrijf_key IN NUMBER)
AS
v_prs_bedrijf_naam VARCHAR2(100);
v_prs_afdeling_key NUMBER(10);
v_prs_perslid_apikey VARCHAR2(100);
v_prs_perslid_key NUMBER(10);
v_prs_srtperslid_key NUMBER(10);
BEGIN
----------- Start procedure ---
-- Functie (prs_srtperslid) voor "woco planning" heeft key 20, om te kunnen onderscheiden van "woco onderhoud".
v_prs_srtperslid_key:= 20;
SELECT prs_bedrijf_naam
INTO v_prs_bedrijf_naam
FROM prs_bedrijf
WHERE prs_bedrijf_key = p_prs_bedrijf_key;
-- de eerste de beste is oke.
SELECT MIN(prs_afdeling_key)
INTO v_prs_afdeling_key
FROM prs_afdeling
WHERE prs_bedrijf_key = p_prs_bedrijf_key;
v_prs_perslid_apikey := DBMS_RANDOM.STRING ('x', 32);
--- Aanmaken persoon met functie 'Opdrachtgever-API' (srtperlid_key = 222), Achternaam overnemen van bedrijfnaam,
INSERT INTO prs_perslid (prs_perslid_module,
prs_srtperslid_key,
prs_afdeling_key,
prs_perslid_naam,
prs_perslid_oslogin,
prs_perslid_apikey)
VALUES ('PRS',
v_prs_srtperslid_key,
v_prs_afdeling_key,
SUBSTR ('PLN-' || v_prs_bedrijf_naam , 1, 60),
SUBSTR ('PLN-' || v_prs_bedrijf_naam , 1, 60),
v_prs_perslid_apikey)
RETURNING prs_perslid_key
INTO v_prs_perslid_key;
-- fac_groep_key 16 is gereserveerd voor woco planning
INSERT INTO fac_gebruikersgroep (fac_groep_key, prs_perslid_key)
VALUES (16, v_prs_perslid_key);
COMMIT;
END;
/
-- MARX#66773 Module Mareon Planning
-- Bestaat er al een gereserveerde/optie res_rsv_ruimte voor deze woco met dit ionr? (op MARX-nivo, dus dat res_rsv_ruimte.mld_opdr_key leeg is)
-- Dus nog zonder dat de mld_opdr aan de res_rsv_ruimte is gekoppeld (dus niet op FCLT-nivo, dus dat res_rsv_ruimte.mld_opdr_key gevuld is)
CREATE OR REPLACE FUNCTION marx_ion_already_planned (v_woco_key IN NUMBER, v_ion_nr IN VARCHAR2)
RETURN NUMBER
AS
v_res_rsv_ruimte_key NUMBER(10);
BEGIN
SELECT MIN(rrr.res_rsv_ruimte_key)
INTO v_res_rsv_ruimte_key
FROM res_rsv_ruimte rrr
WHERE rrr.res_rsv_ruimte_key=
(SELECT MIN(kw2.res_rsv_ruimte_key)
FROM res_kenmerkwaarde kw1, res_kenmerkwaarde kw2
WHERE kw1.res_kenmerk_key = 2
AND kw1.res_kenmerkreservering_waarde = TO_CHAR(v_woco_key)
AND kw1.res_kenmerkwaarde_verwijder IS NULL
AND kw1.res_rsv_ruimte_key = kw2.res_rsv_ruimte_key
AND kw2.res_kenmerk_key = 1
AND kw2.res_kenmerkreservering_waarde = v_ion_nr
AND kw2.res_kenmerkwaarde_verwijder IS NULL)
AND rrr.res_rsv_ruimte_verwijder IS NULL;
RETURN v_res_rsv_ruimte_key;
END;
/
-- MARX#66773 Module Mareon Planning
-- Is de mld_opdr als officieel gepland via een res_rsv_ruimte, dus op FCLT-nivo, res_rsv_ruimte.mld_opdr_key gevuld is
CREATE OR REPLACE FUNCTION marx_mld_opdr_already_planned (v_mld_opdr_key IN NUMBER)
RETURN NUMBER
AS
v_res_rsv_ruimte_key NUMBER(10);
BEGIN
SELECT MIN(res_rsv_ruimte_key)
INTO v_res_rsv_ruimte_key
FROM res_rsv_ruimte
WHERE mld_opdr_key = v_mld_opdr_key
AND res_rsv_ruimte_verwijder IS NULL;
RETURN v_res_rsv_ruimte_key;
END;
/
-- MARX#66773 Module Mareon Planning
-- Is er een mld_opdr die bestaat bij dit IONR van deze WOCO (opdrachtgever)?
CREATE OR REPLACE FUNCTION marx_get_mld_opdr_via_ionr (v_woco_key IN NUMBER, v_ion_nr IN VARCHAR2)
RETURN NUMBER
AS
v_mld_opdr_key NUMBER(10);
BEGIN
SELECT MAX(mld_opdr_key)
INTO v_mld_opdr_key
FROM mld_opdr o, mld_melding m, mar_v_woco_perslid woco1
WHERE mld_opdr_id = v_ion_nr
AND o.mld_melding_key = m.mld_melding_key
AND m.prs_perslid_key = woco1.prs_perslid_key
AND woco1.prs_bedrijf_key = v_woco_key;
RETURN v_mld_opdr_key;
END;
/
CREATE OR REPLACE PROCEDURE marx_delete_res_bij_mld_opdr (v_mld_opdr_key IN NUMBER)
AS
-- Alle toekomstige reserveringen bij opdracht mld_opdr_key
CURSOR c1
IS
SELECT res_rsv_ruimte_key
FROM res_rsv_ruimte
WHERE mld_opdr_key = v_mld_opdr_key
AND res_rsv_ruimte_van > SYSDATE
AND res_rsv_ruimte_verwijder IS NULL;
BEGIN
FOR rec1 IN c1
LOOP
BEGIN
res.remove(rec1.res_rsv_ruimte_key);
END;
END LOOP;
END;
/
-- Initialiseer voor leverancier de PLANning-randvoorwaarden, zoals catalogus, autorisaties etc
-- Controle of leverancier al een eigen 'leveranciers'catalogus voor PLANNEN heeft
CREATE OR REPLACE FUNCTION marx_bedrijf_has_plan_cat(v_bedrijf_key IN NUMBER)
RETURN NUMBER
AS
v_res_ins_discipline_key NUMBER(10);
BEGIN
-- Eerst checken of leverancier al een eigen 'leveranciers' RES-PLANNING catalogus heeft
SELECT MAX(res_ins_discipline_key)
INTO v_res_ins_discipline_key
FROM res_disc_params
WHERE prs_bedrijf_key = v_bedrijf_key;
RETURN v_res_ins_discipline_key;
END;
/
-- v_role_id = PLANNER of PLANBAAR
CREATE OR REPLACE FUNCTION marx_construct_groep_externid(v_bedrijf_key IN NUMBER, v_role_id IN VARCHAR2)
RETURN VARCHAR2
AS
BEGIN
RETURN SUBSTR(v_bedrijf_key || '-' || v_role_id, 1, 128);
END;
/
-- Vanwege ontbreken van prs_bedrijf_key in fac_groep gaan we voor bedrijf X in kolom fac_groep_externid een consequente naamgeving geven, omdat deze nodig is om (op een later moment) een persoon van bedrijf X aan te kunnen koppelen
-- v_role = PLANNER of PLANBAAR
CREATE OR REPLACE FUNCTION marx_bedrijf_facgroep(v_bedrijf_key IN NUMBER, v_role IN VARCHAR2)
RETURN NUMBER
AS
v_fac_groep_key NUMBER(10);
v_fac_groep_externid VARCHAR2(128);
BEGIN
v_fac_groep_externid := marx_construct_groep_externid(v_bedrijf_key, v_role);
-- Eerst checken of leverancier al een eigen 'leveranciers'catalogus heeft
SELECT MAX(fac_groep_key)
INTO v_fac_groep_key
FROM fac_groep
WHERE fac_groep_externid = v_fac_groep_externid;
RETURN v_fac_groep_key;
END;
/
-- Controle of persoon toekomstige reserveringen heeft, dwz al is ingepland (d.w.z. res_rsv_deel records bestaan bij deze persoon).
-- Reserveringen uit het (verre) verleden doen niet mee, en uit het recente verleden (afgelopen 2 weken) worden voor het gemak direct ff afgemeld (is ws de bedoeling).
CREATE OR REPLACE FUNCTION marx_perslid_is_gepland(v_perslid_key IN NUMBER)
RETURN NUMBER
AS
v_aantal NUMBER(10);
BEGIN
-- Een res_deel mag niet inactief worden als er nog *openstaande* reserveringen zijn, zie TRIGGER(res_t_res_deel_B_IU) in bestand RES_TRI.SRC
-- Daarom sluiten we gewoon alle reserveringen met dit res_deel vanaf 14 dagen geleden tot en met nu, dus status op 5 (=afgemeld) zetten
UPDATE res_rsv_deel rd
SET rd.res_status_bo_key = 5
WHERE rd.res_rsv_deel_verwijder IS NULL
AND EXISTS (SELECT 'x' FROM res_deel d
WHERE rd.res_deel_key = d.res_deel_key
AND d.res_prs_perslid_key = v_perslid_key
AND d.res_deel_verwijder IS NULL
AND rd.res_rsv_deel_tot > SYSDATE - 14
AND rd.res_rsv_deel_tot < SYSDATE
AND rd.res_status_bo_key = 2);
SELECT count(*)
INTO v_aantal
FROM res_deel d, res_rsv_deel rd
WHERE d.res_prs_perslid_key = v_perslid_key
AND d.res_deel_verwijder IS NULL
AND rd.res_deel_key = d.res_deel_key
AND rd.res_rsv_deel_tot >= SYSDATE
AND rd.res_status_bo_key = 2
AND rd.res_rsv_deel_verwijder IS NULL;
RETURN v_aantal;
END;
/
-- Maak voor leverancier met v_bedrijf_key de initiele zaken aan, zoals:
-- 1. RES-Catalogus (voor alleen dit bedrijf), en koppelen aan activiteit
-- 2. Autorisatiegroep incl rechten voor PLANNER aanmaken (RESFOF op BEDRIJF nivo), en taggen met unieke 'externe' id
-- 3. Autorisatiegroep voor PLANBAAR aanmaken, en taggen met unieke 'externe' id
CREATE OR REPLACE PROCEDURE marx_init_planning
(v_bedrijf_key IN NUMBER)
AS
l_disc_key NUMBER(10);
v_prs_bedrijf_naam VARCHAR2(100);
v_prefix VARCHAR2(10);
v_ins_discipline_key NUMBER(10);
l_ins_discipline_omschrijving VARCHAR(100);
v_fac_groep_key NUMBER(10);
l_fac_groep_omschrijving VARCHAR(100);
v_fac_groep_externid VARCHAR2(128);
v_facgroep_key NUMBER(10);
v_prs_afdeling_key NUMBER(10);
BEGIN
-- We starten eerst met maken van een eigen afdeling voor LEV, dit ivm RESFOF rechten op BEDRIJF nivo
SELECT prs_afdeling_key, prs_bedrijf_naam
INTO v_prs_afdeling_key, v_prs_bedrijf_naam
FROM marx_v_bedrijf_afdeling
WHERE prs_bedrijf_key = v_bedrijf_key;
IF v_prs_afdeling_key = 1
THEN
-- Dit betekent dat LEV nog ZELF geen afdeling heeft, maar dat alle personen op de algemene afdeling 'Leverancier' (key 1) 'zitten' (default)
-- Dus aanmaken nieuwe afdeling voor LEV...
v_prefix := 'LEV - ';
INSERT INTO prs_afdeling (prs_bedrijf_key, prs_afdeling_naam, prs_afdeling_omschrijving)
VALUES (v_bedrijf_key, 'X', SUBSTR(v_prefix || v_prs_bedrijf_naam,1,60))
RETURNING prs_afdeling_key
INTO v_prs_afdeling_key;
--Eenmalige 'mini'-conversie van de personen van LEV naar de nieuwe afdeling.
UPDATE prs_perslid
SET prs_afdeling_key = v_prs_afdeling_key
WHERE prs_perslid_key IN (SELECT prs_perslid_key FROM prs_contactpersoon
WHERE prs_bedrijf_key = v_bedrijf_key
AND prs_perslid_key IS NOT NULL
AND prs_contactpersoon_verwijder IS NULL);
END IF;
-- Vervolgens checken of leverancier al een eigen 'leveranciers'catalogus heeft
l_disc_key := marx_bedrijf_has_plan_cat(v_bedrijf_key);
IF l_disc_key IS NULL
THEN
-- Nog geen catalogus, dus aanmaken...
-- Unieke naam voor catalogus: bedrijfs_naam + bedrijfs_key
v_prefix := 'PLAN';
l_ins_discipline_omschrijving := SUBSTR(v_prefix || ' - ' || v_prs_bedrijf_naam || ' (' || v_bedrijf_key || ')', 1, 60);
-- ins_discipline_min_level = 4 betekent "Persoon resource"
INSERT INTO ins_tab_discipline (ins_discipline_module, ins_discipline_omschrijving, ins_discipline_min_level, ins_discipline_kpnverplicht, ins_discipline_btw)
VALUES ('RES', l_ins_discipline_omschrijving, 4, 0, 1) RETURNING ins_discipline_key INTO v_ins_discipline_key;
INSERT INTO res_disc_params (prs_bedrijf_key, res_ins_discipline_key, res_disc_params_expire_dagen, res_disc_params_cancel_dagen, res_disc_params_maxduur)
VALUES (v_bedrijf_key, v_ins_discipline_key, 0, 0, 10);
-- Koppelen aan activiteit "Plannen medewerker" (key 11)
INSERT INTO res_activiteitdiscipline(res_discipline_key, res_activiteit_key)
VALUES (v_ins_discipline_key, 11);
END IF;
v_prefix := 'PLANNER';
v_facgroep_key := marx_bedrijf_facgroep(v_bedrijf_key, v_prefix);
IF v_facgroep_key IS NULL
THEN
-- Nog geen vakgroep voor de 'PLANNER', aanmaken dus...
-- Autorisatiegroep Planner (voor deze leverancier), met een unieke omschrijving "PLANNER-key-bedrijfsnaam" (max 30 tekens)
l_fac_groep_omschrijving := SUBSTR(v_prefix || '-' || v_bedrijf_key || '-' || v_prs_bedrijf_naam, 1, 30);
v_fac_groep_externid := marx_construct_groep_externid(v_bedrijf_key, v_prefix);
INSERT INTO fac_groep (fac_groep_omschrijving, fac_groep_externid)
VALUES (l_fac_groep_omschrijving, v_fac_groep_externid) RETURNING fac_groep_key INTO v_fac_groep_key;
-- RESFOF, ALG onbeperkt (nvt) en PRS op BEDRIJF-NIVO (alleen personen binnen het LEV bedrijf)...
INSERT INTO fac_groeprechten (fac_groep_key, fac_functie_key, ins_discipline_key, fac_gebruiker_alg_level_read, fac_gebruiker_alg_level_write, fac_gebruiker_prs_level_read, fac_gebruiker_prs_level_write)
SELECT v_fac_groep_key, fac_functie_key, v_ins_discipline_key, -1, -1, 0, 0
FROM fac_functie
WHERE fac_functie_code = 'WEB_RESFOF';
END IF;
v_prefix := 'PLANBAAR';
v_facgroep_key := marx_bedrijf_facgroep(v_bedrijf_key, v_prefix);
IF v_facgroep_key IS NULL
THEN
-- Nog geen vakgroep voor de 'PLANBAAR' medewerker, aanmaken dus...
-- Autorisatiegroep Planbare medewerker (voor deze leverancier), met een unieke omschrijving "PLANBAAR-key-bedrijfsnaam" (max 30 tekens)
l_fac_groep_omschrijving := SUBSTR(v_prefix || '-' || v_bedrijf_key || '-' || v_prs_bedrijf_naam, 1, 30);
v_fac_groep_externid := marx_construct_groep_externid(v_bedrijf_key, v_prefix);
INSERT INTO fac_groep (fac_groep_omschrijving, fac_groep_externid)
VALUES (l_fac_groep_omschrijving, v_fac_groep_externid) RETURNING fac_groep_key INTO v_fac_groep_key;
-- TODO Hier ook nog rechten voor groep 15, wellicht resuse?
END IF;
-- MARX#82209 "Omgevallen? Toevoegen van medewerkers bij een (RES)planning is niet mogelijk"
-- Het is nodig dat er 'extra' records prs_bedrijfdienstlocatie zijn waarin de diensten bij (extern) bedrijf geregistreerd moeten zijn (eerder was dit niet nodig).
-- Dwz veld prs_bedrijf_key (=leverancier) moet nu gevuld worden: dat doen we met een INSERT:
INSERT INTO prs_bedrijfdienstlocatie (prs_bedrijf_key, prs_dienst_key, mld_autoorder)
SELECT v_bedrijf_key, prs_dienst_key, 1
FROM prs_dienst d
WHERE NOT EXISTS (SELECT 'x' FROM prs_bedrijfdienstlocatie bd WHERE bd.prs_dienst_key = d.prs_dienst_key AND bd.prs_bedrijf_key = v_bedrijf_key);
END;
/
CREATE OR REPLACE PROCEDURE marx_make_perslid_planner (v_bedrijf_key IN NUMBER, v_perslid_key IN NUMBER)
AS
v_disc_key NUMBER(10);
v_prefix VARCHAR2(10);
v_facgroep_key NUMBER(10);
v_aantal NUMBER(10);
----------- Start procedure ---
BEGIN
-- GET RES-PLAN leveranciers'catalogus
v_disc_key := marx_bedrijf_has_plan_cat(v_bedrijf_key);
IF v_disc_key IS NOT NULL
THEN
-- Op zoek naar de autorisatie-groep voor de 'planner' personen dit bedrijf...
v_prefix := 'PLANNER';
v_facgroep_key := marx_bedrijf_facgroep(v_bedrijf_key, v_prefix);
SELECT COUNT (*)
INTO v_aantal
FROM fac_gebruikersgroep
WHERE fac_groep_key = v_facgroep_key AND prs_perslid_key = v_perslid_key;
IF v_aantal = 0
THEN
INSERT INTO fac_gebruikersgroep (fac_groep_key, prs_perslid_key)
VALUES (v_facgroep_key, v_perslid_key);
END IF;
END IF;
END;
/
CREATE OR REPLACE PROCEDURE marx_undo_perslid_planner (v_bedrijf_key IN NUMBER, v_perslid_key IN NUMBER)
AS
v_facgroep_key NUMBER(10);
v_prefix VARCHAR2(10);
v_aantal NUMBER(10);
----------- Start procedure ---
BEGIN
-- Op zoek naar de autorisatie-groep voor de 'planner' personen dit bedrijf...
v_prefix := 'PLANNER';
v_facgroep_key := marx_bedrijf_facgroep(v_bedrijf_key, v_prefix);
DELETE FROM fac_gebruikersgroep
WHERE fac_groep_key = v_facgroep_key
AND prs_perslid_key = v_perslid_key;
END;
/
-- MARX#66773 Module Mareon Planning
CREATE OR REPLACE PROCEDURE marx_make_perslid_planbaar (v_bedrijf_key IN NUMBER, v_perslid_key IN NUMBER)
AS
v_disc_key NUMBER(10);
v_facgroep_key NUMBER(10);
v_res_deel_omschrijving VARCHAR2(60);
v_prefix VARCHAR2(10);
v_aantal NUMBER(10);
----------- Start procedure ---
BEGIN
-- GET RES-PLAN leveranciers'catalogus
v_disc_key := marx_bedrijf_has_plan_cat(v_bedrijf_key);
IF v_disc_key IS NOT NULL
THEN
-- MARX#70903 Meerdere vaardigheden (expertises) voor 1 resource (persoon) kunnen registreren
-- Planbaar had voorheen (exact) 1 soort-perslid (competentie), nu niet meer, planbaar betekent dat je planbaar bent, en of dat nu voor 0, 1, 2 , 3 , ... competenties.
SELECT SUBSTR(prs_perslid_naam_friendly, 1, 60)
INTO v_res_deel_omschrijving
FROM prs_v_perslid_fullnames p
WHERE p.prs_perslid_key = v_perslid_key;
-- Was deze persoon al (eerder) planbaar gemaakt (voor dit bedrijf), b.v. onder andere expertise?
SELECT COUNT(*)
INTO v_aantal
FROM res_deel
WHERE res_discipline_key = v_disc_key
AND res_prs_perslid_key = v_perslid_key
AND res_deel_verwijder IS NULL;
IF v_aantal = 0
THEN
-- Nee dus, niet al (eerder) planbaar gemaakt, dus een insert ...
INSERT INTO res_deel (res_discipline_key, res_deel_omschrijving, res_deel_alg_level,res_prs_perslid_key)
VALUES (v_disc_key, v_res_deel_omschrijving, -1, v_perslid_key);
ELSE
-- Ja dus, was al (eerder) planbaar, theoretisch kan hier nu andere naam staan, we doen voor zekerheid update...
UPDATE res_deel
SET res_deel_omschrijving = v_res_deel_omschrijving
WHERE res_discipline_key = v_disc_key
AND res_prs_perslid_key = v_perslid_key;
END IF;
-- Op zoek naar de autorisatie-groep voor de 'planbare' personen dit bedrijf...
v_prefix := 'PLANBAAR';
v_facgroep_key := marx_bedrijf_facgroep(v_bedrijf_key, v_prefix);
SELECT COUNT (*)
INTO v_aantal
FROM fac_gebruikersgroep
WHERE fac_groep_key = v_facgroep_key AND prs_perslid_key = v_perslid_key;
IF v_aantal = 0
THEN
INSERT INTO fac_gebruikersgroep (fac_groep_key, prs_perslid_key)
VALUES (v_facgroep_key, v_perslid_key);
END IF;
END IF;
END;
/
CREATE OR REPLACE PROCEDURE marx_undo_perslid_planbaar (v_bedrijf_key IN NUMBER, v_perslid_key IN NUMBER)
AS
v_facgroep_key NUMBER(10);
v_prefix VARCHAR2(10);
v_aantal NUMBER(10);
----------- Start procedure ---
BEGIN
-- Is deze persoon nog ingepland, dan kan planbaar niet eraf worden gehaald, we geven dan een foutmelding
v_aantal := marx_perslid_is_gepland(v_perslid_key);
IF v_aantal = 0
THEN
-- Er zijn geen reserveringen meer bij deze persoon, planbaar kan dan weg...
UPDATE res_deel
SET res_deel_verwijder = SYSDATE
WHERE res_prs_perslid_key = v_perslid_key
AND res_deel_verwijder IS NULL;
-- Op zoek naar de autorisatie-groep voor de 'planbare' personen dit bedrijf...
v_prefix := 'PLANBAAR';
v_facgroep_key := marx_bedrijf_facgroep(v_bedrijf_key, v_prefix);
DELETE FROM fac_gebruikersgroep
WHERE fac_groep_key = v_facgroep_key
AND prs_perslid_key = v_perslid_key;
END IF;
END;
/
------------------------------------------
-- Allerlei praktische/handige functies!!
-- Zoek naar de starttijd van planbare medewerker op bepaalde dag, dit is standaard res_t1, echter indien op deze dag inzetbaarheid bij deze medewerker staat geregistreerd, heeft deze de voorkeur en overrule-t daarmee res_t1
-- Parameters:
-- 1. p_res_deel_key is de planbare medewerker
-- 2. p_datum is de datum waar het om gaat
CREATE OR REPLACE FUNCTION marx_get_res_t1
(p_res_deel_key IN NUMBER, p_date IN DATE)
RETURN DATE
AS
l_result_date DATE;
BEGIN
SELECT COALESCE(MAX(TRUNC(p_date) + pi.prs_perslid_inzetbaar_van/(60*24)), TRUNC(p_date) + fac.safe_to_number (fac.getsetting ('res_t1'))/24)
INTO l_result_date
FROM res_deel d, prs_perslid_inzetbaar pi
WHERE d.res_deel_key = p_res_deel_key
AND d.res_deel_verwijder IS NULL
AND pi.prs_perslid_key = d.res_prs_perslid_key
AND pi.prs_perslid_inzetbaar_dag = to_char(p_date,'D') - 1;
RETURN l_result_date;
END;
/
-- Zoek naar de eindtijd van plabare medewerker op bepaalde dag, dit is standaard res_t2, echter indien op deze dag inzetbaarheid bij deze medewerker staat geregistreerd, heeft deze de voorkeur en overrule-t daarmee res_t2
-- Parameters:
-- 1. p_res_deel_key is de planbare medewerker
-- 2. p_datum is de datum waar het om gaat
CREATE OR REPLACE FUNCTION marx_get_res_t2
(p_res_deel_key IN NUMBER, p_date IN DATE)
RETURN DATE
AS
l_result_date DATE;
BEGIN
SELECT COALESCE(MAX(TRUNC(p_date) + pi.prs_perslid_inzetbaar_tot/(60*24)), TRUNC(p_date) + fac.safe_to_number (fac.getsetting ('res_t2'))/24)
INTO l_result_date
FROM res_deel d, prs_perslid_inzetbaar pi
WHERE d.res_deel_key = p_res_deel_key
AND d.res_deel_verwijder IS NULL
AND pi.prs_perslid_key = d.res_prs_perslid_key
AND pi.prs_perslid_inzetbaar_dag = to_char(p_date,'D') - 1;
RETURN l_result_date;
END;
/
-- Zoek naar de dichts bijzijnde reservering voor perslid (res_deel) voorafgaande aan de v_start_datetime1 en die ook een eindtijd heeft na v_start_datetime1 (en die is weer voor v_start_datetime2, anders zit die niet in deze cursor/loop)
-- Is die er niet, dan beginnen we met zoeken vanaf v_start_datetime1.
-- Is die er wel, dan beginnen we met zoeken vanaf de eindtijd van de gevonden reservering.
-- Zijn er hiervan meerdere (wat op zich niet kan) dan zoeken we vanaf de max(eindtijd).
-- Voor alles geldt dat de starttijd wel na de algemene instelling res_t1 moet liggen. En de starttijd wordt vermeerderd met de p_slack_minutes.
-- En uiteraard moet de reservering niet de status "vervallen" hebben, die telt niet mee.
CREATE OR REPLACE FUNCTION marx_get_fromdatetime
(p_res_deel_key IN NUMBER, p_start_datetime IN DATE, p_start_datetime2 IN DATE, p_slack_minutes IN NUMBER)
RETURN DATE
AS
l_zoeken_vanaf_starttijd DATE;
l_zoeken_vanaf_res_t1 DATE;
BEGIN
BEGIN
-- De starttijd mag niet eerder dan instelling res_t1 beginnen
l_zoeken_vanaf_res_t1 := marx_get_res_t1(p_res_deel_key, p_start_datetime);
SELECT MAX(rr.res_rsv_ruimte_tot)
INTO l_zoeken_vanaf_starttijd
FROM res_rsv_ruimte rr, res_rsv_deel rd
WHERE rr.res_rsv_ruimte_key = rd.res_rsv_ruimte_key
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rd.res_deel_key = p_res_deel_key
AND rd.res_rsv_deel_verwijder IS NULL
AND rr.res_rsv_ruimte_van <= GREATEST(p_start_datetime, l_zoeken_vanaf_res_t1)
AND rr.res_rsv_ruimte_tot > GREATEST(p_start_datetime, l_zoeken_vanaf_res_t1)
AND rr.res_status_fo_key <> 4;
IF l_zoeken_vanaf_starttijd IS NULL
THEN
-- Er is geen reservering gevonden die voor p_start_datetime begint en na p_start_datetime eindigt, dus dan is de starttijd gewoon p_start_datetime
l_zoeken_vanaf_starttijd := p_start_datetime;
ELSE
IF l_zoeken_vanaf_starttijd >= p_start_datetime2
THEN
-- De starttijd l_zoeken_vanaf_starttijd ligt hier na de eindtijd, dan kunnen we ook stoppen (en niet meer recursief aanroepen)
l_zoeken_vanaf_starttijd := p_start_datetime2;
ELSE
-- Wat op zich niet voor zou mogen komen, maar toch evt kan (= dirty resevering), als er niet netjes na l_zoeken_vanaf_starttijd een nieuwe reservering begint, maar ervoor, we hebben dan van doen met overlappende reservering)
-- Dan moeten we als starttijd iets naar voren (terug in de tijd), we nemen dan de laatste beginnende reservering met een starttijd na p_start_datetime maar voor l_zoeken_vanaf_starttijd, dus ertussen in.
-- Daarom roepen we deze functie recursief aan ;-)
l_zoeken_vanaf_starttijd := marx_get_fromdatetime(p_res_deel_key, l_zoeken_vanaf_starttijd, p_start_datetime2, p_slack_minutes);
END IF;
END IF;
IF l_zoeken_vanaf_starttijd IS NULL OR l_zoeken_vanaf_starttijd <= l_zoeken_vanaf_res_t1
THEN l_zoeken_vanaf_starttijd := l_zoeken_vanaf_res_t1; -- Bij de starttijd op res_t1 hoeft de p_slack_minutes er niet bij opgesteld te worden
ELSE l_zoeken_vanaf_starttijd := l_zoeken_vanaf_starttijd + (p_slack_minutes/(60*24));
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
l_zoeken_vanaf_starttijd := NULL;
WHEN TOO_MANY_ROWS
THEN
l_zoeken_vanaf_starttijd := NULL;
END;
RETURN l_zoeken_vanaf_starttijd;
END;
/
-- Op zoek naar de eerst volgende reserverings(begin)tijd res_rsv_ruimte_van, vanaf tijdstip 'p_from_datetime'.
-- Kan NULL opleveren als er geen reservering meer is.
-- Voor alles geldt dat de eerst volgende reserveringstijd wel voor de algemene instelling res_t2 moet liggen.
-- En uiteraard moet de reservering niet de status "vervallen" hebben, die telt niet mee.
CREATE OR REPLACE FUNCTION marx_get_next_res_starttijd
(p_res_deel_key IN NUMBER, p_from_datetime IN DATE)
RETURN DATE
AS
l_start_datetime DATE;
BEGIN
BEGIN
SELECT MIN(rr.res_rsv_ruimte_van)
INTO l_start_datetime
FROM res_rsv_ruimte rr, res_rsv_deel rd
WHERE rr.res_rsv_ruimte_key = rd.res_rsv_ruimte_key
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rd.res_deel_key = p_res_deel_key
AND rd.res_rsv_deel_verwijder IS NULL
AND rr.res_rsv_ruimte_van > p_from_datetime
AND rr.res_status_fo_key <> 4;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
l_start_datetime := NULL;
WHEN TOO_MANY_ROWS
THEN
l_start_datetime := NULL;
END;
RETURN l_start_datetime;
END;
/
-- Op zoek naar de eerst volgende reserverings(eind)tijd res_rsv_ruimte_tot, vanaf tijdstip 'p_from_datetime'.
-- Deze eindtijd moet wel vermeerderd worden met de p_slack_minutes.
-- Kan NULL opleveren als er geen reservering meer is.
-- En uiteraard moet de reservering niet de status "vervallen" hebben, die telt niet mee.
CREATE OR REPLACE FUNCTION marx_get_next_res_eindtijd
(p_res_deel_key IN NUMBER, p_from_datetime IN DATE, p_slack_minutes IN NUMBER)
RETURN DATE
AS
l_eind_datetime DATE;
BEGIN
BEGIN
SELECT MIN(rr.res_rsv_ruimte_tot)
INTO l_eind_datetime
FROM res_rsv_ruimte rr, res_rsv_deel rd
WHERE rr.res_rsv_ruimte_key = rd.res_rsv_ruimte_key
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rd.res_deel_key = p_res_deel_key
AND rd.res_rsv_deel_verwijder IS NULL
AND rr.res_rsv_ruimte_van >= p_from_datetime
AND rr.res_status_fo_key <> 4;
l_eind_datetime := l_eind_datetime + (p_slack_minutes/(60*24));
EXCEPTION
WHEN NO_DATA_FOUND
THEN
l_eind_datetime := NULL;
WHEN TOO_MANY_ROWS
THEN
l_eind_datetime := NULL;
END;
RETURN l_eind_datetime;
END;
/
-- Bepaalt het eind moment (datum + tijdstip) van de reservering met een duur van v_duration_minutes, rekening houdende met res_t1 en res_t2.
CREATE OR REPLACE FUNCTION marx_get_enddatetime
(v_res_deel_key IN NUMBER,
v_datetime_start IN DATE,
v_duration_minutes IN NUMBER)
RETURN DATE
AS
v_date DATE;
l_vanaf_res_t1 DATE;
l_tot_res_t2 DATE;
l_working_minutes NUMBER(10);
BEGIN
BEGIN
l_tot_res_t2 := marx_get_res_t2(v_res_deel_key, v_datetime_start);
l_working_minutes := ROUND(24*60*(l_tot_res_t2 - v_datetime_start));
IF l_working_minutes >= v_duration_minutes
THEN
-- Genoeg minuten voor de rest van de dag, we hoeven niet verder naar morgen te kijken, is al oke.
v_date:= v_datetime_start + (v_duration_minutes/(24*60));
ELSE
-- De dag heeft niet genoeg minuten meer, we moeten verder naar morgen kijken...
-- Oftewel de klus pas niet op deze werkdag, dan recursief aanroepen met morgen vanaf start dag, bij v_duration halen we de gewerkte uren (minuten) van vandaag (tot aan einde vd dag) eraf
l_vanaf_res_t1 := marx_get_res_t1(v_res_deel_key, v_datetime_start + 1);
v_date := marx_get_enddatetime(v_res_deel_key, l_vanaf_res_t1, v_duration_minutes - l_working_minutes);
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_date := NULL;
WHEN TOO_MANY_ROWS
THEN
v_date := NULL;
END;
RETURN v_date;
END;
/
-- FUNCTION marx_free_space
-- Bepaalt of het gat tussen v_time1 en v_time2 meer dan v_duration_minutes + v_slack_minutes is, zo ja dan is het gat groot genoeg en voldoet ie (oke).
-- Wanneer v_time1 NULL is, betekent dit oneindig veel ruimte, en is het resultaat per defintie oke is.
-- Wanneer v_time2 NULL is, betekent dit oneindig veel ruimte, en is het resultaat per defintie oke is.
-- Wanneer een klus korter dan een werkdag duurt, dan gaan we de klus niet op meerdere werkdagen splitsen, we willen 1x de afspraak, deelafspraken zijn niet gewenst.
CREATE OR REPLACE FUNCTION marx_free_space
(v_res_deel_key IN NUMBER,
v_time1 IN DATE,
v_time2 IN DATE,
v_duration_minutes IN NUMBER,
v_slack_minutes IN NUMBER
)
RETURN NUMBER
AS
v_free NUMBER(1); -- 0 is niet free (not oke), 1 is wel free (oke)
l_working_minutes NUMBER(10);
l_workingday NUMBER(10);
l_vanaf_res_t1 DATE;
l_tot_res_t2 DATE;
BEGIN
BEGIN
v_free := 0;
l_vanaf_res_t1 := marx_get_res_t1(v_res_deel_key, v_time1); -- Starttijd vd dag
l_tot_res_t2 := marx_get_res_t2(v_res_deel_key, v_time1); -- Eindtijd vd dag
IF (ROUND((24*60*(l_tot_res_t2 - l_vanaf_res_t1))) >= (v_duration_minutes + v_slack_minutes))
THEN
-- De klus kan op 1 dag, we willen alleen een moment goedvinden als genoeg ruimte op die dag er is, m.a.w mag op meerdere dagen vinden we niet goed
-- Dus we willen alleen oke teruggeven als v_time1 IN DATE, v_time2 IN DATE op dezelfde dag liggen, EN (AND) het gat (tijd ertussen) voldoende groot is
-- Let op: omdat v_time2 kan leeg zijn, maximeren we deze op l_tot_res_t2, en we nemen de kleinste tijd (of eindtijd vd dag en anders de reservering van deze dag als die eerder is)
IF ROUND((24*60*(LEAST(COALESCE(v_time2, l_tot_res_t2), l_tot_res_t2) - v_time1))) >= (v_duration_minutes + v_slack_minutes)
THEN
-- Gat is ruim voldoende --> oke
v_free := 1;
END IF;
ELSE
-- Klus duurt langer dan een werkdag, we kunnen de klus wel splitsen op meerdere werkdagen...
-- Dat kan alleen als v_time2 niet vandaag, maar morgen, of nog later is, anders is er ook geen ruimte qua tijd, en kunnen we meteen stoppen.
-- Of als v_time2 NULL is (oneindige ruimte), dan kunnen we ook door gaan
IF v_time2 IS NULL OR TRUNC(v_time2) > TRUNC(v_time1)
THEN
l_working_minutes := ROUND(24*60*(l_tot_res_t2 - v_time1));
-- Klus pas niet op 1 werkdag, dan recursief aanroepen met morgen vanaf start dag, bij v_duration halen we de gewerkte uren (minuten) van vandaag (tot aan einde vd dag) eraf
l_vanaf_res_t1 := marx_get_res_t1(v_res_deel_key, v_time1 + 1);
v_free := marx_free_space(v_res_deel_key, l_vanaf_res_t1, v_time2, v_duration_minutes - l_working_minutes, v_slack_minutes);
END IF;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_free := 0;
WHEN TOO_MANY_ROWS
THEN
v_free := 0;
END;
RETURN v_free;
END;
/
--MARX#70053 Mareon Premium Groene Planningen: plannen met geografische optimalisatie
CREATE OR REPLACE FUNCTION marx_pi
RETURN NUMBER
AS
BEGIN
RETURN acos(-1);
END;
/
CREATE OR REPLACE FUNCTION marx_deg2rad(p_deg IN NUMBER)
RETURN NUMBER
AS
BEGIN
RETURN ROUND(p_deg * (marx_pi()/180), 20);
END;
/
-- Gebaseerd op https://en.wikipedia.org/wiki/Haversine_formula
CREATE OR REPLACE FUNCTION marx_dist_latlon_2_km(p_lat1 IN NUMBER,p_lon1 IN NUMBER, p_lat2 IN NUMBER, p_lon2 IN NUMBER)
RETURN NUMBER
AS
v_earth_R NUMBER(10) := 6371; -- Radius of the earth in km
dLat NUMBER(30,20);
dLon NUMBER(30,20);
a NUMBER(30,20);
c NUMBER(30,20);
d NUMBER(30,20);
BEGIN
dLat := marx_deg2rad(p_lat2-p_lat1); -- marx_deg2rad below
dLon := marx_deg2rad(p_lon2-p_lon1);
a := ROUND(
sin(dLat/2) * sin(dLat/2) +
cos(marx_deg2rad(p_lat1)) * cos(marx_deg2rad(p_lat2)) *
sin(dLon/2) * sin(dLon/2), 20);
c := ROUND(2 * atan2(sqrt(a), sqrt(1-a)), 20);
d := ROUND(v_earth_R * c, 20); -- Distance in km
RETURN d;
END;
/
-- Check of de lat-long coordinaten x en y wel of niet in het werkgebied van de persoon valt, gegeven de datum.
-- Controle van in de tabel inzetbaarheid 'prs_perslid_inzetbaar', als prs_perslid_inzetbaar_plaats_x en prs_perslid_inzetbaar_plaats_y en prs_perslid_inzetbaar_radius (uitgedrukt in KILOMETERS) op de dag van perslid BEIDEN zijn gevuld,
-- dan gaat we checken, en anders beschouwen we dat als 'er is geen specifiek werkgebied aangegeven' waarmee wordt gezegd: elke plaats is OKE (dus dan retoureert deze functie de waarde 1)
-- Dus indien BEIDE velden prs_perslid_inzetbaar_plaats_x en prs_perslid_inzetbaar_plaats_y zijn gevuld, gaan we controleren of de coordinaten in het werkgebied vallen.
-- Resultaat: 0 (=nee) of 1 (=ja)
CREATE OR REPLACE FUNCTION marx_coord_within_perslid_area(p_x IN NUMBER, p_y IN NUMBER, p_prs_perslid_key IN NUMBER, p_datum IN DATE)
RETURN NUMBER
AS
v_perslid_inzetbaar_plaats_x NUMBER(16,6);
v_perslid_inzetbaar_plaats_y NUMBER(16,6);
v_perslid_inzetbaar_radius NUMBER(6);
BEGIN
IF p_x IS NULL OR p_y IS NULL
THEN
-- Geen coordinaten bekend, dan kunnen we geen geo-check doen, en is (beschouwen we) alles oke.
RETURN 1;
END IF;
SELECT prs_perslid_inzetbaar_plaats_x, prs_perslid_inzetbaar_plaats_y, prs_perslid_inzetbaar_radius
INTO v_perslid_inzetbaar_plaats_x, v_perslid_inzetbaar_plaats_y, v_perslid_inzetbaar_radius
FROM prs_perslid_inzetbaar pi
WHERE pi.prs_perslid_key = p_prs_perslid_key
AND pi.prs_perslid_inzetbaar_dag = to_char(p_datum,'D') - 1;
IF v_perslid_inzetbaar_plaats_x IS NOT NULL AND v_perslid_inzetbaar_plaats_y IS NOT NULL AND v_perslid_inzetbaar_radius IS NOT NULL
THEN
-- v_perslid_inzetbaar_radius wordt in meters bewaard, dus met factor 1000 gaan we vergelijken op meters...
IF 1000* marx_dist_latlon_2_km(p_x, p_y, v_perslid_inzetbaar_plaats_x, v_perslid_inzetbaar_plaats_y) <= v_perslid_inzetbaar_radius
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
ELSE
RETURN 1;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN RETURN 1;
END;
/
-- FUNCTION marx_are_you_free
-- "Mister Humphries are you free"? ;-)
-- Check of van bedrijf v_bedrijf_key een contactpersoon/een poppetje met expertise/competentie volgens v_competentie_code
-- op datum v_date de klus van v_duration_minutes minuten kan uitvoeren, beginnend tussen tijdtip v_starttime1 en v_starttime2
-- Parameters zijn allen verplicht:
-- v_bedrijf_key, moet gevuld zijn, alle contactpersonen met gekoppelde perslid binnen dit bedrijf doen mee in de speurtocht naar vrije/geschikte kandidaten..
-- v_competentie_code: gevuld met b.v. ELE (Elektricien), dan alleen op zoek naar personen die ELE zijn, andere codes zijn LOO, SCH, STU, OVE etc
-- v_starttime1, startmoment van de klus niet eerder dan dit tijdstip
-- v_starttime2, startmoment van de klus niet later dan dit tijdstip
-- v_duration_minutes, de duur in minuten hoe lang de klus/opdracht duurt, past dat in het planbord bij betreffende persoon (Humphries)?
-- v_slack_minutes, buffer (in minuten) die voor en na een planning (reservering) die nodig is t.b.v. bijvoorbeeld reistijd. (schoonmaaktijd bij ruimten).
-- En 2 nieuwe parameters agv MARX#70053 Mareon Premium Groene Planningen: plannen met geografische optimalisatie:
-- v_lat, indien niet gevuld, dan geen LAT-coordinaten van Maintenance-locatie bekend
-- v_lng, indien niet gevuld, dan geen LONG-coordinaten van Maintenance-locatie bekend
-- indien v_lat en v_lng wel gevuld, dan gaan we kijken of bedrijf wel rechten heeft cq. de module "Mareon Premium Groene Planningen" heeft anageschaft,
-- en zo ja, dan ook controleren of planvoorstel in geo-gebied van betreffende vakman valt.
-- MARX#75600 Mareon Groene Planning: Aansturing gebiedsoptimalisatie vanuit opdrachtgever
-- en nog optionele parameter (string) v_region_id, mogelijk vanuit Tobias gevuld (C20 in de praktijk) en alleen indien opdrachtnemer Groene Planning heeft aanstaan, anders is deze NULL.
-- indien gevuld dan wordt deze doorgegeven aan functie 'marx_are_you_free', zodat alleen de personen icm dagen in aanmerking komen die deze region-id in Mareon hebben geregsitreerd (via prs_perslid_inzetbaar)
-- MARX#75755 Registratie bij vakman voor welke opdrachtgever(s) deze werkzaamheden uitvoert
-- Nieuwe parameter v_woco_key is nodig, om te kijken of medewerker voor die woco inzetbaar is.
--------------
-- Return: eerste passende res_deel_key met daarbij de start-tijd.
CREATE OR REPLACE FUNCTION marx_are_you_free
(v_woco_key IN NUMBER,
v_bedrijf_key IN NUMBER,
v_competentie_code IN VARCHAR2,
v_start_datetime1 IN DATE,
v_start_datetime2 IN DATE,
v_duration_minutes IN NUMBER,
v_slack_minutes IN NUMBER,
v_lat IN NUMBER,
v_lng IN NUMBER,
v_region_id IN VARCHAR2
)
RETURN VARCHAR2
AS
-- Alle res_delen bij bedrijf (leverancier) 'v_bedrijf_key' met functie 'v_competentie_code' waarbij er geen omvattende (= eerdere starttijd en latere einddtijd) resevering op dat res_deel bestaat (die niet vervallen is)
-- Toevoeging MARX#70053 Mareon Premium Groene Planningen: plannen met geografische optimalisatie. We gaan eerst de vakmannen proberen die het kleinste werkgebied hebben (als die er is, anders maakt volgorde niet uit/dont care)
-- Dat maakt dat eerst vakmannen met het kleinste werkgebied worden gekozen, en als dat niet lukt, dan gaan we verder zoeken naar grotere (omvattende) werkgebieden...
CURSOR free_perslids
IS
SELECT DISTINCT d.res_deel_key, p.prs_perslid_key, pi.prs_perslid_inzetbaar_radius
FROM res_deel d, prs_perslid p, prs_bedrijfdienstlocatie bdl, prs_dienst di, prs_contactpersoon cp, prs_perslid_inzetbaar pi
WHERE d.res_deel_verwijder IS NULL
AND d.res_prs_perslid_key = p.prs_perslid_key
AND p.prs_perslid_verwijder IS NULL
AND COALESCE(bdl.prs_bedrijf_voor_key, v_woco_key) = v_woco_key
AND di.prs_dienst_key = bdl.prs_dienst_key
AND di.prs_dienst_hint = UPPER(v_competentie_code)
AND bdl.prs_perslid_key = p.prs_perslid_key
AND cp.prs_perslid_key = p.prs_perslid_key
AND cp.prs_contactpersoon_verwijder IS NULL
AND cp.prs_bedrijf_key = v_bedrijf_key
AND NOT EXISTS (SELECT 'x' FROM res_rsv_ruimte rr, res_rsv_deel rd
WHERE rr.res_rsv_ruimte_key = rd.res_rsv_ruimte_key
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rd.res_deel_key = d.res_deel_key
AND rd.res_rsv_deel_verwijder IS NULL
AND rr.res_rsv_ruimte_van <= v_start_datetime1
AND rr.res_rsv_ruimte_tot >= v_start_datetime2
AND rr.res_status_fo_key <> 4
)
AND p.prs_perslid_key = pi.prs_perslid_key (+)
AND to_char(v_start_datetime1,'D') - 1 = pi.prs_perslid_inzetbaar_dag (+)
AND UPPER(COALESCE(pi.prs_perslid_inzetbaar_plaats, v_region_id, 'x')) = UPPER(COALESCE(v_region_id, pi.prs_perslid_inzetbaar_plaats, 'x'))
ORDER BY pi.prs_perslid_inzetbaar_radius;
v_free VARCHAR2(100);
l_zoeken_vanaf_starttijd DATE;
l_next_reservering_starttime DATE;
l_check_area_is_oke NUMBER(1);
BEGIN
BEGIN
v_free := NULL;
-- Beschikbaar bij een persoon (object) als:
-- 1. er geen reservering bestaat die geheel de starttijden overlappen, dus er mag geen res bestaan die voor v_starttime1 begint en na v_starttime2 eindigt (dan is de persoon al bezet) --> Dit doet cursor free_perslids
-- 2. er een gat van minimaal v_duration_minutes minuten te vinden is tussen vanaf v_starttime1 en v_starttime2
-- 3. dat gat vanaf de vorige bestaande reservering tot de eerst volgende bestaande reservering minimaal v_slack_minutes + v_duration_minutes + v_slack_minutes is.
-- 1.geeft alle personen (objecten) die geen reservering hebben die starttijden geheel overlapt
FOR rec IN free_perslids
LOOP
BEGIN
-- First of all, eerst checken of dit record op deze dag wel voldoet aan geografisch gebied, anders kunnen we deze gewoon skippen en is uitgebreid zoeken niet nodig.
-- Hiervoor is het dan wel nodig dat de leverancier Mareon Premium Groene Planningen heeft afgenomen, dat gaan we uiteraard eerst checken, want anders gaan we de check op geografische voorwaarde skippen...
-- Default is daarom 1
l_check_area_is_oke := 1;
IF marx_bedrijf_auth_4_greenplan(v_bedrijf_key) = 1 AND v_lat is NOT NULL AND v_lng IS NOT NULL
THEN
-- Oke, leverancier heeft Mareon Groene Planning, en coordinaten zijn bekend (not null), dan nu checken...
l_check_area_is_oke := marx_coord_within_perslid_area(v_lat, v_lng, rec.prs_perslid_key, v_start_datetime1);
END IF;
-- Als l_check_area_is_oke is waarde 0, dan heeft LEV deze module afgenomen en voldoet de vakman niet aan GEO-voorwaarde op die dag, en kunnen we die skippen, als waarde 1 dan wel kijken naar ruimte in zijn agenda...
IF l_check_area_is_oke = 1
THEN
-- Oke, aan GEO-voorwaarde wordt nu voldaan (of leverancier heeft dit niet afgenomen), we gaan nu in de agenda van betreffende vakman naar de vrije ruimte zoeken...
-- Zoek naar de dichts bijzijnde reservering voor perslid (res_deel) voorafgaande aan de v_start_datetime1 en die ook een eindtijd heeft na v_start_datetime1 (en die is weer voor v_start_datetime2, anders zit die niet in deze cursor/loop)
-- Is die er niet, dan beginnen we met zoeken vanaf v_start_datetime1.
-- Is die er wel, dan beginnen we met zoeken vanaf de eindtijd van de gevonden reservering.
-- Zijn er hiervan meerdere (wat op zich niet kan) dan zoeken we vanaf de max(eindtijd).
l_zoeken_vanaf_starttijd := marx_get_fromdatetime(rec.res_deel_key, v_start_datetime1, v_start_datetime2, v_slack_minutes);
-- Zolang de vanaf-tijd nog voor de uiterlijke starttijd (v_start_datetime2) zit, duiken we de loop in....
WHILE (l_zoeken_vanaf_starttijd < v_start_datetime2) AND (v_free IS NULL)
LOOP
-- Zoek in de periode tot aan v_start_datetime2 naar een (of het eerste) gat met een duur van minimaal v_duration_minutes + v_slack_minutes minuten, is die er gevonden,
-- dan voldoet deze res_deel_key, en zetten we v_free op res_deel_key met de startdatum/tijd waarop gat aanwezig is.
-- We zoeken de eerst volgende (in tijd gezien) reservering, als we die niet vonden, is er een oneindig gat, maar er moet wel passen qua duur tot aan einde vd dag
l_next_reservering_starttime := marx_get_next_res_starttijd(rec.res_deel_key, l_zoeken_vanaf_starttijd);
IF marx_free_space(rec.res_deel_key, l_zoeken_vanaf_starttijd, l_next_reservering_starttime, v_duration_minutes, v_slack_minutes) = 1
THEN
v_free := rec.res_deel_key || ';' || to_char(l_zoeken_vanaf_starttijd,'yyyy-mm-dd hh24:mi:ss');
ELSE
-- l_zoeken_vanaf_starttijd := marx_get_next_res_eindtijd(rec.res_deel_key, l_zoeken_vanaf_starttijd, v_slack_minutes);
l_zoeken_vanaf_starttijd := marx_get_fromdatetime(rec.res_deel_key, l_next_reservering_starttime, v_start_datetime2, v_slack_minutes);
END IF;
END LOOP;
END IF;
-- Zodra er een vrij beschikbaar moment is gevonden (v_free is niet meer NULL) dan uit de loop springen...
IF v_free IS NOT NULL
THEN EXIT;
END IF;
END;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_free := NULL;
WHEN TOO_MANY_ROWS
THEN
v_free := NULL;
END;
RETURN v_free;
END;
/
-- FUNCTION marx_get_planproposals
-- Levert maximaal v_max_options aan vrije (beschikbare) planvoorstellen op van een leverancier (v_bedrijf_key) van personen die voldoen aan functieprofiel (v_competentie_code) in de periode v_date_start tot en met v_date_end, rekening houdend
-- met eventuele voorkeursdagen/(start)tijden en waarin de werkzaamheden een duur van v_duration_minutes minuten hebben en moet passen.
-- Parameters:
-- v_bedrijf_key, moet gevuld zijn, alle contactpersonen met gekoppelde perslid binnen dit bedrijf doen mee in de speurtocht naar vrije/geschikte kandidaten..
-- v_competentie_code, indien gevuld met b.v. ELE (Elektricien) (of LOO, SCH, STU...), dan alleen op zoek naar personen die ELE zijn, indien gevuld met NULL, dan op zoek naar alle personen.
-- v_date_start, zoek naar geschikt moment vanaf deze datum, start vande datumrange, indien niet gevuld, dan vanaf vandaag
-- v_date_end, zoek naar geschikt moment t/m deze datum, einde van de datumrange, indien niet gevuld, dan t/m vandaag + 30 dagen.
-- v_mon_times, indien niet gevuld, dan doet maandag niet mee, indien gevuld dan alle maandagen binnen de tijdsippen afspeuren, formaat = '10:00:00-12:00:00;13:00:00-15:00:00;08:00:00-10:00:00;15:00:00-17:00:00;'
-- v_tue_times, indien niet gevuld, dan doet dinsdag niet mee, indien gevuld dan alle dinsdagen binnen de tijdsippen afspeuren,formaat = ...
-- v_wed_times, indien niet gevuld, dan doet woensdag niet mee, indien gevuld dan alle woensdagen binnen de tijdsippen afspeuren,
-- etc
-- etc
-- v_duration_minutes, duur die de werkzaamheden in beslag nemen, en een kandidaat-tijdsblok (op die datum waarin werkzaamheden beginnen) moet voldoende aan vrije ruimte in minuten hebben om als resultaat te voldoen.
-- v_slack_minutes, buffer (in minuten) die voor en na een planning (reservering) die nodig is t.b.v. bijvoorbeeld reistijd. (schoonmaaktijd bij ruimten).
-- v_max_options, maximum aantal te retourneren opties, indien leeg, dan is er geen maximum en wordt iedere mogelijkheid in het resultaat verwerkt.
-- En 2 nieuwe parameters agv MARX#70053 Mareon Premium Groene Planningen: plannen met geografische optimalisatie:
-- v_lat, indien niet gevuld, dan geen LAT-coordinaten van Maintenance-locatie bekend
-- v_lng, indien niet gevuld, dan geen LONG-coordinaten van Maintenance-locatie bekend
-- Beide parameters geven we door aan functie 'marx_are_you_free'.
-- MARX#75600 Mareon Groene Planning: Aansturing gebiedsoptimalisatie vanuit opdrachtgever
-- en nog optionele parameter (string) v_region_id, mogelijk vanuit Tobias gevuld (C20 in de praktijk) en alleen indien opdrachtnemer Groene Planning heeft aanstaan, anders is deze NULL.
-- indien gevuld dan wordt deze doorgegeven aan functie 'marx_are_you_free', zoda alleen de personen icm dagen in aanmerking komen die deze region-id in Mareon hebben geregsitreerd (via prs_perslid_inzetbaar)
-- ----------------------------
-- Resultaat: JSON met datumvoorstellen, dit zijn de bloktijden die voldoen, die worden geretourneerd:
-- Voorbeeld
-- [{ "planproposal": {"res_deel_key": "1234", "startdate": "2021-04-01", "starttime": "09:00", "enddate": "2021-04-01", "endtime": "12:00" } },
-- { "planproposal": {"res_deel_key": "1234", "startdate": "2021-04-01", "starttime": "13:00", "enddate": "2021-04-01", "endtime": "16:00" } },
-- { "planproposal": {"res_deel_key": "9876", "startdate": "2021-04-02", "starttime": "09:00", "enddate": "2021-04-02", "endtime": "12:00" } },
-- { "planproposal": {"res_deel_key": "9876", "startdate": "2021-04-05", "starttime": "13:00", "enddate": "2021-04-05", "endtime": "16:00" } },
-- ]
CREATE OR REPLACE FUNCTION marx_get_planproposals
(v_woco_key IN NUMBER,
v_bedrijf_key IN NUMBER,
v_competentie_code IN VARCHAR2,
v_date_start IN DATE,
v_date_end IN DATE,
v_mon_times IN VARCHAR2,
v_tue_times IN VARCHAR2,
v_wed_times IN VARCHAR2,
v_thu_times IN VARCHAR2,
v_fri_times IN VARCHAR2,
v_sat_times IN VARCHAR2,
v_sun_times IN VARCHAR2,
v_duration_minutes IN NUMBER,
v_slack_minutes IN NUMBER,
v_max_options IN NUMBER,
v_lat IN NUMBER,
v_lng IN NUMBER,
v_region_id IN VARCHAR2) RETURN VARCHAR2
AS
v_result VARCHAR2(4000);
v_result_inner VARCHAR2(4000);
l_aantal_options NUMBER(10);
l_date_start DATE;
l_stop NUMBER(1);
l_day_times VARCHAR2(4000);
l_time_frame VARCHAR2(1000);
l_datum_str VARCHAR2(100);
l_time1_str VARCHAR2(100);
l_time2_str VARCHAR2(100);
l_teller NUMBER(10);
l_datetime1 DATE;
l_datetime2 DATE;
l_free VARCHAR2(1000);
l_res_deel_key NUMBER(10);
BEGIN
v_result := '[]';
BEGIN
l_stop := 0;
-- We gaan zoeken in de periode vanaf v_date_start tot en met v_date_end, beide datums moeten wel vanaf vandaag (sysdate) zijn, dus in de toekomst, in verleden gaan we niet zoeken...
l_date_start := TRUNC(v_date_start);
IF l_date_start < TRUNC(SYSDATE)
THEN l_date_start := TRUNC(SYSDATE);
END IF;
l_aantal_options := 0;
l_day_times := NULL;
WHILE (l_aantal_options < v_max_options) AND (TRUNC(l_date_start) <= TRUNC(v_date_end))
LOOP
CASE
WHEN to_char(l_date_start,'D') = 1 THEN l_day_times := v_sun_times;
WHEN to_char(l_date_start,'D') = 2 THEN l_day_times := v_mon_times;
WHEN to_char(l_date_start,'D') = 3 THEN l_day_times := v_tue_times;
WHEN to_char(l_date_start,'D') = 4 THEN l_day_times := v_wed_times;
WHEN to_char(l_date_start,'D') = 5 THEN l_day_times := v_thu_times;
WHEN to_char(l_date_start,'D') = 6 THEN l_day_times := v_fri_times;
WHEN to_char(l_date_start,'D') = 7 THEN l_day_times := v_sat_times;
ELSE l_day_times := NULL;
END CASE;
-- b.v. l_day_times: '10:00:00-12:00:00;13:00:00-15:00:00;08:00:00-10:00:00;15:00:00-17:00:00;'
IF l_day_times IS NOT NULL
THEN
l_teller := 1;
fac.imp_getfield_nr (l_day_times, ';', l_teller, l_time_frame);
WHILE (l_time_frame IS NOT NULL) AND (l_aantal_options < v_max_options)
LOOP
-- b.v. l_time_frame: '10:00:00-12:00:00'
l_datum_str := to_char(l_date_start,'yyyy-mm-dd');
l_time1_str := SUBSTR(l_time_frame, 1, INSTR(l_time_frame,'-')-1);
l_time2_str := SUBSTR(l_time_frame, INSTR(l_time_frame,'-')+1);
l_datetime1 := to_date(l_datum_str || l_time1_str,'yyyy-mm-dd hh24:mi:ss');
l_datetime2 := to_date(l_datum_str || l_time2_str,'yyyy-mm-dd hh24:mi:ss');
IF l_datetime1 > SYSDATE AND l_datetime2 > SYSDATE
THEN
-- Timeframe kan niet in verleden liggen, die is niet meer (goed) te plannen ;-)
l_free := marx_are_you_free (v_woco_key, v_bedrijf_key, v_competentie_code, l_datetime1, l_datetime2, v_duration_minutes, v_slack_minutes, v_lat, v_lng, v_region_id);
IF (l_free IS NOT NULL) AND (l_aantal_options < v_max_options)
THEN
l_aantal_options := l_aantal_options + 1;
l_res_deel_key := fac.safe_to_number(SUBSTR(l_free, 1, INSTR(l_free,';')-1));
v_result_inner := v_result_inner || ', { "planproposal": {"res_deel_key": "' || l_res_deel_key || '", "startdate": "' || l_datum_str || '", "starttime": "' || l_time1_str || '", "enddate": "' || l_datum_str || '", "endtime": "' || l_time2_str || '" } }';
END IF;
END IF;
l_teller := l_teller + 1;
fac.imp_getfield_nr (l_day_times, ';', l_teller, l_time_frame);
END LOOP;
END IF;
l_date_start := l_date_start + 1;
END LOOP;
IF v_result_inner IS NOT NULL
THEN
v_result := '[' || SUBSTR(v_result_inner, 2) || ']';
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_result := '[]';
WHEN TOO_MANY_ROWS
THEN
v_result := '[]';
END;
RETURN v_result;
END;
/
-- FUNCTION marx_set_planconfirmation
-- Parameters:
-- v_bedrijf_key, moet gevuld zijn, een van de contactpersonen met gekoppelde perslid binnen dit bedrijf wordt ingepland..
-- v_res_rsv_ruimte_key, moet gevuld zijn, is unieke id die leverancier in 1e call (planproposals) heeft teruggegeven aan caller, die deze in 2e call (nu dus) weer mee moet geven, waarmee de andere (STATIC) parameters (prs_bedrijf_key, v_duration_minutes, v_competentie_code) bepaald kunnen worden
-- v_ion_nr, is de unieke InkoopOpdrachtNummer van opdrachtgever die (later) wordt gestuurd, nu alvast in deze planning zodat deze alvast geregistreerd kan worden om later te koppelen aan de ION...
-- v_date_start, verplicht; de reservering moet op deze datum beginnen, formaat
-- v_time_start, verplicht; de reservering moet op/na dit tijdstip beginnen
-- v_time_end, verplicht; de reservering moet uiterlijk op dit tijdstip beginnen
-- Resultaat: JSON met datum/tijd confirmation retour, hier wordt als resultaat bij start- en enddate, maar ook bij start- en endtime, de momenten geretourneerd wanneer de klus daadwerkelijk start en eindigt, rekening houdende met duration, werktijden etc.
-- Voorbeeld
-- [{ "planproposal": {"res_deel_key": "1234", "startdate": "2021-04-01", "starttime": "10:45", "enddate": "2021-04-01", "endtime": "12:40" } }] (deze klus duurt 2 uur en hier wordt geen bloktijden maar de echte geplande datum/tijd weergegeven)
-- of ander voorbeeld:
-- [{ "planproposal": {"res_deel_key": "1234", "startdate": "2021-04-01", "starttime": "9:35", "enddate": "2021-04-02", "endtime": "11:35" } }] (deze klus duurt 12 uur, en gaat over 2 dagen, heeft dus niets met bloktijd van doen)
CREATE OR REPLACE FUNCTION marx_set_planconfirmation
(v_woco_key IN NUMBER,
v_bedrijf_key IN NUMBER,
v_res_rsv_ruimte_key IN NUMBER,
v_ion_nr IN VARCHAR2,
v_date_start IN DATE,
v_time_start IN VARCHAR2,
v_time_end IN VARCHAR2
) RETURN VARCHAR2
AS
v_result VARCHAR2(4000);
l_date_start DATE;
l_datum_str VARCHAR2(100);
l_datetime1 DATE;
l_datetime2 DATE;
l_free VARCHAR2(1000);
l_duration_minutes NUMBER(10);
l_slack_minutes NUMBER(10);
l_competentie_code VARCHAR2(1000);
l_res_deel_key NUMBER(10);
l_datetime_start DATE;
l_datetime_end DATE;
l_date_start_str VARCHAR2(100);
l_time_start_str VARCHAR2(100);
l_date_end_str VARCHAR2(100);
l_time_end_str VARCHAR2(100);
l_lat NUMBER(20,15);
l_lng NUMBER(20,15);
-- prs_perslid_inzetbaar_plaats
l_region_id VARCHAR(200);
v_result_inner VARCHAR2(4000);
BEGIN
v_result := '[]';
BEGIN
l_date_start := TRUNC(v_date_start);
IF l_date_start >= TRUNC(SYSDATE)
THEN
-- Startdatum moet niet in verleden liggen..
l_datum_str := to_char(l_date_start,'yyyy-mm-dd');
l_datetime1 := to_date(l_datum_str || v_time_start,'yyyy-mm-dd hh24:mi:ss');
l_datetime2 := to_date(l_datum_str || v_time_end,'yyyy-mm-dd hh24:mi:ss');
IF l_datetime1 > SYSDATE AND l_datetime2 > SYSDATE
THEN
-- Timeframe kan niet in verleden liggen, dan die is niet meer (goed) te plannen ;-)
SELECT 24*60*(res_rsv_ruimte_tot - res_rsv_ruimte_van), 0
INTO l_duration_minutes, l_slack_minutes
FROM res_rsv_ruimte
WHERE res_rsv_ruimte_key = v_res_rsv_ruimte_key;
SELECT MAX(res_kenmerkreservering_waarde)
INTO l_competentie_code
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 9
AND res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
SELECT fac.safe_to_number(MAX(res_kenmerkreservering_waarde))
INTO l_lat
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 6
AND res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
SELECT fac.safe_to_number(MAX(res_kenmerkreservering_waarde))
INTO l_lng
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 7
AND res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
-- MARX#75600 Mareon Groene Planning: Aansturing gebiedsoptimalisatie vanuit opdrachtgever
SELECT MAX(res_kenmerkreservering_waarde)
INTO l_region_id
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 10
AND res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
l_free := marx_are_you_free (v_woco_key, v_bedrijf_key, l_competentie_code, l_datetime1, l_datetime2, l_duration_minutes, l_slack_minutes, l_lat, l_lng, l_region_id);
IF (l_free IS NOT NULL)
THEN
-- Er is een passende planning, het is gelukt, we kunnen de confirmation wederom confirmen, Wel gaan we eerst de dummy proforma reservering goed zetten...
-- l_free bestaat uit string met 2 delen gescheiden door ";", en bevat res_deel_key en starttijd (in formaat yyyy-mm-dd hh24:mi:ss), dus b.v. "1234;2021-03-31 17:25:00"
l_res_deel_key := fac.safe_to_number(SUBSTR(l_free, 1, INSTR(l_free,';')-1));
l_datetime_start := fac.safe_to_date(SUBSTR(l_free, INSTR(l_free,';')+1), 'yyyy-mm-dd hh24:mi:ss');
l_datetime_end := marx_get_enddatetime(l_res_deel_key, l_datetime_start, l_duration_minutes);
l_date_start_str := to_char(l_datetime_start,'yyyy-mm-dd');
l_time_start_str := to_char(l_datetime_start,'hh24:mi:ss');
l_date_end_str := to_char(l_datetime_end,'yyyy-mm-dd');
l_time_end_str := to_char(l_datetime_end,'hh24:mi:ss');
--marx_put_res_dummy_2_real gaan we niet hier uitvoeren, maar ivm UPDATE actie (kan niet in functie) doen we dat iets later, in de asp.
--Daarom retourneren we alle gegevens (zoals res_deel_key en alle datum/tijden) via v_result....
v_result_inner := v_result_inner || ', { "planproposal": {"res_deel_key": "' || l_res_deel_key || '", "startdate": "' || l_date_start_str || '", "starttime": "' || l_time_start_str || '", "enddate": "' || l_date_end_str || '", "endtime": "' || l_time_end_str || '" } }';
END IF;
END IF;
END IF;
IF v_result_inner IS NOT NULL
THEN
v_result := '[' || SUBSTR(v_result_inner, 2) || ']';
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
v_result := '[]';
WHEN TOO_MANY_ROWS
THEN
v_result := '[]';
END;
RETURN v_result;
END;
/
CREATE OR REPLACE FUNCTION marx_get_api_user(v_bedrijf_key IN NUMBER)
RETURN NUMBER
AS
prs_perslid_key NUMBER(10);
BEGIN
SELECT MIN(prs_perslid_key)
INTO prs_perslid_key
FROM mar_v_leverancier_api_perslid
WHERE prs_bedrijf_key = v_bedrijf_key;
RETURN prs_perslid_key;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN NULL;
WHEN TOO_MANY_ROWS
THEN
RETURN NULL;
END;
/
-- Tijdelijk vasthouden van de gegevens van een planverzoek, zoals expertise (competentie), duur, maar ook voor generatie van een uniek planningsnummer t.b.v. de confirmation-bericht.
-- Er wordt een dummy res_reservering met dito res_rsv_ruimte en res_rsv_deel aangemaakt:
-- Voor woco v_woco_key, betreft prs_bedrijf_key van opdrachtgever (woco), die we moeten vastleggen zodat op een later moment, wanneer de opdracht (vanuit woco) wordt gestuurd, we de reservering uniek erbij kunnen vinden, samen met ION (die ook nog komt in PLNCFM
-- Voor leverancier v_bedrijf_key
-- Voor competentie v_competentie_code
-- Voor de duur van v_duration_minutes minuten
-- Onder uniek registratie-nummer v_res_rsv_ruimte_key, deze moet dus van te voren via NEW sequence worden opgehaald voordat deze procedure gebruikt kan worden, indien NULL wordt meegegeven, wordt deze door deze PROC bepaald.
-- LatLong worden hier bewaard (indien gevuld), zodat ze later in de 2e call bij de planbevestiging nog eens kunnen worden gebruikt tbv GEO-voorwaarde.
CREATE OR REPLACE PROCEDURE marx_put_dummy_res_reservering
(v_woco_key IN NUMBER,
v_bedrijf_key IN NUMBER,
v_competentie_code IN VARCHAR2,
v_duration_minutes IN NUMBER,
v_res_rsv_ruimte_key IN NUMBER,
v_lat IN NUMBER,
v_lng IN NUMBER,
v_region_id IN VARCHAR2)
AS
v_res_reservering_key NUMBER(10);
v_mld_opdr_key NUMBER(10);
v_res_rsv_ruimte_cvab_mode NUMBER(10);
v_res_activiteit_key NUMBER(10);
v_res_status_fo_key NUMBER(10);
v_res_rsv_ruimte_van DATE;
v_res_rsv_ruimte_tot DATE;
v_api_perslid_key NUMBER(10);
v_res_deel_key NUMBER(10);
v_res_rsv_deel_dirtlevel NUMBER(10);
l_res_rsv_ruimte_key NUMBER(10);
G_date_far_in_the_past VARCHAR2(10);
FUNCTION marx_get_first_res_deel(v_competentie_code IN VARCHAR2)
RETURN NUMBER
AS
res_deel_key NUMBER(10);
BEGIN
-- Zoek 'eerste' res_deel met juiste competentie van leverancier op
SELECT MIN(d.res_deel_key)
INTO res_deel_key
FROM res_deel d, prs_perslid p, prs_contactpersoon cp, prs_bedrijfdienstlocatie bdl, prs_dienst di
WHERE d.res_deel_verwijder IS NULL
AND d.res_prs_perslid_key = p.prs_perslid_key
AND p.prs_perslid_verwijder IS NULL
AND di.prs_dienst_key = bdl.prs_dienst_key
AND di.prs_dienst_hint = UPPER(v_competentie_code)
AND bdl.prs_perslid_key = p.prs_perslid_key
AND cp.prs_perslid_key = p.prs_perslid_key
AND cp.prs_contactpersoon_verwijder IS NULL
AND cp.prs_bedrijf_key = v_bedrijf_key;
RETURN res_deel_key;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN NULL;
WHEN TOO_MANY_ROWS
THEN
RETURN NULL;
END;
----------- Start procedure ---
BEGIN
-- In Mareon is er 1 ruimte, die (helaas) tbv reserveringen aanwezig moet zijn (res_rsv_ruimte vereist deze).. om de res_delen te kunnen reserveren.
-- v_alg_ruimte_key := 3;
-- Sinds MARX#66033 - "Planbord voor resource-voorzieningen" is alg_ruimte voor personen niet meer nodig ;-)
-- Wel een mld_opdr_key, maar die is nog niet bekend, we doen een constante mld_opdr_key = 1 die niet meer actueel is.
v_mld_opdr_key := 1;
-- We bezorgen gewoon
v_res_rsv_ruimte_cvab_mode := 3;
-- De activiteit Planning in Mareon is key 11
v_res_activiteit_key := 11;
-- v_res_rsv_ruimte_van en v_res_rsv_ruimte_van zijn nu nog dummy, en plannen we ver in het verleden, op 24 jun 1968 12:00u en 13:00u
G_date_far_in_the_past := '24-06-1968';
v_res_rsv_ruimte_van := to_date(G_date_far_in_the_past || ' 12:00:00','dd-mm-yyyy hh24:mi:ss');
-- We verwerken de v_duration_minutes in v_res_rsv_ruimte_tot...
v_res_rsv_ruimte_tot := v_res_rsv_ruimte_van + (v_duration_minutes/(60*24));
-- We plannen hier als optie...
v_res_status_fo_key := 1;
v_res_rsv_deel_dirtlevel := 256;
v_api_perslid_key := marx_get_api_user(v_bedrijf_key);
IF v_api_perslid_key IS NOT NULL
THEN
v_res_deel_key := marx_get_first_res_deel(v_competentie_code);
END IF;
IF v_api_perslid_key IS NOT NULL AND v_res_deel_key IS NOT NULL
THEN
IF v_res_rsv_ruimte_key IS NULL
THEN
SELECT res_s_res_rsv_ruimte_key.nextval INTO l_res_rsv_ruimte_key from dual;
ELSE
l_res_rsv_ruimte_key := v_res_rsv_ruimte_key;
END IF;
INSERT INTO res_reservering (res_reservering_aanmaak) VALUES (SYSDATE) RETURNING res_reservering_key INTO v_res_reservering_key;
INSERT INTO res_rsv_ruimte(res_rsv_ruimte_key , res_reservering_key, res_rsv_ruimte_volgnr, res_rsv_ruimte_contact_key, res_rsv_ruimte_host_key, mld_opdr_key , res_rsv_ruimte_cvab_mode , res_activiteit_key , res_rsv_ruimte_van , res_rsv_ruimte_tot , res_status_fo_key)
VALUES(l_res_rsv_ruimte_key, v_res_reservering_key, 1, v_api_perslid_key , v_api_perslid_key , v_mld_opdr_key , v_res_rsv_ruimte_cvab_mode, v_res_activiteit_key, v_res_rsv_ruimte_van, v_res_rsv_ruimte_tot, v_res_status_fo_key);
INSERT INTO res_rsv_deel(res_deel_key , res_rsv_deel_aantal , res_status_bo_key, res_rsv_ruimte_key , res_rsv_deel_van , res_rsv_deel_tot , res_rsv_deel_dirtlevel)
VALUES(v_res_deel_key, 1 , 2 , l_res_rsv_ruimte_key, v_res_rsv_ruimte_van, v_res_rsv_ruimte_tot, v_res_rsv_deel_dirtlevel);
-- Woco-bedrijfskey ff bewaren in een hidden flexprop met key 2.
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(2, v_res_rsv_ruimte_key, v_woco_key);
-- Als LatLong niet LEEG zijn, dan ff bewaren in een betreffende hidden flexprop velden Plaats_X (key 6) en Plaats_Y (key 7)
IF v_lat IS NOT NULL AND v_lng IS NOT NULL
THEN
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(6, v_res_rsv_ruimte_key, ROUND(v_lat, 6));
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(7, v_res_rsv_ruimte_key, ROUND(v_lng, 6));
END IF;
-- MARX#70903: Competentie is niet meer 1-op-1 en daarmee niet meer te bepalen adhv perslid, daarom moeten we competentiecode nu wel onthouden!
IF v_competentie_code IS NOT NULL
THEN
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(9, v_res_rsv_ruimte_key, v_competentie_code);
END IF;
-- MARX#75600 Mareon Groene Planning: Aansturing gebiedsoptimalisatie vanuit opdrachtgever
IF v_region_id IS NOT NULL
THEN
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(10, v_res_rsv_ruimte_key, v_region_id);
END IF;
END IF;
END;
/
-- Opschoon PROC die (te) oude (met aanmaak-datum van meer dan "p_aantal_dagen" dagen geleden) dummy reserveringen die zijn achtergebleven, opruimt (=verwijdert)
--
CREATE OR REPLACE PROCEDURE marx_clean_dummy_reservering
(p_aantal_dagen IN NUMBER)
AS
G_date_far_in_the_past VARCHAR2(10);
----------- Start procedure ---
BEGIN
G_date_far_in_the_past := '24-06-1968';
DELETE FROM res_rsv_deel
WHERE TRUNC(res_rsv_deel_aanmaak) <= TRUNC(SYSDATE - p_aantal_dagen)
AND TRUNC(res_rsv_deel_van) = to_date(G_date_far_in_the_past,'dd-mm-yyyy');
DELETE FROM res_rsv_ruimte
WHERE TRUNC(res_rsv_ruimte_aanmaak) <= TRUNC(SYSDATE - p_aantal_dagen)
AND TRUNC(res_rsv_ruimte_van) = to_date(G_date_far_in_the_past,'dd-mm-yyyy');
DELETE FROM res_reservering rr
WHERE NOT EXISTS (SELECT 'X' FROM res_rsv_ruimte rrr WHERE rrr.res_reservering_key = rr.res_reservering_key);
COMMIT;
END;
/
-- MARX#75240 ORA-02291: Integriteitsbeperking (MARX.RES_R_RES_RSV_RUIMTE_KEY2) is geschonden
-- Is de reservering een dummy
-- Resulteert in 0 (=nee, false) of 1 (=ja, true)
CREATE OR REPLACE FUNCTION marx_is_reservering_dummy (v_res_rsv_ruimte_key IN NUMBER)
RETURN NUMBER
AS
G_date_far_in_the_past VARCHAR2(10);
v_aantal NUMBER(10);
BEGIN
G_date_far_in_the_past := '24-06-1968';
SELECT COUNT(*)
INTO v_aantal
FROM res_rsv_ruimte
WHERE res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND TRUNC(res_rsv_ruimte_van) = to_date(G_date_far_in_the_past,'dd-mm-yyyy')
AND res_rsv_ruimte_verwijder IS NULL;
RETURN v_aantal;
END;
/
-- Past een (dummy) reservering aan naar een echte/bevestigde reservering (confirmation)
-- Er is namelijk inderdaad een plekje vrij, we gaan hem boeken door:
-- a) wanneer v_ion_nr (icm v_woco_key) nog NIET eerder gepland was (dus dit is een NIEUWE planning) --> de DUMMY "ProForma" res_reservering OM TE ZETTEN naar de juiste datum/tijdstip en persoon, dus van DUMMY naar REAL reservering
-- b) wanneer v_ion_nr (icm v_woco_key) nog WEL eerder gepland was (dus dit is aanpassing van BESTAANDE planning) --> de DUMMY "Proforma" verwijderen en de bestaande res_rsv_ruimte aanpassen (qua tijd maar ook evt qua persoon, kan nl iemand anders zijn geworden die past op nieuwe datum/tijd).
-- Het betreft in beide gevallen record v_res_rsv_ruimte en bijbehorende record v_res_rsv_deel, die worden op de nieuwe start en enddatum gezet, en ook op de nieuwe res_deel_key.
CREATE OR REPLACE PROCEDURE marx_put_res_dummy_2_real
( v_woco_key IN NUMBER,
v_res_rsv_ruimte_key IN NUMBER,
v_res_deel_key IN NUMBER,
v_date_start IN DATE,
v_date_end IN DATE,
v_time_start_vroegst IN VARCHAR2,
v_time_start_uiterlijk IN VARCHAR2,
v_ion_nr IN VARCHAR2)
AS
v_aantal NUMBER(10);
l_res_rsv_ruimte_key NUMBER(10);
l_mld_opdr_key NUMBER(10);
l_currentstatus NUMBER (10);
l_opdr_status_is_oke_to_change NUMBER (1);
v_mld_opdr_plandatum DATE;
v_prs_perslid_key NUMBER(10);
l_res_is_dummy NUMBER(10);
v_count_differences NUMBER (10);
v_do_send_opdr NUMBER (10);
v_do_send_changed_opdr NUMBER (10);
----------- Start procedure ---
BEGIN
-- Init...
l_mld_opdr_key := NULL;
-- MARX#75240: Robuuste check dat wel een dummy reservering wordt aangeroepen met v_res_rsv_ruimte_key
-- Oftewel alleen een dummy kan real worden gemaakt, een real die al real is doen we niets mee en skippen we
l_res_is_dummy := marx_is_reservering_dummy(v_res_rsv_ruimte_key);
IF l_res_is_dummy = 1
THEN
-- Check: is de dummy reservering door dezelfde woco gemaakt die 'm nu definitief kiest in PLNCFM-proces?
SELECT COUNT(*)
INTO v_aantal
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 2
AND res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND res_kenmerkreservering_waarde = v_woco_key
AND res_kenmerkwaarde_verwijder IS NULL;
l_opdr_status_is_oke_to_change := 0;
IF v_aantal = 1
THEN
-- Eerst checken of hier voor deze ION (van deze woco) al eens eerder een geplande res_rsv_ruimte is aangemaakt, want dan moeten we deze bestaande res_rsv_ruimte aanpassen, en niet de DUMMY.
-- En als die niet bestaat, dus geheel nieuwe planning betreft, dan gaan we de DUMMY updaten.
-- Kortom: bepaal nu de l_res_rsv_ruimte_key: of een bestaande, of de dummy...
l_res_rsv_ruimte_key := marx_ion_already_planned (v_woco_key, v_ion_nr);
IF l_res_rsv_ruimte_key IS NULL
THEN
-- Bestaat nog niet, is dus geheel nieuw, we moeten de DUMMY aanpassen
l_res_rsv_ruimte_key := v_res_rsv_ruimte_key;
ELSE
-- Bestaat dus al wel, we moeten deze bestaande aanpassen, en de DUMMY verwijderen...
res.remove(v_res_rsv_ruimte_key);
END IF;
l_mld_opdr_key := marx_get_mld_opdr_via_ionr(v_woco_key, v_ion_nr);
IF l_mld_opdr_key IS NOT NULL
THEN
-- Opdracht bestaat al, kan zijn omdat:
-- 1. De planning (na een tijdje) door huurder gewijzigd wordt, en de opdracht inmiddels (al enige tijd) bestaat
-- 2. wat onwaarschijnlijk, maar timing-issue, dat de opdracht (net) iets eerder binnen is gekomen dan de bevestiging door huuder.
SELECT mld_statusopdr_key
INTO l_currentstatus
FROM mld_opdr
WHERE mld_opdr_key = l_mld_opdr_key;
-- Zie ook api_opdrsoap en/of mld.setopdrachtstatus (package-functie)
-- Allen bij lopende opdracht mag een wijziging, anders niet, dus alleen als status <> 1, 2, 6, 7, 9, dan is wijziging akkoord.
-- 1=Afgewezen / 2=Niet akkoord / 6=Afgemeld / 7=Verwerkt / 9=Afgerond
IF NOT (l_currentstatus = 1 OR l_currentstatus = 2 OR l_currentstatus = 6 OR l_currentstatus = 7 OR l_currentstatus = 9)
THEN
l_opdr_status_is_oke_to_change := 1;
END IF;
END IF;
IF (l_mld_opdr_key IS NULL) OR (l_opdr_status_is_oke_to_change = 1)
THEN
-- Opdracht mag gemuteerd worden, of is er nog niet...
-- We gaan de boel alleen aanpassen wanneer er nog geen opdracht is, of wel een opdracht is maar dan alleen als de opdracht nog wel muteerbaar mag worden (en niet gesloten/afgewezen is)
-- Wel even van de dummy de exacte begintijd (res_rsv_ruimte_van) en eindtijd (res_rsv_ruimte_tot) overnemen, die kan evt anders zijn geworden (tov de bestaande)
UPDATE res_rsv_ruimte
SET res_rsv_ruimte_van = v_date_start, res_rsv_ruimte_tot = v_date_end
WHERE res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_rsv_ruimte_verwijder IS NULL;
UPDATE res_rsv_deel
SET res_rsv_deel_van = v_date_start, res_rsv_deel_tot = v_date_end, res_rsv_deel_dirtlevel = 0
WHERE res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_rsv_deel_verwijder IS NULL;
IF v_res_deel_key IS NOT NULL
THEN
UPDATE res_rsv_deel
SET res_deel_key = v_res_deel_key
WHERE res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_rsv_deel_verwijder IS NULL;
END IF;
IF v_ion_nr IS NOT NULL
THEN
-- Bestaat ionr al in flexprop (key 1), dan update, anders insert
SELECT COUNT(*)
INTO v_aantal
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 1
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
IF v_aantal = 0
THEN
-- Zeer waarschijnlijk is dit de 1e keer (en dus nog niet eerder) dat huurder een afspraak maakt m.b.t. dit IONR
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(1, l_res_rsv_ruimte_key, v_ion_nr);
ELSE
-- Zeer waarschijnlijk is dit niet de 1e keer (en dus nog wel eerder) dat huurder een afspraak maakt m.b.t. dit IONR, en nu wellicht wil wijzigen.
UPDATE res_kenmerkwaarde
SET res_kenmerkreservering_waarde = v_ion_nr
WHERE res_kenmerk_key = 1
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
END IF;
END IF;
IF l_mld_opdr_key IS NOT NULL
THEN
-- De opdracht (mld_opdr) bestaat dus al, we gaan:
-- 1. deze ook maar meteen officieel koppelen...
-- 2. status (van optie) naar definitief te zetten...
UPDATE res_rsv_ruimte
SET mld_opdr_key = l_mld_opdr_key, res_status_fo_key = 2
WHERE res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_rsv_ruimte_verwijder IS NULL;
-- En ook de plandatum van de opdracht bijwerken, d.w.z. alleen als die anders is (dan ie was)...
SELECT mld_opdr_plandatum, prs_perslid_key
INTO v_mld_opdr_plandatum, v_prs_perslid_key
FROM mld_opdr
WHERE mld_opdr_key = l_mld_opdr_key;
v_count_differences := 0;
v_count_differences := mar_diff_date (v_mld_opdr_plandatum,
v_date_start,
l_mld_opdr_key,
v_prs_perslid_key,
'Plan(afspraak) datum',
'#ORDUPD');
UPDATE mld_opdr
SET mld_opdr_plandatum = v_date_start
WHERE mld_opdr_key = l_mld_opdr_key;
-- OPNIEUW opdracht versturen naar aannemer, indien:
-- 1. aannemer een technisch adres voor (dit type) opdracht heeft waarop de bon of (ketenstandaard)XML bericht op afgeleverd kan worden
-- 2. aannemer bij (ketenstandaard)-XML bericht wel premium aannemer is
-- 3. aannemer gewijzigde opdrachten wel wil/kan ontvangen, dit wordt vastgelegd in het kenmerk '$MAR_PUO_MODE' bij de leverancier (prs_kenmerk_key = 23)
-- 4. er wel wijzigingen zijn
-- Eerst punten 1 en 2, oftewel check of aannemer tech adres heeft voor deze opdracht(type) waarnaar opdrachten gestuurd kunnen worden
v_do_send_opdr := mar_send_mld_opdr_to_supplier (l_mld_opdr_key);
-- Daarna punt 3, wil/kan de aannemer ook de gewijzigde opdracht ontvangen.
v_do_send_changed_opdr := mar_check_resend_changed_opdr (l_mld_opdr_key);
IF v_do_send_opdr = 1 AND v_do_send_changed_opdr = 1 AND v_count_differences > 0
THEN
mar_resend_mld_opdr_2_lev (l_mld_opdr_key, 2);
END IF;
END IF;
IF v_date_start IS NOT NULL
THEN
-- Bestaat v_date_start al in flexprop (key 3), dan update, anders insert
SELECT COUNT(*)
INTO v_aantal
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 3
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
IF v_aantal = 0
THEN
-- Zeer waarschijnlijk is dit de 1e keer (en dus nog niet eerder) dat huurder een afspraak maakt m.b.t. dit startdatum
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(3, l_res_rsv_ruimte_key, TO_CHAR(v_date_start,'DD-MM-YYYY'));
ELSE
-- Zeer waarschijnlijk is dit niet de 1e keer (en dus nog wel eerder) dat huurder een afspraak maakt m.b.t. dit startmoment tijdsblok, en nu wellicht wil wijzigen.
UPDATE res_kenmerkwaarde
SET res_kenmerkreservering_waarde = TO_CHAR(v_date_start,'DD-MM-YYYY')
WHERE res_kenmerk_key = 3
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
END IF;
END IF;
IF v_time_start_vroegst IS NOT NULL
THEN
-- Bestaat v_time_start_vroegst al in flexprop (key 4), dan update, anders insert
SELECT COUNT(*)
INTO v_aantal
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 4
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
IF v_aantal = 0
THEN
-- Zeer waarschijnlijk is dit de 1e keer (en dus nog niet eerder) dat huurder een afspraak maakt m.b.t. dit startmoment tijdsblok
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(4, l_res_rsv_ruimte_key, v_time_start_vroegst);
ELSE
-- Zeer waarschijnlijk is dit niet de 1e keer (en dus nog wel eerder) dat huurder een afspraak maakt m.b.t. dit startmoment tijdsblok, en nu wellicht wil wijzigen.
UPDATE res_kenmerkwaarde
SET res_kenmerkreservering_waarde = v_time_start_vroegst
WHERE res_kenmerk_key = 4
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
END IF;
END IF;
IF v_time_start_uiterlijk IS NOT NULL
THEN
-- Bestaat v_time_start_uiterlijk al in flexprop (key 5), , dan update, anders insert
SELECT COUNT(*)
INTO v_aantal
FROM res_kenmerkwaarde
WHERE res_kenmerk_key = 5
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
IF v_aantal = 0
THEN
-- Zeer waarschijnlijk is dit de 1e keer (en dus nog niet eerder) dat huurder een afspraak maakt m.b.t. dit eindmoment tijdsblok
INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES(5, l_res_rsv_ruimte_key, v_time_start_uiterlijk);
ELSE
-- Zeer waarschijnlijk is dit niet de 1e keer (en dus nog wel eerder) dat huurder een afspraak maakt m.b.t. dit startmoment tijdsblok, en nu wellicht wil wijzigen.
UPDATE res_kenmerkwaarde
SET res_kenmerkreservering_waarde = v_time_start_uiterlijk
WHERE res_kenmerk_key = 5
AND res_rsv_ruimte_key = l_res_rsv_ruimte_key
AND res_kenmerkwaarde_verwijder IS NULL;
END IF;
END IF;
END IF; -- Opdracht mag gemuteerd worden, of is er nog niet...
END IF; -- Check of dummy reservering door dezelfde woco gemaakt die 'm nu definitief kiest in PLNCFM-proces?
END IF; -- Check of het een dummy reservering betreft
COMMIT;
END;
/
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Bij 1e aanmaak van opdracht (proces opdrachtverstrekking), indien er een officieuze reservering/planning bij de opdracht bestaat (= via flexprop, dan moet deze officieel nog gekoppeld worden.
CREATE OR REPLACE PROCEDURE marx_koppel_res_plan(v_mld_opdr_key IN NUMBER, v_prs_woco_key In NUMBER, v_ion_nr IN VARCHAR2)
AS
v_res_rsv_ruimte_key NUMBER(10);
----------- Start procedure ---
BEGIN
IF v_mld_opdr_key IS NOT NULL AND v_prs_woco_key IS NOT NULL AND v_ion_nr IS NOT NULL
THEN
SELECT MAX(rk.res_rsv_ruimte_key)
INTO v_res_rsv_ruimte_key
FROM res_kenmerkwaarde rk, res_kenmerkwaarde rk2
WHERE rk.res_kenmerkreservering_waarde = v_ion_nr
AND rk.res_kenmerk_key = 1
AND rk.res_kenmerkwaarde_verwijder IS NULL
AND rk2.res_kenmerkreservering_waarde = v_prs_woco_key
AND rk2.res_kenmerk_key = 2
AND rk2.res_kenmerkwaarde_verwijder IS NULL
AND rk.res_rsv_ruimte_key = rk2.res_rsv_ruimte_key;
IF v_res_rsv_ruimte_key IS NOT NULL
THEN
UPDATE res_rsv_ruimte rr
SET rr.mld_opdr_key = v_mld_opdr_key
WHERE rr.res_rsv_ruimte_key = v_res_rsv_ruimte_key
AND rr.res_rsv_ruimte_verwijder IS NULL;
END IF;
-- TODO: tracking-record erbij...
END IF;
END;
/
-- Rapportage van de vertaaltabel van vaardigheden (expertises) die leverancier kan instellen.
-- Elke vaardigheid (code) vanuit opdrachtgever kan worden vertaald naar de vaardigheid (code) die leverancier hanteert...
CREATE OR REPLACE VIEW marx_udr_vertaal_vaardigheden
(FCLT_3D_USER_KEY, code_opdrachtgever, code_opdrachtnemer)
AS
SELECT cp.prs_perslid_key, SUBSTR(fac_usrdata_upper, INSTR(fac_usrdata_upper,'|')+1), fac_usrdata_omschr
FROM fac_usrdata, prs_contactpersoon cp
WHERE fac_usrtab_key = 8
AND SUBSTR(fac_usrdata_upper, 1, INSTR(fac_usrdata_upper,'|')-1) = cp.prs_bedrijf_key
AND fac_usrdata_verwijder IS NULL
AND cp.prs_contactpersoon_verwijder IS NULL
AND cp.prs_perslid_key IS NOT NULL;
------ payload end ------
SET DEFINE OFF
BEGIN adm.systrackscriptId ('$Id$', 1); END;
/
COMMIT;
SET ECHO OFF
SPOOL OFF
SET DEFINE ON
PROMPT Logfile of this upgrade is: &fcltlogfile