Files
Database/EXC/EXC_PAC.SRC
Koen Reefman f69cdb8f82 FCLT#84628 Savepoint deadlock preventie
svn path=/Database/trunk/; revision=67963
2025-02-12 16:13:02 +00:00

1934 lines
93 KiB
Plaintext
Raw Blame History

#ifdef EXC
/*
* $Revision$
* $Id$
*/
CREATE OR REPLACE PACKAGE exc
AS
FUNCTION getOpstelling(p_room_id IN VARCHAR2)
RETURN NUMBER;
FUNCTION getActiviteit(p_room_id IN VARCHAR2)
RETURN NUMBER;
PROCEDURE set_ruimtes_clean(p_import_key IN NUMBER);
PROCEDURE importBezoekers(p_import_key IN NUMBER, p_appt_id IN VARCHAR2, p_recur_id IN VARCHAR2, p_rsv_ruimte_key IN NUMBER, date_interval_start IN DATE, date_interval_end IN DATE);
PROCEDURE import_exchange(p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90);
PROCEDURE update_exchange(p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90);
PROCEDURE import_exchfull(p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90);
PROCEDURE update_exchfull(p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90);
END exc;
/
CREATE OR REPLACE PACKAGE BODY exc
AS
-- Zoek de default (of anders oudste) opstelling bij de ruimte obv room-id
FUNCTION getOpstelling (p_room_id IN VARCHAR2)
RETURN NUMBER
IS
v_ruimte_opstel_key NUMBER (10);
BEGIN
v_ruimte_opstel_key := NULL;
SELECT COALESCE (ro1.res_ruimte_opstel_key, ro2.res_ruimte_opstel_key) res_ruimte_opstel_key
INTO v_ruimte_opstel_key
FROM res_ruimte r,
(SELECT *
FROM res_ruimte_opstelling
WHERE res_ruimte_opstel_verwijder IS NULL
AND res_ruimte_opstel_default = 1) ro1,
(SELECT *
FROM res_ruimte_opstelling
WHERE res_ruimte_opstel_verwijder IS NULL) ro2
WHERE UPPER(r.res_ruimte_extern_id) = UPPER(p_room_id)
AND r.res_ruimte_verwijder IS NULL
AND ro1.res_ruimte_key(+) = r.res_ruimte_key
AND ro2.res_ruimte_key = r.res_ruimte_key
AND ro2.res_ruimte_opstel_key =
(SELECT MIN (res_ruimte_opstel_key)
FROM res_ruimte_opstelling
WHERE res_ruimte_opstel_verwijder IS NULL
AND res_ruimte_key = r.res_ruimte_key);
RETURN v_ruimte_opstel_key;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN NULL;
END;
-- Zoek de activiteit (met het laagste volgnr | key) bij de ruimte obv room-id
FUNCTION getActiviteit (p_room_id IN VARCHAR2)
RETURN NUMBER
IS
v_activiteit_key NUMBER (10);
BEGIN
v_activiteit_key := NULL;
SELECT res_activiteit_key
INTO v_activiteit_key
FROM ( SELECT ra.res_activiteit_key
FROM res_ruimte rr, res_activiteitdiscipline rad, res_activiteit ra
WHERE UPPER (rr.res_ruimte_extern_id) =
UPPER (p_room_id)
AND rr.res_discipline_key = rad.res_discipline_key
AND rad.res_activiteit_key = ra.res_activiteit_key
ORDER BY res_activiteit_volgnr, res_activiteit_key)
WHERE ROWNUM = 1;
RETURN v_activiteit_key;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
RETURN NULL;
END;
PROCEDURE importBezoekers (p_import_key IN NUMBER, p_appt_id IN VARCHAR2, p_recur_id IN VARCHAR2, p_rsv_ruimte_key IN NUMBER, date_interval_start IN DATE, date_interval_end IN DATE)
IS
v_afspraak_key bez_afspraak.bez_afspraak_key%TYPE := -1;
CURSOR bezoekers IS
SELECT subject,
starttime,
endtime,
organizer,
att_name,
att_mail,
appt_id,
recur_id
FROM exc_import
WHERE starttime <= date_interval_end
AND endtime >= date_interval_start
AND appt_id || '|' || recur_id = p_appt_id || '|' || p_recur_id
AND gelukt IS NULL
AND NOT REGEXP_LIKE (att_mail, (SELECT COALESCE (fac_setting_pvalue, fac_setting_default)
FROM fac_setting
WHERE fac_setting_name = 'exchange_internal_email_regexp'));
BEGIN
FOR exc_bez IN bezoekers
LOOP
IF v_afspraak_key = -1
THEN
SELECT bez_s_bez_afspraak_key.NEXTVAL INTO v_afspraak_key FROM DUAL;
INSERT INTO bez_afspraak (bez_afspraak_key,
prs_perslid_key,
bez_afspraak_datum,
bez_actie_key,
bez_afspraak_ruimte,
bez_afspraak_opmerking,
bez_afspraak_eind,
alg_locatie_key,
alg_onrgoed_keys,
bez_afspraak_host_key,
bez_afspraak_contact_key,
res_rsv_ruimte_key)
SELECT v_afspraak_key,
rr.res_rsv_ruimte_contact_key,
rr.res_rsv_ruimte_van,
r.bez_actie_key,
SUBSTR (r.res_ruimte_nr, 1, 30),
SUBSTR ('Overgenomen uit Exchange', 1, 320),
rr.res_rsv_ruimte_tot,
g.alg_locatie_key,
MIN (rar.alg_ruimte_key),
rr.res_rsv_ruimte_host_key,
rr.res_rsv_ruimte_contact_key,
p_rsv_ruimte_key
FROM res_rsv_ruimte rr,
res_ruimte_opstelling ro,
res_ruimte r,
res_alg_ruimte rar,
alg_v_aanwezigruimte ar,
alg_verdieping v,
alg_gebouw g
WHERE rr.res_rsv_ruimte_key = p_rsv_ruimte_key
AND ro.res_ruimte_opstel_key = rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND rar.res_ruimte_key = r.res_ruimte_key
AND rar.res_alg_ruimte_verwijder IS NULL
AND ar.alg_ruimte_key = rar.alg_ruimte_key
AND v.alg_verdieping_key = ar.alg_verdieping_key
AND g.alg_gebouw_key = v.alg_gebouw_key
GROUP BY rr.res_rsv_ruimte_contact_key,
rr.res_rsv_ruimte_van,
r.bez_actie_key,
r.res_ruimte_nr,
rr.res_rsv_ruimte_tot,
g.alg_locatie_key,
rr.res_rsv_ruimte_host_key,
rr.res_rsv_ruimte_contact_key;
END IF;
INSERT INTO bez_bezoekers (bez_afspraak_key,
bez_afspraak_naam,
bez_bezoekers_email)
VALUES (v_afspraak_key,
SUBSTR (exc_bez.att_name, 1, 60),
exc_bez.att_mail);
END LOOP;
END;
-- Welbeschouwd kunnen door de Exchange-constraints ruimte reserveringen nooit overlappen
-- Als er in FACILITOR toch een overlap is ontstaan is dat eigenlijk een gebrek van
-- de synchronisatie procedure
-- Daarom veronderstellen wij dat toch degene die dirty was geworden de waarheid is
-- en de 'andere' dirty had moeten worden of sterker nog: we verwijderen de andere
PROCEDURE set_ruimtes_clean (p_import_key IN NUMBER)
IS
dirtlevel res_rsv_ruimte.res_rsv_ruimte_dirtlevel%TYPE;
v_errorhint VARCHAR2 (1000);
CURSOR c_prsv_ruimte_new IS
SELECT rr.res_rsv_ruimte_key,
r.res_ruimte_key,
res_rsv_ruimte_van,
res_reservering_key,
res_rsv_ruimte_volgnr
FROM res_ruimte r, res_ruimte_opstelling ro, res_rsv_ruimte rr
WHERE ro.res_ruimte_opstel_key = rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND res_rsv_ruimte_dirtlevel = 512 -- alleen ruimteoverlap corrigeren we
AND res_rsv_ruimte_verwijder IS NULL
AND res_ruimte_extern_id IS NOT NULL
AND res_rsv_ruimte_van > TRUNC (SYSDATE)
ORDER BY res_rsv_ruimte_key DESC
FOR UPDATE OF res_rsv_ruimte_dirtlevel;
BEGIN
FOR prsv_ruimte_new IN c_prsv_ruimte_new
LOOP
-- Wij in ieder geval niet meer dirty
v_errorhint :=
'Cleanup reservering '
|| TO_CHAR (prsv_ruimte_new.res_reservering_key)
|| '/'
|| prsv_ruimte_new.res_rsv_ruimte_volgnr
|| ' ('
|| TO_CHAR (prsv_ruimte_new.res_rsv_ruimte_key)
|| ')';
fac.imp_writelog (p_import_key,
'I',
v_errorhint,
'');
UPDATE res_rsv_ruimte
SET res_rsv_ruimte_dirtlevel = 0
WHERE CURRENT OF c_prsv_ruimte_new; -- geen tracking
-- Controleer alle andere reserveringen op die dag in die zaal om te weten welke
-- ons dirty had gemaakt
FOR prsv_ruimte_old
IN (SELECT rr.res_rsv_ruimte_key,
res_rsv_ruimte_van,
res_rsv_ruimte_tot,
res_reservering_key,
res_rsv_ruimte_volgnr
FROM res_ruimte r,
res_ruimte_opstelling ro,
res_rsv_ruimte rr
WHERE r.res_ruimte_key = prsv_ruimte_new.res_ruimte_key
AND rr.res_rsv_ruimte_key <>
prsv_ruimte_new.res_rsv_ruimte_key
AND ro.res_ruimte_opstel_key =
rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND BITAND (res_rsv_ruimte_dirtlevel, 512) = 0
AND res_rsv_ruimte_verwijder IS NULL
AND res_rsv_ruimte_van BETWEEN TRUNC (
prsv_ruimte_new.res_rsv_ruimte_van)
AND TRUNC (
prsv_ruimte_new.res_rsv_ruimte_van)
+ 1)
LOOP
-- Degene die met ons overlapte zal dirty worden nu wij vrij zijn
v_errorhint :=
'Checking reservering '
|| TO_CHAR (prsv_ruimte_old.res_reservering_key)
|| '/'
|| prsv_ruimte_old.res_rsv_ruimte_volgnr
|| ' ('
|| TO_CHAR (prsv_ruimte_old.res_rsv_ruimte_key)
|| ')';
fac.imp_writelog (p_import_key,
'I',
v_errorhint,
'');
res.set_ruimte_dirty (prsv_ruimte_old.res_rsv_ruimte_key); -- deze houdt rekening met schoonmaaak
SELECT res_rsv_ruimte_dirtlevel
INTO dirtlevel
FROM res_rsv_ruimte
WHERE res_rsv_ruimte_key = prsv_ruimte_old.res_rsv_ruimte_key;
IF BITAND (dirtlevel, 512) <> 0
THEN
v_errorhint :=
'Remove dirty reservering '
|| TO_CHAR (prsv_ruimte_old.res_reservering_key)
|| '/'
|| prsv_ruimte_old.res_rsv_ruimte_volgnr
|| ' ('
|| TO_CHAR (prsv_ruimte_old.res_rsv_ruimte_key);
fac.imp_writelog (p_import_key,
'I',
v_errorhint,
'');
UPDATE res_rsv_ruimte
SET res_status_fo_key = 1, -- nooit doorbelasten
res_rsv_ruimte_verwijder = SYSDATE
WHERE res_rsv_ruimte_key =
prsv_ruimte_old.res_rsv_ruimte_key;
fac.trackaction ('RESDEL',
prsv_ruimte_old.res_rsv_ruimte_key,
NULL,
SYSDATE,
NULL);
res.set_ruimtes_clean (prsv_ruimte_old.res_rsv_ruimte_van); -- onwaarschijnlijk
res.follow_artikel (prsv_ruimte_old.res_rsv_ruimte_key,
prsv_ruimte_old.res_rsv_ruimte_van,
prsv_ruimte_old.res_rsv_ruimte_tot);
res.follow_deel (prsv_ruimte_old.res_rsv_ruimte_key,
prsv_ruimte_old.res_rsv_ruimte_van,
prsv_ruimte_old.res_rsv_ruimte_tot);
v_errorhint := 'res_reservering verwijderen';
UPDATE res_reservering
SET res_reservering_verwijder = SYSDATE
WHERE res_reservering_key =
prsv_ruimte_old.res_reservering_key
AND NOT EXISTS
(SELECT *
FROM res_v_aanwezigrsv_ruimte
WHERE res_reservering_key =
prsv_ruimte_old.res_reservering_key);
END IF;
END LOOP;
END LOOP;
END;
-- Met behulp van imp_exchange.gelukt kunnen importregels bewaard worden, zodat mutaties
-- aan appointments die gefaald zijn, alsnog kunnen worden doorgevoerd. Betekenis waarden 'gelukt':
-- NULL = niet correct verwerkt in vorige import --> nogmaals proberen (of gewoon 'verse' regels toch .. ?)
-- 1 = succesvol verwerkt in vorige import --> importregel verwijderen
-- 2 = er is in een latere import een nieuwere status van dezelfde appointment ingelezen,
-- dus deze importregel is outdated --> regel verwijderen
-- 3 = a. Delete gevolgd door een Create/Update (komt toch niet voor .. ?)
-- b. Delete van onbekende reservering (komt volgens mij ook niet meer voor, wordt afgevangen in de asp-code)
-- 4 = Dit betreft een reservering die buiten het geconfigureerde datum-interval valt (die komt hier toch ook niet meer, de subscription luistert alleen naar changes binnen dit interval)
-- 5 = Regels die gaan over de res_ruimte als deelnemer
PROCEDURE import_exchange (p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90)
IS
c_fielddelimitor VARCHAR2 (1) := ';';
v_newline VARCHAR2 (1000); -- Input line
v_aanduiding VARCHAR2 (600);
v_errorhint VARCHAR2 (1000);
v_errormsg VARCHAR2 (1000);
oracle_err_num NUMBER;
oracle_err_mes VARCHAR2 (200);
header_is_valid NUMBER;
v_ongeldig NUMBER (1);
v_count_tot NUMBER (10);
v_count_error NUMBER (10);
v_count_import NUMBER (10);
v_import_filenaam fac_import.fac_import_filenaam%TYPE;
v_ruimte_id res_ruimte.res_ruimte_extern_id%TYPE;
date_interval_start DATE := TRUNC (SYSDATE) - p_days_from;
date_interval_end DATE := TRUNC (SYSDATE) + p_days_to;
-- De importvelden:
v_room_id VARCHAR2 (200);
v_subject VARCHAR2 (200);
v_starttime VARCHAR2 (100);
v_endtime VARCHAR2 (100);
v_organizer VARCHAR2 (200);
v_att_mail VARCHAR2 (200);
v_att_name VARCHAR2 (200);
v_visibility VARCHAR2 (100);
v_modifier VARCHAR2 (100);
v_appt_id VARCHAR2 (500);
v_recur_id VARCHAR2 (500);
v_seq_nr VARCHAR2 (100);
d_starttime DATE;
d_endtime DATE;
n_seq_nr NUMBER (13);
CURSOR c IS
SELECT *
FROM fac_imp_file
WHERE fac_import_key = p_import_key
ORDER BY fac_imp_file_index;
BEGIN
-- AKZA#36457: de ID van de ruimte is niet meer uit de inhoud van de XML te halen.
-- Dan maar de bestandsnaam gebruiken (refkey is niet handig, want dan moeten we voor
-- elke room de import draaien).
v_errorhint := 'Fout bij het (eenduidig) bepalen van de reserveerbare ruimte die we moeten updaten';
SELECT r.res_ruimte_extern_id, i.fac_import_filenaam
INTO v_ruimte_id, v_import_filenaam
FROM res_ruimte r, fac_import i
WHERE i.fac_import_key = p_import_key
AND r.res_ruimte_verwijder IS NULL
AND r.res_ruimte_extern_id IS NOT NULL
AND UPPER (i.fac_import_filenaam) = UPPER ('SYNC_' || r.res_ruimte_extern_id); -- 'SYNC_' is de harde prefix zoals in /UTILS/Exchange/ms_graph.js gedefinieerd
fac.imp_writelog (p_import_key,
'S',
'Start inlezen importbestand in importtabel',
v_import_filenaam);
-- We willen mislukte regels uit eerdere imports bewaren, zodat we die nog eens kunnen proberen.
-- Alle correct verwerkte importregels krijgen een vlag, dus die gooien we weg.
-- Deletes die al deleted zijn, zijn schijnbaar al gelukt
BEGIN
FOR r
IN (SELECT exc_import_key
FROM exc_import e
WHERE gelukt IS NOT NULL
OR (SELECT fac_import_datum_gelezen
FROM fac_import
WHERE fac_import_key = e.fac_import_key) <
SYSDATE - 1 / 24 -- Regels ouder dan 1u hoeven we ook nooit meer opnieuw te proberen
OR ( modifier = 'D'
AND EXISTS
(SELECT 1
FROM res_rsv_ruimte
WHERE res_rsv_ruimte_verwijder
IS NOT NULL
AND res_rsv_ruimte_externnr =
appt_id || '|' || recur_id))
FOR UPDATE
SKIP LOCKED) -- Dan doen we deze later wel, geen haast
LOOP
DELETE FROM exc_import
WHERE exc_import_key = r.exc_import_key;
END LOOP;
END;
-- We gaan uit van een geldig bestand, mogelijk verandert dat onderweg
header_is_valid := 0;
v_ongeldig := 0;
v_count_tot := 0;
v_count_error := 0;
v_count_import := 0;
FOR rec IN c
LOOP
BEGIN
v_newline := rec.fac_imp_file_line;
v_aanduiding := '';
d_starttime := NULL;
d_endtime := NULL;
v_errorhint := 'Fout bij opvragen te importeren rij';
-- Lees alle veldwaarden
-- AKZA#36457: room ID wordt voortaan opgehaald uit de bestandsnaam van de import
v_room_id := v_ruimte_id;
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 1, v_subject);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 2, v_starttime);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 3, v_endtime);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 4, v_organizer);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 5, v_att_mail);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 6, v_att_name);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 7, v_visibility);
IF (v_visibility IN ('C', 'U', 'D')) -- De modifier is in v_visibility opgeslagen; nog even in backwards-compatibility-mode blijven
THEN
v_visibility := '1';
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 7, v_modifier);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 8, v_appt_id);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 9, v_recur_id);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 10, v_seq_nr);
ELSE
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 8, v_modifier);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 9, v_appt_id);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 10, v_recur_id);
fac.imp_getfield_nr (v_newline, c_fielddelimitor, 11, v_seq_nr);
END IF;
v_aanduiding := '[' || v_room_id || '|' || v_starttime || '|' || v_att_mail || '] ';
-- Ik controleer of ik een geldige header heb, dat is: in de juiste kolommen
-- de juiste kolomkop. Ik controleer daarbij ALLE kolommen!
-- Ik negeer alles totdat ik een geldige header ben gepasseerd.
-- NB: doordat deze import een stylesheet gebruikt, zullen deze kolommen altijd kloppen,
-- ook al wordt een verkeerd bestand ingelezen (mits de stylesheet klopt)
IF (header_is_valid = 0)
THEN
IF UPPER (v_subject) = 'SUBJECT'
AND UPPER (v_starttime) = 'STARTTIME'
THEN
header_is_valid := 1;
END IF;
ELSE
-- Bij volgende importbestanden headerregels overslaan
IF UPPER (v_subject) = 'SUBJECT'
AND UPPER (v_starttime) = 'STARTTIME'
THEN
CONTINUE;
END IF;
v_count_tot := v_count_tot + 1;
-- Controleer tijden (delete's hebben geen tijden)
IF v_modifier <> 'D'
THEN
v_errorhint := 'Ongeldige starttijd';
v_starttime := TRIM (v_starttime);
IF (fac.safe_to_date (v_starttime,
'YYYY-MM-DD"T"HH24:MI:SS"Z"')
IS NOT NULL)
THEN
d_starttime :=
CAST (
(FROM_TZ (
CAST (
fac.safe_to_date (
v_starttime,
'YYYY-MM-DD"T"HH24:MI:SS"Z"')
AS TIMESTAMP),
'+00:00')
AT TIME ZONE 'Europe/Amsterdam') AS DATE);
ELSE
v_ongeldig := 1;
v_count_error := v_count_error + 1;
fac.imp_writelog (p_import_key,
'W',
v_aanduiding || 'Starttijd ontbreekt',
'');
END IF;
v_errorhint := 'Ongeldige eindtijd';
v_endtime := TRIM (v_endtime);
IF (fac.safe_to_date (v_endtime,
'YYYY-MM-DD"T"HH24:MI:SS"Z"')
IS NOT NULL)
THEN
d_endtime :=
CAST (
(FROM_TZ (
CAST (
fac.safe_to_date (
v_endtime,
'YYYY-MM-DD"T"HH24:MI:SS"Z"')
AS TIMESTAMP),
'+00:00')
AT TIME ZONE 'Europe/Amsterdam') AS DATE);
ELSE
v_ongeldig := 1;
v_count_error := v_count_error + 1;
fac.imp_writelog (p_import_key,
'W',
v_aanduiding || 'Eindtijd ontbreekt',
'');
END IF;
END IF;
v_errorhint := 'Opschonen naam bezoeker';
v_att_name := TRIM (BOTH '''' FROM v_att_name);
v_errorhint := 'Ongeldig sequence nr';
v_seq_nr := TRIM (v_seq_nr);
IF (fac.safe_to_number (v_seq_nr) IS NOT NULL)
THEN
n_seq_nr := fac.safe_to_number (v_seq_nr);
ELSE
v_ongeldig := 1;
v_count_error := v_count_error + 1;
fac.imp_writelog (
p_import_key,
'W',
v_aanduiding || 'Sequence nr ontbreekt',
'');
END IF;
-- Insert geformatteerde import record,
-- mits het een toekomstige appointment betreft
IF ( v_ongeldig = 0
AND ( v_modifier = 'D'
OR ( d_starttime <= date_interval_end
AND d_endtime >= date_interval_start)))
THEN
BEGIN
v_errorhint := 'Fout bij toevoegen regel aan importtabel';
INSERT INTO exc_import (room_id,
subject,
starttime,
endtime,
organizer,
att_mail,
att_name,
visibility,
modifier,
appt_id,
recur_id,
seq_nr,
fac_import_key)
VALUES (v_room_id,
v_subject,
d_starttime,
d_endtime,
v_organizer,
v_att_mail,
v_att_name,
v_visibility,
v_modifier,
v_appt_id,
v_recur_id,
n_seq_nr,
p_import_key);
v_count_import := v_count_import + 1;
EXCEPTION
WHEN OTHERS
THEN
oracle_err_num := SQLCODE;
oracle_err_mes := SUBSTR (SQLERRM, 1, 200);
v_errormsg :=
v_errorhint
|| ': ORACLE (error '
|| oracle_err_num
|| '/'
|| oracle_err_mes
|| ')';
v_ongeldig := 1;
fac.imp_writelog (
p_import_key,
'E',
v_aanduiding || v_errormsg,
'Ingelezen regel kan niet worden weggeschreven!');
COMMIT;
END;
END IF;
END IF;
END;
END LOOP;
IF (header_is_valid = 0)
THEN
fac.imp_writelog (
p_import_key,
'E',
'Ongeldig importbestand! Geen header of header niet volgens specificatie.',
'Heeft u wel het juiste bestand ingelezen?');
ELSIF (v_ongeldig = 1)
THEN
fac.imp_writelog (
p_import_key,
'E',
'Ongeldig importbestand! Bestand bevat een of meer ongeldige regels.',
'');
ELSE
fac.imp_writelog (
p_import_key,
'S',
'Importbestand succesvol ingelezen: '
|| TO_CHAR (v_count_import)
|| ' regels',
'');
END IF;
COMMIT;
-- import_exchange() wordt voor elk importbestand aangeroepen. Dat gebeurt steeds met dezelfde
-- fac_import_key, dus er kan achteraf niet bepaald worden welke importregels bij welk bestand (en
-- dus welke ruimte horen. Daarom fac_imp_file handmatig legen, zodat we bij het volgende bestand
-- met een schone lei beginnen.
DELETE FROM fac_imp_file
WHERE fac_import_key = p_import_key;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
oracle_err_num := SQLCODE;
oracle_err_mes := SUBSTR (SQLERRM, 1, 200);
v_errormsg :=
'OTHERS (error '
|| oracle_err_num
|| '/'
|| oracle_err_mes
|| ')';
fac.imp_writelog (p_import_key,
'E',
v_aanduiding || v_errormsg,
v_errorhint);
-- AKZA#38120: ook als er iets mis gaat bij inlezen (bijvoorbeeld de extern_id bestaat niet, of
-- komt vaker voor) de importregels weggooien, anders worden ze bij de volgende ruimte ingelezen.
-- Liever niets inlezen (totdat de situatie verholpen is), dan fout inlezen.
DELETE FROM fac_imp_file
WHERE fac_import_key = p_import_key;
COMMIT;
END import_exchange;
-- Merk op dat er veel meer dan gewoonlijk COMMIT's tussendoor staan
-- Dat is allemaal om zo veel mogelijk deadlocks te voorkomen
-- Pas ook op met de volgorde van statements (binnen een transactie)
-- Voorkom altijd UPDATE exc_import, dan UPDATE res_rsv_ruimte en dan weer UPDATE exc_import
-- De laatste UPDATE exc_import moet voor de UPDATE res_rsv_ruimte
PROCEDURE update_exchange (p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90)
IS
v_aanduiding VARCHAR2 (600);
v_errorhint VARCHAR2 (1000);
v_errormsg VARCHAR2 (1000);
oracle_err_num NUMBER;
oracle_err_mes VARCHAR2 (200);
v_count_error NUMBER (10);
v_count NUMBER (10);
v_ruimte_extern_id res_ruimte.res_ruimte_extern_id%TYPE;
v_count_wanted NUMBER (10);
v_count_all_booked NUMBER (10);
v_count_all_needed NUMBER (10);
v_debug BOOLEAN := FALSE;
sync_level fac_setting.fac_setting_pvalue%TYPE;
date_interval_start DATE := TRUNC (SYSDATE) - p_days_from;
date_interval_end DATE := TRUNC (SYSDATE) + p_days_to;
c_activiteit_key NUMBER (10);
v_reservering_key NUMBER (10);
v_rsv_ruimte_volgnr res_rsv_ruimte.res_rsv_ruimte_volgnr%TYPE;
v_ruimte_opstel_key NUMBER (10);
v_rsv_ruimte_key NUMBER (10);
v_perslid_key NUMBER (10);
v_kostenplaats_key NUMBER (10);
v_status_fo_key NUMBER (10);
v_discipline_key NUMBER (10);
v_organizer VARCHAR2(200);
v_trackingnew VARCHAR2(1000);
-- ANNULEREN
-- Eerst alle reserveringen waar geen appointments meer bij zijn annuleren, zodat
-- ruimte ontstaat voor nieuwe/omgeboekte reserveringen.
-- Triggers voor het annuleren van een deelreservering:
-- - DELETE-modifier in synchro; appointment is verwijderd
-- - UPDATE-modifier in synchro, met bekend appointment-ID, maar zonder resource: de appointment
-- bestaat nog, maar is niet meer in een bekende zaal (TODO: krijgen we die dan als UPD, of als DEL?)
-- - UPDATE-modifier in synchro, met bekend appointment-ID, maar voorheen zonder recurrence-ID (= single)
-- en nu met recurrence-ID (= occurence). Die single verwijderen, daarna de occurences toevoegen.
-- NB: checken of in deze synchro een appointment niet zowel toegevoegd/bijgewerkt als verwijderd is;
-- dan hoeven we 'm natuurlijk niet meer toe te voegen / bij te werken.
-- TODO: notificeren
CURSOR c_del IS
SELECT 'Cancelled' reden, i.*, rr.*
FROM (SELECT DISTINCT room_id,
subject,
starttime,
endtime,
organizer,
modifier,
appt_id,
recur_id
FROM exc_import
WHERE modifier = 'D'
AND gelukt IS NULL) i,
res_rsv_ruimte rr
WHERE rr.res_rsv_ruimte_externnr = i.appt_id || '|' || i.recur_id
AND rr.res_rsv_ruimte_verwijder IS NULL
UNION ALL
SELECT 'Unknown room' reden, i.*, rr.*
FROM (SELECT DISTINCT room_id,
subject,
starttime,
endtime,
organizer,
modifier,
appt_id,
recur_id
FROM exc_import
WHERE modifier = 'U'
AND starttime <= date_interval_end
AND endtime >= date_interval_start
AND gelukt IS NULL) i,
res_rsv_ruimte rr
WHERE rr.res_rsv_ruimte_externnr = i.appt_id || '|' || i.recur_id
AND rr.res_rsv_ruimte_verwijder IS NULL
AND NOT EXISTS
(SELECT 1
FROM res_ruimte
WHERE res_ruimte_extern_id = i.room_id
AND res_ruimte_verwijder IS NULL)
UNION ALL
-- AKZA#35459: appointments die eerst single waren en nu recurring (eerst geen
-- recur_id, nu wel). Daar kan vanalles mee gebeurd zijn (andere ruimte, ander tijdstip,
-- meerdere ruimtes). Dan maar verwijderen en opnieuw aanmaken...
-- (recur_id en tijden niet ophalen, anders wordt de 'oude' single voor elke recurrence verwijderd)
SELECT 'Made recurring' reden, i.*, rr.*
FROM (SELECT DISTINCT room_id,
subject,
NULL starttime,
NULL endtime,
organizer,
modifier,
appt_id,
NULL recur_id
FROM exc_import
WHERE modifier = 'U'
AND starttime <= date_interval_end
AND endtime >= date_interval_start
AND recur_id IS NOT NULL
AND gelukt IS NULL) i,
res_rsv_ruimte rr
WHERE rr.res_rsv_ruimte_externnr = i.appt_id || '|'
AND rr.res_rsv_ruimte_verwijder IS NULL;
-- TODO: Voor later: res_cat_t1 en res_t1 gebruiken ipv TRUNC
CURSOR c_del_doorbelast (p_rsv_ruimte_key IN NUMBER)
IS
SELECT soort,
ref_key,
oms,
van,
fac.safe_to_number (SYSDATE - TRUNC (SYSDATE)) * 24
uren,
DECODE (
exp_tijd,
NULL, van - exp_dagen,
DECODE (
SIGN (
exp_tijd
- fac.safe_to_number (SYSDATE - TRUNC (SYSDATE))
* 24),
1, TRUNC (van),
TRUNC (van) + 1))
t_expire,
exp_dagen,
exp_tijd,
cnl_dagen
FROM (SELECT 'ruimte' soort,
rr.res_rsv_ruimte_key ref_key,
r.res_ruimte_nr oms,
rr.res_rsv_ruimte_van van,
dp.res_disc_params_kosten kosten,
dp.res_disc_params_expire_dagen exp_dagen,
dp.res_disc_params_expire_tijd exp_tijd,
dp.res_disc_params_cancel_dagen cnl_dagen
FROM res_rsv_ruimte rr,
res_ruimte_opstelling ro,
res_ruimte r,
res_discipline d,
res_disc_params dp
WHERE rr.res_rsv_ruimte_key = p_rsv_ruimte_key
AND ro.res_ruimte_opstel_key =
rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND d.ins_discipline_key = r.res_discipline_key
AND dp.res_ins_discipline_key = d.ins_discipline_key
AND dp.res_disc_params_kosten > 0
UNION ALL
SELECT 'artikel' soort,
ra.res_rsv_artikel_key,
a.res_artikel_omschrijving,
ra.res_rsv_artikel_levering,
dp.res_disc_params_kosten,
dp.res_disc_params_expire_dagen,
dp.res_disc_params_expire_tijd,
dp.res_disc_params_cancel_dagen
FROM res_rsv_artikel ra,
res_artikel a,
res_discipline d,
res_disc_params dp
WHERE ra.res_rsv_ruimte_key = p_rsv_ruimte_key
AND a.res_artikel_key = ra.res_artikel_key
AND d.ins_discipline_key = a.res_discipline_key
AND dp.res_ins_discipline_key = d.ins_discipline_key
AND dp.res_disc_params_kosten > 0
UNION ALL
SELECT 'deel' soort,
rd.res_rsv_deel_key,
de.res_deel_omschrijving,
rd.res_rsv_deel_van,
dp.res_disc_params_kosten,
dp.res_disc_params_expire_dagen,
dp.res_disc_params_expire_tijd,
dp.res_disc_params_cancel_dagen
FROM res_rsv_deel rd,
res_deel de,
res_discipline d,
res_disc_params dp
WHERE rd.res_rsv_ruimte_key = p_rsv_ruimte_key
AND de.res_deel_key = rd.res_deel_key
AND d.ins_discipline_key = de.res_discipline_key
AND dp.res_ins_discipline_key = d.ins_discipline_key
AND dp.res_disc_params_kosten > 0);
-- BIJWERKEN
-- Triggers voor het bijwerken van een bestaande toekomstige deelreservering:
-- - UPDATE-modifier in synchro, met bekend appointment-ID en bekende resource(s) (zonder bekende resource
-- krijgen we 'm niet eens binnen)
-- TODO: combi van appt_id, recur_id en room_id!
-- Dan checken of het nog wel om dezelfde resources (ruimtes) gaat, tijden zijn aangepast, deelnemers gewijzigd,
-- andere omschrijving, ...
-- - Omschrijving kan zonder notificatie aangepast worden
-- - Andere ruimte --> Moet er worden doorbelast? Voorwaarden voor catering hetzelfde (van MC naar OF bijv)?
-- TODO: notificeren
-- - Deelnemers erbij / eraf --> Bezoekers toevoegen / verwijderen, deelnemerslijst bijwerken.
-- TODO: notificeren
-- NB: checken of in deze synchro een appointment niet zowel bijgewerkt als verwijderd is;
-- dan hoeven we 'm natuurlijk niet meer bij te werken (weet niet of dat <20>berhaupt voorkomt met EWS)
-- TODO: dit detecteert geen room changes, alleen mutaties aan res op dezelfde ruimte.
CURSOR c_upd IS
SELECT i.*,
rr.*,
rnew.res_ruimte_key,
rnew.res_ruimte_nr,
rnew.res_ruimte_extern_id,
rnew.res_discipline_key
FROM ( SELECT room_id,
subject,
starttime,
endtime,
organizer,
visibility,
modifier,
appt_id,
recur_id
FROM exc_import
WHERE modifier = 'U'
AND starttime <= date_interval_end
AND endtime >= date_interval_start
AND gelukt IS NULL
AND NOT EXISTS
(SELECT 1
FROM res_ruimte
WHERE UPPER (res_ruimte_extern_id) =
UPPER (att_mail))
GROUP BY recur_id,
appt_id,
room_id,
subject,
starttime,
endtime,
organizer,
visibility,
modifier) i,
res_rsv_ruimte rr,
res_ruimte rnew
WHERE rr.res_rsv_ruimte_externnr = i.appt_id || '|' || i.recur_id
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rnew.res_ruimte_extern_id = i.room_id
AND rnew.res_ruimte_verwijder IS NULL;
-- TOEVOEGEN
-- Triggers voor het toevoegen van een toekomstige (deel)reservering:
-- - ADD-modifier in synchro; appointment is nieuw
-- - UPDATE-modifier in synchro, met onbekend appointment- en recurrence-ID voor deze room: dan (<28>f)
-- - appointment bestond al, maar er is nu pas een ruimte aan toegevoegd;
-- - het was een single en nu recurring.
-- - appointment met meerdere ruimtes, maar nog geen deelreservering voor deze ruimte (zal vooral
-- voorkomen bij calendarview, als we de boekingen voor alle ruimtes op dit tijdstip binnenkrijgen --
-- bij de synchro-import is dat niet gegarandeerd)
-- TODO: verwijderde deelreserveringen 'undeleten'?
CURSOR c_add IS
SELECT i.*, r.*
FROM ( SELECT room_id,
subject,
starttime,
endtime,
organizer,
visibility,
modifier,
appt_id,
recur_id,
seq_nr,
COUNT (*) num_bez
FROM exc_import
WHERE modifier = 'C'
AND starttime <= date_interval_end
AND endtime >= date_interval_start
AND gelukt IS NULL
AND NOT EXISTS
(SELECT 1
FROM res_ruimte
WHERE UPPER (res_ruimte_extern_id) =
UPPER (att_mail))
GROUP BY recur_id,
appt_id,
seq_nr,
room_id,
subject,
starttime,
endtime,
organizer,
visibility,
modifier) i,
res_v_aanwezigruimte r
WHERE i.room_id = r.res_ruimte_extern_id
UNION ALL
SELECT i.*, r.*
FROM ( SELECT room_id,
subject,
starttime,
endtime,
organizer,
visibility,
modifier,
appt_id,
recur_id,
seq_nr,
COUNT (*) num_bez
FROM exc_import
WHERE modifier = 'U'
AND starttime <= date_interval_end
AND endtime >= date_interval_start
AND gelukt IS NULL
AND NOT EXISTS
(SELECT 1
FROM res_ruimte
WHERE UPPER (res_ruimte_extern_id) =
UPPER (att_mail))
GROUP BY recur_id,
appt_id,
seq_nr,
room_id,
subject,
starttime,
endtime,
organizer,
visibility,
modifier) i,
res_v_aanwezigruimte r
WHERE i.room_id = r.res_ruimte_extern_id
AND NOT EXISTS
(SELECT 1
FROM res_rsv_ruimte rr,
res_ruimte_opstelling ro,
res_ruimte r
WHERE rr.res_rsv_ruimte_externnr = i.appt_id || '|' || i.recur_id
AND rr.res_rsv_ruimte_verwijder IS NULL
AND ro.res_ruimte_opstel_key =
rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND r.res_ruimte_verwijder IS NULL
AND r.res_ruimte_extern_id = i.room_id)
ORDER BY 9;
BEGIN
SELECT BITAND (COALESCE (fac_setting_pvalue, fac_setting_default), 4)
INTO sync_level
FROM fac_setting
WHERE fac_setting_name = 'msgraph_sync_level';
/*
Onderstaande UPDATE set het gelukt bitje naar een error-waarde (niet '1', want dat betekent succesvol voltooid)
Of NULL (= 'te verwerken') als er zich geen fout situatie voordoet
*/
UPDATE exc_import i
SET gelukt =
CASE
WHEN EXISTS
(SELECT 1
FROM res_ruimte
WHERE UPPER (res_ruimte_extern_id) = UPPER (att_mail))
THEN 5 -- res_ruimtes als deelnemers, dat kan natuurlijk niet
WHEN i.fac_import_key = p_import_key
AND ( starttime > date_interval_end
OR endtime < date_interval_start)
THEN 4 -- We doen niets met boekingen die buiten het geconfigureerde interval vallen
WHEN modifier = 'D'
AND ( EXISTS
(SELECT 1
FROM exc_import
WHERE modifier != 'D'
AND appt_id || '|' || recur_id =
i.appt_id || '|' || i.recur_id
AND seq_nr > i.seq_nr)
OR NOT EXISTS
(SELECT 1
FROM res_rsv_ruimte
WHERE INSTR (res_rsv_ruimte_externnr,
i.appt_id || '|') =
1))
THEN 3 -- Dit zijn [D]eletes die nog gevolgd worden door nieuwere niet-[D]elete-regels of [D]eletes van niet bestaande Facilitor reserveringen
WHEN modifier IN ('C', 'U')
AND EXISTS
(SELECT 1
FROM exc_import
WHERE appt_id || '|' || recur_id =
i.appt_id || '|' || i.recur_id
AND fac_import_key !=
i.fac_import_key
AND seq_nr > i.seq_nr)
THEN 2 -- Er bestaan 2 = er is in een latere import een nieuwere status van dezelfde appointment ingelezen
ELSE
NULL -- 'te verwerken'
END
WHERE gelukt IS NULL
AND i.fac_import_key = p_import_key;
COMMIT; -- Cleanup
FOR rec IN c_del
LOOP
BEGIN
v_aanduiding :=
rec.res_reservering_key
|| '/'
|| rec.res_rsv_ruimte_volgnr
|| ' ('
|| rec.res_rsv_ruimte_key
|| '|'
|| rec.room_id
|| '|'
|| rec.subject
|| ')';
v_perslid_key := NULL;
v_kostenplaats_key := NULL;
v_rsv_ruimte_key := NULL;
v_status_fo_key := 1;
v_count := 0;
-- Zie ook res_delete_save.asp
IF (v_debug)
THEN
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'VERWIJDEREN ' || v_aanduiding);
END IF;
v_errorhint := 'Doorbelasting kosten';
-- Moeten kosten worden doorbelast?
-- (I.e. zitten we binnen de expiretijd van een van de onderdelen?)
FOR rec_db IN c_del_doorbelast (rec.res_rsv_ruimte_key)
LOOP
v_count := v_count + 1;
END LOOP;
-- Minstens <20><>n onderdeel moet worden doorbelast
-- FO-status van rsv_ruimte wordt "Vervallen" (4)
IF (v_count > 0)
THEN
v_status_fo_key := 4;
FOR rec_db IN c_del_doorbelast (rec.res_rsv_ruimte_key)
LOOP
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
rec_db.oms
|| ' kosteloos annuleerbaar tot '
|| TO_CHAR (rec_db.t_expire,
'DD-MM-YYYY HH24:MI'));
END IF;
END LOOP;
END IF;
v_errorhint := 'Deelreservering verwijderen';
-- Succesvol afgerond; zet vlag.
-- AKZA#35459: vlag niet zetten voor een single die recurring is geworden;
-- die recurrence moeten we straks in de add-cursor nog toevoegen.
IF NOT (rec.reden = 'Made recurring')
THEN
UPDATE exc_import
SET gelukt = 1
WHERE appt_id || '|' || recur_id =
rec.appt_id || '|' || rec.recur_id
AND gelukt IS NULL;
END IF;
UPDATE res_rsv_ruimte
SET res_status_fo_key = v_status_fo_key,
res_rsv_ruimte_verwijder = SYSDATE
WHERE res_rsv_ruimte_key = rec.res_rsv_ruimte_key;
fac.trackaction ('RESDEL',
rec.res_rsv_ruimte_key,
NULL,
SYSDATE,
NULL);
res.set_ruimte_dirty (rec.res_rsv_ruimte_key);
res.set_ruimtes_clean (rec.res_rsv_ruimte_van);
res.follow_artikel (rec.res_rsv_ruimte_key,
rec.res_rsv_ruimte_van,
rec.res_rsv_ruimte_tot);
res.follow_deel (rec.res_rsv_ruimte_key,
rec.res_rsv_ruimte_van,
rec.res_rsv_ruimte_tot);
v_errorhint := 'res_reservering verwijderen';
UPDATE res_reservering
SET res_reservering_verwijder = SYSDATE
WHERE res_reservering_key = rec.res_reservering_key
AND NOT EXISTS
(SELECT *
FROM res_v_aanwezigrsv_ruimte
WHERE res_reservering_key =
rec.res_reservering_key);
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'Deelreservering verwijderd.');
EXCEPTION
WHEN OTHERS
THEN
v_count_error := v_count_error + 1;
oracle_err_num := SQLCODE;
oracle_err_mes := SUBSTR (SQLERRM, 1, 200);
v_errormsg :=
'OTHERS (error '
|| oracle_err_num
|| '/'
|| oracle_err_mes
|| ')';
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
v_errorhint || ': ' || v_errormsg);
END;
END LOOP;
COMMIT; -- de DELETE's
-- Dan bestaande bijwerken, anders kan het gebeuren dat we op basis van een UPDATE
-- eerst een rsv_ruimte aanmaken en 'm daarna meteen proberen bij te werken.
-- TODO: is dat nog steeds zo met "gelukt = 1"?
FOR rec IN c_upd
LOOP
BEGIN
v_aanduiding :=
rec.room_id
|| '|'
|| rec.subject
|| '|'
|| TO_CHAR (rec.starttime, 'DD-MM-YYYY HH24:MI')
|| '-->'
|| rec.res_reservering_key
|| '/'
|| rec.res_rsv_ruimte_volgnr;
v_perslid_key := NULL;
v_kostenplaats_key := NULL;
v_rsv_ruimte_volgnr := 1;
v_rsv_ruimte_key := NULL;
v_count := NULL;
v_count_all_booked := NULL;
v_count_all_needed := NULL;
v_count_wanted := NULL;
v_ruimte_extern_id := NULL;
-- Bepalen of dit een single-room of multi-room boeking is, door te achterhalen hoeveel ruimtes er in
-- FACILITOR geboekt (count_all_booked) zijn en hoeveel we er uit EWS hebben binnengekregen (count_all_needed).
-- Als count_all_booked > 1 en/of count_all_needed > 1, dan betreft het een appointment met meerdere
-- rooms en dus meerdere rsv_ruimtes. Dan moeten we nog meer weten.
-- Als count_all_booked = 1 <20>n count_all_needed = 1, dan betreft het een single-room boeking en kunnen we
-- r<>cksichtslos bijwerken.
-- (Dat is niet correct als er een room aan een bestaande appointment is toegevoegd, waar we nu nog
-- maar <20><>n room van hebben. Maar de sync-functionaliteit van EWS biedt geen manier om die situatie te
-- achterhalen... Met de calendar view kan dit wel, omdat we dan alle gelijktijdige boekingen op de
-- verschillende ruimtes binnenkrijgen, daarom:)
-- Als we een full import doen (calendar view), kan het maar zo zijn dat we in de import meerdere
-- ruimtes in dezelfde appointment tegenkomen (count_all_needed > 1), terwijl we daar nu nog maar <20><>n
-- ruimte van kennen (count_all_booked = 1). Dan is het dus een multi-room boeking, die nog niets alszodanig
-- bekend stond.
v_errorhint := 'Totaal aantal geboekte zalen bepalen';
SELECT COUNT (*)
INTO v_count_all_booked
FROM res_rsv_ruimte rr
WHERE rr.res_rsv_ruimte_externnr = rec.appt_id || '|' || rec.recur_id
AND rr.res_rsv_ruimte_verwijder IS NULL;
v_errorhint := 'Totaal aantal benodigde zalen bepalen';
SELECT COUNT (DISTINCT room_id)
INTO v_count_all_needed
FROM exc_import i
WHERE i.modifier IN ('U', 'C')
AND i.starttime <= date_interval_end
AND i.endtime >= date_interval_end
AND i.appt_id || '|' || i.recur_id || '|' =
rec.appt_id || '|' || rec.recur_id || '|';
-- De cursor bevat voor iedere appointment alle rsv_ruimtes met dezelfde appt_id en recur_id.
-- Er zal hoogstens <20><>n rsv_ruimte op de betreffende room zijn.
-- Bestaat er al een rsv_ruimte voor deze room (count = 1)?
v_errorhint := 'Bepalen of zaal al geboekt is';
SELECT COUNT (*)
INTO v_count
FROM res_rsv_ruimte rr,
res_ruimte_opstelling rops,
res_ruimte r
WHERE rr.res_rsv_ruimte_externnr = rec.appt_id || '|' || rec.recur_id
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rops.res_ruimte_opstel_key = rr.res_ruimte_opstel_key
AND r.res_ruimte_key = rops.res_ruimte_key
AND r.res_ruimte_extern_id = rec.room_id;
-- Als er al een rsv_ruimte voor deze room is, is dat dan degene die we nu in de cursor hebben?
-- Zo ja, dan willen we die bijwerken.
-- Zo nee, dan doen we niets
v_errorhint := 'Bepalen zaal huidige deelreservering';
SELECT r.res_ruimte_extern_id
INTO v_ruimte_extern_id
FROM res_rsv_ruimte rr, res_ruimte_opstelling ro, res_ruimte r
WHERE rr.res_rsv_ruimte_key = rec.res_rsv_ruimte_key
AND ro.res_ruimte_opstel_key = rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND r.res_ruimte_verwijder IS NULL;
-- De room is nog niet geboekt. Dan kunnen we <20>f een bestaande boeking omhangen naar deze ruimte,
-- <20>f een nieuwe boeking maken (in de ADD-cursor)
-- Daarom: kunnen we de huidige rsv_ruimte aanpassen, of is die ruimte nog gewoon geboekt in Exchange?
v_errorhint :=
'Bepalen of voor room/zaal nog een boeking gewenst is';
SELECT COUNT (DISTINCT room_id)
INTO v_count_wanted
FROM exc_import i
WHERE appt_id || '|' || recur_id || '|' =
rec.appt_id || '|' || rec.recur_id || '|'
AND room_id = v_ruimte_extern_id;
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
v_count_all_booked
|| ' deelreservering(en) bij deze appointment ('
|| v_count_all_needed
|| ' nodig), waarvan '
|| v_count
|| ' voor deze room');
END IF;
-- NB: Deze oplossing is niet waterdicht. Daarvoor moet je eigenlijk weten in welke room een appointment
-- eerst was. Het lijkt handig om daarvoor uit de EWS-XML de Location en OldLocation nodes
-- te gebruiken, omdat daarin alle uitgenodigde ruimtes uitgelijst staan, maar helaas is Location
-- aanpasbaar in Outlook...
-- Multi-room? Dan nog wat checks, anders 'gewoon' bijwerken.
IF (v_count_all_booked > 1 OR v_count_all_needed > 1)
THEN
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Deze deelres. is op '
|| v_ruimte_extern_id
|| '. Benodigde deelres.: '
|| v_count_all_needed
|| ', waarvan op deze ruimte: '
|| v_count_wanted);
END IF;
-- Hebben we al een boeking voor deze zaal?
IF (v_count = 1)
THEN
-- Met deze rsv_ruimte?
-- Zo niet, dan skippen.
-- Zo ja, dan bijwerken (hier niets doen)
IF (v_ruimte_extern_id != rec.res_ruimte_extern_id)
THEN
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Skip (boeking op deze ruimte met andere rsv_ruimte)');
END IF;
CONTINUE;
END IF;
ELSIF (v_count = 0)
THEN
-- Willen we de ruimte van deze rsv_ruimte nog?
-- Zo ja, dan skippen.
-- Zo niet, dan kunnen we deze rsv_ruimte bijwerken (hier niets doen)
IF (v_count_wanted > 0)
THEN
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Skip (deze boeking ''bewaren'')');
END IF;
CONTINUE;
END IF;
END IF;
END IF;
-- Succesvol afgerond; zet vlag.
-- All<6C><6C>n voor nu beschouwde ruimte! (appointments kunnen op meerdere ruimtes zijn)
-- TODO: komen we hier ook als er iets mis ging met de bezoekers?
UPDATE exc_import
SET gelukt = 1
WHERE appt_id || '|' || recur_id =
rec.appt_id || '|' || rec.recur_id
AND room_id = rec.room_id
AND gelukt IS NULL;
-- We hebben niet geskipt, dus willen we deze rsv_ruimte bijwerken
-- Basisgegevens reservering gewijzigd?
IF ( v_ruimte_extern_id != rec.res_ruimte_extern_id
OR rec.res_rsv_ruimte_omschrijving !=
SUBSTR (rec.subject, 1, 60)
OR rec.res_rsv_ruimte_visibility != rec.visibility
OR rec.res_rsv_ruimte_van != rec.starttime
OR rec.res_rsv_ruimte_tot != rec.endtime)
THEN
v_errorhint := 'Opstelling ophalen';
v_ruimte_opstel_key :=
exc.getOpstelling (rec.room_id);
IF (v_ruimte_opstel_key IS NULL)
THEN
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
'Geen ruimte-opstelling gedefinieerd');
CONTINUE;
END IF;
v_errorhint := 'Basisgegevens bijwerken';
UPDATE res_rsv_ruimte
SET res_ruimte_opstel_key = v_ruimte_opstel_key,
res_rsv_ruimte_omschrijving =
SUBSTR (rec.subject, 1, 60),
res_rsv_ruimte_van = rec.starttime,
res_rsv_ruimte_tot = rec.endtime,
res_rsv_ruimte_visibility = rec.visibility
WHERE res_rsv_ruimte_key = rec.res_rsv_ruimte_key;
-- Opruimen en voorzieningen en bezoekers laten volgen
v_errorhint := 'Dirty, clean, voorzieningen';
res.set_ruimte_dirty (rec.res_rsv_ruimte_key);
res.set_ruimtes_clean (rec.starttime);
res.follow_artikel (rec.res_rsv_ruimte_key,
rec.res_rsv_ruimte_van,
rec.res_rsv_ruimte_tot);
res.follow_deel (rec.res_rsv_ruimte_key,
rec.res_rsv_ruimte_van,
rec.res_rsv_ruimte_tot);
res.follow_afspraak (rec.res_rsv_ruimte_key, 0);
--TODO: tracking + notificatie
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'RES: '
|| rec.res_reservering_key
|| '/'
|| rec.res_rsv_ruimte_volgnr);
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Room: '
|| v_ruimte_extern_id
|| '-->'
|| rec.res_ruimte_extern_id);
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Desc: "'
|| rec.res_rsv_ruimte_omschrijving
|| '"-->"'
|| SUBSTR (rec.subject, 1, 60)
|| '"');
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Start: '
|| TO_CHAR (rec.res_rsv_ruimte_van,
'DD-MM-YYYY HH24:MI')
|| '-->'
|| TO_CHAR (rec.starttime, 'DD-MM-YYYY HH24:MI'));
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Einde: '
|| TO_CHAR (rec.res_rsv_ruimte_tot,
'DD-MM-YYYY HH24:MI')
|| '-->'
|| TO_CHAR (rec.endtime, 'DD-MM-YYYY HH24:MI'));
END IF;
fac.trackaction ('RESUPD',
rec.res_rsv_ruimte_key,
NULL,
SYSDATE,
NULL);
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'Reservering bijgewerkt');
ELSE
IF (v_debug)
THEN
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'Geen verschil in basisgegevens');
END IF;
END IF;
IF (v_debug)
THEN
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'gelukt=1');
END IF;
EXCEPTION
WHEN OTHERS
THEN
v_count_error := v_count_error + 1;
oracle_err_num := SQLCODE;
oracle_err_mes := SUBSTR (SQLERRM, 1, 200);
v_errormsg :=
'OTHERS (error '
|| oracle_err_num
|| '/'
|| oracle_err_mes
|| ')';
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
v_errorhint || ': ' || v_errormsg);
END;
END LOOP;
COMMIT; -- de UPDATE's
-- Ten slotte nieuwe reserveringen toevoegen
FOR rec IN c_add
LOOP
BEGIN
v_aanduiding := rec.room_id || '|' || rec.subject;
v_perslid_key := NULL;
v_kostenplaats_key := NULL;
v_reservering_key := NULL;
v_rsv_ruimte_volgnr := 1;
v_rsv_ruimte_key := NULL;
v_trackingnew := NULL;
v_errorhint :=
'Host '
|| rec.organizer
|| ' onbekend, of meer personen met dit e-mailadres! Geen boeking.';
IF (rec.organizer LIKE '##%@%##') -- _MSGRAPH_FALLBACK_UNKNOWN
THEN
SELECT prs_perslid_email
INTO v_organizer
FROM prs_v_aanwezigperslid
WHERE prs_perslid_oslogin = '_MSGRAPH_FALLBACK_UNKNOWN';
v_trackingnew := REPLACE(lcl.l('lcl_res_is_resnew_exchange'), '{0}', SUBSTR(rec.organizer, 3, LENGTH(rec.organizer) - 4));
ELSE
v_organizer := rec.organizer;
END IF;
-- Kennen we deze persoon eigenlijk wel?
SELECT COUNT (*)
INTO v_count
FROM prs_v_aanwezigperslid p
WHERE UPPER (p.prs_perslid_email) = UPPER (v_organizer);
-- Niet bekend, of niet eenduidig --> jammer dan.
IF (v_count != 1)
THEN
fac.imp_writelog (p_import_key,
'E',
v_errorhint,
v_aanduiding);
-- Eenduidig bekend --> reservering maken
ELSE
v_errorhint := 'Persoonsgegevens ophalen';
SELECT p.prs_perslid_key, a.prs_kostenplaats_key
INTO v_perslid_key, v_kostenplaats_key
FROM prs_v_aanwezigperslid p, prs_v_aanwezigafdeling a
WHERE UPPER (p.prs_perslid_email) =
UPPER (v_organizer)
AND a.prs_afdeling_key = p.prs_afdeling_key;
v_errorhint := 'Opstelling ophalen';
v_ruimte_opstel_key :=
exc.getOpstelling (rec.room_id);
IF (v_ruimte_opstel_key IS NULL)
THEN
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
'Geen ruimte-opstelling gedefinieerd');
CONTINUE;
END IF;
-- Is dit een op zichzelf staande appointment, of onderdeel van een reeks (recurrence)?
-- (obv recur_id, die samen met appt_id in res_rsv_ruimte_externnr staat)
v_errorhint := 'Check recurrence';
SELECT COUNT (*)
INTO v_count
FROM res_rsv_ruimte
WHERE res_rsv_ruimte_externnr IS NOT NULL
AND INSTR(res_rsv_ruimte_externnr, rec.appt_id || '|') = 1
-- AND res_rsv_ruimte_externnr NOT LIKE '%|'||rec.recur_id||'|%'
AND res_rsv_ruimte_verwijder IS NULL;
-- We gaan deze afronden; zet vlag.
UPDATE exc_import
SET gelukt = 1
WHERE appt_id || '|' || recur_id =
rec.appt_id || '|' || rec.recur_id
AND fac_import_key = p_import_key
AND gelukt IS NULL;
IF (v_debug)
THEN
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'gelukt=1');
END IF;
-- Er bestaan al deelreserveringen voor andere occurences van deze recurring appointment
-- Deelreservering binnen de bijbehorende res_reservering aanmaken
IF (v_count > 0)
THEN
v_errorhint := 'Reservering + volgnr ophalen';
SELECT res_reservering_key,
MAX (res_rsv_ruimte_volgnr) + 1
INTO v_reservering_key, v_rsv_ruimte_volgnr
FROM res_rsv_ruimte
WHERE INSTR(res_rsv_ruimte_externnr,
rec.appt_id || '|') = 1
-- AND res_rsv_ruimte_externnr NOT LIKE '%|'||rec.recur_id||'|%'
AND res_rsv_ruimte_verwijder IS NULL
GROUP BY res_reservering_key;
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'Is occurence van ' || v_reservering_key);
-- Nog geen andere occurences --> nieuwe res_reservering
ELSE
v_errorhint := 'Reservering aanmaken';
-- res_reservering aanmaken
INSERT INTO res_reservering (res_reservering_ispool)
VALUES (0)
RETURNING res_reservering_key
INTO v_reservering_key;
END IF;
v_errorhint := 'Activiteit van de nieuwe reservering opzoeken';
c_activiteit_key :=
exc.getActiviteit (rec.room_id);
IF (c_activiteit_key IS NULL)
THEN
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
'Geen activiteit te vinden via de catalogus van de reserveerbare ruimte');
CONTINUE;
END IF;
v_errorhint := 'Deelreservering aanmaken';
BEGIN
-- res_rsv_ruimte aanmaken voor deze appointment+resource
INSERT INTO res_rsv_ruimte (res_rsv_ruimte_omschrijving,
res_rsv_ruimte_opmerking,
res_rsv_ruimte_externnr,
res_ruimte_opstel_key,
res_rsv_ruimte_van,
res_rsv_ruimte_tot,
prs_kostenplaats_key,
res_rsv_ruimte_host_key,
res_activiteit_key,
res_status_fo_key,
res_rsv_ruimte_ordernr,
res_rsv_ruimte_kosten_klant,
res_rsv_ruimte_contact_key,
res_rsv_ruimte_bezoekers,
res_rsv_ruimte_visibility,
res_reservering_key,
res_rsv_ruimte_volgnr,
res_status_bo_key)
VALUES (
SUBSTR (rec.subject, 1, 60),
NULL,
rec.appt_id
|| '|'
|| rec.recur_id,
v_ruimte_opstel_key,
rec.starttime,
rec.endtime,
v_kostenplaats_key,
v_perslid_key,
c_activiteit_key,
2,
NULL,
1,
v_perslid_key,
rec.num_bez,
rec.visibility,
v_reservering_key,
v_rsv_ruimte_volgnr,
2)
RETURNING res_rsv_ruimte_key
INTO v_rsv_ruimte_key;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN -- Er bestaat al een reservering met dit externnr
IF NOT (v_count > 0) -- Verwijder dan ook het zojuist aangemaakte res_reservering-record weer
THEN
DELETE FROM res_reservering WHERE res_reservering_key = v_reservering_key;
END IF;
fac.imp_writelog (p_import_key,
'I',
v_aanduiding,
'Deze exacte reservering is al bekend in Facilitor -> Geen boeking.');
CONTINUE;
END;
IF (v_debug)
THEN
fac.imp_writelog (
p_import_key,
'I',
v_aanduiding,
'RESERVERING '
|| v_reservering_key
|| '/'
|| v_rsv_ruimte_volgnr
|| ' ('
|| v_rsv_ruimte_key
|| ')');
END IF;
v_errorhint := 'Toevoegen bezoekers';
exc.importBezoekers(p_import_key, rec.appt_id, rec.recur_id, v_rsv_ruimte_key, date_interval_start, date_interval_end);
-- res_discipline achterhalen; alleen tracken voor EXCO en MC zalen
v_errorhint := 'res_discipline bepalen';
SELECT r.res_discipline_key
INTO v_discipline_key
FROM res_ruimte r,
res_ruimte_opstelling ro,
res_rsv_ruimte rr
WHERE rr.res_rsv_ruimte_key = v_rsv_ruimte_key
AND ro.res_ruimte_opstel_key =
rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key;
-- Altijd tracken <20>n notificeren!
v_errorhint := 'Tracking NEW';
fac.trackaction ('RESNEW',
v_rsv_ruimte_key,
NULL,
SYSDATE,
v_trackingnew);
-- Is er iets dirty?
res.set_ruimte_dirty (v_rsv_ruimte_key);
fac.imp_writelog (
p_import_key,
'I',
v_reservering_key
|| '/'
|| v_rsv_ruimte_volgnr
|| '('
|| TO_CHAR (rec.starttime, 'DD-MM-YYYY HH24:MI')
|| ' - '
|| TO_CHAR (rec.endtime, 'HH24:MI')
|| ') aangemaakt',
rec.subject);
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS
THEN
v_count_error := v_count_error + 1;
oracle_err_num := SQLCODE;
oracle_err_mes := SUBSTR (SQLERRM, 1, 200);
v_errormsg :=
'OTHERS (error '
|| oracle_err_num
|| '/'
|| oracle_err_mes
|| ')';
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
v_errorhint || ': ' || v_errormsg);
END;
END LOOP;
IF BITAND(sync_level, 7) = 1
THEN
-- Bij dirty ruimtes de *oudere* opruimen
v_aanduiding := 'Calling set_ruimtes_clean';
v_errorhint := '';
exc.set_ruimtes_clean (p_import_key);
END IF;
COMMIT; -- de INSERT's
EXCEPTION
WHEN OTHERS
THEN
v_count_error := v_count_error + 1;
oracle_err_num := SQLCODE;
oracle_err_mes := SUBSTR (SQLERRM, 1, 200);
v_errormsg :=
'OTHERS (error '
|| oracle_err_num
|| '/'
|| oracle_err_mes
|| ')';
fac.imp_writelog (p_import_key,
'E',
v_aanduiding,
v_errorhint || ': ' || v_errormsg);
COMMIT;
END update_exchange;
PROCEDURE import_exchfull (p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90)
IS
BEGIN
import_exchange (p_import_key, p_days_from, p_days_to);
END;
PROCEDURE update_exchfull (p_import_key IN NUMBER, p_days_from IN NUMBER DEFAULT 0, p_days_to IN NUMBER DEFAULT 90)
IS
v_errorhint VARCHAR2 (1000);
date_interval_start DATE := TRUNC (SYSDATE) - p_days_from;
date_interval_end DATE := TRUNC (SYSDATE) + p_days_to;
BEGIN
update_exchange (p_import_key, p_days_from, p_days_to); -- Eerst de gewone import
-- Nu alle reserveringen die niet zijn aangetroffen verwijderen
-- (Alleen voor ruimtes die in de importtabel voorkomen. Normaliter zijn dat alle ruimtes,
-- maar zo voorkom je dat je alle reserveringen weggooit als een ruimte 'per ongeluk' een
-- keer niet in de import zit. Handmatig verwijderen kan altijd.)
FOR rec
IN (WITH
this_import
AS
(SELECT *
FROM exc_import
WHERE fac_import_key = p_import_key)
SELECT res_rsv_ruimte_key,
res_rsv_ruimte_van,
res_rsv_ruimte_tot,
res_reservering_key,
res_rsv_ruimte_volgnr
FROM res_rsv_ruimte rr, res_ruimte_opstelling ro, res_ruimte r
WHERE rr.res_rsv_ruimte_externnr IS NOT NULL
AND ( (SELECT BITAND ( COALESCE (fac_setting_pvalue, fac_setting_default), 6)
FROM fac_setting
WHERE fac_setting_name = 'msgraph_sync_level') = 4
OR ( rr.res_rsv_ruimte_externnr IS NOT NULL -- Sluit Facilitor initiated reserveringen uit bij S(msgraph_sync_level) &2
AND rr.res_rsv_ruimte_externnr2 IS NULL
AND rr.res_rsv_ruimte_externsyncdate IS NULL))
AND rr.res_rsv_ruimte_verwijder IS NULL
AND rr.res_rsv_ruimte_tot >= date_interval_start
AND rr.res_rsv_ruimte_van <= date_interval_end
AND ro.res_ruimte_opstel_key = rr.res_ruimte_opstel_key
AND r.res_ruimte_key = ro.res_ruimte_key
AND r.res_ruimte_extern_id IN (SELECT DISTINCT room_id
FROM this_import)
AND NOT EXISTS
(SELECT 1
FROM this_import i
WHERE rr.res_rsv_ruimte_externnr = i.appt_id || '|' || i.recur_id
AND r.res_ruimte_extern_id = i.room_id))
LOOP
v_errorhint :=
'Verwijderen reservering '
|| TO_CHAR (rec.res_reservering_key)
|| '/'
|| rec.res_rsv_ruimte_volgnr
|| ' ('
|| TO_CHAR (rec.res_rsv_ruimte_key)
|| ')';
fac.imp_writelog (p_import_key,
'I',
v_errorhint,
'');
UPDATE res_rsv_ruimte
SET res_status_fo_key = 1, -- nooit doorbelasten of v_status_fo_key?
res_rsv_ruimte_verwijder = SYSDATE
WHERE res_rsv_ruimte_key = rec.res_rsv_ruimte_key;
fac.trackaction ('RESDEL',
rec.res_rsv_ruimte_key,
NULL,
SYSDATE,
NULL);
res.set_ruimte_dirty (rec.res_rsv_ruimte_key);
res.set_ruimtes_clean (rec.res_rsv_ruimte_van);
res.follow_artikel (rec.res_rsv_ruimte_key,
rec.res_rsv_ruimte_van,
rec.res_rsv_ruimte_tot);
res.follow_deel (rec.res_rsv_ruimte_key,
rec.res_rsv_ruimte_van,
rec.res_rsv_ruimte_tot);
v_errorhint := 'res_reservering verwijderen';
UPDATE res_reservering
SET res_reservering_verwijder = SYSDATE
WHERE res_reservering_key = rec.res_reservering_key
AND NOT EXISTS
(SELECT *
FROM res_v_aanwezigrsv_ruimte
WHERE res_reservering_key = rec.res_reservering_key);
END LOOP;
END;
END exc;
/
REGISTERRUN('$Id$')
#endif // EXC