#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 COALESCE (r.res_ruimte_vervaldatum, SYSDATE + 1) > SYSDATE 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 -- 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 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) := ';'; c_max_errors NUMBER := 100; v_newline VARCHAR2 (1000); -- Input line v_aanduiding VARCHAR2 (200); 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_count NUMBER; 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_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). 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) LIKE '%' || UPPER (r.res_ruimte_extern_id) || '%'; 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 DELETE FROM exc_import WHERE gelukt IS NOT NULL 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)); -- 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_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); 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, 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_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; 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 (200); v_errorhint VARCHAR2 (1000); v_errormsg VARCHAR2 (1000); oracle_err_num NUMBER; oracle_err_mes VARCHAR2 (200); v_count_tot NUMBER (10); 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_ongeldig NUMBER (1); 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); -- 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 ü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, 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, 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 (ó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, 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, 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, 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, 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'; -- We doen niets met boekingen die buiten het geconfigureerde interval vallen UPDATE exc_import i SET gelukt = 4 WHERE starttime > date_interval_end OR endtime < date_interval_start; -- En res_ruimtes als deelnemers, dat kan natuurlijk niet UPDATE exc_import i SET gelukt = 5 WHERE EXISTS (SELECT 1 FROM res_ruimte WHERE UPPER (res_ruimte_extern_id) = UPPER (att_mail)); -- Eerst verwijderen; dat scheelt onterechte "dirties" bij toevoegen -- Bij verplaatsen naar een andere ruimte krijg je mogelijk een delete op de oude -- ruimte; die voeren we niet uit. Ook deletes van niet-bekende appointments negeren we. UPDATE exc_import i SET gelukt = 3 WHERE modifier IN ('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); UPDATE exc_import i SET gelukt = 3 WHERE modifier IN ('D') AND NOT EXISTS (SELECT 1 FROM res_rsv_ruimte WHERE INSTR(res_rsv_ruimte_externnr, i.appt_id || '|') = 1); 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 éé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'; 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); -- 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; 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; -- Omdat we entries die gefaald zijn 'bewaren', kan het zijn dat we voor één appointment -- meerdere updates - of zelfs een delete - hebben. Dan zijn we alleen geïnteresseerd in de -- nieuwste, de rest kan genegeerd/weg. (Als we een nieuwere UPDate hebben, kan de originele -- ADD/create ook weg; een update van een nog-niet-bestaande reservering zorgt voor aanmaken.) -- Hoger seq_nr = latere mutatie in Exchange UPDATE exc_import i SET gelukt = 2 WHERE 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); -- Hetzelfde voor deletes van niet-bestaande reserveringen UPDATE exc_import i SET gelukt = 2 WHERE modifier = 'D' AND NOT EXISTS (SELECT 1 FROM res_rsv_ruimte WHERE res_rsv_ruimte_externnr = i.appt_id || '|' || i.recur_id); -- 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 é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 éé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 éé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 éé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 óf een bestaande boeking omhangen naar deze ruimte, -- ó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; -- 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_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 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; -- Succesvol afgerond; zet vlag. -- Alléé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; 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; -- 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_errorhint := 'Host ' || rec.organizer || ' onbekend, of meer personen met dit e-mailadres! Geen boeking.'; -- Kennen we deze persoon eigenlijk wel? SELECT COUNT (*) INTO v_count FROM prs_v_aanwezigperslid p WHERE UPPER (p.prs_perslid_email) = UPPER (rec.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 (rec.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; -- 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_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, 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; -- Pas het 'gelukt' bitje aan zodat we hem later niet weer opnieuw proberen UPDATE exc_import SET gelukt = 2 WHERE appt_id || '|' || recur_id = rec.appt_id || '|' || rec.recur_id AND gelukt IS NULL; 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); -- Succesvol afgerond; zet vlag. -- 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 gelukt IS NULL; IF (v_debug) THEN fac.imp_writelog (p_import_key, 'I', v_aanduiding, 'gelukt=1'); END IF; -- 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 én notificeren! v_errorhint := 'Tracking NEW'; fac.trackaction ('RESNEW', v_rsv_ruimte_key, NULL, SYSDATE, NULL); -- 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; 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); 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 AND rr.res_rsv_ruimte_externnr2 IS NULL AND rr.res_rsv_ruimte_externsyncdate IS NOT NULL)) AND rr.res_rsv_ruimte_verwijder IS NULL AND rr.res_rsv_ruimte_van >= (SELECT MIN (starttime) FROM this_import) AND rr.res_rsv_ruimte_van <= (SELECT MAX (starttime) FROM this_import) 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