-- -- $Id$ --- Script containing customer specific db-configuration for STPH DEFINE thisfile = 'STPH_EXCHANGE.SQL' DEFINE dbuser = '^STPH' SET ECHO ON SET DEFINE ON COLUMN fcltlogfile NEW_VALUE fcltlogfile NOPRINT; COLUMN fcltcusttxt NEW_VALUE fcltcusttxt NOPRINT; WHENEVER SQLERROR CONTINUE; SELECT adm.getscriptspoolfile('&thisfile') AS fcltlogfile FROM DUAL; SPOOL &fcltlogfile WHENEVER SQLERROR EXIT; SELECT adm.checkscriptcust('&dbuser') AS fcltcusttxt FROM DUAL; WHENEVER SQLERROR CONTINUE; --------------------------------------- PROMPT &fcltcusttxt --------------------------------------- SET DEFINE OFF ------ payload begin ------ -- modifiers: -- ADD: appointment is niew, dus ook een nieuwe reservering -- DEL: appointment is verwijderd, dus reservering annuleren -- UPD: appointment is gewijzigd en kan daarmee effectief ook een ADD of DEL zijn -- *************************************************************************** -- Bovenstaande nog even laten staan. Voor STPH is de koppeling gerealiseerd voor: -- Catalogus Vergaderzaal te reserveren vanuit Exchange (key=24) -- Activiteit Ruimtereservering vanuit Exchange (key=10). -- *************************************************************************** -------------------------------------------------------------------------------------------------- ------------------------------- PACKAGE ---------------------------------------------------------- -------------------------------------------------------------------------------------------------- CREATE OR REPLACE PACKAGE stph_exchange AS FUNCTION getAantalDagenInPeriode (p_van IN DATE, p_tot IN DATE, p_periode_van IN DATE, p_periode_tot IN DATE := NULL) RETURN NUMBER; -- Maakt afspraak met bezoekers aan, indien nodig PROCEDURE setBezoekers (p_import_key IN NUMBER, p_appt_id IN VARCHAR2, p_recur_id IN VARCHAR2, p_rsv_ruimte_key IN NUMBER); -- Haalt bestaande afspraak bij rsv_ruimte op, of maakt een nieuwe FUNCTION getAfspraak (p_rsv_ruimte_key IN NUMBER, p_createnew IN NUMBER) RETURN NUMBER; -- Update of insert bezoeker met de juiste voorwaarden PROCEDURE upsertBezoeker (p_import_key IN NUMBER, p_afspraak_key IN NUMBER, p_bezoekers_key IN NUMBER, p_att_mail IN VARCHAR2, p_att_name IN VARCHAR2, p_perslid_key IN NUMBER, p_afdeling_naam IN VARCHAR2); PROCEDURE upsertkenmerk_bez (p_kenmerk_key IN NUMBER, p_bez_key IN NUMBER, p_waarde IN VARCHAR2); PROCEDURE upsertkenmerk_res (p_kenmerk_key IN NUMBER, p_rsv_ruimte_key IN NUMBER, p_waarde IN VARCHAR2); FUNCTION getOpstelling (p_room_id IN VARCHAR2) RETURN NUMBER; PROCEDURE checkParking (p_bezoekers_key IN NUMBER); PROCEDURE set_ruimtes_clean (p_import_key IN NUMBER); END; / CREATE OR REPLACE PACKAGE BODY stph_exchange AS -- Zorg dat de bezoekers bij de deelreservering matchen met de genodigden bij de appointment -- - host niet toevoegen als bezoeker -- - AMB-en SSCA-medewerkers met een badgenummer alleen in een genodigdenlijst -- Afspraak aanmaken of verwijderen indien nodig -- Bezoekers aanmaken, bijwerken of verwijderen zoals nodig -- Als vergaderruimte op kantoorverdieping (OF-ruimte), dan geen bezoekers (alleen genodigdenlijst), -- noch voorzieningen -- - OF = res_disc 1485 "Vergaderruimtes nw A'dam" -- - EXCO = res_disc 1505 "Vergaderzalen 9de PA's" -- - MC = res_disc 1445 "Vergaderzalen NW Amsterdam" -- TODO: nu worden voor appointments met meerdere zalen waarschijnlijk de attendees bij iedere -- deelreservering toegevoegd. -- KFSG#57950: Voor Schiphol geldt (voor enige locatie/catalogus/activiteit) alleen externen als -- bezoeker (en eigen medewerkers in Genodigden-kenmerk?). PROCEDURE setBezoekers(p_import_key IN NUMBER, p_appt_id IN VARCHAR2, p_recur_id IN VARCHAR2, p_rsv_ruimte_key IN NUMBER) IS v_debug BOOLEAN := TRUE; v_count NUMBER (10); c_km_key_genodigden NUMBER (10) := 181; v_genodigden VARCHAR2 (4000); v_afspraak_key NUMBER (10); v_datum_old DATE; v_eind_old DATE; v_datum_new DATE; v_eind_new DATE; v_discipline_key NUMBER (10) := NULL; -- Alle bezoekers bij deze rsv_ruimte, die niet meer in het importbestand zitten -- AKZA#38972: zorgen dat personen die als bezoeker aangemeld waren, maar nu 'slechts' genodigde zijn, ook verwijderd worden -- En als we toch bezig zijn: ruimtes kunnen geen bezoekers meer zijn; ook die weggooien dus. CURSOR c_del IS -- Niet meer in de import SELECT a.res_rsv_ruimte_key, kw.bez_kenmerkwaarde_waarde bez_email, b.* FROM bez_afspraak a, bez_bezoekers b, bez_kenmerkwaarde kw WHERE a.res_rsv_ruimte_key = p_rsv_ruimte_key AND b.bez_afspraak_key = a.bez_afspraak_key AND kw.bez_bezoekers_key = b.bez_bezoekers_key AND kw.bez_kenmerk_key = 1000 -- E-mailadres Exchange AND kw.bez_kenmerkwaarde_verwijder IS NULL AND NOT EXISTS (SELECT 1 FROM stph_imp_exchange WHERE UPPER(att_mail) = UPPER(kw.bez_kenmerkwaarde_waarde) ) UNION ALL -- Naam al aanwezig in lijst van genodigden SELECT a.res_rsv_ruimte_key, kw.bez_kenmerkwaarde_waarde bez_email, b.* FROM bez_afspraak a, bez_bezoekers b, bez_kenmerkwaarde kw, res_kenmerkwaarde rkw WHERE a.res_rsv_ruimte_key = p_rsv_ruimte_key AND b.bez_afspraak_key = a.bez_afspraak_key AND kw.bez_bezoekers_key = b.bez_bezoekers_key AND kw.bez_kenmerk_key = 1000 -- E-mailadres Exchange AND kw.bez_kenmerkwaarde_verwijder IS NULL AND rkw.res_kenmerk_key = c_km_key_genodigden AND rkw.res_kenmerkwaarde_verwijder IS NULL AND rkw.res_rsv_ruimte_key = a.res_rsv_ruimte_key AND rkw.res_kenmerkreservering_waarde LIKE '%'||b.bez_afspraak_naam||'%' UNION ALL -- Mailadres bekend als extern ID van ruimte SELECT a.res_rsv_ruimte_key, kw.bez_kenmerkwaarde_waarde bez_email, b.* FROM bez_afspraak a, bez_bezoekers b, bez_kenmerkwaarde kw WHERE a.res_rsv_ruimte_key = p_rsv_ruimte_key AND b.bez_afspraak_key = a.bez_afspraak_key AND kw.bez_bezoekers_key = b.bez_bezoekers_key AND kw.bez_kenmerk_key = 1000 -- E-mailadres Exchange AND kw.bez_kenmerkwaarde_verwijder IS NULL AND EXISTS (SELECT 1 FROM res_ruimte WHERE UPPER(res_ruimte_extern_id) = UPPER(kw.bez_kenmerkwaarde_waarde)); -- Voor iedere persoon kijken of dit een bekende AN-medewerker is en op welke locatie -- Als mailadres deelnemer == mailadres organizer, dan negeren -- Group by, zodat we voor mensen op AMB/SSCA (en AHO) alleen die werkplek overhouden (overige locaties leveren NULL) -- AKZA#38968: ook badgenummer ophalen CURSOR c_attendees IS SELECT att_mail, COALESCE(prs_perslid_naam_full, att_name) att_name, prs_perslid_key, prs_afdeling_naam, MAX(alg_locatie_key) alg_locatie_key, MAX(alg_locatie_code) alg_locatie_code, --badgenr, bez_bezoekers_key FROM ( SELECT DISTINCT att_mail, att_name FROM stph_imp_exchange WHERE appt_id||'|'||recur_id = p_appt_id||'|'||p_recur_id AND att_mail != organizer AND NOT EXISTS (SELECT 1 FROM res_ruimte WHERE UPPER(res_ruimte_extern_id) = UPPER(att_mail) ) ) e LEFT OUTER JOIN ( SELECT p.prs_perslid_key, p.prs_perslid_email, pf.prs_perslid_naam_full, --kl.prs_kenmerklink_waarde badgenr a.prs_afdeling_naam, l.alg_locatie_key, l.alg_locatie_code FROM prs_perslid p, prs_v_perslid_fullnames pf, --(SELECT * FROM prs_kenmerklink -- WHERE prs_kenmerk_key = -1 -- Badgenummer (van medewerker) -- AND prs_kenmerklink_niveau = 'P' -- AND prs_kenmerklink_verwijder IS NULL) kl, prs_afdeling a, prs_perslidwerkplek pw, prs_werkplek w, alg_ruimte r, alg_verdieping v, alg_gebouw g, (SELECT * FROM alg_locatie WHERE alg_locatie_key = 41) l -- SHG - Schipholgebouw WHERE p.prs_perslid_verwijder IS NULL AND p.prs_perslid_email IS NOT NULL --AND kl.prs_link_key(+) = p.prs_perslid_key AND pf.prs_perslid_key = p.prs_perslid_key AND a.prs_afdeling_key = p.prs_afdeling_key AND pw.prs_perslid_key = p.prs_perslid_key AND w.prs_werkplek_key = pw.prs_werkplek_key AND r.alg_ruimte_key = w.prs_alg_ruimte_key AND r.alg_ruimte_verwijder IS NULL AND v.alg_verdieping_key = r.alg_verdieping_key AND g.alg_gebouw_key = v.alg_gebouw_key AND l.alg_locatie_key(+) = g.alg_locatie_key) p ON UPPER(p.prs_perslid_email) = UPPER(att_mail) LEFT OUTER JOIN ( SELECT b.bez_bezoekers_key, kw.bez_kenmerkwaarde_waarde email FROM bez_afspraak a, bez_bezoekers b, bez_kenmerkwaarde kw WHERE a.res_rsv_ruimte_key = p_rsv_ruimte_key AND b.bez_afspraak_key = a.bez_afspraak_key AND kw.bez_bezoekers_key = b.bez_bezoekers_key AND kw.bez_kenmerk_key = 1000 -- E-mailadres Exchange AND kw.bez_kenmerkwaarde_verwijder IS NULL) b ON UPPER(b.email) = UPPER(att_mail) GROUP BY att_mail, att_name, prs_perslid_key, prs_perslid_naam_full, prs_afdeling_naam, --badgenr, bez_bezoekers_key; BEGIN v_genodigden := NULL; SELECT COUNT(*) INTO v_count FROM stph_imp_exchange WHERE appt_id||'|'||recur_id = p_appt_id||'|'||p_recur_id AND att_mail != organizer; IF (v_count = 0) THEN IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, 'Geen gasten'); END IF; -- Lijst genodigden wissen DELETE res_kenmerkwaarde WHERE res_kenmerk_key = c_km_key_genodigden AND res_rsv_ruimte_key = p_rsv_ruimte_key; -- Afspraak wissen v_afspraak_key := stph_exchange.getAfspraak(p_rsv_ruimte_key, 0); IF v_afspraak_key IS NOT NULL THEN IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, 'Afspraak verwijderen'); END IF; DELETE bez_afspraak WHERE bez_afspraak_key = v_afspraak_key; END IF; ELSE -- Niet-meer bekende attendees verwijderen FOR rec IN c_del LOOP IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, 'Bezoeker '||rec.bez_email||' verwijderen'); END IF; DELETE bez_kenmerkwaarde WHERE bez_bezoekers_key = rec.bez_bezoekers_key; DELETE bez_bezoekers WHERE bez_bezoekers_key = rec.bez_bezoekers_key; END LOOP; FOR rec IN c_attendees LOOP -- Bepalen om wat voor soort ruimte het gaat (OF vs MC/EXCO) IF (v_discipline_key IS NULL) THEN 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 = p_rsv_ruimte_key AND ro.res_ruimte_opstel_key = rr.res_ruimte_opstel_key AND r.res_ruimte_key = ro.res_ruimte_key; IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, 'Discipline = '||v_discipline_key); END IF; END IF; -- AMB- of SSCA-medewerker: alleen in tekstveld zetten -- (Zowel bij create als update hele string weer opbouwen) -- Voor OF-ruimtes (res_disc 1485) behandelen we iedereen als AMB-/SSCA-medewerker -- AKZA#38968: badgenummer is voortaan vereist om genodigde te zijn -- AKZA#40274: bepaling van bezoekers/deelnemers voor ruimtes uit disc 1485 op dezelfde wijze als andere ruimtes / op verzoek van André weer ongedaan gemaakt -- KFSG#57950: Bovenstaande nog even laten staan. Voor Schiphol geldt dat medewerkers (@schiphol in e-mail adres) in Genodigden-veld komen. -- TODO: Of Genodigden-veld helemaal weg??? --IF (rec.alg_locatie_key IS NOT NULL AND rec.badgenr IS NOT NULL) IF (rec.alg_locatie_key IS NOT NULL AND INSTR (UPPER (rec.att_mail), '@SCHIPHOL.NL') > 0) THEN v_genodigden := v_genodigden || rec.att_name || CHR(13); -- Overige AN-medewerkers en gasten aanmelden als bezoeker (of registratie bijwerken) ELSE -- Er zijn niet-AMB-/SSCA-medewerker attendees, zorgen dat er een afspraak is IF (v_afspraak_key IS NULL) THEN v_afspraak_key := stph_exchange.getAfspraak(p_rsv_ruimte_key, 1); -- Moet de afspraak verplaatst worden in de tijd? SELECT bez_afspraak_datum, bez_afspraak_eind, rr.res_rsv_ruimte_van, rr.res_rsv_ruimte_tot INTO v_datum_old, v_eind_old, v_datum_new, v_eind_new FROM res_rsv_ruimte rr, bez_afspraak a WHERE rr.res_rsv_ruimte_key = p_rsv_ruimte_key AND a.res_rsv_ruimte_key = rr.res_rsv_ruimte_key; IF (v_datum_old != v_datum_new OR v_eind_old != v_eind_new) THEN UPDATE bez_afspraak SET bez_afspraak_datum = v_datum_new, bez_afspraak_eind = v_eind_new WHERE bez_afspraak_key = v_afspraak_key; IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key||', AFSPRAAK '||v_afspraak_key, 'Tijden aangepast van ' ||TO_CHAR(v_datum_old,'HH24:MI')||'-' ||TO_CHAR(v_eind_old, 'HH24:MI')||' --> ' ||TO_CHAR(v_datum_new,'HH24:MI')||'-' ||TO_CHAR(v_eind_new, 'HH24:MI') ); END IF; END IF; IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, 'AFSPRAAK '||v_afspraak_key); END IF; END IF; stph_exchange.upsertBezoeker(p_import_key, v_afspraak_key, rec.bez_bezoekers_key, rec.att_mail, rec.att_name, rec.prs_perslid_key, rec.prs_afdeling_naam ); END IF; -- Opruiming: afspraken zonder bezoekers (kan gebeuren als er alleen nog interne deelnemers zijn, -- of de meeting is verplaatst naar een OF-ruimte) DELETE bez_afspraak a WHERE res_rsv_ruimte_key = p_rsv_ruimte_key AND NOT EXISTS (SELECT 1 FROM bez_bezoekers WHERE bez_afspraak_key = a.bez_afspraak_key); END LOOP; IF (v_debug AND v_discipline_key IS NOT NULL) THEN fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, 'Ruimte-catalogus = '||v_discipline_key); fac.imp_writelog (p_import_key, 'D', p_rsv_ruimte_key, SUBSTR('GENODIGDEN: '||CHR(13) ||v_genodigden, 1, 1000) ); END IF; stph_exchange.upsertkenmerk_res(c_km_key_genodigden, p_rsv_ruimte_key, v_genodigden ); END IF; END; -- Haalt bestaande afspraak bij rsv_ruimte op, of maakt een nieuwe FUNCTION getAfspraak (p_rsv_ruimte_key IN NUMBER, p_createnew IN NUMBER) RETURN NUMBER IS v_count NUMBER; r_afspraak_key NUMBER; BEGIN r_afspraak_key := NULL; --Bestaat er al een afspraak? SELECT COUNT(*) INTO v_count FROM bez_afspraak WHERE res_rsv_ruimte_key IS NOT NULL AND res_rsv_ruimte_key = p_rsv_ruimte_key; -- Nee, maak eerst een nieuwe, mits createnew = 1 IF (v_count = 0 AND p_createnew = 1) THEN INSERT INTO bez_afspraak ( 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 rr.res_rsv_ruimte_contact_key, rr.res_rsv_ruimte_van, NULL, 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, rr.res_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.res_ruimte_nr, rr.res_rsv_ruimte_tot, g.alg_locatie_key, rr.res_rsv_ruimte_host_key, rr.res_rsv_ruimte_contact_key, rr.res_rsv_ruimte_key; -- TODO: -- BEGIN fac.trackaction('BEZMUT', -1, 3, NULL, NULL); END; END IF; -- Haal bestaande / nieuwe key op (RETURNING kan niet met een INSERT .. SELECT) -- (alleen als we er net een hebben aangemaakt of er al een was IF NOT (v_count = 0 AND p_createnew = 0) THEN SELECT bez_afspraak_key INTO r_afspraak_key FROM bez_afspraak WHERE res_rsv_ruimte_key IS NOT NULL AND res_rsv_ruimte_key = p_rsv_ruimte_key; END IF; RETURN r_afspraak_key; END; PROCEDURE upsertBezoeker (p_import_key IN NUMBER, p_afspraak_key IN NUMBER, p_bezoekers_key IN NUMBER, p_att_mail IN VARCHAR2, p_att_name IN VARCHAR2, p_perslid_key IN NUMBER, p_afdeling_naam IN VARCHAR2) IS v_debug BOOLEAN := TRUE; v_bez_flags NUMBER (10); v_bezoekers_key NUMBER (10); v_count NUMBER; BEGIN v_bez_flags := 0; -- AN-medewerkers op overige locaties: -- aanmelden als bezoeker (met perslid_key, als bekend), zonder (mogelijkheid tot) parkeerplaats -- flags (AKZA#34209) -- 2: andere locatie -- 16: geen parkeerplaats mogelijk IF (UPPER(p_att_mail) LIKE '%@SCHIPHOL.NL') THEN IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_afspraak_key, 'SG-mw '||p_att_name|| ' ('||COALESCE(TO_CHAR(p_perslid_key), p_att_mail)||')'); END IF; v_bez_flags := 2 + 16; -- Gasten: aanmelden als gewone bezoeker (zonder perslid_key), met parkeerplaats -- flags = 0 ELSE IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', p_afspraak_key, 'Gast '||p_att_name|| ' ('||p_att_mail||')'); END IF; v_bez_flags := 0; END IF; -- Bestaat bezoeker al bij deelreservering? Dan alleen basisgegevens bijwerken IF (p_bezoekers_key IS NOT NULL) THEN -- Bijwerken UPDATE bez_bezoekers SET prs_perslid_key = p_perslid_key, bez_afspraak_naam = SUBSTR(p_att_name, 1, 30), bez_afspraak_bedrijf = SUBSTR(p_afdeling_naam, 1, 60), bez_bezoekers_flags = v_bez_flags WHERE bez_bezoekers_key = p_bezoekers_key; -- Als deze bezoeker een parkeerplaats heeft, probeer dan een nieuwe te claimen -- alg_gebouw "SHG" 48 IF ( bez.hasparking(p_bezoekers_key) = 1) THEN DELETE FROM res_rsv_deel WHERE bez_bezoekers_key = p_bezoekers_key; IF ( BITAND(v_bez_flags, 16) = 0) THEN bez.claim_parking(p_bezoekers_key, 48); END IF; -- TODO: track? END IF; -- Nieuwe bezoeker: toevoegen, plus parkeerplaats en mailadres ELSE INSERT INTO bez_bezoekers ( bez_afspraak_key, prs_perslid_key, bez_afspraak_naam, bez_afspraak_bedrijf, bez_bezoekers_flags) VALUES ( p_afspraak_key, p_perslid_key, SUBSTR(p_att_name, 1, 30), SUBSTR(p_afdeling_naam, 1, 60), v_bez_flags) RETURNING bez_bezoekers_key INTO v_bezoekers_key; -- Voor nieuwe gasten een parkeerplek claimen -- alg_gebouw "SHG" 48 IF ( BITAND(v_bez_flags, 16) = 0) THEN bez.claim_parking(v_bezoekers_key, 48); END IF; -- Mailadres opslaan -- bez_kenmerk E-mail 1000 stph_exchange.upsertkenmerk_bez(1000, v_bezoekers_key, p_att_mail); END IF; -- TODO: tracking; liefst geen aparte regel per bezoeker -- fac.trackaction('BEZMUT', p_afspraak_key, NULL, NULL, 'Bezoeker '||p_att_name||' toegevoegd/gewijzigd'); END; PROCEDURE upsertkenmerk_bez (p_kenmerk_key IN NUMBER, p_bez_key IN NUMBER, p_waarde IN VARCHAR2) IS v_count NUMBER; BEGIN SELECT COUNT ( * ) INTO v_count FROM bez_kenmerkwaarde WHERE bez_bezoekers_key = p_bez_key AND bez_kenmerk_key = p_kenmerk_key AND bez_kenmerkwaarde_verwijder IS NULL; IF v_count = 1 THEN IF p_waarde IS NULL THEN DELETE bez_kenmerkwaarde WHERE bez_bezoekers_key = p_bez_key AND bez_kenmerk_key = p_kenmerk_key AND bez_kenmerkwaarde_verwijder IS NULL; ELSE UPDATE bez_kenmerkwaarde SET bez_kenmerkwaarde_waarde = p_waarde WHERE bez_bezoekers_key = p_bez_key AND bez_kenmerk_key = p_kenmerk_key AND bez_kenmerkwaarde_verwijder IS NULL; END IF; ELSE IF p_kenmerk_key IS NOT NULL AND p_waarde IS NOT NULL THEN INSERT INTO bez_kenmerkwaarde (bez_kenmerk_key, bez_bezoekers_key, bez_kenmerkwaarde_waarde) VALUES (p_kenmerk_key, p_bez_key, p_waarde); END IF; END IF; END; PROCEDURE upsertkenmerk_res(p_kenmerk_key IN NUMBER, p_rsv_ruimte_key IN NUMBER, p_waarde IN VARCHAR2) IS v_count NUMBER; BEGIN SELECT COUNT ( * ) INTO v_count FROM res_kenmerkwaarde WHERE res_rsv_ruimte_key = p_rsv_ruimte_key AND res_kenmerk_key = p_kenmerk_key AND res_kenmerkwaarde_verwijder IS NULL; IF v_count = 1 THEN IF p_waarde IS NULL THEN DELETE res_kenmerkwaarde WHERE res_rsv_ruimte_key = p_rsv_ruimte_key AND res_kenmerk_key = p_kenmerk_key AND res_kenmerkwaarde_verwijder IS NULL; ELSE UPDATE res_kenmerkwaarde SET res_kenmerkreservering_waarde = p_waarde WHERE res_rsv_ruimte_key = p_rsv_ruimte_key AND res_kenmerk_key = p_kenmerk_key AND res_kenmerkwaarde_verwijder IS NULL; END IF; ELSE IF p_kenmerk_key IS NOT NULL AND p_waarde IS NOT NULL THEN INSERT INTO res_kenmerkwaarde (res_kenmerk_key, res_rsv_ruimte_key, res_kenmerkreservering_waarde) VALUES (p_kenmerk_key, p_rsv_ruimte_key, p_waarde); END IF; END IF; END; -- 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 r.res_ruimte_extern_id = 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; -- Aangeroepen vanuit bez_postsave hook. Controleert of deze bezoeker wel een parkeerplaats -- mag hebben (obv bez_bezoekers_flags) en verwijdert zonodig PROCEDURE checkParking(p_bezoekers_key IN NUMBER) IS v_bez_flags bez_bezoekers.bez_bezoekers_flags%TYPE; v_rsv_deel_key NUMBER (10); BEGIN -- Haal bezoeker-flags op, en een eventuele SELECT b.bez_bezoekers_flags, rd.res_rsv_deel_key INTO v_bez_flags, v_rsv_deel_key FROM bez_bezoekers b, (SELECT * FROM res_rsv_deel WHERE res_rsv_deel_verwijder IS NULL) rd WHERE b.bez_bezoekers_key = p_bezoekers_key AND rd.bez_bezoekers_key(+) = b.bez_bezoekers_key; -- Bezoeker mag geen parkeerplaats, maar heeft er wel een --> weg ermee! -- bits: +1 Medewerker uit eigen locatie, is waarschijnlijk al binnen -- +2 Medewerker van andere locatie (heeft doorgaans bedrijfspasje) -- +4 Deelnemer die niet fysiek komt (Skype/Video conference) -- +8 Bezoekers meldt zich niet aan de balie (waarschijnlijk bij een +1/2/4) -- +16 Geen parkeerplaats toe (te) kennen of af te pakken (vaak icm. +1/2/4) IF ( BITAND(v_bez_flags, 31) != 0 AND v_rsv_deel_key IS NOT NULL) THEN DELETE res_rsv_deel WHERE res_rsv_deel_key = v_rsv_deel_key; END IF; EXCEPTION WHEN NO_DATA_FOUND THEN NULL; 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, 'D', 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; -- Bepaal aantal dagen in begin- of eindperiode waarvoor huur betaald moet worden -- Periode moet binnen dezelfde kalendermaand liggen. -- Als p_periode_tot leeg is, gaan we uit van het einde van de maand -- Als p_van en/of p_tot leeg zijn, dan zetten we die op begin resp. eind van de periode FUNCTION getAantalDagenInPeriode(p_van IN DATE, p_tot IN DATE, p_periode_van IN DATE, p_periode_tot IN DATE := NULL) RETURN NUMBER IS o_aantal_dagen NUMBER(4); v_periode_tot DATE; v_van DATE; v_tot DATE; BEGIN -- Einddatum van de periode die we beschouwen. -- Als geen einddatum, dan einde van de maand (startdatum zou dan eerste dag van de maand moeten zijn) v_periode_tot := COALESCE( p_periode_tot, LAST_DAY(p_periode_van) ); -- Valt periode (p_van - p_tot) geheel buiten (p_periode_van - p_periode_tot)? Dan nul dagen overlap! IF ( p_tot < p_periode_van OR p_van > p_periode_tot) THEN RETURN 0; END IF; -- Aantal dagen is maximaal de hele periode o_aantal_dagen := CAST( TO_CHAR(v_periode_tot, 'DD') AS INT) - CAST( TO_CHAR(p_periode_van, 'DD') AS INT) + 1; v_van := p_van; v_tot := p_tot; -- Als geen van/tot datum opgegeven, of als van/tot datum buiten periode valt, -- dan zet op begin-/einddatum van de periode (periode) IF (v_van IS NULL OR v_van < p_periode_van) THEN v_van := p_periode_van; END IF; IF (v_tot IS NULL OR v_tot > v_periode_tot) THEN v_tot := v_periode_tot; END IF; -- Beslaat het contract de volledige periode, of beginnen/eindigen we halverwege? -- DAN: -- - ingangsmaand is hetzelfde als van huidige periode -- - ingangsdag is later dan de eerste dag van de periode -- EN/OF: -- - eindmaand is hetzelfde als van huidige periode -- - einddag is eerder dan de laatste dag van de periode IF ( ( TRUNC(v_van, 'MM') = TRUNC(p_periode_van, 'MM') AND TRUNC(v_van, 'DD') > p_periode_van ) OR ( TRUNC(v_tot, 'MM') = TRUNC(v_periode_tot, 'MM') AND TRUNC(v_tot, 'DD') < v_periode_tot ) ) THEN -- prijsfactor = aantal_dagen_gehuurd / aantal_dagen_in_deze_periode -- = einddag - begindag + 1 / aantal_dagen_in_deze_periode o_aantal_dagen := ( CAST( TO_CHAR(v_tot, 'DD') AS INT) - CAST( TO_CHAR(v_van, 'DD') AS INT) + 1 ); END IF; RETURN o_aantal_dagen; END; END; / xxxxxxxxxxxxxxxx -------------------------------------------------------------------------------------------------- ------------------------------- IMPORT ----------------------------------------------------------- -------------------------------------------------------------------------------------------------- -- Met behulp van stph_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 CREATE OR REPLACE PROCEDURE stph_import_exchange ( p_import_key IN NUMBER ) 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; -- 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. DELETE FROM stph_imp_exchange WHERE gelukt IS NOT NULL; -- 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 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; 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 d_starttime > SYSDATE) THEN BEGIN v_errorhint := 'Fout bij toevoegen regel aan importtabel'; INSERT INTO stph_imp_exchange (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, SUBSTR(v_modifier, 1, 1), 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, 100); 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 (deelnemers).', '' ); END IF; COMMIT; -- stph_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, 100); 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 stph_import_exchange; / CREATE OR REPLACE PROCEDURE stph_update_exchange ( p_import_key IN NUMBER ) 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 := TRUE; c_activiteit_key NUMBER (10) := 70; -- Vergadering vanuit Exchange 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_code VARCHAR2(7); -- ANNULEREN -- Eerst alle toekomstige 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: weet niet of dat überhaupt voorkomt met EWS) -- 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 stph_imp_exchange WHERE modifier = 'D' AND starttime > SYSDATE AND gelukt IS NULL) i, res_rsv_ruimte rr WHERE rr.res_rsv_ruimte_externnr IS NOT NULL AND rr.res_rsv_ruimte_externnr LIKE 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 stph_imp_exchange WHERE modifier = 'U' AND starttime > SYSDATE AND gelukt IS NULL) i, res_rsv_ruimte rr WHERE rr.res_rsv_ruimte_externnr LIKE 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 stph_imp_exchange WHERE modifier = 'U' AND starttime > SYSDATE AND recur_id IS NOT NULL AND gelukt IS NULL) i, res_rsv_ruimte rr WHERE rr.res_rsv_ruimte_externnr LIKE 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, COUNT(*) num_bez FROM stph_imp_exchange WHERE modifier = 'U' AND starttime > SYSDATE 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 LIKE 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 stph_imp_exchange WHERE modifier = 'C' AND starttime > SYSDATE 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 stph_imp_exchange WHERE modifier = 'U' AND starttime > SYSDATE 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 IS NOT NULL AND rr.res_rsv_ruimte_externnr LIKE 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); BEGIN -- We doen niets met boekingen in het verleden UPDATE stph_imp_exchange i SET gelukt = 4 WHERE endtime < SYSDATE; -- En res_ruimtes als deelnemers, dat kan natuurlijk niet UPDATE stph_imp_exchange 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 stph_imp_exchange i SET gelukt = 3 WHERE modifier IN ('D') AND EXISTS (SELECT 1 FROM stph_imp_exchange WHERE modifier != 'D' AND appt_id||'|'||recur_id = i.appt_id||'|'||i.recur_id AND seq_nr > i.seq_nr); UPDATE stph_imp_exchange i SET gelukt = 3 WHERE modifier IN ('D') AND NOT EXISTS (SELECT 1 FROM res_rsv_ruimte WHERE res_rsv_ruimte_externnr LIKE i.appt_id||'|%'); 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, 'D', 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, 'D', 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 stph_imp_exchange 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 stph_imp_exchange i SET gelukt = 2 WHERE modifier IN ('C', 'U') AND EXISTS (SELECT 1 FROM stph_imp_exchange 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 stph_imp_exchange i SET gelukt = 2 WHERE modifier = 'D' AND NOT EXISTS (SELECT 1 FROM res_rsv_ruimte WHERE res_rsv_ruimte_externnr LIKE 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 LIKE 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 stph_imp_exchange i WHERE i.modifier IN ('U', 'C') AND i.starttime > SYSDATE AND i.appt_id||'|'||i.recur_id||'|' LIKE 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 LIKE 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 stph_imp_exchange 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, 'D', 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, 'D', 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, 'D', 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, 'D', 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_bezoekers != rec.num_bez 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 := stph_exchange.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_bezoekers = rec.num_bez 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, 'D', v_aanduiding, 'RES: '||rec.res_reservering_key||'/'||rec.res_rsv_ruimte_volgnr); fac.imp_writelog (p_import_key, 'D', v_aanduiding, 'Room: '||v_ruimte_extern_id||'-->'||rec.res_ruimte_extern_id); fac.imp_writelog (p_import_key, 'D', v_aanduiding, 'Desc: "'||rec.res_rsv_ruimte_omschrijving||'"-->"'||SUBSTR(rec.subject, 1, 60)||'"'); fac.imp_writelog (p_import_key, 'D', 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, 'D', v_aanduiding, 'Einde: '||TO_CHAR(rec.res_rsv_ruimte_tot,'DD-MM-YYYY HH24:MI')||'-->'||TO_CHAR(rec.endtime,'DD-MM-YYYY HH24:MI')); fac.imp_writelog (p_import_key, 'D', v_aanduiding, 'Bezoekers: '||rec.res_rsv_ruimte_bezoekers||'-->'||rec.num_bez); 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, 'D', v_aanduiding, 'Geen verschil in basisgegevens'); END IF; END IF; -- Bezoekers bijwerken v_errorhint := 'Bezoekers bijwerken'; stph_exchange.setBezoekers(p_import_key, rec.appt_id, rec.recur_id, rec.res_rsv_ruimte_key); -- 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 stph_imp_exchange 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, 'D', 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 := stph_exchange.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 res_rsv_ruimte_externnr LIKE rec.appt_id||'|%' -- 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 res_rsv_ruimte_externnr IS NOT NULL AND res_rsv_ruimte_externnr LIKE rec.appt_id||'|%' -- 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 := 'Deelreservering aanmaken'; -- 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||'|'||rec.seq_nr, 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; IF (v_debug) THEN fac.imp_writelog (p_import_key, 'D', v_aanduiding, 'RESERVERING '||v_reservering_key||'/'||v_rsv_ruimte_volgnr||' ('||v_rsv_ruimte_key||')'); END IF; v_errorhint := 'Toevoegen bezoekers'; stph_exchange.setBezoekers(p_import_key, rec.appt_id, rec.recur_id, v_rsv_ruimte_key); -- Succesvol afgerond; zet vlag. -- TODO: komen we hier ook als er iets mis ging met de bezoekers? UPDATE stph_imp_exchange 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, 'D', 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'; v_code := 'RESNEW'; fac.trackaction (v_code, v_rsv_ruimte_key, NULL, SYSDATE, 'Booking confirmation meeting room, booking ref.: '||v_reservering_key||'/'||v_rsv_ruimte_volgnr); -- 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; -- Bij dirty ruimtes de *oudere* opruimen v_aanduiding := 'Calling set_ruimtes_clean'; v_errorhint := ''; stph_exchange.set_ruimtes_clean(p_import_key); 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 stph_update_exchange; / CREATE OR REPLACE PROCEDURE stph_import_exchsync ( p_import_key IN NUMBER ) IS BEGIN stph_import_exchange(p_import_key); END; / CREATE OR REPLACE PROCEDURE stph_update_exchsync ( p_import_key IN NUMBER ) IS BEGIN stph_update_exchange(p_import_key); END; / CREATE OR REPLACE PROCEDURE stph_import_exchfull ( p_import_key IN NUMBER ) IS BEGIN stph_import_exchange(p_import_key); END; / CREATE OR REPLACE PROCEDURE stph_update_exchfull ( p_import_key IN NUMBER ) IS v_errorhint VARCHAR2 (1000); BEGIN stph_update_exchange(p_import_key); -- 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 stph_imp_exchange 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 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 LIKE 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; / ------ payload end ------ SET DEFINE OFF BEGIN adm.systrackscriptId ('$Id$', 0); END; / COMMIT; SET ECHO OFF SPOOL OFF SET DEFINE ON PROMPT Logfile of this upgrade is: &fcltlogfile