#ifdef RES
/* RES_PAC.SRC
 *
 *   $Revision$
 *   $Id$
 */

CREATE OR REPLACE PACKAGE res AS
   FUNCTION res_copy_res (pres_key IN NUMBER,
                          newdate IN DATE,
                          puserkey NUMBER,
                          pmetbez NUMBER DEFAULT 0,
                          newreskey NUMBER DEFAULT NULL) RETURN NUMBER;
   FUNCTION res_copy_deelres (prsv_ruimte_key IN NUMBER,
                              newdate IN DATE,
                              puserkey NUMBER,
                              pmetbez NUMBER DEFAULT 1,
                              newreskey NUMBER DEFAULT NULL,
                              newvolgnr NUMBER DEFAULT NULL) RETURN NUMBER;
   PROCEDURE res_sync_deelres (prsv_ruimte_key_from IN NUMBER, prsv_ruimte_key_to IN NUMBER, flags IN NUMBER, pres_copy_to_bez IN NUMBER);
   PROCEDURE set_catalogus_approve(prsv_ruimte_key IN NUMBER, puserkey IN NUMBER);
   PROCEDURE send_need_approval_noti (prsv_ruimte_key IN NUMBER, puserkey IN NUMBER);
   PROCEDURE set_ruimte_dirty (prsv_ruimte_key IN NUMBER);
   PROCEDURE set_ruimtes_clean (checkdate IN DATE);
   PROCEDURE set_delen_dirty (prsv_ruimte_key IN NUMBER);
   PROCEDURE set_deel_dirty (prsv_deel_key IN NUMBER);
   PROCEDURE set_artikelen_dirty (prsv_ruimte_key IN NUMBER);
   PROCEDURE set_artikel_dirty (prsv_artikel_key IN NUMBER);
   FUNCTION dirty_level_all (prsv_ruimte_key IN NUMBER) RETURN NUMBER;
   PROCEDURE set_delen_clean (pdeel_key IN NUMBER, checkdate_van IN DATE, checkdate_tot IN DATE);
   PROCEDURE follow_artikel (prsv_ruimte_key IN NUMBER, oldvan IN DATE, oldtot IN DATE, check_scope IN NUMBER DEFAULT 1);
   PROCEDURE follow_deel (prsv_ruimte_key IN NUMBER, oldvan IN DATE, oldtot IN DATE);
   PROCEDURE follow_afspraak (prsv_ruimte_key IN NUMBER, pres_copy_to_bez IN NUMBER);
   FUNCTION res_deel_in_scope (pres_deel_key IN NUMBER, pres_rsv_ruimte_key IN NUMBER)  RETURN BOOLEAN;
   FUNCTION res_artikel_in_scope (pres_rsv_artikel_key IN NUMBER)  RETURN BOOLEAN;
   FUNCTION getresruimteprijs (pres_ruimte_key IN NUMBER, pvan IN DATE DEFAULT SYSDATE, ptot IN DATE DEFAULT SYSDATE, pextern IN NUMBER DEFAULT 0) RETURN NUMBER;
   FUNCTION getruimteprijs (pres_rsv_ruimte_key IN NUMBER, ignoretotaal IN NUMBER DEFAULT NULL)  RETURN NUMBER;
   FUNCTION getdeelprijs (pres_rsv_deel_key IN NUMBER)  RETURN NUMBER;
   FUNCTION getartikelprijs (pres_rsv_artikel_key IN NUMBER)  RETURN NUMBER;
   FUNCTION getdeelresprijs (pres_rsv_ruimte_key IN NUMBER)  RETURN NUMBER;
   FUNCTION sprintf (ps IN VARCHAR2 , pres_rsv_ruimte_key IN NUMBER) RETURN VARCHAR2;
   FUNCTION notifypool (pbez_bezoeker_key IN NUMBER, pcode IN VARCHAR2) RETURN NUMBER;
   PROCEDURE notifybackoffice (prsvkey IN NUMBER, pcode IN VARCHAR2, ptype IN VARCHAR2 DEFAULT NULL, pkey IN NUMBER DEFAULT NULL);
   PROCEDURE remove(p_rsv_ruimte_key IN NUMBER);
END res;
/

CREATE OR REPLACE PACKAGE BODY res
AS
   FUNCTION res_copy_res (pres_key IN NUMBER,
                          newdate IN DATE,
                          puserkey NUMBER,
                          pmetbez NUMBER DEFAULT 0,
                          newreskey NUMBER DEFAULT NULL) RETURN NUMBER
   AS
      nextkey res_reservering.res_reservering_key%TYPE;
      rsv_key res_rsv_ruimte.res_rsv_ruimte_key%TYPE;
      newvolgnr res_rsv_ruimte.res_rsv_ruimte_volgnr%TYPE;
   BEGIN
      IF newreskey IS NOT NULL
      THEN
         nextkey := newreskey;
      ELSE
         SELECT res_s_res_reservering_key.NEXTVAL INTO nextkey FROM DUAL;
         INSERT INTO res_reservering (res_reservering_key, res_reservering_ispool)
              SELECT nextkey, res_reservering_ispool
                FROM res_reservering
               WHERE res_reservering_key = pres_key;
      END IF;

      newvolgnr := 1;
      FOR prsv_ruimte
      IN (SELECT   res_rsv_ruimte_key
            FROM   res_v_aanwezigrsv_ruimte
           WHERE   res_reservering_key = pres_key)
      LOOP
         rsv_key := res.res_copy_deelres (prsv_ruimte.res_rsv_ruimte_key, newdate, puserkey, pmetbez, nextkey, newvolgnr);
         res.set_catalogus_approve(rsv_key, puserkey);
         newvolgnr := newvolgnr + 1;
      END LOOP;
     RETURN nextkey;
   END;

   FUNCTION res_copy_deelres (prsv_ruimte_key IN NUMBER,
                              newdate IN DATE,
                              puserkey NUMBER,
                              pmetbez NUMBER DEFAULT 1,
                              newreskey NUMBER DEFAULT NULL,
                              newvolgnr NUMBER DEFAULT NULL) RETURN NUMBER
   AS
      nextvolg res_rsv_ruimte.res_rsv_ruimte_volgnr%TYPE;
      nextkey res_rsv_ruimte.res_rsv_ruimte_key%TYPE;
      destatus res_rsv_ruimte.res_status_bo_key%TYPE;
      fo_status res_rsv_ruimte.res_status_fo_key%TYPE;
      fo_status_res res_rsv_ruimte.res_status_fo_key%TYPE;
   BEGIN
      SELECT   res_s_res_rsv_ruimte_key.NEXTVAL INTO nextkey FROM DUAL;
      SELECT   MAX (a.res_rsv_ruimte_volgnr) + 1, MAX(a.res_status_bo_key)
        INTO   nextvolg, destatus
        FROM   res_rsv_ruimte a, res_rsv_ruimte b
       WHERE   a.res_reservering_key = b.res_reservering_key AND b.res_rsv_ruimte_key = prsv_ruimte_key;
      -- De status is NULL (als opstelkey leeg is, dus CV-reserveringen) of iets.
      -- Als het iets is, dan wordt de status van de kopie 2 (=nieuw)
      IF destatus IS NOT NULL THEN
        destatus :=  2;
      END IF;

      -- Als de fo status van de res_ruimte NULL is of het is geen ruimtereservering,
      -- neem dan de waarde van de setting "res_default_fo_status_key".
      SELECT COALESCE(rr.res_status_fo_key, fac.safe_to_number (fac.getsetting ('res_default_fo_status_key')))
           , rrr.res_status_fo_key
        INTO fo_status
           , fo_status_res
        FROM res_rsv_ruimte rrr,
             res_ruimte_opstelling rro,
             res_ruimte rr
       WHERE rrr.res_ruimte_opstel_key = rro.res_ruimte_opstel_key(+)
         AND rro.res_ruimte_key = rr.res_ruimte_key(+)
         AND rrr.res_rsv_ruimte_key = prsv_ruimte_key;

      -- Als status van rsv_ruimte =3 (Blokkade) dan deze overnemen.
      IF (fo_status_res = 3) THEN
         fo_status := 3;
      END IF;

      INSERT INTO res_rsv_ruimte (res_rsv_ruimte_key,
                                  res_reservering_key,
                                  res_rsv_ruimte_volgnr,
                                  res_rsv_ruimte_omschrijving,
                                  res_rsv_ruimte_opmerking,
                                  alg_ruimte_key,
                                  res_ruimte_opstel_key,
                                  mld_opdr_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_status_bo_key,
                                  res_rsv_ruimte_kosten_klant,
                                  res_rsv_ruimte_contact_key,
                                  res_rsv_ruimte_bezoekers,
                                  res_rsv_ruimte_cvab_mode,
                                  res_rsv_ruimte_telefoon,
                                  res_rsv_ruimte_extern_meeting
                                 )
         SELECT   nextkey,
                  COALESCE(newreskey, res_reservering_key),
                  COALESCE(newvolgnr, nextvolg),
                  res_rsv_ruimte_omschrijving,
                  res_rsv_ruimte_opmerking,
                  alg_ruimte_key,
                  res_ruimte_opstel_key,
                  mld_opdr_key,
                  newdate + (res_rsv_ruimte_van - TRUNC (res_rsv_ruimte_van)),
                  newdate + (res_rsv_ruimte_tot - TRUNC (res_rsv_ruimte_van)),
                  prs_kostenplaats_key,
                  res_rsv_ruimte_host_key,
                  res_activiteit_key,
                  fo_status,
                  destatus,
                  res_rsv_ruimte_kosten_klant,
                  res_rsv_ruimte_contact_key,
                  res_rsv_ruimte_bezoekers,
                  res_rsv_ruimte_cvab_mode,
                  res_rsv_ruimte_telefoon,
                  res_rsv_ruimte_extern_meeting
           FROM   res_rsv_ruimte
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key;
      -- Now make the copy have the same childeren as the original
      -- (all main data is already uptodate)
      res.res_sync_deelres (prsv_ruimte_key, nextkey, 128 + 256 + pmetbez*512 + 1024, 0);
      -- Het hekje voorkomt individuele notificaties
      fac.trackaction ('#RESNEW', nextkey, puserkey, NULL, NULL);
      RETURN nextkey;
   END;

   PROCEDURE res_sync_deelres (prsv_ruimte_key_from IN NUMBER, prsv_ruimte_key_to IN NUMBER, flags IN NUMBER, pres_copy_to_bez IN NUMBER)
   AS
      --flags (0-131071)
      -- 0 Niks
      -- 1 Omschrijving
      -- 2 Opmerking
      -- 4 Tijdstip  (impliceert deels impact op 128, 256 en 512)
      -- 2048 Datum
      -- 8 Aantal personen
      -- 16 Ruimte/opstelling
      -- 32 Gastheer
      -- 64 Kostenplaats
      -- 128 Voorzieningen (delen)
      -- 256 Catering (artikelen)
      -- 512 Bezoekers
      -- 1024 Flexkenmerken
      -- 2048 Datum
      -- 4096 Naam
      -- 8192 Reserveringsstatus
      -- 16384 Afgesproken ruimteprijs
      -- 32768 Korting
      -- 65536 Flags (bolletjes)
      -- Neem van alles (afh. flags) van prsv_ruimte_key_from over naar prsv_ruimte_key_to
      -- Misschien inzetbaar bij follow_artikel met  prsv_ruimte_key_from==prsv_ruimte_key_to
      -- Bepaal de rsv_ruimte van dezelfde reservering die verder in de toekomst liggen
      -- dan de meegegeven rsv_ruimte
      rsv_from res_rsv_ruimte%ROWTYPE;
      rsv_to res_rsv_ruimte%ROWTYPE;
      new_ruimte_van DATE;
      new_ruimte_tot DATE;
      bez_parkingdiscipline_key NUMBER;
   BEGIN
      SELECT   *
        INTO   rsv_from
        FROM   res_rsv_ruimte rr
       WHERE   rr.res_rsv_ruimte_key = prsv_ruimte_key_from;
      SELECT   *
        INTO   rsv_to
        FROM   res_rsv_ruimte rr
       WHERE   rr.res_rsv_ruimte_key = prsv_ruimte_key_to;
      -- 0 Niks
      IF BITAND (flags, 131071) = 0
      THEN
         RETURN;
      END IF;
      -- Als de tijd moet worden genegeerd, dan is de nieuwe tijd dus ook de oude,
      -- anders bepaal ik het nieuwe tijdstip
      IF BITAND (flags, 4) = 4
      THEN
         -- De tijd moet worden aangepast. De datum verandert hier niet
         -- De kopie moet hier net zo laat op Die datum plaatsvinden als het origineel
         -- Bepaling van-tijd en tot-tijd in Oracle-decimaal (12 uur middag is 0,5)
         new_ruimte_van := -- orginele datum + nieuwe tijdstip
            TRUNC (rsv_to.res_rsv_ruimte_van) + (rsv_from.res_rsv_ruimte_van - TRUNC (rsv_from.res_rsv_ruimte_van));
         new_ruimte_tot :=
            TRUNC (rsv_to.res_rsv_ruimte_tot) + (rsv_from.res_rsv_ruimte_tot - TRUNC (rsv_from.res_rsv_ruimte_tot));
      ELSE
         new_ruimte_van :=  rsv_to.res_rsv_ruimte_van;
         new_ruimte_tot :=  rsv_to.res_rsv_ruimte_tot;
      END IF;
      -- vars new_ruimte_van en new_ruimte_tot zijn nu gezet
      IF BITAND (flags, 2048) = 2048
      THEN
         -- De datum moet worden aangepast. De tijd verandert hier niet
         -- new_ruimte_van/tot = nieuwe datum + orginele tijdstip
         new_ruimte_van := TRUNC (rsv_from.res_rsv_ruimte_van) + (new_ruimte_van - TRUNC (new_ruimte_van));
         new_ruimte_tot := TRUNC (rsv_from.res_rsv_ruimte_tot) + (new_ruimte_tot - TRUNC (new_ruimte_tot));
      END IF;
      --
      -- Nu alle velden een voor een updaten
      --
      -- 1 Omschrijving
      IF BITAND (flags, 1) = 1
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_omschrijving = rsv_from.res_rsv_ruimte_omschrijving
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 2 Opmerking
      IF BITAND (flags, 2) = 2
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_opmerking = rsv_from.res_rsv_ruimte_opmerking
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 4 Tijdstip 2048 datum
      IF BITAND (flags, 4) = 4 OR BITAND (flags, 2048) = 2048
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_van = new_ruimte_van, res_rsv_ruimte_tot = new_ruimte_tot
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
          res.set_ruimtes_clean(rsv_to.res_rsv_ruimte_van);
          res.follow_deel(prsv_ruimte_key_to, rsv_to.res_rsv_ruimte_van, rsv_to.res_rsv_ruimte_tot);
          res.follow_artikel(prsv_ruimte_key_to, rsv_to.res_rsv_ruimte_van, rsv_to.res_rsv_ruimte_tot);
          res.follow_afspraak(prsv_ruimte_key_to, 0);  -- Opmerking en flex eventueel aan het eind aanpassen. Hier nog niet.
      END IF;
      -- 8 Aantal personen
      IF BITAND (flags, 8) = 8
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_bezoekers = rsv_from.res_rsv_ruimte_bezoekers
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 16 Ruimte+opstelling (niet: alleen opstelling)
      IF BITAND (flags, 16) = 16
      THEN
         -- Dit is iets ingewikkelder: als de ruimte anders is, is de opstelkey ook anders
         -- Zoek dan de equivalente opstelling en gebruik dan die key
         -- en/of algruimte?
         -- TODO
         UPDATE   res_rsv_ruimte
            SET   res_ruimte_opstel_key = rsv_from.res_ruimte_opstel_key, alg_ruimte_key = rsv_from.alg_ruimte_key
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
          res.set_ruimtes_clean(rsv_from.res_rsv_ruimte_van);
      END IF;
      -- 32 Gastheer
      IF BITAND (flags, 32) = 32
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_host_key = rsv_from.res_rsv_ruimte_host_key
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 64 Kostenplaats
      IF BITAND (flags, 64) = 64
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_kosten_klant = rsv_from.res_rsv_ruimte_kosten_klant,
                  prs_kostenplaats_key = rsv_from.prs_kostenplaats_key,
                  res_rsv_ruimte_ordernr = rsv_from.res_rsv_ruimte_ordernr
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 4096 Naam
      IF BITAND (flags, 4096) = 4096
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_contact_key = rsv_from.res_rsv_ruimte_contact_key
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 8192 Reserveringsstatus
      IF BITAND (flags, 8192) = 8192
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_status_fo_key = rsv_from.res_status_fo_key
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 16384 Afgesproken ruimteprijs
      IF BITAND (flags, 16384) = 16384
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_totaal = rsv_from.res_rsv_ruimte_totaal
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 32768 Korting
      IF BITAND (flags, 32768) = 32768
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_korting = rsv_from.res_rsv_ruimte_korting
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 65536 Flags (bolletjes)
      IF BITAND (flags, 65536) = 65536
      THEN
         UPDATE   res_rsv_ruimte
            SET   res_rsv_ruimte_flag = rsv_from.res_rsv_ruimte_flag
          WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- 128 Voorzieningen (delen)
      IF BITAND (flags, 128) = 128
      THEN
         bez_parkingdiscipline_key :=  fac.safe_to_number (fac.getsetting ('vis_parking_key'));
         -- Verwijder de huidige artikelen voor de te wijzigen rsv_ruimte
         DELETE FROM   res_rsv_deel
               WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to
                 AND   res_deel_key not in (select res_deel_key from res_deel where res_discipline_key = bez_parkingdiscipline_key); -- die komen straks wel
         -- Kopieer de delen van referentie ruimte, hanteer dezelfde tijd-offset tov de ruimte als bij het origineel
         BEGIN
            INSERT INTO res_rsv_deel (res_deel_key, res_rsv_deel_aantal, res_rsv_ruimte_key, res_rsv_deel_prijs, res_status_bo_key, res_rsv_deel_van, res_rsv_deel_tot
                                     )
               SELECT   ra.res_deel_key,
                        ra.res_rsv_deel_aantal,
                        prsv_ruimte_key_to,
                        ra.res_rsv_deel_prijs,
                        2,                                                                                  -- ingevoerd
                        TRUNC (rsv_to.res_rsv_ruimte_van) + (ra.res_rsv_deel_van - TRUNC (rsv_from.res_rsv_ruimte_van)),
                        TRUNC (rsv_to.res_rsv_ruimte_van) + (ra.res_rsv_deel_tot - TRUNC (rsv_from.res_rsv_ruimte_tot))
                 FROM   res_rsv_deel ra, res_deel rd
                WHERE   ra.res_rsv_ruimte_key = prsv_ruimte_key_from
                  AND   ra.res_deel_key = rd.res_deel_key
                  AND   rd.res_discipline_key <> bez_parkingdiscipline_key; -- die komen straks wel
         END;
      END IF;
      -- 256 Catering (artikelen)
      IF BITAND (flags, 256) = 256
      THEN
         -- Verwijder de huidige artikelen voor de te wijzigen rsv_ruimte
         DELETE FROM   res_rsv_artikel
               WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to;
         -- Als nieuwe leveringstijd tussen ruimte_van en ruimte_tot tijden ligt dan leveringstijd nemen,
         -- anders rsv_ruimte_van tijd
         -- Kopieer de artikelen van referentie ruimte
         BEGIN
            -- behoud de oorspronkelijke artikeltijd indien deze binnen de deelreserveringstijd valt
            INSERT INTO res_rsv_artikel (res_artikel_key, res_rsv_artikel_aantal, res_rsv_ruimte_key, res_rsv_artikel_prijs, res_rsv_artikel_levering, res_rsv_artikel_afhalen
                                        )
               SELECT   ra.res_artikel_key,
                        ra.res_rsv_artikel_aantal,
                        prsv_ruimte_key_to,
                        ra.res_rsv_artikel_prijs,
                        TRUNC (rsv_to.res_rsv_ruimte_van)
                        + (ra.res_rsv_artikel_levering - TRUNC (ra.res_rsv_artikel_levering)),
                        ra.res_rsv_artikel_afhalen
                 FROM   res_rsv_artikel ra
                WHERE   TRUNC (rsv_to.res_rsv_ruimte_van)
                        + (ra.res_rsv_artikel_levering - TRUNC (ra.res_rsv_artikel_levering)) BETWEEN new_ruimte_van
                                                                                                  AND  new_ruimte_tot
                        AND ra.res_rsv_ruimte_key = prsv_ruimte_key_from;
            -- of reset de oorspronkelijke artikeltijd naar begin van deelreservering indien deze buiten de deelreserveringstijd valt
            INSERT INTO res_rsv_artikel (res_artikel_key, res_rsv_artikel_aantal, res_rsv_ruimte_key, res_rsv_artikel_prijs, res_rsv_artikel_levering
                                        )
               SELECT   ra.res_artikel_key,
                        ra.res_rsv_artikel_aantal,
                        prsv_ruimte_key_to,
                        ra.res_rsv_artikel_prijs,
                        new_ruimte_van
                 FROM   res_rsv_artikel ra
                WHERE   NOT TRUNC (rsv_to.res_rsv_ruimte_van)
                            + (ra.res_rsv_artikel_levering - TRUNC (ra.res_rsv_artikel_levering)) BETWEEN new_ruimte_van AND  new_ruimte_tot
                        AND ra.res_rsv_ruimte_key = prsv_ruimte_key_from;
         END;
         -- Kenmerken ook kopieren.
         IF BITAND (flags, 1024) = 1024
         THEN
            -- Verwijder eerst de oude niet-file kenmerken
            -- Artikel kenmerken.
            DELETE FROM   res_kenmerkartikel
                  WHERE   res_rsv_artikel_key IN (SELECT res_rsv_artikel_key
                                                    FROM res_rsv_artikel
                                                   WHERE res_rsv_ruimte_key = prsv_ruimte_key_to)
                    AND   res_kenmerk_key IN
                              (SELECT k.res_kenmerk_key
                                 FROM res_kenmerkartikel w,
                                      res_kenmerk k,
                                      res_srtkenmerk sk
                                WHERE w.res_kenmerk_key = k.res_kenmerk_key
                                  AND k.res_srtkenmerk_key = sk.res_srtkenmerk_key
                                  AND w.res_rsv_artikel_key IN (SELECT res_rsv_artikel_key
                                                                  FROM res_rsv_artikel
                                                                 WHERE res_rsv_ruimte_key = prsv_ruimte_key_to)
                                  AND sk.res_srtkenmerk_kenmerktype NOT IN ('F', 'M', 'E'));
            --
            -- Artikel kenmerken.
            -- Artikel is al toegevoegd indien catering is aangevinkt.
            -- De kenmerken van de oude en nieuwe reserveringen zijn exact hetzelfde met dezelfde kenmerk keys enz.
            -- De kenmerken van de oude en nieuwe reservering in dezelfde volgorde zetten en dan de waarden overnemen.
            INSERT INTO res_kenmerkartikel (res_rsv_artikel_key,
                                            res_kenmerk_key,
                                            res_kenmerkartikel_waarde)
                 SELECT newkenmerk.res_rsv_artikel_key,
                        newkenmerk.res_kenmerk_key,
                        oldkenmerk.res_kenmerkartikel_waarde
                   FROM (SELECT ka.res_rsv_artikel_key,
                                ka.res_kenmerk_key,
                                ka.res_kenmerkartikel_waarde,
                                ra.res_artikel_key,
                                ROW_NUMBER()
                                    OVER(ORDER BY
                                             rra.res_rsv_artikel_key,
                                             k.res_kenmerk_key)
                                    AS RN
                           FROM res_kenmerkartikel ka,
                                res_kenmerk k,
                                res_srtkenmerk sk,
                                res_rsv_ruimte rr,
                                res_rsv_artikel rra,
                                res_artikel ra
                          WHERE ka.res_kenmerk_key = k.res_kenmerk_key
                            AND k.res_srtkenmerk_key = sk.res_srtkenmerk_key
                            AND (k.res_artikel_key = rra.res_artikel_key
                              OR k.res_discipline_key = ra.res_discipline_key)
                            AND ra.res_artikel_key = rra.res_artikel_key
                            AND ka.res_rsv_artikel_key = rra.res_rsv_artikel_key
                            AND rra.res_rsv_ruimte_key = rr.res_rsv_ruimte_key
                            --AND k.res_activiteit_key IS NULL      -- Niet nodig: Als res_activiteit_key gevuld is dan is res_kenmerk_niveau 'A'.
                            AND k.res_kenmerk_niveau IN ('C', 'D')
                            AND k.res_kenmerk_volgnummer < 900
                            AND k.res_kenmerk_verwijder IS NULL
                            AND ka.res_kenmerkartikel_verwijder IS NULL
                            AND sk.res_srtkenmerk_kenmerktype NOT IN ('F', 'M', 'E')
                            AND rr.res_rsv_ruimte_key = prsv_ruimte_key_from) oldkenmerk,
                        (SELECT rra.res_rsv_artikel_key,
                                k.res_kenmerk_key,
                                ra.res_artikel_key,
                                ROW_NUMBER()
                                    OVER(ORDER BY
                                             rra.res_rsv_artikel_key,
                                             k.res_kenmerk_key)
                                    AS rn
                           FROM res_rsv_ruimte rr,
                                res_rsv_artikel rra,
                                res_artikel ra,
                                res_kenmerk k
                          WHERE rra.res_rsv_ruimte_key = rr.res_rsv_ruimte_key
                            AND (k.res_artikel_key = rra.res_artikel_key
                              OR k.res_discipline_key = ra.res_discipline_key)
                            AND ra.res_artikel_key = rra.res_artikel_key
                            AND rr.res_rsv_ruimte_key = prsv_ruimte_key_to) newkenmerk
                  WHERE oldkenmerk.rn = newkenmerk.rn
                    AND oldkenmerk.res_kenmerk_key = newkenmerk.res_kenmerk_key
                    AND oldkenmerk.res_artikel_key = newkenmerk.res_artikel_key
                  ORDER BY newkenmerk.res_rsv_artikel_key,
                           newkenmerk.res_kenmerk_key;
         END IF;
      END IF;
      -- 512 Bezoekers
      IF BITAND (flags, 512) = 512
      THEN
         bez.sync_resafspraak (prsv_ruimte_key_from, prsv_ruimte_key_to);
      END IF;
      -- flexkenmerken
      -- Bestandskenmerken worden NIET gesynchroniseerd, by design
      -- Zou meekopieren van de bestanden via het OS vereisen, en we
      -- achten de wenselijkheid zeldzaam
      IF BITAND (flags, 1024) = 1024
      THEN
         -- Verwijder eerst de oude niet-file kenmerken
         -- Ruimte kenmerken.
         DELETE FROM   res_kenmerkwaarde
               WHERE   res_rsv_ruimte_key = prsv_ruimte_key_to
                 AND   res_kenmerk_key IN
                           (SELECT k.res_kenmerk_key
                              FROM res_kenmerkwaarde w, res_kenmerk k, res_srtkenmerk sk
                             WHERE w.res_kenmerk_key = k.res_kenmerk_key
                               AND k.res_srtkenmerk_key = sk.res_srtkenmerk_key
                               AND w.res_rsv_ruimte_key = prsv_ruimte_key_to
                               AND sk.res_srtkenmerk_kenmerktype NOT IN ('F', 'M', 'E'));
         --
         -- Ruimte kenmerken.
         INSERT INTO res_kenmerkwaarde (res_rsv_ruimte_key, res_kenmerk_key, res_kenmerkreservering_waarde)
             SELECT prsv_ruimte_key_to
                  , k.res_kenmerk_key
                  , waarde_from.res_kenmerkreservering_waarde
               FROM res_kenmerk k
                  , res_srtkenmerk s
                  , res_rsv_ruimte r
                  , ( SELECT w1.res_kenmerkreservering_waarde
                           , k1.res_kenmerk_groep
                           , k1.res_srtkenmerk_key
                           , k1.res_activiteit_key
                           , k1.res_kenmerk_key
                           , k1.res_kenmerk_omschrijving
                           , s1.res_srtkenmerk_omschrijving
                        FROM res_kenmerkwaarde w1
                           , res_kenmerk k1
                           , res_srtkenmerk s1
                           , res_rsv_ruimte r1
                       WHERE w1.res_kenmerk_key = k1.res_kenmerk_key
                         AND k1.res_srtkenmerk_key = s1.res_srtkenmerk_key
                         AND k1.res_activiteit_key = r1.res_activiteit_key
                         AND k1.res_artikel_key IS NULL
                         AND w1.res_rsv_ruimte_key = r1.res_rsv_ruimte_key
                         AND w1.res_kenmerkwaarde_verwijder IS NULL
                         AND s1.res_srtkenmerk_kenmerktype NOT IN ('F', 'M', 'E')
                         AND r1.res_rsv_ruimte_key = prsv_ruimte_key_from
                    ) waarde_from
              WHERE k.res_activiteit_key = r.res_activiteit_key
                AND k.res_kenmerk_niveau = 'A'
                AND k.res_kenmerk_volgnummer < 900
                AND k.res_kenmerk_verwijder IS NULL
                AND s.res_srtkenmerk_verwijder IS NULL
                AND k.res_srtkenmerk_key = s.res_srtkenmerk_key
                AND s.res_srtkenmerk_kenmerktype NOT IN ('F', 'M', 'E')
                AND waarde_from.res_srtkenmerk_key = k.res_srtkenmerk_key
                AND COALESCE(waarde_from.res_kenmerk_omschrijving, waarde_from.res_srtkenmerk_omschrijving) = COALESCE(k.res_kenmerk_omschrijving, s.res_srtkenmerk_omschrijving)
                AND waarde_from.res_kenmerk_groep = k.res_kenmerk_groep
                AND r.res_rsv_ruimte_key = prsv_ruimte_key_to;
      END IF;
      -- Opmerking en/of Flexkenmerken (2 en/of 1024) aanpassen als de setting "res_copy_to_bez" dit aangeeft
      IF (BITAND (flags, 2) = 2 OR BITAND (flags, 1024) = 1024) AND BITAND(pres_copy_to_bez, 4) = 4
      THEN
         res.follow_afspraak(prsv_ruimte_key_to, pres_copy_to_bez);  -- Opmerking en/of flexkenmerken van de afspraak aanpassen.
      END IF;
      -- and verify the validity
      res.set_ruimte_dirty (prsv_ruimte_key_to);
      res.set_delen_dirty (prsv_ruimte_key_to);
      res.set_artikelen_dirty (prsv_ruimte_key_to);
   END;
   -- Er moet aangegeven worden of de artikelregels gefiatteerd dienen te worden of direct goedgekeurd kunnen worden.
   PROCEDURE set_catalogus_approve (prsv_ruimte_key IN NUMBER, puserkey IN NUMBER)
   AS
      hastoapprove        NUMBER := 0;
      -- Voor elke artikelregel het totaalbedrag en drempelbedrag van zijn catalogus opleveren.
      CURSOR prsv_artikel_cat_appr
      IS
         SELECT (  SELECT SUM(res.getartikelprijs(rra1.res_rsv_artikel_key)) sum_cat_artprijs
                     FROM res_rsv_artikel rra1,
                          res_artikel ra1
                    WHERE rra1.res_artikel_key = ra1.res_artikel_key
                      AND rra1.res_rsv_artikel_dirtlevel = 0
                      AND rra1.res_rsv_ruimte_key = rra.res_rsv_ruimte_key
                      AND ra1.res_discipline_key = ra.res_discipline_key
                 GROUP BY ra1.res_discipline_key) sum_cat_artprijs,
                rdp.res_disc_params_threshold
           FROM res_rsv_artikel rra,
                res_artikel ra,
                res_v_aanwezigdiscipline rd,
                res_disc_params rdp
          WHERE rra.res_artikel_key = ra.res_artikel_key
            AND ra.res_discipline_key = rd.ins_discipline_key
            AND rd.ins_discipline_key = rdp.res_ins_discipline_key
            AND rra.res_rsv_ruimte_key = prsv_ruimte_key;
   BEGIN
      FOR prsv_art_cat_appr IN prsv_artikel_cat_appr
      LOOP
         -- Voor elke artikelregel bepalen of deze nog gefiatteerd dient te worden of dat de artikelregel direct goedgekeurd kan worden.
         IF hastoapprove = 0 AND prsv_art_cat_appr.sum_cat_artprijs > prsv_art_cat_appr.res_disc_params_threshold
         THEN
           hastoapprove := 1;
         END IF;
      END LOOP;
      -- De res_rsv_artikel_approved velden aanpassen. De default waarde is 1.
      -- Rsv artikel setting res_rsv_artikel_approved: De artikelregel is 0=Niet gefiatteerd, 1=Goedgekeurd (default), 2=Afgewezen.
      UPDATE res_rsv_artikel
         SET res_rsv_artikel_approved = CASE
                                        WHEN hastoapprove = 1
                                        THEN 0
                                        ELSE 1
                                        END
       WHERE res_rsv_ruimte_key = prsv_ruimte_key;
      -- Het res_rsv_ruimte_cat_appr veld aanpassen.
      -- Er moet worden gefiatteerd als hastoapprove true is. Er zijn dan catalogussen met een totaal bestelbedrag die boven de drempelwaarde ligt.
      -- Catalogus setting res_rsv_ruimte_cat_appr: Artikelregels wel of niet fiatteren {0=Nee of 1=Ja}.
      UPDATE res_rsv_ruimte
         SET res_rsv_ruimte_cat_appr = CASE
                                       WHEN hastoapprove = 1
                                       THEN 1
                                       ELSE 0
                                       END
       WHERE res_rsv_ruimte_key = prsv_ruimte_key;
      IF hastoapprove = 1
      THEN
         res.send_need_approval_noti(prsv_ruimte_key, puserkey);
      END IF;
   END;

   -- Kopie van res.sendNeedApprovalNotification()
   PROCEDURE send_need_approval_noti (prsv_ruimte_key IN NUMBER, puserkey IN NUMBER)
   AS
      lapprover_key                 prs_kostenplaats.prs_perslid_key%TYPE;
      lres_ruimte_opstel_key        res_ruimte_opstelling.res_ruimte_opstel_key%TYPE;
      lres_reservering_key          res_reservering.res_reservering_key%TYPE;
      lalg_ruimte_key               alg_ruimte.alg_ruimte_key%TYPE;
      lsender                       alg_locatie.alg_locatie_email%TYPE;
      lomsfia                       fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      lreceiver                     VARCHAR2(1000);
      ltracking                     VARCHAR2(4000);  -- moet tijdelijk groter dan fac_srtnotificatie.fac_srtnotificatie_oms%TYPE kunnen zijn
   BEGIN

      BEGIN
         SELECT k.prs_perslid_key
           INTO lapprover_key
           FROM res_rsv_ruimte rr,
                prs_kostenplaats k
          WHERE rr.prs_kostenplaats_key = k.prs_kostenplaats_key
            AND rr.res_rsv_ruimte_key = prsv_ruimte_key;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            -- Er is geen fiatteur
            RETURN;
      END;

      IF lapprover_key < 0 OR prsv_ruimte_key < 0
      THEN
         RETURN;
      END IF;

      SELECT res_ruimte_opstel_key,
             res_reservering_key,
             alg_ruimte_key
        INTO lres_ruimte_opstel_key,
             lres_reservering_key,
             lalg_ruimte_key
        FROM res_rsv_ruimte
       WHERE res_rsv_ruimte_key = prsv_ruimte_key;

      IF lres_ruimte_opstel_key IS NOT NULL AND lres_ruimte_opstel_key > 0
      THEN
         SELECT MAX(l.alg_locatie_email)
           INTO lsender
           FROM res_ruimte_opstelling ro
              , res_ruimte rr
              , res_alg_ruimte rag
              , alg_ruimte r
              , alg_verdieping v
              , alg_gebouw g
              , alg_locatie l
          WHERE l.alg_locatie_key = g.alg_locatie_key
            AND g.alg_gebouw_key = v.alg_gebouw_key
            AND r.alg_verdieping_key = v.alg_verdieping_key
            AND r.alg_ruimte_key = rag.alg_ruimte_key
            AND rag.res_ruimte_key = rr.res_ruimte_key
            AND rr.res_ruimte_key = ro.res_ruimte_key
            AND ro.res_ruimte_opstel_key = lres_ruimte_opstel_key;
      ELSIF lalg_ruimte_key IS NOT NULL AND lalg_ruimte_key > 0
      THEN
         SELECT MAX(l.alg_locatie_email)
           INTO lsender
           FROM alg_ruimte r
              , alg_verdieping v
              , alg_gebouw g
              , alg_locatie l
          WHERE l.alg_locatie_key = g.alg_locatie_key
            AND g.alg_gebouw_key = v.alg_gebouw_key
            AND r.alg_verdieping_key = v.alg_verdieping_key
            AND r.alg_ruimte_key = lalg_ruimte_key;
      END IF;

      SELECT lcl.x('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms)
        INTO lomsfia
        FROM fac_srtnotificatie
       WHERE fac_srtnotificatie_code = 'RESFIA';

      -- Notificatie en tracking: Reservering ##KEY## (##DESC##) is ter fiattering aangeboden aan ##FIATTEUR##.
      fac.putnotificationsrtprio (NULL,
                                  lapprover_key,
                                  'RESFIA',
                                  lres_reservering_key,
                                  res.sprintf(lomsfia, prsv_ruimte_key),
                                  NULL,
                                  NULL,
                                  NULL,
                                  prsv_ruimte_key,
                                  2,
                                  lsender
                                 );

      SELECT prs_perslid_naam_full
        INTO lreceiver
        FROM prs_v_perslid_fullnames_all
       WHERE prs_perslid_key = lapprover_key;

      -- ltracking := 'Notitificatie ''{0}'' verstuurd aan {1}';
      ltracking := lcl.l('lcl_res_notification_sent_to');
      ltracking := REPLACE (ltracking, '{0}', 'RESFIA');
      ltracking := REPLACE (ltracking, '{1}', lreceiver);

      fac.trackaction ('RESFIA', prsv_ruimte_key, puserkey, NULL, SUBSTR(ltracking, 1, 2048));  -- maxlengte van fac_srtnotificatie_oms
   END;

   -- Moeten wijzelf misschien dirty worden (door overlap met anderen)
   -- of schoon worden
   PROCEDURE set_ruimte_dirty (prsv_ruimte_key IN NUMBER)
   AS
      preposttime       NUMBER(5,4); -- we gaan nog delen door 24, res_disc_params.res_disc_params_preposttime%TYPE is dan te klein;
      ruimte_blok_van   NUMBER(5,4);
      ruimte_blok_tot   NUMBER(5,4);
      my_res_ruimte_key res_ruimte.res_ruimte_key%TYPE;
      n_overlap         NUMBER (10);
      CURSOR prsv_ruimtecur
      IS
             SELECT   rr.alg_ruimte_key,
                      rr.res_ruimte_opstel_key,
                      rr.mld_opdr_key,
                      ro.res_ruimte_opstel_tijd,
                      rr.res_status_fo_key,
                      rr.res_rsv_ruimte_van,
                      rr.res_rsv_ruimte_tot,
                      ra.res_activiteit_posttime
               FROM   res_rsv_ruimte rr,
                      res_activiteit ra,
                      res_ruimte_opstelling ro
              WHERE   rr.res_rsv_ruimte_key = prsv_ruimte_key
                AND   rr.res_activiteit_key = ra.res_activiteit_key
                AND   rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key(+)
         FOR UPDATE   OF res_rsv_ruimte_dirtlevel;
      prsv_ruimte prsv_ruimtecur%ROWTYPE;
   BEGIN
      DBMS_OUTPUT.PUT_LINE('set_ruimte_dirty ' || prsv_ruimte_key);
      OPEN prsv_ruimtecur;
      FETCH prsv_ruimtecur INTO   prsv_ruimte;
      IF prsv_ruimte.alg_ruimte_key IS NOT NULL OR prsv_ruimte.mld_opdr_key IS NOT NULL
      THEN
         NULL; -- CV reserveringen en opdrachten worden in de ASP code behandeld
      ELSE
         IF prsv_ruimte.res_ruimte_opstel_key IS NULL
         THEN
            UPDATE   res_rsv_ruimte
               SET   res_rsv_ruimte_dirtlevel = 256                                                       -- Geen ruimte
             WHERE   CURRENT OF prsv_ruimtecur;
         ELSE
            -- Is er een ander res_rsv_ruimte die nu met ons overlapt?
            -- Zoek schoonmaaktijd. Let wel: we nemen aan dat een eventuele
            -- 'andere' ruimte dezelfde schoonmaaktijd heeft
            SELECT   res_disc_params_preposttime / 24,
                     ru.res_ruimte_begintijdblok / 24,
                     ru.res_ruimte_eindtijdblok  / 24,
                     ru.res_ruimte_key
              INTO   preposttime,
                     ruimte_blok_van,
                     ruimte_blok_tot,
                     my_res_ruimte_key
              FROM   res_disc_params dp, res_ruimte ru, res_ruimte_opstelling ro
             WHERE       ru.res_discipline_key = dp.res_ins_discipline_key
                     AND ro.res_ruimte_key = ru.res_ruimte_key
                     AND ro.res_ruimte_opstel_key = prsv_ruimte.res_ruimte_opstel_key;
            IF prsv_ruimte.res_status_fo_key = 3                                              -- Blokkade (van onszelf!)
            THEN
               preposttime :=  0;
            ELSIF prsv_ruimte.res_rsv_ruimte_van BETWEEN SYSDATE - 5/60/24 AND SYSDATE + 5/60/24
            THEN
            -- Als *nu* gereserveerd negeren we schoonmaaktijd. Handig voor pda-reserveringen met noshow
               preposttime :=  0;
            END IF;
            -- 1 Minuut marge voor afrondfouten
            IF preposttime > 1/24/60 THEN
                preposttime := preposttime - 1/24/60;
            END IF;
            DBMS_OUTPUT.PUT_LINE('Catalogus preposttime (dagen): ' || TO_CHAR(preposttime));
            DBMS_OUTPUT.PUT_LINE('Activiteit posttime (uren): ' || TO_CHAR(prsv_ruimte.res_activiteit_posttime));
            --
            n_overlap := 0;
            -- Controleer op blokkade van ruimte ivm middagpauze
            IF (ruimte_blok_van IS NOT NULL AND ruimte_blok_tot IS NOT NULL)
            THEN
                IF (   (prsv_ruimte.res_rsv_ruimte_van < TRUNC(prsv_ruimte.res_rsv_ruimte_van)+ruimte_blok_tot - 1/24/60)
                   AND (prsv_ruimte.res_rsv_ruimte_tot > TRUNC(prsv_ruimte.res_rsv_ruimte_van)+ruimte_blok_van + 1/24/60)
                   )
                THEN
                    n_overlap := 1;
                END IF;
            END IF;
            -- Oke, hoeveel overlappende alg_ruimte hebben we nu
            SELECT   COUNT (DISTINCT rb.res_ruimte_key) + n_overlap
              INTO   n_overlap
              FROM   res_alg_ruimte rb,                                                                           -- ikzelf
                     res_v_rsv_ruimte_2_alg_ruimte rr,                                                            -- de andere
                     (SELECT res_ruimte_key, res_disc_params_preposttime
                        FROM res_disc_params, res_ruimte
                       WHERE res_disc_params.res_ins_discipline_key = res_ruimte.res_discipline_key) rsv_prepost  -- prepost van de ander
             WHERE   rr.alg_ruimte_key = rb.alg_ruimte_key AND rb.res_ruimte_key = my_res_ruimte_key
                     AND rsv_prepost.res_ruimte_key = rr.res_ruimte_key
                     -- Redundant maar zéér goed voor performance
                     -- ONGETEST/komt niet voor maar: meerdaagse reserveringen zou zo maar goed kunnen gaan
                     AND rb.res_alg_ruimte_verwijder IS NULL
                     AND rr.res_rsv_ruimte_van BETWEEN TRUNC (prsv_ruimte.res_rsv_ruimte_van)
                                                   AND TRUNC (prsv_ruimte.res_rsv_ruimte_tot)+1
                     -- Er is overlap als
                     -- A) de andere ruimte begint voor ons einde
                     -- B) en eindigt na ons begin
                     -- Let op: bij Blokkade(3) van de ander rekenen we geen schoonmaaktijd.
                     -- Dat gebeurt ietwat getruct door te tegen-corrigeren, vandaar
                     -- de rr.res_rsv_ruimte_van PLUS preposttime
                     AND CASE rr.res_status_fo_key
                           WHEN 3 THEN rr.res_rsv_ruimte_van
                           ELSE rr.res_rsv_ruimte_van - GREATEST(preposttime,
                                                                 rsv_prepost.res_disc_params_preposttime / 24,
                                                                 prsv_ruimte.res_activiteit_posttime / 24,
                                                                 (SELECT CASE rr.res_ruimte_opstel_key
                                                                            WHEN prsv_ruimte.res_ruimte_opstel_key THEN 0 -- Geen omsteltijd bij dezelfde opstelling
                                                                            ELSE GREATEST (prsv_ruimte.res_ruimte_opstel_tijd, rr.res_ruimte_opstel_tijd) / 24
                                                                         END
                                                                    FROM DUAL))
                        END < prsv_ruimte.res_rsv_ruimte_tot
                     AND CASE rr.res_status_fo_key
                           WHEN 3 THEN rr.res_rsv_ruimte_tot
                           ELSE rr.res_rsv_ruimte_tot + GREATEST(preposttime,
                                                                 rsv_prepost.res_disc_params_preposttime / 24,
                                                                 rr.res_activiteit_posttime / 24,
                                                                 (SELECT CASE rr.res_ruimte_opstel_key
                                                                            WHEN prsv_ruimte.res_ruimte_opstel_key THEN 0 -- Geen omsteltijd bij dezelfde opstelling
                                                                            ELSE GREATEST (prsv_ruimte.res_ruimte_opstel_tijd, rr.res_ruimte_opstel_tijd) / 24
                                                                         END
                                                                    FROM DUAL))
                        END > prsv_ruimte.res_rsv_ruimte_van
                     AND rr.res_rsv_ruimte_key != prsv_ruimte_key
                     AND res_rsv_ruimte_dirtlevel < 256 --And die anderen niet zwaar dirty!
                     AND rr.res_alg_ruimte_verwijder IS NULL; -- of verwijderd

            IF n_overlap = 0
            THEN
               UPDATE   res_rsv_ruimte
                  SET   res_rsv_ruimte_dirtlevel = 0
                WHERE   CURRENT OF prsv_ruimtecur;
            ELSE
               UPDATE   res_rsv_ruimte
                  SET   res_rsv_ruimte_dirtlevel = 512
                WHERE   CURRENT OF prsv_ruimtecur;
            --bitor (prsv_ruimte.res_rsv_ruimte_dirtlevel, 512);
            END IF;
         END IF;
      END IF;
      CLOSE prsv_ruimtecur;
   END;
   -- Zijn door *onze* wijziging vandaag andere ruimtes 'clean' geworden?
   -- checkdate is op zich redundant maar heel goed voor de performance
   PROCEDURE set_ruimtes_clean (checkdate IN DATE)
   AS
      dirtlevel   res_rsv_ruimte.res_rsv_ruimte_dirtlevel%TYPE;
      contact_key res_rsv_ruimte.res_rsv_ruimte_contact_key%TYPE;
   BEGIN
      FOR prsv_ruimte
      IN (SELECT   res_rsv_ruimte_key
            FROM   res_rsv_ruimte
           WHERE   res_rsv_ruimte_dirtlevel <> 0
                   AND res_rsv_ruimte_verwijder IS NULL
                   AND (res_status_bo_key IS NULL OR res_status_bo_key <> 6) -- status 6 is niet bij te werken.
                   AND res_rsv_ruimte_van BETWEEN TRUNC (checkdate) AND TRUNC (checkdate + 1))
      loop
         set_ruimte_dirty (prsv_ruimte.res_rsv_ruimte_key);
         --
         SELECT res_rsv_ruimte_dirtlevel,
                res_rsv_ruimte_contact_key
           INTO dirtlevel,
                contact_key
           FROM res_rsv_ruimte
          WHERE res_rsv_ruimte_key = prsv_ruimte.res_rsv_ruimte_key;
         --
         IF dirtlevel = 0 THEN
           fac.trackaction ('RESCLN', prsv_ruimte.res_rsv_ruimte_key, contact_key, NULL, NULL);
         END IF;
         -- TODO: Alle ruimtes met Dirty-bitje bekijken
      end loop;
   END;
   -- Moeten wijzelf misschien dirty worden
   -- (door overlap met andere reserveringen van hetzelfde deel)
   -- Of doordat we 'uit scope' zijn gevallen
   PROCEDURE set_delen_dirty (prsv_ruimte_key IN NUMBER)
   AS
   BEGIN
      FOR prsv_deel IN (SELECT   res_rsv_deel_key
                          FROM   res_rsv_deel
                         WHERE   res_rsv_ruimte_key = prsv_ruimte_key
                             AND res_rsv_deel_verwijder IS NULL)
      loop
         set_deel_dirty (prsv_deel.res_rsv_deel_key);
      end loop;
   END;
   -- Moeten wijzelf misschien dirty worden
   -- Bijv. doordat we 'uit scope' zijn gevallen
   PROCEDURE set_artikelen_dirty (prsv_ruimte_key IN NUMBER)
   AS
   BEGIN
      FOR prsv_artikel IN (SELECT   res_rsv_artikel_key
                             FROM   res_rsv_artikel
                            WHERE   res_rsv_ruimte_key = prsv_ruimte_key
                                AND res_rsv_artikel_verwijder IS NULL)
      loop
         set_artikel_dirty (prsv_artikel.res_rsv_artikel_key);
      end loop;
   END;
   -- Maximale dirtlevel over hele deelreservering
   -- merk op dat je er niet meer aan kunt zien of het over
   -- de ruimte dan wel delen ging!
   FUNCTION dirty_level_all (prsv_ruimte_key IN NUMBER)
    RETURN NUMBER
   AS
      dirtlevel   res_rsv_ruimte.res_rsv_ruimte_dirtlevel%TYPE;
   BEGIN
      SELECT MAX (dirtlevel)
        INTO dirtlevel
        FROM (SELECT ra.res_rsv_ruimte_key,
                     res_rsv_artikel_dirtlevel dirtlevel
                FROM res_rsv_artikel ra
               WHERE res_rsv_artikel_verwijder IS NULL
              UNION ALL
              SELECT res_rsv_ruimte_key,
                     CASE
                        WHEN (res_rsv_deel_dirtlevel < 256
                              OR res_rsv_deel_verwijder IS NOT NULL)
                        THEN
                           0
                        ELSE
                           res_rsv_deel_dirtlevel
                     END
                        dirtlevel
                FROM res_rsv_deel rd
               WHERE res_rsv_deel_verwijder IS NULL
              UNION ALL
              SELECT res_rsv_ruimte_key,
                     CASE
                        WHEN (res_rsv_ruimte_dirtlevel = 16) -- geen catering
                        THEN
                           0
                        ELSE
                           res_rsv_ruimte_dirtlevel
                     END dirtlevel
                FROM res_rsv_ruimte)
       WHERE res_rsv_ruimte_key = prsv_ruimte_key;

      RETURN dirtlevel;
   END;
   -- Mag dit res_deel in de (koppel)ruimte van de reservering gereserveerd worden
   FUNCTION res_deel_in_scope (pres_deel_key IN NUMBER, pres_rsv_ruimte_key IN NUMBER)
      RETURN BOOLEAN IS
   result BOOLEAN;
   n_inscope INTEGER;
   l_alg_ruimte_count NUMBER (10);
   BEGIN
        SELECT COUNT (1)
          INTO l_alg_ruimte_count
          FROM res_rsv_ruimte rr, res_ruimte_opstelling ro, res_alg_ruimte ra
         WHERE     rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key(+)
               AND ro.res_ruimte_key = ra.res_ruimte_key(+)
               AND rr.res_rsv_ruimte_key = pres_rsv_ruimte_key
               AND COALESCE (rr.alg_ruimte_key, ra.alg_ruimte_key) IS NOT NULL
               AND ra.res_alg_ruimte_verwijder IS NULL;      -- Het kan ook een koppelruimte zijn die uit meerdere ruimten bestaat

      IF l_alg_ruimte_count = 0 THEN -- reservering onder opdracht heeft geen ALG-scope
          SELECT   COUNT (d.ins_deel_key)
                INTO n_inscope
                FROM   ins_deel d,
                       res_v_aanwezigdeel r,
                       res_v_deelscope ds,
                       res_v_aanwezigdiscipline r_disc
               WHERE       r.res_discipline_key = r_disc.ins_discipline_key
                       AND r.res_deel_key = pres_deel_key
                       AND r.res_ins_deel_key = d.ins_deel_key
                       AND ds.res_deel_alg_level = -1
                       AND r.res_deel_key = ds.res_deel_key;
      ELSE
          SELECT   COUNT (d.ins_deel_key)
            INTO n_inscope
            FROM   ins_deel d,
                   res_v_aanwezigdeel r,
                   (SELECT d.alg_regio_key,
                           l.alg_district_key,
                           l.alg_locatie_key,
                           g.alg_gebouw_key,
                           v.alg_verdieping_key,
                           r.alg_ruimte_key
                      FROM alg_district d, alg_locatie l, alg_gebouw g, alg_verdieping v, alg_ruimte r
                     WHERE r.alg_ruimte_key IN (SELECT COALESCE(rr.alg_ruimte_key, ra.alg_ruimte_key) alg_ruimte_key
                                                  FROM res_rsv_ruimte rr,
                                                       res_ruimte_opstelling ro,
                                                       res_alg_ruimte ra
                                                 WHERE rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key(+)
                                                   AND ro.res_ruimte_key = ra.res_ruimte_key(+)
                                                   AND rr.res_rsv_ruimte_key = pres_rsv_ruimte_key
                                                   AND ra.res_alg_ruimte_verwijder IS NULL)
                       AND r.alg_verdieping_key = v.alg_verdieping_key
                       AND v.alg_gebouw_key = g.alg_gebouw_key
                       AND g.alg_locatie_key = l.alg_locatie_key
                       AND l.alg_district_key = d.alg_district_key) scope,
                   res_v_deelscope ds,
                   res_v_aanwezigdiscipline r_disc
           WHERE       r.res_discipline_key = r_disc.ins_discipline_key
                   AND r.res_deel_key = pres_deel_key
                   AND r.res_ins_deel_key = d.ins_deel_key
                   AND COALESCE(d.ins_alg_ruimte_type_org, d.ins_alg_ruimte_type) IN ('R', 'T')
                   AND (   ds.alg_regio_key = scope.alg_regio_key
                        OR ds.alg_district_key = scope.alg_district_key
                        OR ds.alg_locatie_key = scope.alg_locatie_key
                        OR ds.alg_gebouw_key = scope.alg_gebouw_key
                        OR ds.alg_verdieping_key = scope.alg_verdieping_key
                        OR ds.alg_ruimte_key = scope.alg_ruimte_key
                        OR ds.res_deel_alg_level = -1)
                   AND r.res_deel_key = ds.res_deel_key;
      END IF;
      DBMS_OUTPUT.put_line ('res_deel_in_scope('  ||  pres_deel_key  ||  ','  ||  pres_rsv_ruimte_key  ||  ') -->' || n_inscope);
      RETURN n_inscope > 0;
   END;
   -- Moeten wijzelf misschien dirty worden
   -- (door overlap met andere reserveringen van hetzelfde deel)
   -- of door out-of-scope geraakt
   PROCEDURE set_deel_dirty (prsv_deel_key IN NUMBER)
   AS
      n_overlap NUMBER (10);
      preposttime NUMBER(5,4); -- we gaan nog delen door 24, res_disc_params.res_disc_params_preposttime%TYPE is dan te klein;
      lres_deel_key res_rsv_deel.res_deel_key%TYPE;
      lres_ins_deel_key res_deel.res_ins_deel_key%TYPE;
      lres_prs_perslid_key res_deel.res_prs_perslid_key%TYPE;
      lres_deel_vervaldatum res_deel.res_deel_vervaldatum%TYPE;
      lrsv_ruimte_key res_rsv_deel.res_rsv_ruimte_key%TYPE;
      lrsv_deel_key res_rsv_deel.res_rsv_deel_key%TYPE;
      lrsv_deel_van res_rsv_deel.res_rsv_deel_van%TYPE;
      lrsv_deel_tot res_rsv_deel.res_rsv_deel_tot%TYPE;
      lres_rsv_deel_verwijder res_rsv_deel.res_rsv_deel_verwijder%TYPE;
      newdirtlevel res_rsv_deel.res_rsv_deel_dirtlevel%TYPE;
      lruimtevan res_rsv_ruimte.res_rsv_ruimte_van%TYPE;
      lruimtetot res_rsv_ruimte.res_rsv_ruimte_tot%TYPE;
   BEGIN
      BEGIN
          SELECT   d.res_deel_key,
                   rd.res_ins_deel_key,
                   rd.res_prs_perslid_key,
                   rd.res_deel_vervaldatum,
                   d.res_rsv_ruimte_key,
                   res_rsv_deel_key,
                   res_rsv_deel_van,
                   res_rsv_deel_tot,
                   r.res_rsv_ruimte_van,
                   r.res_rsv_ruimte_tot,
                   res_rsv_deel_verwijder,
                   res_disc_params_preposttime / 24
            INTO   lres_deel_key,
                   lres_ins_deel_key,
                   lres_prs_perslid_key,
                   lres_deel_vervaldatum,
                   lrsv_ruimte_key,
                   lrsv_deel_key,
                   lrsv_deel_van,
                   lrsv_deel_tot,
                   lruimtevan,lruimtetot,
                   lres_rsv_deel_verwijder,
                   preposttime
            FROM   res_rsv_deel d,
                   res_rsv_ruimte r,
                   res_deel rd,
                   res_disc_params dp
           WHERE   d.res_rsv_ruimte_key = r.res_rsv_ruimte_key
             AND   res_rsv_deel_key = prsv_deel_key
             AND   d.res_deel_key = rd.res_deel_key
             AND   rd.res_discipline_key = dp.res_ins_discipline_key;
      END;
      -- 1 Minuut marge voor afrondfouten
      IF preposttime > 1/24/60 THEN
          preposttime := preposttime - 1/24/60;
      END IF;
      newdirtlevel :=  0;                                                                                -- Begin 'Clean'
      IF lres_rsv_deel_verwijder IS NULL
      THEN
          -- Oke, hoeveel overlappende res_deel hebben we nu

          SELECT   COUNT (DISTINCT res_rsv_deel_key)
            INTO n_overlap
            FROM   res_v_aanwezigrsv_deel rad,                                                                  -- de andere
                   res_deel rd
           WHERE rd.res_deel_key = rad.res_deel_key
             AND (rd.res_ins_deel_key = lres_ins_deel_key -- Er kunnen meerdere res_deel-en zijn met dezelfde ins_deel_key/ prs_perslid_key
                  OR rd.res_prs_perslid_key = lres_prs_perslid_key)
                   -- Er is overlap als
                   -- A) de andere ruimte begint voor ons einde
                   -- B) en eindigt na ons begin
                   AND res_rsv_deel_van < lrsv_deel_tot + preposttime
                   AND res_rsv_deel_tot > lrsv_deel_van - preposttime
                   AND res_rsv_deel_key <> lrsv_deel_key
                   AND res_rsv_deel_dirtlevel < 256;  -- And die anderen niet zwaar dirty!
          IF n_overlap > 0
          THEN
             newdirtlevel :=  512;                                                                                 -- Overlap
          END IF;
          IF lres_prs_perslid_key IS NULL THEN
              IF NOT res_deel_in_scope (lres_deel_key, lrsv_ruimte_key) OR
                 lres_deel_vervaldatum <= lrsv_deel_tot
              THEN
                 newdirtlevel :=  newdirtlevel + 256;                                                               -- OutOfScope/Not Allowed
              END IF;
          END IF;
          IF (lrsv_deel_van < lruimtevan OR lrsv_deel_tot > lruimtetot)
          THEN
             newdirtlevel :=  newdirtlevel + 1;                                                -- Valt buiten de ruimtetijden
          END IF;
      END IF;
      UPDATE   res_rsv_deel
         SET   res_rsv_deel_dirtlevel = newdirtlevel
       WHERE   res_rsv_deel_key = prsv_deel_key;
   END;
   -- Zijn door *onze* wijziging vandaag andere delen'clean' geworden?
   -- checkdate is op zich redundant maar heel goed voor de performance
   PROCEDURE set_delen_clean (pdeel_key IN NUMBER, checkdate_van IN DATE, checkdate_tot IN DATE)
   AS
      preposttime NUMBER(5,4); -- we gaan nog delen door 24, res_disc_params.res_disc_params_preposttime%TYPE is dan te klein;
   BEGIN
      BEGIN
          SELECT   res_disc_params_preposttime / 24
            INTO   preposttime
            FROM   res_deel rd,
                   res_disc_params dp
           WHERE   rd.res_deel_key = pdeel_key
             AND   rd.res_discipline_key = dp.res_ins_discipline_key;
      END;
      -- 1 Minuut marge voor afrondfouten
      IF preposttime > 1/24/60 THEN
          preposttime := preposttime - 1/24/60;
      END IF;

      FOR prsv_deel
      IN (SELECT   res_rsv_deel_key
            FROM   res_rsv_deel
           WHERE   res_deel_key = pdeel_key
             AND   res_rsv_deel_dirtlevel <> 0
             AND   res_rsv_deel_van < checkdate_tot + preposttime
             AND   res_rsv_deel_tot > checkdate_van - preposttime
             AND   res_rsv_deel_verwijder IS NULL)
      loop
         set_deel_dirty (prsv_deel.res_rsv_deel_key);
      -- TODO: Alle ruimtes met Dirty-bitje bekijken
      end loop;
   END;
   -- Mag dit res_dartikel in de (koppel)ruimte van de reservering gereserveerd worden
   FUNCTION res_artikel_in_scope (pres_rsv_artikel_key IN NUMBER)
      RETURN BOOLEAN IS
   result BOOLEAN;
   n_inscope INTEGER;
   BEGIN
      DBMS_OUTPUT.put_line ('res_artikel_in_scope('  ||  pres_rsv_artikel_key  ||  ')');
      SELECT COUNT(DISTINCT ra.res_rsv_artikel_key)
        INTO n_inscope
        FROM res_rsv_ruimte rr,
             res_ruimte_opstelling ro,
             res_alg_ruimte rar,
             res_v_alg_ruimte_gegevens rg,
             res_srtartikel_onrgoed sao,
             res_v_aanwezigartikel a,
             res_rsv_artikel ra
       WHERE rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key(+)
         AND ro.res_ruimte_key = rar.res_ruimte_key(+)
         AND a.res_discipline_key = sao.res_discipline_key
         AND (rg.alg_locatie_key = sao.alg_onrgoed_key AND sao.alg_onrgoed_niveau = 'L'
              OR rg.alg_gebouw_key = sao.alg_onrgoed_key AND sao.alg_onrgoed_niveau = 'G'
              OR rg.alg_verdieping_key = sao.alg_onrgoed_key AND sao.alg_onrgoed_niveau = 'V'
              OR rg.alg_ruimte_key = sao.alg_onrgoed_key AND sao.alg_onrgoed_niveau = 'R')
         AND rg.alg_ruimte_key = COALESCE (rr.alg_ruimte_key, rar.alg_ruimte_key)
         AND rr.res_rsv_ruimte_key = ra.res_rsv_ruimte_key
         AND ra.res_artikel_key = a.res_artikel_key
         AND sao.res_srtartikel_og_verwijder IS NULL
         AND rg.alg_ruimte_key IS NOT NULL
         AND rar.res_alg_ruimte_verwijder IS NULL -- Het kan ook een koppelruimte zijn die uit meerdere ruimten bestaat
         AND ra.res_rsv_artikel_key = pres_rsv_artikel_key
         -- Levering tussen begintijd artikel en eindtijd artikel.
         AND ra.res_rsv_artikel_levering BETWEEN TRUNC (rr.res_rsv_ruimte_van) + COALESCE (a.res_artikel_begintijd, fac.safe_to_number (fac.getsetting ('res_t1'))) / 24
                                             AND TRUNC (rr.res_rsv_ruimte_van) + COALESCE (a.res_artikel_eindtijd, fac.safe_to_number (fac.getsetting ('res_t2'))) / 24;
      RETURN n_inscope > 0;
   END;
   -- Moeten wijzelf misschien dirty worden
   --  door out-of-scope geraakt
   PROCEDURE set_artikel_dirty (prsv_artikel_key IN NUMBER)
   AS
      CURSOR prsv_artikelcur
      IS
             SELECT   res_artikel_key,
                      res_rsv_ruimte_key,
                      res_rsv_artikel_key,
                      res_rsv_artikel_verwijder
               FROM   res_rsv_artikel
              WHERE   res_rsv_artikel_key = prsv_artikel_key
         FOR UPDATE   OF res_rsv_artikel_dirtlevel;
      prsv_artikel prsv_artikelcur%ROWTYPE;
      newdirtlevel res_rsv_artikel.res_rsv_artikel_dirtlevel%TYPE;
   BEGIN
      OPEN prsv_artikelcur;
      FETCH prsv_artikelcur INTO   prsv_artikel;
      newdirtlevel :=  0;                                                                                -- Begin 'Clean'
      IF prsv_artikel.res_rsv_artikel_verwijder IS NULL
        AND NOT res_artikel_in_scope (prsv_artikel.res_rsv_artikel_key)
      THEN
         newdirtlevel :=  newdirtlevel + 256;                                                               -- OutOfScope
      END IF;
      UPDATE   res_rsv_artikel
         SET   res_rsv_artikel_dirtlevel = newdirtlevel
       WHERE   CURRENT OF prsv_artikelcur;
      CLOSE prsv_artikelcur;
   END;
   -- prsv_ruimte_key is gewijzigd
   -- Als het artikel op het begintijdstip van de ruimte stond,
   -- dan wordt deze nu aangepast naar het nieuwe tijdstip
   -- Als het artikel op een afwijkende tijd stond, dan wordt die behouden
   -- mits die tijd binnen de nieuwe reserveertijd van de ruimte valt. Als dat
   -- niet zo is, dan wordt die alsnog op de begintijd daarvan gezet.
   -- Elk artikel valt hierna dus zeker in het ruimte-interval.
   -- Een artikel kan niet dirty worden door deze wijziging
   -- Een dirty artikel kan wel clean worden hierdoor, of er
   -- kunnen theoretisch andere reden zijn voor dirty
   PROCEDURE follow_artikel (prsv_ruimte_key IN NUMBER, oldvan IN DATE, oldtot IN DATE, check_scope IN NUMBER DEFAULT 1)
   AS
      CURSOR prsv_artikelcur
      IS
         SELECT   *
           FROM   res_rsv_artikel rra
          WHERE   rra.res_rsv_ruimte_key = prsv_ruimte_key;
      prsv_artikel prsv_artikelcur%ROWTYPE;
      newvan res_rsv_ruimte.res_rsv_ruimte_van%TYPE;
      newtot res_rsv_ruimte.res_rsv_ruimte_tot%TYPE;
      oldvantijd VARCHAR2(5);
      oldtottijd VARCHAR2(5);
      newvandatum VARCHAR2(10);
      newvantijd VARCHAR2(5);
      newtottijd VARCHAR2(5);
   BEGIN
      SELECT   res_rsv_ruimte_van, res_rsv_ruimte_tot, to_char(res_rsv_ruimte_van,'HH24:MI'), to_char(res_rsv_ruimte_tot,'HH24:MI')
        INTO   newvan, newtot, newvantijd, newtottijd
        FROM   res_rsv_ruimte
       WHERE   res_rsv_ruimte_key = prsv_ruimte_key;
      SELECT to_char(oldvan,'HH24:MI')  INTO oldvantijd FROM DUAL;
      SELECT to_char(oldtot,'HH24:MI')  INTO oldtottijd FROM DUAL;
      SELECT to_char(newvan,'DD-MM-YYYY')  INTO newvandatum FROM DUAL;
      IF oldvantijd <> newvantijd OR oldtottijd <> newtottijd
      THEN
         -- alleen aanpassen indien de tijden zijn veranderd
         -- Als de status "Verwerkt(6)" krijg je hier een foutmelding via de trigger res_t_res_rsv_artikel_B_IU.
         -- Dat het artikel dan niet meer aangepast kan worden is niet erg omdat het artikel al helemaal afgehandeld is.
         UPDATE   res_rsv_artikel rra
            SET   rra.res_rsv_artikel_levering = newvan
          WHERE   rra.res_rsv_ruimte_key = prsv_ruimte_key
                  AND (   rra.res_rsv_artikel_levering = oldvan
                       OR rra.res_rsv_artikel_levering > newtot
                       OR rra.res_rsv_artikel_levering < newvan);
      ELSE
         -- change date-part only to keep the item-dates within the from-to date range
         UPDATE   res_rsv_artikel rra
            SET   rra.res_rsv_artikel_levering = TO_DATE (newvandatum || ' ' || TO_CHAR (res_rsv_artikel_levering, 'HH24:MI'), 'DD-MM-YYYY HH24:MI')
          WHERE   rra.res_rsv_ruimte_key = prsv_ruimte_key
                  AND (   rra.res_rsv_artikel_levering = oldvan
                       OR rra.res_rsv_artikel_levering > newtot
                       OR rra.res_rsv_artikel_levering < newvan);
      END IF;
      -- now (re)set the dirty marks
      FOR prsv_artikel IN prsv_artikelcur
      LOOP
         -- Alleen kijken naar dirty als het artikel nog niet verwerkt/afgehandeld is. Dan wordt er ook geen dirty update uitgevoerd.
         -- Als het artikel "Verwerkt(6)" is dan doet dirty er ook niet meer toe.
         IF (prsv_artikel.res_status_bo_key < 6 AND check_scope = 1)
         THEN
            set_artikel_dirty (prsv_artikel.res_rsv_artikel_key);
         END IF;
      END LOOP;
   END;
   -- prsv_ruimte_key is gewijzigd
   -- wijzig eventueel tijdstip delen en/of maak ze dirty
   -- niet de parkeerplaatsen, dat doet de afspraak
   PROCEDURE follow_deel (prsv_ruimte_key IN NUMBER, oldvan IN DATE, oldtot IN DATE)
   AS
      newvan res_rsv_ruimte.res_rsv_ruimte_van%TYPE;
      newtot res_rsv_ruimte.res_rsv_ruimte_tot%TYPE;
      CURSOR prsv_deelcur
      IS
             SELECT   *
               FROM   res_rsv_deel rrd
              WHERE   rrd.res_rsv_ruimte_key = prsv_ruimte_key
                AND   bez_bezoekers_key IS NULL
         FOR UPDATE   OF res_rsv_deel_dirtlevel;
      prsv_deel prsv_deelcur%ROWTYPE;
   BEGIN
      -- Nieuwe tijden ophalen
      SELECT   rr.res_rsv_ruimte_van, rr.res_rsv_ruimte_tot
        INTO newvan,newtot
        FROM   res_rsv_ruimte rr
       WHERE   rr.res_rsv_ruimte_key = prsv_ruimte_key;
      IF oldvan <> newvan OR oldtot <> newtot
      THEN
         -- alleen aanpassen indien de tijden zijn veranderd
         -- en de deeltijden matchten met de ruimtetijden
         -- begintijd
         UPDATE   res_rsv_deel rra
            SET   rra.res_rsv_deel_van = newvan
          WHERE   rra.res_rsv_ruimte_key = prsv_ruimte_key AND rra.res_rsv_deel_van = oldvan;
         -- eindtijd
         UPDATE   res_rsv_deel rra
            SET   rra.res_rsv_deel_tot = newtot
          WHERE   rra.res_rsv_ruimte_key = prsv_ruimte_key AND rra.res_rsv_deel_tot = oldtot;
      END IF;
      -- en set_deel_dirty/ set_delen_clean aan te roepen
      -- veronderstelt dat de cursor de zojuist bijgewerkte gegevens heeft.
      FOR prsv_deel IN prsv_deelcur
      loop
         set_deel_dirty (prsv_deel.res_rsv_deel_key);
         set_delen_clean (prsv_deel.res_deel_key, oldvan, oldtot);
      -- TODO: Alle ruimtes met Dirty-bitje bekijken? Lijkt me niet onze verantwoording hier
      end loop;
   END;

   -- Werkt de onderliggende afspraak bij na wijziging van een deelreservering
   -- Dit gaat maar om een deel van de gegevens
    PROCEDURE follow_afspraak (prsv_ruimte_key IN NUMBER, pres_copy_to_bez IN NUMBER)
    AS
       afspraak_key    bez_afspraak.bez_afspraak_key%TYPE;
       newvan          res_rsv_ruimte.res_rsv_ruimte_van%TYPE;
       newtot          res_rsv_ruimte.res_rsv_ruimte_tot%TYPE;
       newopm          res_rsv_ruimte.res_rsv_ruimte_opmerking%TYPE;
       oldvan          bez_afspraak.bez_afspraak_datum%TYPE;
       oldtot          bez_afspraak.bez_afspraak_eind%TYPE;
       ruimtekey       alg_ruimte.alg_ruimte_key%TYPE;
       locatiekey      alg_locatie.alg_locatie_key%TYPE;
       oldloc          bez_afspraak.alg_locatie_key%TYPE;
       waarde          res_kenmerkwaarde.res_kenmerkreservering_waarde%TYPE;
       bezremark       VARCHAR2(2100); -- bez_afspraak.bez_afspraak_opmerking%TYPE is te kort
       lremarkfilled   BOOLEAN;

       CURSOR ckenmerk
       IS
           SELECT k.res_kenmerk_key
                , t.res_srtkenmerk_kenmerktype
                , t.res_srtkenmerk_nmin nmin
                , t.res_srtkenmerk_nmax nmax
                , t.fac_kenmerkdomein_key
                , k.res_kenmerk_volgnummer
                , COALESCE(lcl.x ('res_kenmerk_omschrijving', k.res_kenmerk_key, k.res_kenmerk_omschrijving)
                         , lcl.x ('res_srtkenmerk_omschrijving', t.res_srtkenmerk_key, t.res_srtkenmerk_omschrijving)) kenmerk_omschrijving
                , v.res_kenmerkreservering_waarde
             FROM res_srtkenmerk t
                , res_kenmerk k
                , res_kenmerkwaarde v
            WHERE v.res_kenmerk_key = k.res_kenmerk_key
              AND k.res_srtkenmerk_key = t.res_srtkenmerk_key
              AND k.res_kenmerk_verwijder IS NULL
              AND t.res_srtkenmerk_verwijder IS NULL
              AND k.res_kenmerk_niveau = 'A'
              AND v.res_rsv_ruimte_key = prsv_ruimte_key
            ORDER BY k.res_kenmerk_volgnummer
                , UPPER(COALESCE(lcl.x ('res_kenmerk_omschrijving', k.res_kenmerk_key, k.res_kenmerk_omschrijving)
                               , lcl.x ('res_srtkenmerk_omschrijving', t.res_srtkenmerk_key, t.res_srtkenmerk_omschrijving)));

    BEGIN
       BEGIN
          SELECT   bez_afspraak_key
            INTO   afspraak_key
            FROM   bez_afspraak
           WHERE   res_rsv_ruimte_key = prsv_ruimte_key;
       EXCEPTION
          WHEN NO_DATA_FOUND
          THEN
             -- Er is helemaal geen afspraak
             RETURN;
       END;

       -- NOTE: RES-updates of host or contact "cascade" to BEZ by triggers and should not be handled here!
       -- Nieuwe tijden en opmerking ophalen
       SELECT   rr.res_rsv_ruimte_van, rr.res_rsv_ruimte_tot, rr.res_rsv_ruimte_opmerking
         INTO   newvan, newtot, newopm
         FROM   res_rsv_ruimte rr
        WHERE   rr.res_rsv_ruimte_key = prsv_ruimte_key;

       -- In geval van koppelruimten worden meerdere locatie keys opgeleverd. De locaties zullen echter toch hetzelfde zijn.
       -- Voor de ruimte waar de bezoeker naar toe moet kiezen we de laagste key (we kennen niet het concept van
       -- bezoekers naar res_ruimtes)
       SELECT   MIN(g.alg_locatie_key), MIN(r.alg_ruimte_key)
         INTO   locatiekey, ruimtekey
         FROM   alg_ruimte r, alg_verdieping v, alg_gebouw g
        WHERE       g.alg_gebouw_key = v.alg_gebouw_key
                AND v.alg_verdieping_key = r.alg_verdieping_key
                AND r.alg_ruimte_key IN (SELECT COALESCE (rr.alg_ruimte_key, ra.alg_ruimte_key) alg_ruimte_key
                                           FROM res_rsv_ruimte rr,
                                                res_ruimte_opstelling ro,
                                                res_alg_ruimte ra
                                          WHERE rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key(+)
                                            AND ro.res_ruimte_key = ra.res_ruimte_key(+)
                                            AND rr.res_rsv_ruimte_key = prsv_ruimte_key
                                            AND ra.res_alg_ruimte_verwijder IS NULL);

       SELECT   bez_afspraak_datum, bez_afspraak_eind, alg_locatie_key
         INTO   oldvan, oldtot, oldloc
         FROM   bez_afspraak
        WHERE   bez_afspraak_key = afspraak_key;

       bezremark := '';
       lremarkfilled := FALSE;
       IF BITAND(pres_copy_to_bez, 4) = 4
       THEN
         IF BITAND(pres_copy_to_bez, 1) = 1
         THEN
           IF newopm IS NOT NULL OR newopm != ''
           THEN
             bezremark := newopm;
             lremarkfilled := TRUE;
           END IF;
         END IF;
         IF BITAND(pres_copy_to_bez, 2) = 2
         THEN
           -- vullen opmerkingsveld bij bezoeker met flexkenmerken van de reservering
           IF lremarkfilled
           THEN
             bezremark := bezremark || chr(13) || chr(10); -- Carriage Return + Linefeed (CR + LF) toevoegen
           END IF;
           --
           FOR ck IN ckenmerk
           LOOP
             waarde := ck.res_kenmerkreservering_waarde;
             IF waarde IS NOT NULL AND waarde <> '-1'
             -- gevuld
             THEN
               IF ck.res_srtkenmerk_kenmerktype = 'V'
               -- checkbox
               THEN
                 IF waarde = '0'
                 THEN
                   waarde := lcl.l ('lcl_check_0');
                 ELSIF waarde = '1'
                 THEN
                   waarde := lcl.l ('lcl_check_1');
                 END IF;
               ELSIF ck.res_srtkenmerk_kenmerktype = 'R' OR ck.res_srtkenmerk_kenmerktype = 'S'
               -- referentie
               THEN
                 waarde := flx.getdomeinwaarde (ck.fac_kenmerkdomein_key, TO_NUMBER (waarde));
               END IF;
               -- In het zeldzame geval dat de tekst te lang zou worden slaan we sommige
               -- kenmerken gewoon silent over. Niet ideaal maar toch vrij theoretisch
               IF (COALESCE(LENGTH(bezremark),0) + LENGTH(ck.kenmerk_omschrijving) + LENGTH(waarde) < 3990)
               THEN
                 IF lremarkfilled
                 THEN
                   bezremark := bezremark || CHR(10) || ck.kenmerk_omschrijving || ': ' || waarde;
                 ELSE
                   bezremark := ck.kenmerk_omschrijving || ': ' || waarde;
                   lremarkfilled := TRUE;
                 END IF;
               END IF;
             END IF;
           END LOOP;
         END IF;
       END IF;

       IF BITAND(pres_copy_to_bez, 7) > 4
       THEN -- Opmerking ook opslaan
         UPDATE   bez_afspraak
            SET   bez_afspraak_datum = newvan,
                  bez_afspraak_eind = newtot,
                  alg_locatie_key = locatiekey,
                  alg_onrgoed_keys = ruimtekey,
                  bez_afspraak_opmerking = SUBSTR(bezremark, 1, 320)
          WHERE   bez_afspraak_key = afspraak_key;
       ELSE -- Opmerking niet opslaan
         UPDATE   bez_afspraak
            SET   bez_afspraak_datum = newvan,
                  bez_afspraak_eind = newtot,
                  alg_locatie_key = locatiekey,
                  alg_onrgoed_keys = ruimtekey
          WHERE   bez_afspraak_key = afspraak_key;
       END IF;
       -- Parkeerplaatsen opnieuw claimen als locatie of tijd wijzigt
       IF oldvan <> newvan OR
          oldtot <> newtot OR
          oldloc <> locatiekey THEN
          FOR rpark IN (SELECT   b.bez_bezoekers_key,
                                 COALESCE(org.alg_gebouw_key, org.alg_terreinsector_key) gebterkey
                          FROM   bez_bezoekers b,
                                 res_rsv_deel rd,
                                 res_deel d,
                                 ins_deel id,
                                 alg_v_allonrgoed_gegevens org
                         WHERE   res_rsv_deel_verwijder IS NULL
                                 AND rd.bez_bezoekers_key = b.bez_bezoekers_key
                                 AND rd.res_deel_key = d.res_deel_key
                                 AND d.res_ins_deel_key = id.ins_deel_key
                                 AND id.ins_alg_ruimte_key = org.alg_onroerendgoed_keys
                                 AND b.bez_afspraak_key = afspraak_key)
          LOOP
            DELETE FROM res_rsv_deel WHERE bez_bezoekers_key = rpark.bez_bezoekers_key;
            IF oldloc <> locatiekey
            THEN
               bez.claim_parking(rpark.bez_bezoekers_key, null); -- opnieuw claimen
            ELSE -- Tijd is gewijzigd, locatie niet
               bez.claim_parking(rpark.bez_bezoekers_key, rpark.gebterkey); -- opnieuw claimen in/op hetzelfde gebouw/terrein
            END IF;
          END LOOP;
       END IF;
    END;


   FUNCTION getresruimteprijs ( pres_ruimte_key IN NUMBER
                              , pvan IN DATE DEFAULT SYSDATE
                              , ptot IN DATE DEFAULT SYSDATE
                              , pextern IN NUMBER DEFAULT 0
                              ) RETURN NUMBER
   IS
      res_roompricingmethod  NUMBER;
      lres_t_middag          NUMBER;
      lres_t_avond           NUMBER;
      room_price             res_ruimte.res_ruimte_prijs%TYPE;
      room_price_fixed       res_ruimte.res_ruimte_prijs_vast%TYPE;
      price_morning          res_ruimte.res_ruimte_prijs_ochtend%TYPE;
      price_afternoon        res_ruimte.res_ruimte_prijs_middag%TYPE;
      price_evening          res_ruimte.res_ruimte_prijs_avond%TYPE;
      price_allday           res_ruimte.res_ruimte_prijs_dag%TYPE;
      res_length_morning     NUMBER;
      res_length_afternoon   NUMBER;
      res_length_evening     NUMBER;
      cost_morning           NUMBER;
      cost_afternoon         NUMBER;
      cost_evening           NUMBER;
      res_1e_dagblok         NUMBER;
      res_2e_dagblok         NUMBER;
      res_ruimte_length      NUMBER;
      res_ruimte_begin       NUMBER;
      res_ruimte_end         NUMBER;
      thisroomprice          NUMBER;
   BEGIN
      res_roompricingmethod := fac.safe_to_number (fac.getsetting ('res_roompricingmethod'));
      lres_t_middag := fac.safe_to_number (fac.getsetting ('res_t_middag'));
      lres_t_avond  := fac.safe_to_number (fac.getsetting ('res_t_avond'));

      -- Wat basisgegevens
      BEGIN
         SELECT CASE pextern
                   WHEN 0
                   THEN COALESCE (ru.res_ruimte_intprijs, 0) -- Intern
                   ELSE COALESCE (ru.res_ruimte_prijs, 0)    -- Extern
                END,
                ru.res_ruimte_prijs_vast,
                CASE pextern
                   WHEN 0
                   THEN COALESCE (ru.res_ruimte_intprijs_ochtend, 0) -- Intern
                   ELSE COALESCE (ru.res_ruimte_prijs_ochtend, 0)    -- Extern
                END,
                CASE pextern
                   WHEN 0
                   THEN COALESCE (ru.res_ruimte_intprijs_middag, 0) -- Intern
                   ELSE COALESCE (ru.res_ruimte_prijs_middag, 0)    -- Extern
                   END,
                CASE pextern
                   WHEN 0
                   THEN COALESCE (ru.res_ruimte_intprijs_avond, 0) -- Intern
                   ELSE COALESCE (ru.res_ruimte_prijs_avond, 0)    -- Extern
                END,
                CASE pextern
                   WHEN 0
                   THEN COALESCE (ru.res_ruimte_intprijs_dag, 0) -- Intern
                   ELSE COALESCE (ru.res_ruimte_prijs_dag, 0)    -- Extern
                END,
                fac.safe_to_number (TO_CHAR (ptot - pvan)) * 24,
                fac.safe_to_number (TO_CHAR (pvan, 'HH24')) + fac.safe_to_number (TO_CHAR (pvan, 'MI')) / 60,
                fac.safe_to_number (TO_CHAR (ptot, 'HH24')) + fac.safe_to_number (TO_CHAR (ptot, 'MI')) / 60
           INTO room_price,
                room_price_fixed,
                price_morning,
                price_afternoon,
                price_evening,
                price_allday,
                res_ruimte_length,
                res_ruimte_begin,
                res_ruimte_end
           FROM res_ruimte ru
          WHERE ru.res_ruimte_key = pres_ruimte_key;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            -- Geen R-reservering maar een CV-reservering, dan kost de ruimte niks. Klaar.
            RETURN 0;
      END;
      --
      -- Uren dagdeel ochtend: [0 - lres_t_middag]
      res_length_morning :=  LEAST (res_ruimte_end, lres_t_middag) - res_ruimte_begin;
      IF res_length_morning < 0
      THEN
         res_length_morning :=  0;
      END IF;
      -- Uren dagdeel middag: [lres_t_middag - lres_t_avond]
      res_length_afternoon :=  LEAST (res_ruimte_end, lres_t_avond) - GREATEST (res_ruimte_begin, lres_t_middag);
      IF res_length_afternoon < 0
      THEN
         res_length_afternoon :=  0;
      END IF;
      -- Uren dagdeel avond: [lres_t_avond - 24]
      res_length_evening :=  res_ruimte_end - GREATEST (res_ruimte_begin, lres_t_avond);
      IF res_length_evening < 0
      THEN
         res_length_evening :=  0;
      END IF;
      --
      --
      IF res_roompricingmethod = 1
      THEN
         -- Zoals we het altijd deden
         IF (lres_t_middag > 0 AND lres_t_middag < 24 AND lres_t_avond > 0 AND lres_t_avond < 24)
         THEN                                                                                  -- Prijsbepaling per dagdeel
            IF room_price_fixed = 1
            THEN
               -- Een prijs per blok (kennelijk). Tellen hoeveel blokken dan
               IF res_length_morning > 0
               THEN
                  res_length_morning :=  1;
               END IF;
               IF res_length_afternoon > 0
               THEN
                  res_length_afternoon :=  1;
               END IF;
               IF res_length_evening > 0
               THEN
                  res_length_evening :=  1;
               END IF;
            END IF;
            thisroomprice := price_morning * res_length_morning
                           + price_afternoon * res_length_afternoon
                           + price_evening * res_length_evening;
         ELSE                                                                                      -- Prijsbepaling per dag
            IF room_price_fixed = 1
            THEN
               res_ruimte_length :=  1;
            END IF;
            thisroomprice := room_price * res_ruimte_length;
         END IF;
      ELSIF res_roompricingmethod = 2
      THEN
         -- Lever voor de duur van de reservering de laagste prijs op: zie NYBU#25763
         -- Dagprijs -> Uren uitgesplitst per dagdeel (uur van dat dagdeel x prijs) en vergelijken met dagdeelprijs, en daarvan het goedkoopste.
         -- Voor alle 3 dagdelen verkijgen we dan een goedkoopste gedrag (D1 + D2 +D3), die optellen en vergelijken met dagprijs, en daarvan de goedkoopste.
         -- room_price_fixed = 1 werkt alleen op dagdeelprijs, en NIET op uurtarief (eigenlijk zouden we 2 vinkjes moeten hebben, voor ieder 1 afzonderlijk).
         -- En tenslotte nog vergelijken met dagprijs, neem de goedkoopste.
         cost_morning := 0;
         cost_afternoon := 0;
         cost_evening := 0;
         -- Hieronder de uren uitsplitsen naar dagdelen en vergelijken met dagdeelprijzen, daarvan de goedkoopste.
         -- Net als bij res_roompricingmethod = 1, ook kijken of de middag en avond tijden zijn ingesteld, anders doen die niet mee.
         IF (lres_t_middag > 0 AND lres_t_middag < 24 AND lres_t_avond > 0 AND lres_t_avond < 24)
         THEN
            -- Een prijs per blok (kennelijk). Tellen hoeveel blokken dan
            IF res_length_morning > 0
            THEN
                IF room_price_fixed = 1
                THEN
                    cost_morning := price_morning;
                ELSE
                    cost_morning := price_morning * res_length_morning;
                END IF;
                IF (res_length_morning * room_price) < cost_morning
                THEN
                    cost_morning := res_length_morning * room_price;
                END IF;
            END IF;
            IF res_length_afternoon > 0
            THEN
                IF room_price_fixed = 1
                THEN
                    cost_afternoon := price_afternoon;
                ELSE
                    cost_afternoon := price_afternoon * res_length_afternoon;
                END IF;
                IF (res_length_afternoon * room_price) < cost_afternoon
                THEN
                    cost_afternoon := res_length_afternoon * room_price;
                END IF;
            END IF;
            IF res_length_evening > 0
            THEN
                IF room_price_fixed = 1
                THEN
                    cost_evening := price_evening;
                ELSE
                    cost_evening := price_evening * res_length_evening;
                END IF;
                IF (res_length_evening * room_price) < cost_evening
                THEN
                    cost_evening := res_length_evening * room_price;
                END IF;
            END IF;
            thisroomprice := cost_morning + cost_afternoon + cost_evening;
            --
            -- Als dagprijs = 0 (d.i. price_allday is NULL cq. is niet gevuld), dan telt die niet mee, en moet de nieuwe prijsberekening gelden.
            -- Of als dagprijs lager is lager is dan de nieuwe prijsberekening, dan ook.
            IF (price_allday <> 0) AND price_allday < thisroomprice
            THEN
                thisroomprice := price_allday;
            END IF;
         ELSE
            thisroomprice := price_allday;
         END IF;
      ELSIF res_roompricingmethod = 3
      THEN
         -- Methode 3: STAFFELS van b.v. 4 en 8: zie WIBC#26163
         -- uurprijs, dagdeelprijs en dagprijs volgens onderstaande methodiek (x = vergaderduur):
         -- x < 4 uur:      duur x uurprijs
         -- 4 <= x < 8 uur: dagdeelprijs (ochtend) + (duur - 4) x uurprijs
         -- x >= 8 uur:     dagprijs, (of indien dagprijs niet is ingesteld, dan dagdeelprijs (middag) + (duur - 8) x uurprijs
         -- Bij methode 3 wordt lres_t_middag niet als tijdsgrens tussen morgen en middag ingesteld, maar als een 'blok' van een aantal uren.
         -- En idem voor avond, die is het 2e blok (groter aantal) uren dan het 1e blok.
         --
         res_1e_dagblok := lres_t_middag;
         res_2e_dagblok := lres_t_avond;
         -- MB: Overlegd met DEVELOP (PF): geconstateerd dat res_ruimte_res bij een reservering van 10:00-14:00 niet exact 4 is, maar 4.000000en-een-beetje.
         -- Tot dusver ook geen probleem met voorgaande price-methodes, maar nu gaan we (exact) vergelijken met een staffel, en dan kan die net de verkeerde kant (if-then-else) opvallen!
         -- Vandaar deze foef om af te ronden, alleen op deze plaats.
         res_ruimte_length := ROUND(res_ruimte_length, 2);
         --
         IF (res_1e_dagblok > 0 AND res_1e_dagblok < 24)
         THEN
            -- Er is een 1e block gedefinieerd
            IF res_ruimte_length < res_1e_dagblok
            THEN
               -- Reserv. duur is kleiner dan 1e blok uren, gewoon uur x prijs.
               -- Ook hier doet setting room_price_fixed ook gewoon mee.
               IF room_price_fixed = 1
               THEN
                  res_ruimte_length :=  1;
               END IF;
               thisroomprice := room_price * res_ruimte_length;
            ELSE
               -- Reserv. duur is groter dan 1e blok uren, is er een 2e blok gedefinieerd?
               -- Als 2e blok er is, en aantal uren is ook nog meer dan 2e blok, dan de dagprijs.
               -- Ook hier doet setting room_price_fixed ook gewoon mee.
               IF (res_2e_dagblok > 0 AND res_2e_dagblok < 24)
               THEN
                  -- Er is een 2e block gedefinieerd
                  IF res_ruimte_length >= res_2e_dagblok
                  THEN
                     -- Reserv. duur is GROTER dan 2e blok uren, dan geldt de dagprijs indien deze is ingesteld.
                     -- Als de dagprijs NIET is ingesteld, dan dagdeelprijs (middag) + (duur - 8) x uurprijs
                     IF price_allday > 0
                     THEN
                        -- Er is een dagprijs voor de ruimte ingesteld, die telt dan.
                        thisroomprice := price_allday;
                     ELSE
                        -- Er is geen dagprijs ingesteld, neem dan dagdeelprijs (middag) + (duur - 8) x uurprijs
                        IF room_price_fixed = 1 AND res_ruimte_length > res_2e_dagblok
                        THEN
                           -- Niet 1 (zoals overal anders, maar 1 optellen bij het 2e dagblok (voor hieronder om weer 1 over te houden)!!
                           -- En alleen indien res_ruimte_length groter is dan 2e dagblok (anders geen 1 bij optellen, dan geldt alleen dagdeelprijs)
                           res_ruimte_length :=  res_2e_dagblok + 1;
                        END IF;
                        thisroomprice := price_afternoon + (room_price * (res_ruimte_length - res_2e_dagblok));
                     END IF;
                  ELSE
                     -- Reserv. duur is ligt tussen 1e en 2e blok uren in,
                     -- dan geldt dagdeelprijs (ochtend) + (duur - 4) x uurprijs
                     IF room_price_fixed = 1 AND res_ruimte_length > res_1e_dagblok
                     THEN
                        -- Niet 1 (zoals overal anders, maar 1 optellen bij het 1e dagblok (voor hieronder om weer 1 over te houden)!!
                        -- En alleen indien res_ruimte_length groter is dan 1e dagblok (anders geen 1 bij optellen, dan geldt alleen dagdeelprijs)
                        res_ruimte_length :=  res_1e_dagblok + 1;
                     END IF;
                     thisroomprice := price_morning + (room_price * (res_ruimte_length - res_1e_dagblok));
                  END IF;
               ELSE
                  -- Er is geen 2e blok uren gedefinieerd, alleen een 1e urenblok.
                  -- Dan gewoon dagdeelprijs (ochtend) + (duur - 4) x uurprijs
                  IF room_price_fixed = 1 AND res_ruimte_length > res_1e_dagblok
                  THEN
                     -- Niet 1 (zoals overal anders, maar 1 optellen bij het 1e dagblok (voor hieronder om weer 1 over te houden)!!
                     -- En alleen indien res_ruimte_length groter is dan 1e dagblok (anders geen 1 bij optellen, dan geldt alleen dagdeelprijs)
                     res_ruimte_length :=  res_1e_dagblok + 1;
                  END IF;
                  thisroomprice := price_morning + (room_price * (res_ruimte_length - res_1e_dagblok));
               END IF;
            END IF;
         ELSE
            -- Er is geen 1e blok gedefinieerd.
            -- Dan maar gewoon uur x prijs.
            -- Ook hier doet setting room_price_fixed ook gewoon mee.
            IF room_price_fixed = 1
            THEN
               res_ruimte_length :=  1;
            END IF;
            thisroomprice := room_price * res_ruimte_length;
         END IF;
      ELSIF res_roompricingmethod = 9
      THEN
         -- Kost nooit wat.
         thisroomprice := 0;
      END IF;
      --
      --
      RETURN ROUND(thisroomprice, 2);
   END getresruimteprijs;

   FUNCTION getruimteprijs ( pres_rsv_ruimte_key IN NUMBER
                           , ignoretotaal IN NUMBER DEFAULT NULL
                           ) RETURN NUMBER
   IS
      room_price           res_ruimte.res_ruimte_prijs%TYPE;
      afgesprokentotaal    res_rsv_ruimte.res_rsv_ruimte_totaal%TYPE;
      verwijderdatum       res_rsv_ruimte.res_rsv_ruimte_verwijder%TYPE;
      statusfokey          res_rsv_ruimte.res_status_fo_key%TYPE;
      doorbelasting        res_disc_params.res_disc_params_kosten%TYPE;
      res_ruimte_key       res_ruimte_opstelling.res_ruimte_key%TYPE;
      kostenplaats_extern  prs_kostenplaats.prs_kostenplaats_extern%TYPE;
      rsv_ruimte_van       res_rsv_ruimte.res_rsv_ruimte_van%TYPE;
      rsv_ruimte_tot       res_rsv_ruimte.res_rsv_ruimte_tot%TYPE;
      thisroomprice        NUMBER;
   BEGIN
      -- Is de reservering verwijderd
      SELECT rrr.res_rsv_ruimte_verwijder
           , rrr.res_status_fo_key
           , res_rsv_ruimte_totaal
        INTO verwijderdatum
           , statusfokey
           , afgesprokentotaal
        FROM res_rsv_ruimte rrr
       WHERE rrr.res_rsv_ruimte_key = pres_rsv_ruimte_key;

      -- Bepaal doorbelasting
      IF verwijderdatum IS NULL -- Actuele reservering: 100% kosten doorberekenen.
      THEN
         doorbelasting := 100;
      ELSIF statusfokey = 4 -- Verwijderde reservering en FO status is vervallen: X% kosten doorberekenen
      THEN
         -- Hoeveel moet worden doorbelast
         BEGIN
            -- Hoeveel van de ruimte kosten doorberekenen
            SELECT rdp.res_disc_params_kosten
              INTO doorbelasting
              FROM res_rsv_ruimte rrr
                 , res_ruimte_opstelling rro
                 , res_ruimte rr
                 , res_disc_params rdp
             WHERE rrr.res_ruimte_opstel_key = rro.res_ruimte_opstel_key
               AND rro.res_ruimte_key = rr.res_ruimte_key
               AND rr.res_discipline_key = rdp.res_ins_discipline_key
               AND rrr.res_rsv_ruimte_key = pres_rsv_ruimte_key;
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN
               -- Geen R-reservering maar een CV-reservering, dan kost de ruimte niks
               RETURN 0;
         END;
      ELSE -- Verwijderde reservering en FO status is niet vervallen: 0% kosten doorberekenen
         RETURN 0;
      END IF;

      IF afgesprokentotaal IS NOT NULL AND ignoretotaal IS NULL
      THEN
         return afgesprokentotaal; -- dit is simpel
      END IF;

      -- Als Uitgevoerd/verwerkt, dan is de prijs al geregistreerd en bekend
      BEGIN
         SELECT res_rsv_ruimte_prijs
           INTO room_price
           FROM res_rsv_ruimte
          WHERE res_rsv_ruimte_key = pres_rsv_ruimte_key AND res_status_bo_key IN (5, 6);
         RETURN room_price * doorbelasting / 100;
      EXCEPTION
         WHEN OTHERS
         THEN
            NULL;
      END;

      -- Nu zijn er verschillende berekeningsmethoden om de prijs van een gereserveerde ruimte
      -- te bepalen. Welke methode gehanteerd wordt is bepaald door setting 'res_roompricingmethod'.
      -- Maar dat laten we over aan de functie getresruimteprijs().
      BEGIN
         SELECT ro.res_ruimte_key
              , COALESCE(kp.prs_kostenplaats_extern, 0)
              , rr.res_rsv_ruimte_van
              , rr.res_rsv_ruimte_tot
           INTO res_ruimte_key
              , kostenplaats_extern
              , rsv_ruimte_van
              , rsv_ruimte_tot
           FROM res_rsv_ruimte rr
              , res_ruimte_opstelling ro
              , prs_kostenplaats kp
          WHERE rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key
            AND rr.prs_kostenplaats_key = kp.prs_kostenplaats_key(+)
            AND rr.res_rsv_ruimte_key = pres_rsv_ruimte_key;

         thisroomprice := getresruimteprijs ( res_ruimte_key
                                            , rsv_ruimte_van
                                            , rsv_ruimte_tot
                                            , kostenplaats_extern
                                            );
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            -- Geen R-reservering maar een CV-reservering, dan kost de ruimte niks. Klaar.
            RETURN 0;
      END;

      -- Doorbelastingspercentage (bij annuleren) op het laatste moment nog.
      -- Voor de berekening van de doorbelasting moet gerekend worden met een op twee decimalen afgeronde ruimteprijs.
      thisroomprice := ROUND(thisroomprice, 2) * doorbelasting / 100;

      -- De uiteindelijke ruimteprijs die afgeleverd wordt (return waarde) moet een op twee decimalen afgeronde prijs zijn. Vanwege doorbelasting opnieuw afronden.
      RETURN ROUND(thisroomprice, 2);
   END getruimteprijs;

   FUNCTION getdeelprijs (pres_rsv_deel_key IN NUMBER)
      RETURN NUMBER IS
   deel_price res_deel.res_deel_prijs%TYPE;
   deel_price_fixed res_deel.res_deel_prijs_vast%TYPE;
   deel_price_total res_rsv_deel.res_rsv_deel_prijs%TYPE;
   res_deel_length NUMBER;
   res_deel_begin NUMBER;
   res_deel_end NUMBER;
   res_length_morning NUMBER;
   res_length_afternoon NUMBER;
   res_length_evening NUMBER;
   lres_t_middag NUMBER;
   lres_t_avond NUMBER;
   verwijderdatum res_rsv_ruimte.res_rsv_ruimte_verwijder%TYPE;
   BEGIN
      -- Is de reservering verwijderd
      SELECT rrr.res_rsv_ruimte_verwijder
        INTO verwijderdatum
        FROM res_rsv_ruimte rrr,
             res_rsv_deel rrd
       WHERE rrr.res_rsv_ruimte_key = rrd.res_rsv_ruimte_key
         AND rrd.res_rsv_deel_key = pres_rsv_deel_key;

      IF verwijderdatum IS NOT NULL -- Reserveerbare objecten worden bij een verwijderde reservering nooit doorbelast.
      THEN
        RETURN 0;
      END IF;
      -- Actuele reservering: 100% kosten doorberekenen.

      -- Als Uitgevoerd/verwerkt, dan is de prijs al geregistreerd en bekend
      BEGIN
         SELECT   res_rsv_deel_prijs
           INTO deel_price
           FROM   res_rsv_deel
          WHERE   res_rsv_deel_key = pres_rsv_deel_key AND res_status_bo_key IN (5, 6);
         RETURN deel_price;
      EXCEPTION
         WHEN OTHERS
         THEN
            NULL;
      END;
      SELECT   COALESCE (d.res_deel_prijs, 0),
               d.res_deel_prijs_vast,
               fac.safe_to_number (TO_CHAR (rd.res_rsv_deel_tot - rd.res_rsv_deel_van)) * 24,
               fac.safe_to_number (TO_CHAR (rd.res_rsv_deel_van, 'HH24'))
               + fac.safe_to_number (TO_CHAR (rd.res_rsv_deel_van, 'MI')) / 60,
               fac.safe_to_number (TO_CHAR (rd.res_rsv_deel_tot, 'HH24'))
               + fac.safe_to_number (TO_CHAR (rd.res_rsv_deel_tot, 'MI')) / 60
        INTO   deel_price,
               deel_price_fixed,
               res_deel_length,
               res_deel_begin,
               res_deel_end
        FROM   res_rsv_deel rd, res_deel d
       WHERE   rd.res_deel_key = d.res_deel_key AND rd.res_rsv_deel_key = pres_rsv_deel_key;
      IF deel_price_fixed = 1
      THEN
         res_deel_length :=  1;
      ELSE
         lres_t_middag :=  fac.safe_to_number (fac.getsetting ('res_t_middag'));
         lres_t_avond :=  fac.safe_to_number (fac.getsetting ('res_t_avond'));
         IF lres_t_middag = -1 AND lres_t_avond = -1
         THEN
            -- real time, price is per hour
            res_deel_length :=  res_deel_length;
         ELSE
            -- day parts, price is per part
            res_length_morning :=  LEAST (res_deel_end, lres_t_middag) - res_deel_begin;
            res_length_afternoon :=  LEAST (res_deel_end, lres_t_avond) - GREATEST (res_deel_begin, lres_t_middag);
            res_length_evening :=  res_deel_end - GREATEST (res_deel_begin, lres_t_avond);
            res_deel_length :=  0;
            IF res_length_morning > 0
            THEN
               res_deel_length :=  res_deel_length + 1;
            END IF;
            IF res_length_afternoon > 0
            THEN
               res_deel_length :=  res_deel_length + 1;
            END IF;
            IF res_length_evening > 0
            THEN
               res_deel_length :=  res_deel_length + 1;
            END IF;
         END IF;
      END IF;
      -- De uiteindelijke artikelprijs die afgeleverd wordt (return waarde) moet een op twee decimalen afgeronde prijs zijn.
      -- Afronden op twee decimalen gaat automatisch omdat deel_price_total twee decimalen heeft.
      deel_price_total :=  deel_price * res_deel_length;
      RETURN deel_price_total;
   END;
   FUNCTION getartikelprijs (pres_rsv_artikel_key IN NUMBER)
      RETURN NUMBER IS
   res_artikel_aantal res_rsv_artikel.res_rsv_artikel_aantal%TYPE;
   artikel_price_total res_rsv_artikel.res_rsv_artikel_prijs%TYPE;
   verwijderdatum res_rsv_ruimte.res_rsv_ruimte_verwijder%TYPE;
   statusfokey res_rsv_ruimte.res_status_fo_key%TYPE;
   doorbelasting res_disc_params.res_disc_params_kosten%TYPE;
   BEGIN
      -- Is de reservering verwijderd
      SELECT rrr.res_rsv_ruimte_verwijder,
             rrr.res_status_fo_key
        INTO verwijderdatum,
             statusfokey
        FROM res_rsv_ruimte rrr,
             res_rsv_artikel rra
       WHERE rrr.res_rsv_ruimte_key = rra.res_rsv_ruimte_key
         AND rra.res_rsv_artikel_key = pres_rsv_artikel_key;

      -- Bepaal doorbelasting
      IF verwijderdatum IS NULL -- Actuele reservering: 100% kosten doorberekenen.
      THEN
        doorbelasting := 100;
      ELSIF statusfokey = 4 -- Verwijderde reservering en FO status is vervallen: X% kosten doorberekenen
      THEN
        -- Hoeveel moet worden doorbelast
        SELECT res_disc_params_kosten
          INTO doorbelasting
          FROM res_rsv_artikel rra,
               res_artikel ra,
               res_disc_params rdp
         WHERE rra.res_artikel_key = ra.res_artikel_key
           AND ra.res_discipline_key = rdp.res_ins_discipline_key
           AND res_rsv_artikel_dirtlevel = 0
           AND res_rsv_artikel_key = pres_rsv_artikel_key;
      ELSE -- Verwijderde reservering en FO status is niet vervallen: 0% kosten doorberekenen
        return 0;
      END IF;

      -- Als de prijs al geregistreerd in res_rsv_artikel_prijs dan nemen we die
      BEGIN
         SELECT   res_rsv_artikel_prijs
           INTO   artikel_price_total
           FROM   res_rsv_artikel ra, res_artikel a
          WHERE   res_rsv_artikel_key = pres_rsv_artikel_key
            AND   ra.res_artikel_key = a.res_artikel_key
            AND   res_rsv_artikel_prijs IS NOT NULL
            AND   (res_status_bo_key >= 5 OR res_artikel_prijs_vast <> 1);
         -- De uiteindelijke artikelprijs die afgeleverd wordt (return waarde) moet een op twee decimalen afgeronde prijs zijn. Vanwege doorbelasting opnieuw afronden.
         RETURN ROUND(artikel_price_total * doorbelasting / 100, 2);
      EXCEPTION
         WHEN OTHERS
         THEN
            NULL;
      END;
      -- We hebben een vaste prijs-artikel die nog niet is afgemeld
      -- Of een vrije prijs artikel die nog niet door de BO is bewerkt
      -- In beide gevallen moeten we de default prijs uit res_artikel halen
      SELECT   COALESCE (a.res_artikel_prijs, 0) * COALESCE (ra.res_rsv_artikel_aantal, 0)
        INTO   artikel_price_total
        FROM   res_rsv_artikel ra, res_artikel a
       WHERE   ra.res_artikel_key = a.res_artikel_key AND ra.res_rsv_artikel_key = pres_rsv_artikel_key;
      -- De uiteindelijke artikelprijs die afgeleverd wordt (return waarde) moet een op twee decimalen afgeronde prijs zijn. Vanwege doorbelasting opnieuw afronden.
      RETURN ROUND(artikel_price_total * doorbelasting / 100, 2);
   END;
   -- Bepaal de totaalprijs van een reservering
   FUNCTION getdeelresprijs (pres_rsv_ruimte_key IN NUMBER)
      RETURN NUMBER IS
        ruimteprijs  NUMBER := 0;
        artikelprijs NUMBER :=  0;
        deelprijs NUMBER :=  0;
        korting res_rsv_ruimte.res_rsv_ruimte_korting%TYPE;
        verwijderdatum res_rsv_ruimte.res_rsv_ruimte_verwijder%TYPE;
        statusfokey res_rsv_ruimte.res_status_fo_key%TYPE;
      CURSOR cartikel
      IS
         SELECT  res_rsv_artikel_key
           FROM  res_rsv_artikel
          WHERE  res_rsv_artikel_dirtlevel = 0
            AND  res_rsv_ruimte_key = pres_rsv_ruimte_key;
      CURSOR cdeel
      IS
         SELECT   res_rsv_deel_key
           FROM   res_rsv_deel
          WHERE   res_rsv_deel_dirtlevel = 0
            AND   res_rsv_ruimte_key = pres_rsv_ruimte_key;
   BEGIN
        -- Is de reservering verwijderd
        SELECT rrr.res_rsv_ruimte_verwijder,
               rrr.res_status_fo_key,
               COALESCE(res_rsv_ruimte_korting, 0)
          INTO verwijderdatum,
               statusfokey,
               korting
          FROM res_rsv_ruimte rrr
         WHERE rrr.res_rsv_ruimte_key = pres_rsv_ruimte_key;

        -- Bepaal doorbelasting korting of afgesproken totaal
        IF verwijderdatum IS NOT NULL AND statusfokey != 4 -- Verwijderde reservering met FO status die niet is vervallen: 0% korting doorberekenen.
        THEN
            korting := 0;
        -- ELSE -- Actuele reservering of verwijderde reservering met FO status is vervallen: 100% korting doorberekenen
        END IF;

        ruimteprijs :=  res.getruimteprijs(pres_rsv_ruimte_key);
        FOR ca IN cartikel
        LOOP
            artikelprijs :=  artikelprijs + res.getartikelprijs(ca.res_rsv_artikel_key);
        END LOOP;
        FOR cd IN cdeel
        LOOP
            deelprijs :=  deelprijs + res.getdeelprijs(cd.res_rsv_deel_key);
        END LOOP;

        RETURN ruimteprijs + artikelprijs + deelprijs - korting;
   END;
   FUNCTION sprintf (ps IN VARCHAR2 , pres_rsv_ruimte_key IN NUMBER)
      RETURN VARCHAR2  IS
      s            VARCHAR2 (2048 CHAR);
      nr           VARCHAR2 (30);
      omschrijving res_rsv_ruimte.res_rsv_ruimte_omschrijving%TYPE;
      fiatteur     prs_v_perslid_fullnames_all.prs_perslid_naam_full%TYPE;
      datumvan     res_rsv_ruimte.res_rsv_ruimte_van%TYPE;
      datumtot     res_rsv_ruimte.res_rsv_ruimte_tot%TYPE;
   BEGIN
      s :=  ps;
      -- TODO We support substitution of placeholders in the messages
      -- ##DESC##     = res_rsv_ruimte_omschrijving
      -- ##KEY##      = res_reservering_nr
      -- ##DATUM##    = res_rsv_ruimte_van (DD-MM-YY)
      -- ##TIJD##     = res_rsv_ruimte_van (HH24:MI)
      -- ##TIJD2##    = res_rsv_ruimte_tot (HH24:MI)
      -- ##FIATTEUR## = budgethouder van de kostenplaats.
      SELECT TO_CHAR (res_reservering_key)  ||  '/'  ||  TO_CHAR (rr.res_rsv_ruimte_volgnr)
           , rr.res_rsv_ruimte_omschrijving
           , prs_perslid_naam_full
           , res_rsv_ruimte_van
           , res_rsv_ruimte_tot
        INTO nr
           , omschrijving
           , fiatteur
           , datumvan
           , datumtot
        FROM res_rsv_ruimte rr
           , prs_kostenplaats k
           , prs_v_perslid_fullnames_all
       WHERE rr.prs_kostenplaats_key = k.prs_kostenplaats_key(+)
         AND k.prs_perslid_key = prs_v_perslid_fullnames_all.prs_perslid_key(+)
         AND rr.res_rsv_ruimte_key = pres_rsv_ruimte_key;
      s :=  REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (s, '##DESC##', omschrijving), '##KEY##', nr), '##FIATTEUR##', fiatteur), '##DATUM##', TO_CHAR(datumvan, 'DD-MM-YY')), '##TIJD##', TO_CHAR(datumvan, 'HH24:MI')), '##TIJD2##', TO_CHAR(datumtot, 'HH24:MI'));
      s :=  REPLACE (s, ' ()', '');
      RETURN s;
   END;
   FUNCTION notifypool (pbez_bezoeker_key IN NUMBER, pcode IN VARCHAR2)
      RETURN NUMBER IS
      lnrreceivers   NUMBER;
      lcode          fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
      lreceivers     fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      lreceivers1    fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      lbericht       fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      lbezoeker      bez_bezoekers.bez_afspraak_naam%TYPE;
      lmailfrom      alg_locatie.alg_locatie_email%TYPE;
      ltracking      VARCHAR2(4000);  -- moet tijdelijk groter dan fac_srtnotificatie.fac_srtnotificatie_oms%TYPE kunnen zijn
      s              NUMBER;
   BEGIN
      s := 0;
      IF (pcode = 'BEZDO2' OR pcode = 'BEZUNI') THEN
         SELECT bez_afspraak_naam
           INTO lbezoeker
           FROM bez_bezoekers
          WHERE bez_bezoekers_key = pbez_bezoeker_key;

         IF pcode = 'BEZDO2' THEN
            lbericht := lcl.l('lcl_bez_is_in_1') || lbezoeker || lcl.l('lcl_bez_is_in_2');
         ELSIF pcode = 'BEZUNI' THEN
            lbericht := lcl.l('lcl_bez_is_in_1') || lbezoeker || lcl.l('lcl_bez_is_in_3');
         --ELSIF pcode = 'BEZOUT' THEN
         --   lbericht := lcl.l('lcl_bez_is_out_1') || lbezoeker || lcl.l('lcl_bez_is_out_2');
         END IF;

         lcode := 'BEZDO2'; -- Behandel undo_checkin als srtnotificatie checkin.
         lnrreceivers := 0;
         lreceivers := '';

         SELECT l.alg_locatie_email
           INTO lmailfrom
           FROM bez_bezoekers b
              , bez_afspraak a
              , alg_locatie l
          WHERE b.bez_afspraak_key = a.bez_afspraak_key
            AND a.alg_locatie_key = l.alg_locatie_key
            AND b.bez_bezoekers_key = pbez_bezoeker_key;

         FOR hosts IN (SELECT DISTINCT k.res_rsv_ruimte_host_key
                         FROM res_rsv_ruimte k
                        WHERE k.res_reservering_key =
                            ( SELECT r.res_reservering_key
                                FROM bez_afspraak a
                                   , bez_bezoekers b
                                   , res_rsv_ruimte r
                                   , res_reservering v
                               WHERE a.bez_afspraak_key = b.bez_afspraak_key
                                 AND a.res_rsv_ruimte_key = r.res_rsv_ruimte_key
                                 AND r.res_reservering_key = v.res_reservering_key
                                 AND v.res_reservering_ispool = 1
                                 AND b.bez_bezoekers_key = pbez_bezoeker_key
                            )
                          AND k.res_rsv_ruimte_verwijder IS NULL
                      )
         LOOP
            fac.putnotificationsrtprio (NULL,
                                        hosts.res_rsv_ruimte_host_key,
                                        lcode,
                                        pbez_bezoeker_key,
                                        lbericht,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL,
                                        lmailfrom
                                       );
            SELECT prs_perslid_naam_friendly
              INTO lreceivers1
              FROM prs_v_perslid_fullnames
             WHERE prs_perslid_key = hosts.res_rsv_ruimte_host_key;

            IF lnrreceivers = 0 THEN
               lreceivers := lreceivers1;
            ELSE
               lreceivers := lreceivers||', '||lreceivers1;
            END IF;
            lnrreceivers := lnrreceivers+1;
            s := 1;
         END LOOP;

         IF lnrreceivers > 0 THEN
            DBMS_OUTPUT.PUT_LINE(lnrreceivers);
            ltracking :=  lcl.l ('lcl_mld_notification_sent_to');
            DBMS_OUTPUT.PUT_LINE(ltracking);
            ltracking := REPLACE (ltracking, '{0}', lbericht);
            ltracking := REPLACE (ltracking, '{1}', lreceivers);
            DBMS_OUTPUT.PUT_LINE(ltracking);
            fac.trackaction ('#BEZDO2', pbez_bezoeker_key, NULL, NULL, SUBSTR(ltracking,1,2048));  -- maxlengte van fac_srtnotificatie_oms
         END IF;
      END IF;
      RETURN s;
   END;

   PROCEDURE notifybackoffice (prsvkey IN NUMBER, pcode IN VARCHAR2, ptype IN VARCHAR2 DEFAULT NULL, pkey IN NUMBER DEFAULT NULL)
   AS
      --lloc_key       alg_locatie.alg_locatie_key%TYPE;
      --lroom_key      alg_ruimte.alg_ruimte_key%TYPE;
      --lafd_key       prs_perslid.prs_afdeling_key%TYPE;
      --ldisc_key      res_disc_params.res_ins_discipline_key%TYPE;
      loms2bo        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      l2bomode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
      lsrtnoticode   fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
      lfunctiecode   fac_functie.fac_functie_code%TYPE;
      lnrreceivers   NUMBER;
      bericht        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;                         -- kan te kort zijn na substitutie
      lreceivers     fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      lreceivers1    fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      ltracking      VARCHAR2(4000);  -- moet tijdelijk groter dan fac_srtnotificatie.fac_srtnotificatie_oms%TYPE kunnen zijn
      lref_key       NUMBER;
      lext_key       NUMBER;
   BEGIN
      BEGIN
         -- De discipline setting RES_DISC_PARAMS_BONOTIFY geeft aan of de notificatie moeten worden verstuurd.
         -- RES_DISC_PARAMS_BONOTIFY: 0=niet, 1=bof.
         --
         SELECT lcl.x('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms)
              , fac_srtnotificatie_mode
           INTO loms2bo
              , l2bomode
           FROM fac_srtnotificatie
          WHERE fac_srtnotificatie_code = 'RES2BO';
         --
         IF (l2bomode > 0) AND (pcode = 'RESNEW' OR pcode = 'RESUPD')
         THEN
            lfunctiecode := 'WEB_RESBOF';
            lsrtnoticode := 'RES2BO';
            bericht := res.sprintf (loms2bo, prsvkey);  -- de variabelen invullen
         ELSE
            -- hoeft niets te doen
            RETURN;
         END IF;
         --
         lnrreceivers := 0;
         lreceivers := '';
         --
         FOR disc
            IN (SELECT x.alg_locatie_key
                     , x.res_discipline_key
                     , x.prs_afdeling_key
                     , x.alg_ruimte_key
                     , x.res_reservering_key
                  FROM (
                        SELECT rg.alg_locatie_key    -- RES_RUIMTE
                             , rg.res_discipline_key
                             , p.prs_afdeling_key
                             , ra.alg_ruimte_key
                             , rr.res_reservering_key
                          FROM res_v_res_ruimte_gegevens rg
                             , res_alg_ruimte ra
                             , res_ruimte_opstelling ro
                             , res_rsv_ruimte rr
                             , prs_perslid p
                         WHERE rg.res_ruimte_key = ro.res_ruimte_key
                           AND rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key
                           AND ra.res_ruimte_key = ro.res_ruimte_key
                           AND rr.res_rsv_ruimte_host_key = p.prs_perslid_key
                           AND TRUNC(rr.res_rsv_ruimte_van) = TRUNC(sysdate)
                           AND ptype IS NULL
                           AND rr.res_status_bo_key = 2
                           AND rr.res_rsv_ruimte_key = prsvkey
                        UNION
                        SELECT g.alg_locatie_key    -- RES_DEEL
                             , d.res_discipline_key
                             , p.prs_afdeling_key
                             , rr.alg_ruimte_key
                             , rr.res_reservering_key
                          FROM res_rsv_ruimte rr
                             , res_rsv_deel rd
                             , res_deel d
                             , ins_deel i
                             , prs_perslid p
                             , alg_v_allonroerendgoed g
                         WHERE i.ins_alg_ruimte_key = g.alg_ruimte_key
                           AND i.ins_alg_ruimte_type = g.alg_type
                           AND i.ins_deel_key = d.res_ins_deel_key
                           AND rd.res_deel_key = d.res_deel_key
                           AND rd.res_rsv_ruimte_key = rr.res_rsv_ruimte_key
                           AND rr.res_rsv_ruimte_host_key = p.prs_perslid_key
                           AND TRUNC(rr.res_rsv_ruimte_van) = TRUNC(sysdate)
                           AND (   ptype IS NULL
                               OR (ptype = 'V' AND d.res_deel_key = pkey)
                               )
                           AND rd.res_status_bo_key = 2
                           AND rr.res_rsv_ruimte_key = prsvkey
                        UNION
                        SELECT rg.alg_locatie_key    -- RES_ARTIKEL
                             , a.res_discipline_key
                             , p.prs_afdeling_key
                             , rar.alg_ruimte_key
                             , rr.res_reservering_key
                          FROM res_rsv_ruimte rr
                             , res_rsv_artikel ra
                             , res_artikel a
                             , prs_perslid p
                             , res_ruimte_opstelling ro
                             , res_alg_ruimte rar
                             , res_v_res_ruimte_gegevens rg
                         WHERE rr.res_rsv_ruimte_key = ra.res_rsv_ruimte_key
                           AND ra.res_artikel_key = a.res_artikel_key
                           AND rr.res_rsv_ruimte_host_key = p.prs_perslid_key
                           AND rr.res_ruimte_opstel_key = ro.res_ruimte_opstel_key(+)
                           AND ro.res_ruimte_key = rar.res_ruimte_key(+)
                           AND ro.res_ruimte_key = rg.res_ruimte_key(+)
                           AND TRUNC(rr.res_rsv_ruimte_van) = TRUNC(sysdate)
                           AND (   ptype IS NULL
                               OR (ptype = 'C' AND a.res_artikel_key = pkey)
                               )
                           AND ra.res_status_bo_key = 2
                           AND rr.res_rsv_ruimte_key = prsvkey
                       ) x
               )
         LOOP
            FOR boer
               IN (SELECT g.prs_perslid_key
                     FROM fac_v_webgebruiker g
                        , fac_functie f
                        , prs_perslid p
                        , prs_v_afdeling d
                    WHERE g.fac_functie_key = f.fac_functie_key
                      AND g.ins_discipline_key = disc.res_discipline_key
                      AND g.prs_perslid_key = p.prs_perslid_key
                      AND d.prs_afdeling_key = p.prs_afdeling_key
                      AND (      g.fac_gebruiker_prs_level_write = -1
                          OR (   g.fac_gebruiker_prs_level_write = 0
                             AND d.prs_bedrijf_key =
                                    (SELECT aa.prs_bedrijf_key
                                       FROM prs_v_afdeling aa
                                      WHERE aa.prs_afdeling_key = disc.prs_afdeling_key
                                    )
                             )
                          OR (   g.fac_gebruiker_prs_level_write > 0
                             AND p.prs_afdeling_key IN
                                    (SELECT prs_afdeling_key
                                       FROM prs_v_afdeling_familie a
                                      WHERE a.prs_afdeling_elder_key IN
                                            (SELECT aa.prs_afdeling_elder_key
                                               FROM prs_v_afdeling_familie aa
                                              WHERE aa.prs_afdeling_key = disc.prs_afdeling_key
                                                AND aa.niveau = g.fac_gebruiker_prs_level_write
                                            )
                                    )
                             )
                          )
                      -- in ASP:  if (params.loc_key>0)
                      -- Bij ruimte reservering wordt altijd een ruimte ingevuld die is gekoppeld aan alg_ruimte_key. Dus hier op ruimte niveau checken.
                      AND (g.fac_gebruiker_alg_level_write = -1
                           OR (g.fac_gebruiker_alg_level_write < 9
                               AND disc.alg_ruimte_key IN
                                        (SELECT   alg_ruimte_key
                                           FROM   fac_v_my_rooms
                                          WHERE   prs_perslid_key = p.prs_perslid_key
                                            AND   niveau = fac_gebruiker_alg_level_write
                                        )))
                      AND fac_functie_code = lfunctiecode
                  )
            LOOP
               IF (lsrtnoticode = 'RES2BO') THEN
                  lref_key := disc.res_reservering_key;
                  lext_key := prsvkey;
               ELSE
                  lref_key := prsvkey;
                  lext_key := NULL;
               END IF;
               fac.putnotificationsrtprio (NULL,
                                           boer.prs_perslid_key,
                                           lsrtnoticode,
                                           lref_key,
                                           bericht,
                                           NULL,
                                           NULL,
                                           NULL,
                                           lext_key,
                                           NULL,
                                           NULL
                                          );

               SELECT prs_perslid_naam_friendly
                 INTO lreceivers1
                 FROM prs_v_perslid_fullnames
                WHERE prs_perslid_key = boer.prs_perslid_key; -- key van bo-er
               --
               IF lnrreceivers = 0 THEN
                  lreceivers := lreceivers1;
               ELSE
                  lreceivers := lreceivers||', '||lreceivers1;
               END IF;
               lnrreceivers := lnrreceivers+1;
            END LOOP;
         END LOOP;
         --
         IF lnrreceivers > 0 THEN
            DBMS_OUTPUT.PUT_LINE(lnrreceivers);
            ltracking :=  lcl.l ('lcl_mld_notification_sent_to');
            --ltracking := 'Notitificatie ''{0}'' verstuurd aan {1}';
            DBMS_OUTPUT.PUT_LINE(ltracking);
            ltracking := REPLACE (ltracking, '{0}', bericht);
            ltracking := REPLACE (ltracking, '{1}', lreceivers);
            DBMS_OUTPUT.PUT_LINE(ltracking);
            fac.trackaction ('#RES2BO', prsvkey, NULL, NULL, SUBSTR(ltracking,1,2048));  -- maxlengte van fac_srtnotificatie_oms
         END IF;
         --
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            RETURN;
      END;
   END;

   PROCEDURE remove(p_rsv_ruimte_key IN NUMBER)
   IS
      CURSOR c_bijlagen(p_refkey IN NUMBER) IS
         SELECT fac_bijlagen_key
           FROM fac_bijlagen b
              , res_rsv_ruimte r
          WHERE b.fac_bijlagen_refkey = r.res_rsv_ruimte_key
            AND b.fac_bijlagen_module = 'RES'
            AND b.fac_bijlagen_refkey = p_refkey;

      res_key  res_reservering.res_reservering_key%TYPE;
   BEGIN
      -- Verwijder afspraken en de bezoekers daarvan bij deelreservering.
      FOR ref_afspraak IN (SELECT bez_afspraak_key
                             FROM bez_afspraak
                            WHERE res_rsv_ruimte_key = p_rsv_ruimte_key
                          )
      LOOP
         bez.remove(ref_afspraak.bez_afspraak_key);
      END LOOP;

      -- Verwijder de deelreservering.
      fac.remove_tracking('reservering', p_rsv_ruimte_key);
      fac.remove_tracking('xreservering', p_rsv_ruimte_key);

      SELECT res_reservering_key
        INTO res_key
        FROM res_rsv_ruimte
       WHERE res_rsv_ruimte_key = p_rsv_ruimte_key;

      FOR ref_bijlagen IN c_bijlagen(p_rsv_ruimte_key)
      LOOP
         flx.deleteflexbijlage (ref_bijlagen.fac_bijlagen_key);
      END LOOP;

      DELETE FROM res_rsv_ruimte
       WHERE res_rsv_ruimte_key = p_rsv_ruimte_key;

      -- Van de volgende tabellen worden de records die naar deze res_rsv_ruimte_key
      -- verwijzen met ON DELETE CASCADE ook verwijderd:
      --  res_kenmerkwaarde
      --  res_rsv_artikel
      --  res_rsv_deel
      -- In de volgende tabel wordt res_rsv_ruimte_key leeg gemaakt bij het verwijderen van res_rsv_ruimte:
      --  bez_afspraak
      --  mld_melding

      -- Als dit de laatste deelreservering in de reservering is mag de reservering ook weg.
      DELETE FROM res_reservering
       WHERE NOT EXISTS (SELECT 1
                           FROM res_rsv_ruimte
                          WHERE res_reservering_key = res_key
                        )
         AND res_reservering_key = res_key;

      -- Geen tracking op res_reservering.
   END;

END res;
/

REGISTERRUN('$Id$')

#endif // RES
