--
-- $Id$
--
-- Script containing customer specific sql statements for the FACILITOR database

DEFINE thisfile = 'AKZA_EXCHANGE.SQL'
DEFINE dbuser   = '^AKZA'
DEFINE custid   = 'AKZA'

SET ECHO ON
SET DEFINE ON
COLUMN fcltlogfile NEW_VALUE fcltlogfile NOPRINT;
WHENEVER SQLERROR EXIT;
SELECT adm.scriptspoolfile('&dbuser', '&thisfile') AS fcltlogfile FROM DUAL;
WHENEVER SQLERROR CONTINUE;
SPOOL &fcltlogfile
SET DEFINE OFF

------ payload begin ------

-- Soorten ruimtes:
-- OF: office floor room; geen catering, geen bezoek
-- MC: meeting center room; wel catering, wel bezoek
-- EXCO: management ruimte; wel catering, wel bezoek

-- Soorten deelnemers (zie ook AKZA#55440, door splitsing AN/Nouryon ook Nouryon mailadressen toevoegen als interne medewerkers):
-- AMS-mw: medewerkers locatie Amsterdam; zijn NOOIT een bezoeker
--         e-mail @akzonobel.com, standplaats AMB
--         e-mail @@nouryon.com, standplaats AMB
-- AN-mw/ Nouryon:  medewerkers overige AkzoNobel-locaties; zijn bezoeker, maar mogen geen parkeerplaats
--         e-mail @akzonobel.com, overige standplaatsen
--         e-mail @@nouryon.com, overige standplaatsen
-- Gast:   extern persoon; bezoeker met parkeerplaats
--         alle andere e-mailadressen

-- modifiers:
-- ADD: appointment is niew, dus ook een nieuwe reservering
-- DEL: appointment is verwijders, dus reservering annuleren
-- UPD: appointment is gewijzigd en kan daarmee effectief ook een ADD of DEL zijn

--------------------------------------------------------------------------------------------------
------------------------------- PACKAGE ----------------------------------------------------------
--------------------------------------------------------------------------------------------------
CREATE OR REPLACE PACKAGE akza_exchange
AS
   -- 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 akza_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.
   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)       :=    222;

      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);

      -- 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
            AND kw.bez_kenmerkwaarde_verwijder IS NULL
            AND NOT EXISTS (SELECT 1
                              FROM akza_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
            AND kw.bez_kenmerkwaarde_verwijder IS NULL
            AND rkw.res_kenmerk_key = 222
            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
            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 akza_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,
                   a.prs_afdeling_naam,
                   l.alg_locatie_key,
                   l.alg_locatie_code,
                   kl.prs_kenmerklink_waarde badgenr
              FROM prs_perslid p,
                   prs_v_perslid_fullnames pf,
                   (SELECT * FROM prs_kenmerklink
                     WHERE prs_kenmerk_key = 1000
                       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 IN (2, 161, 201) ) l
             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
               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 akza_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 := 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
            IF (   ( rec.alg_locatie_key IS NOT NULL AND rec.badgenr IS NOT NULL ) OR v_discipline_key = 1485
                        )
            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 := 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;
               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;
         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', 148905, 7520, 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 '%AKZONOBEL.COM') OR  ( UPPER(p_att_mail) LIKE '%NOURYON.COM') )
      THEN
         IF (v_debug) THEN
            fac.imp_writelog (p_import_key, 'D',
                              p_afspraak_key, 'AN-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     "AMB"          14465
         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, 14465);
            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     "AMB"          14465
         IF ( BITAND(v_bez_flags, 16) = 0)
         THEN
            bez.claim_parking(v_bezoekers_key, 14465);
         END IF;

         -- Mailadres opslaan
         -- bez_kenmerk    E-mail          1000
         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;
END;
/


--------------------------------------------------------------------------------------------------
------------------------------- IMPORT -----------------------------------------------------------
--------------------------------------------------------------------------------------------------

-- Met behulp van akza_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 akza_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(10);

   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 'CALITEM_'||UPPER(r.res_ruimte_extern_id)||'_%.XML';

   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 akza_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 akza_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;

   -- akza_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 akza_import_exchange;
/

CREATE OR REPLACE PROCEDURE akza_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)       :=   2;  -- "n.v.t."
   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 akza_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 akza_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 akza_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 akza_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 akza_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 akza_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 akza_imp_exchange i
      SET gelukt = 4
    WHERE endtime < SYSDATE;

   -- En res_ruimtes als deelnemers, dat kan natuurlijk niet
   UPDATE akza_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 akza_imp_exchange i
      SET gelukt = 3
    WHERE modifier IN ('D')
      AND EXISTS (SELECT 1 FROM akza_imp_exchange
                   WHERE modifier != 'D'
                     AND appt_id||'|'||recur_id = i.appt_id||'|'||i.recur_id
                     AND seq_nr > i.seq_nr);
   UPDATE akza_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 akza_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 akza_imp_exchange i
      SET gelukt = 2
    WHERE modifier IN ('C', 'U')
      AND EXISTS (SELECT 1 FROM akza_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 akza_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 akza_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 akza_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 := akza_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';
         akza_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 akza_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 := akza_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';
            akza_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 akza_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, maar alleen notificeren als niet discipline 1485
            -- AKZA#40274 ook notificeren als discipline = 1485  Mail André 6-7: voorlopig terugdraaien
            v_errorhint := 'Tracking NEW';
            v_code := 'RESNEW';
            IF (v_discipline_key = 1485)
            THEN
              v_code := '#RESNEW';
            END IF;
            fac.trackaction (v_code, v_rsv_ruimte_key, NULL, SYSDATE, 'Booking confirmation Meeting Center, 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 := '';
   akza_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 akza_update_exchange;
/

CREATE OR REPLACE PROCEDURE akza_import_exchfull (
   p_import_key IN NUMBER
)
IS
BEGIN
    akza_import_exchange(p_import_key);
END;
/

CREATE OR REPLACE PROCEDURE akza_update_exchfull (
   p_import_key IN NUMBER
)
IS
   v_errorhint VARCHAR2 (1000);
BEGIN
   akza_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 akza_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;
/

-- MS-Exchange sync-import: onthoudt de laatste syncstate van een reserveerbare ruimte
-- met betekenis: tot die markering ben ik bij.
-- (tijdelijke) versie met een CLOB voor de syncstate, omdat die in de praktijk langer
-- dan 4000 karakters blijkt te kunnen zijn. De XSL-stylesheet knipt de syncstate uit
-- de XML op in stukken van max 4000 karakters -- deze import plakt die weer aan elkaar.
CREATE OR REPLACE PROCEDURE akza_import_exchsync (p_import_key IN NUMBER)
AS
   v_newline          fac_imp_file.fac_imp_file_line%TYPE;                      -- Input line
   v_fielddelimitor   VARCHAR2 (1);
   v_errormsg         VARCHAR2 (200);
   oracle_err_mes     VARCHAR2 (200);
   header_is_valid    NUMBER;
   --
   v_res_ruimte_key   res_ruimte.res_ruimte_key%TYPE;
   v_syncstate        VARCHAR2 (4000);
   v_len              NUMBER;

   CURSOR c1
   IS
        SELECT *
          FROM fac_imp_file
         WHERE fac_import_key = p_import_key
      ORDER BY fac_imp_file_index;

   rec1               c1%ROWTYPE;
BEGIN
   v_fielddelimitor := ';';
   header_is_valid := 0;
   v_len := 0;

   -- De res_ruimte_key waar we het over hebben zit in de refkey van de import
   SELECT fac_import_refkey
     INTO v_res_ruimte_key
     FROM fac_import
    WHERE fac_import_key = p_import_key;

   -- Syncstate leegmaken, zodat we 'n append kunnen doen.
   UPDATE res_ruimte
      SET res_ruimte_syncstate = NULL
    WHERE res_ruimte_key = v_res_ruimte_key
      AND res_ruimte_extern_id IS NOT NULL;

   FOR rec1 IN c1 LOOP
      BEGIN
         v_newline := rec1.fac_imp_file_line;
         fac.imp_getfield (v_newline, v_fielddelimitor, v_syncstate);

         IF header_is_valid = 0
         THEN
            IF UPPER (TRIM (v_syncstate)) LIKE '%SYNCSTATE%'
            THEN
               header_is_valid := 1;
               --DBMS_OUTPUT.put_line ('goeie header');
            END IF;
         ELSE
            v_errormsg := 'Fout bij update van syncstate';
            --DBMS_OUTPUT.put_line ('echte data');

            -- Stylesheet knipt syncstates langer dan 4000 karakters op in meerdere delen
            -- Hier weer aan elkaar plakken.
            UPDATE res_ruimte
               SET res_ruimte_syncstate = res_ruimte_syncstate || TRIM(v_syncstate)
             WHERE res_ruimte_key = v_res_ruimte_key
               AND res_ruimte_extern_id IS NOT NULL;
         END IF;
      END;
   END LOOP;

   -- Lange syncstate? (>4000) Dat even loggen.
   v_errormsg := 'Fout bij bepalen lengte syncstate';
   SELECT LENGTH(res_ruimte_syncstate)
     INTO v_len
     FROM res_ruimte
    WHERE res_ruimte_key = v_res_ruimte_key
      AND res_ruimte_extern_id IS NOT NULL;

   IF (v_len > 4000)
   THEN
      fac.imp_writelog (p_import_key,
                        'I',
                        'Lange syncstate, ' || v_len || ' karakters',
                        'res_ruimte_key: ' || v_res_ruimte_key);
   END IF;

EXCEPTION
   WHEN OTHERS
   THEN
      oracle_err_mes := SUBSTR (SQLERRM, 1, 1000);
      v_errormsg := oracle_err_mes;
      fac.imp_writelog (p_import_key,
                        'E',
                        v_errormsg,
                        'res_ruimte_key: ' || v_res_ruimte_key);
END;
/

CREATE OR REPLACE PROCEDURE akza_update_exchsync (p_import_key IN NUMBER)
AS
BEGIN
   NULL;
END;
/

--------------------------------------------------------------------------------------------------
------------------------------- RAPPORTAGE-VIEWS -------------------------------------------------
--------------------------------------------------------------------------------------------------

-- AKZA#33693: Voor de Exchange-import worden boekers gematcht op e-mailadres. Dan zijn dubbele mailadressen
-- ongewenst. Controlerapportage (lowercase mailadres, want dat sorteert beter in de resultset).
CREATE OR REPLACE VIEW akza_v_rap_dubbele_emails
AS
   SELECT DISTINCT
          LOWER(p.prs_perslid_email) email_lower,
          pf.prs_perslid_naam_full naam,
          p.prs_perslid_key,
          p.prs_perslid_oslogin login,
          TRUNC(p.prs_perslid_aanmaak) aangemaakt,
          DECODE(i.organizer, NULL, NULL, 'Ja') in_import
     FROM (SELECT * FROM akza_imp_exchange WHERE gelukt IS NULL) i,
          prs_v_aanwezigperslid p,
          prs_v_perslid_fullnames pf
    WHERE pf.prs_perslid_key = p.prs_perslid_key
      AND EXISTS (SELECT 1 FROM prs_v_aanwezigperslid
                   WHERE UPPER(prs_perslid_email) = UPPER(p.prs_perslid_email)
                     AND prs_perslid_key != p.prs_perslid_key)
      AND UPPER(p.prs_perslid_email) = UPPER(i.organizer(+))
    ORDER BY LOWER(p.prs_perslid_email), TRUNC(p.prs_perslid_aanmaak);

-- AKZA#33693: Overzicht van alle e-mailsadressen in de Exchange-import, die niet in FACILITOR voorkomen
CREATE OR REPLACE VIEW akza_v_rap_exchange_missing
AS
   SELECT DISTINCT i.organizer
     FROM (SELECT * FROM akza_imp_exchange WHERE gelukt IS NULL) i
    WHERE NOT EXISTS (SELECT 1 FROM prs_v_aanwezigperslid p
                       WHERE UPPER(p.prs_perslid_email) = UPPER(i.organizer) );

-- AKZA#38233: Overzicht van incorrect geconfigureerde ruimtes
CREATE OR REPLACE VIEW akza_v_rap_exch_ruimte_opstel
AS
   SELECT r.res_ruimte_nr fclt_f_ruimte,
          r.res_ruimte_extern_id fclt_f_extern_id,
          r.res_ruimte_vervaldatum vervaldatum,
          d.ins_discipline_omschrijving catalogus,
          NULL schoonmaaktijd
     FROM res_ruimte r,
          res_discipline d
    WHERE r.res_ruimte_extern_id IS NOT NULL
      AND r.res_ruimte_verwijder IS NULL
      AND akza_exchange.getOpstelling(res_ruimte_extern_id) IS NULL
      AND d.ins_discipline_key = r.res_discipline_key
UNION ALL
   SELECT r.res_ruimte_nr,
          r.res_ruimte_extern_id,
          r.res_ruimte_vervaldatum,
          d.ins_discipline_omschrijving,
          dp.res_disc_params_preposttime
     FROM res_ruimte r,
          res_discipline d,
          res_disc_params dp
    WHERE r.res_ruimte_extern_id IS NOT NULL
      AND r.res_ruimte_verwijder IS NULL
      AND d.ins_discipline_key = r.res_discipline_key
      AND dp.res_ins_discipline_key = r.res_discipline_key
      AND dp.res_disc_params_preposttime != 0;

--------------------------------------------------------------------------------------------------
------------------------------- NOTIFICATIE-JOBS -------------------------------------------------
--------------------------------------------------------------------------------------------------
-- Welkomstmail naar bezoekers in AMB en SSCA (AKZA#37788)
-- Alleen versturen als we niet gisteren ook al gestuurd hebben (ivm werkdagen en weekenden/feestdagen)
CREATE OR REPLACE VIEW akza_v_noti_bezoekers
(
   sender,
   receiver,
   text,
   code,
   fac_srtnotificatie_key,
   KEY,
   xkey,
   xemail,
   xmobile,
   attachments
)
AS
   SELECT NULL sender,
          NULL receiver,
          DECODE(a.alg_locatie_key,
                 201, 'Welcome to the AkzoNobel Meeting Center Amsterdam',
                 2,   'Welcome to the AkzoNobel Shared Services Center Arnhem',
                 'Welcome to AkzoNobel') text,
          'CUST04' code,
          (SELECT fac_srtnotificatie_key
             FROM fac_srtnotificatie
            WHERE fac_srtnotificatie_code = 'CUST04') fac_srtnotificatie_key,
          b.bez_afspraak_key key,
          b.bez_bezoekers_key xkey,
          COALESCE(kw1.bez_kenmerkwaarde_waarde, kw2.bez_kenmerkwaarde_waarde) xemail,
          NULL xmobile,
             DECODE(a.alg_locatie_key,
                 201,  '../Exchange/attachement/AkzoNobel Center Amsterdam_Welcome new.pdf',
                 2,    '../Exchange/attachement/AkzoNobel Arnhem_Welcome Leaflet Guests.pdf',
                 'Welcome to AkzoNobel') attachement        
     FROM bez_afspraak a,
          bez_bezoekers b,
          (SELECT * FROM bez_kenmerkwaarde
            WHERE bez_kenmerk_key = 1000
              AND bez_kenmerkwaarde_verwijder IS NULL) kw1,
          (SELECT * FROM bez_kenmerkwaarde
            WHERE bez_kenmerk_key = 1001
              AND bez_kenmerkwaarde_verwijder IS NULL) kw2
    WHERE a.bez_afspraak_datum > SYSDATE
      AND fac.count_Work_Days(SYSDATE, a.bez_afspraak_datum) = 2
      AND fac.count_Work_Days(SYSDATE-1, a.bez_afspraak_datum) != 2
      AND a.alg_locatie_key IN (201, 2)
      AND b.bez_afspraak_key = a.bez_afspraak_key
      AND b.bez_bezoekers_key = kw1.bez_bezoekers_key(+)
      AND b.bez_bezoekers_key = kw2.bez_bezoekers_key(+)
      AND COALESCE(kw1.bez_kenmerkwaarde_waarde, kw2.bez_kenmerkwaarde_waarde) IS NOT NULL
      AND UPPER(COALESCE(kw1.bez_kenmerkwaarde_waarde, kw2.bez_kenmerkwaarde_waarde) ) NOT LIKE '%AKZONOBEL%'
      AND NOT EXISTS (SELECT 1 FROM bez_bezoekers b1, bez_afspraak a1
                       WHERE a1.bez_afspraak_datum > SYSDATE
                         AND b1.bez_afspraak_key = a1.bez_afspraak_key
                         AND b1.bez_afspraak_naam = b.bez_afspraak_naam
                         AND TRUNC(a1.bez_afspraak_datum) = TRUNC(a.bez_afspraak_datum)
                         AND TRUNC(a1.bez_afspraak_eind) = TRUNC(a.bez_afspraak_eind)
                         AND b1.bez_bezoekers_key < b.bez_bezoekers_key);

-- AKZA#38968: notificeren als check-rapportages over e-mailadressen en reserveerbare ruimtes resultaten bevatten
-- usrrap_key  724   dubbele mailadressen
-- usrrap_key  725   ontbrekende mailadressen
-- usrrap_key  904   incorrect geconfigureerde ruimtes
CREATE OR REPLACE VIEW akza_v_noti_exchange_check
(
   code,
   sender,
   receiver,
   text,
   KEY,
   xkey
)
AS
   WITH recv AS (
         SELECT 'PRSINF' code,
                NULL sender,
                prs_perslid_key receiver
           FROM fac_gebruikersgroep
          WHERE fac_groep_key = 131
            AND prs_perslid_key != 7520)
   SELECT r.code,
          r.sender,
          r.receiver,
          COUNT(*) || ' dubbele e-mailadressen in FACILITOR' text,
          NULL key,
          NULL xkey
     FROM akza_v_rap_dubbele_emails,
          recv r
    WHERE NOT (email_lower = 'piet.vandijken@akzonobel.com' AND in_import IS NULL)
    GROUP BY r.code, r.sender, r.receiver
   UNION ALL
   SELECT r.code,
          r.sender,
          r.receiver,
          COUNT(*) || ' ontbrekende e-mailadressen in FACILITOR Exchange import' text,
          NULL key,
          NULL xkey
     FROM akza_v_rap_exchange_missing,
          recv r
    GROUP BY r.code, r.sender, r.receiver
   UNION ALL
   SELECT r.code,
          r.sender,
          r.receiver,
          COUNT(*) || ' incorrect geconfigureerde ruimtes voor Exchange import in FACILITOR' text,
          NULL key,
          NULL xkey
     FROM akza_v_rap_exch_ruimte_opstel,
          recv r
    GROUP BY r.code, r.sender, r.receiver;

--------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------
------ 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
