#ifdef MLD
/*
 * $Revision$
 * $Id$
 */

#undef TRUNC

CREATE OR REPLACE PACKAGE mld AS
  PROCEDURE updatemeldingstatus (meldingkey   IN   NUMBER,
                                 closeit      IN   NUMBER,
                                 user_key     IN   NUMBER);
  PROCEDURE updatemeldingstatusAV (meldingkey IN number, closeit IN number, user_key IN number, autoav IN number);
  FUNCTION  getmeldingstatusdate (pmeldingkey IN number, pstatus IN number) RETURN date;
  FUNCTION  getmeldinguser (pmeldingkey IN number) RETURN NUMBER;
  PROCEDURE setmeldingstatus (pmeldingkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER, pnotificeren IN NUMBER DEFAULT 1);
  FUNCTION  getopdrachtstatusdate (popdrkey IN number, pstatus IN number) RETURN date;
  PROCEDURE setopdrachtstatus (popdrachtkey IN NUMBER,
                               pstatus IN NUMBER,
                               puserkey IN NUMBER,
                               popdr_note_key IN NUMBER DEFAULT NULL,
                               pnotificeren IN NUMBER DEFAULT 1);
  PROCEDURE notifybackoffice (pmeldingkey IN NUMBER, pcode IN VARCHAR2, pdisc_level IN NUMBER DEFAULT 1, pdisckey IN NUMBER DEFAULT NULL);
  PROCEDURE notifybehandelaar (pto IN NUMBER, pcode IN VARCHAR2, pmeldingkey IN NUMBER);
  PROCEDURE notifyprio (pmeldingkey IN NUMBER, prio IN NUMBER, pperslid_key IN NUMBER, pdisc_level IN NUMBER DEFAULT 1);
  PROCEDURE notifyopdrgoedkeurders (popdrkey IN NUMBER);
  PROCEDURE notifyopdrbedrijven (popdrkey              NUMBER,
                                 ptrackingkey          NUMBER,
                                 pnotidelay            NUMBER DEFAULT NULL);
  PROCEDURE notifymeldingbedrijven (pmldkey               NUMBER,
                                    ptrackingkey          NUMBER,
                                    pnotidelay            NUMBER DEFAULT NULL);
  FUNCTION getinstemmer (pmldkey IN NUMBER) RETURN NUMBER;
  PROCEDURE notifyinstemmer (pmldkey IN NUMBER);
  FUNCTION mld_besteed_budget_pgb (p_prs_key IN NUMBER, p_disc_key IN NUMBER)
     RETURN NUMBER;
  FUNCTION mld_besteed_budget_agb (p_kp_key IN NUMBER)
     RETURN NUMBER;
  PROCEDURE mld_addautoorder (p_melding_key IN NUMBER);

  PROCEDURE mld_nextworkflowstep     (p_melding_key        IN NUMBER
                                     ,p_success            IN NUMBER
                                     ,p_user_key           IN NUMBER DEFAULT NULL);
  FUNCTION getlowestobjectuitvoer    (p_melding_key        IN NUMBER) RETURN NUMBER;
  FUNCTION uitvoertijd_to_char       (uitvoertijd          IN MLD_T_UITVOERTIJD) RETURN VARCHAR;
  FUNCTION uitvoertijd_to_unit       (tijd MLD_T_UITVOERTIJD, eenheid VARCHAR2) RETURN NUMBER;
  FUNCTION geteinddatum              (startdate            IN DATE,
                                      stdm_key             IN NUMBER,
                                      prio                 IN NUMBER,
                                      alg_key              IN NUMBER,
                                      ins_key              IN NUMBER,
                                      uitvoertijd_object IN MLD_T_UITVOERTIJD DEFAULT MLD_T_UITVOERTIJD(NULL, NULL)) RETURN DATE;
  FUNCTION geteinddatum              (p_melding_key        IN NUMBER,
                                      p_uitvoertijd_object IN MLD_T_UITVOERTIJD DEFAULT MLD_T_UITVOERTIJD(NULL, NULL),
                                      p_startdate          IN DATE DEFAULT NULL) RETURN DATE;
  FUNCTION getactualuitvoer          (startdate   IN DATE,
                                      enddate     IN DATE,
                                      stdm_key    IN NUMBER,
                                      prio        IN NUMBER,
                                      alg_key     IN NUMBER,
                                      ins_key     IN NUMBER,
                                      eenheid     IN VARCHAR2 DEFAULT NULL
                                      ) RETURN MLD_T_UITVOERTIJD;
  FUNCTION getactualuitvoer          (p_melding_key IN NUMBER) RETURN MLD_T_UITVOERTIJD;
  FUNCTION getactualaccept           (startdate   IN DATE,
                                      enddate     IN DATE,
                                      stdm_key    IN NUMBER,
                                      prio        IN NUMBER,
                                      alg_key     IN NUMBER,
                                      ins_key     IN NUMBER,
                                      eenheid     IN VARCHAR2 DEFAULT NULL
                                      ) RETURN MLD_T_UITVOERTIJD;
  FUNCTION getactualaccept           (p_melding_key IN NUMBER) RETURN MLD_T_UITVOERTIJD;
  FUNCTION getstduitvoer             (stdm_key    IN NUMBER,
                                      prio        IN NUMBER,
                                      alg_key     IN NUMBER,
                                      ins_key     IN NUMBER) RETURN MLD_T_UITVOERTIJD;
  FUNCTION getstduitvoer             (p_melding_key IN NUMBER) RETURN MLD_T_UITVOERTIJD;
  PROCEDURE getSLAparams (stdm_key    IN NUMBER,
                          prio        IN NUMBER,
                          alg_key     IN NUMBER, -- Altijd gebouw of hoger, locatie niet ondersteund
                          ins_key     IN NUMBER,
                          v_mld_stdmelding_regime OUT  NUMBER,
                          v_uitvoertijd_object    OUT  MLD_T_UITVOERTIJD,
                          v_accepttijd            OUT  MLD_T_UITVOERTIJD,
                          v_beginuur              OUT  NUMBER,
                          v_einduur               OUT  NUMBER,
                          v_werkdagen             OUT  NUMBER
                        );
  FUNCTION getacceptdatum            (startdate IN DATE, stdm_key IN NUMBER, alg_key IN NUMBER, p_prio IN NUMBER DEFAULT 3)  RETURN DATE;
  FUNCTION getnettotijdsbesteding    (p_opdr_key    IN NUMBER, p_prs_key IN NUMBER DEFAULT NULL) RETURN NUMBER;
  FUNCTION bepaalopdrmeldingvolgnr   (p_melding_key IN NUMBER) RETURN NUMBER;
  FUNCTION bepaalopdrcontractvolgnr  (p_contract_key IN NUMBER) RETURN NUMBER;
  FUNCTION mldsprintf                (ps IN VARCHAR2, p_melding_key IN NUMBER) RETURN VARCHAR2;
  FUNCTION opdrsprintf               (ps IN VARCHAR2, p_opdr_key IN NUMBER) RETURN VARCHAR2;
  PROCEDURE upsertmeldingkenmerk (p_kenmerk_key   IN NUMBER,
                                  p_mld_key       IN NUMBER,
                                  p_waarde        IN VARCHAR2);
  PROCEDURE upsertopdrachtkenmerk (p_kenmerk_key   IN NUMBER,
                                   p_opdr_key       IN NUMBER,
                                   p_waarde        IN VARCHAR2);
  FUNCTION mldflexsummary (pmelding_key IN NUMBER) RETURN VARCHAR2;
  PROCEDURE remove(p_melding_key IN NUMBER);
  PROCEDURE remove_opdr(p_mld_opdr_key IN NUMBER);
  PROCEDURE resetpostafmeldactie (p_actiecode IN NUMBER DEFAULT 2, p_days IN NUMBER DEFAULT 7);
END mld;
/
CREATE OR REPLACE PACKAGE BODY mld AS
    PROCEDURE updatemeldingstatusAV (meldingkey IN number, closeit IN number, user_key IN number, autoav IN number)
    AS
       openopdrachten number;
       opdrachten number;
       nietavopdrachten number;
    BEGIN
       -- Als closeit=1 dan wordt de melding afgesloten als dat al niet zo was
       -- Anders:
       -- Als er open opdrachten zijn wordt de melding op Uitgegeven gezet als dat al niet zo was
       -- Als er uitsluitend Verwerkte opdrachten zijn, dan worden de melding ook verwerkt als dat al niet zo was
       -- maar alleen als autoav=1. Men kan er voor kiezen dat zelf te regelen (AAIT#24697)
       -- It needs typically to be called after changes in mld_opdr.
       IF closeit = 1
       THEN
          setmeldingstatus (meldingkey, 5, user_key);
       ELSE
          SELECT   COUNT ( * )
            INTO   openopdrachten
            FROM   mld_opdr
           WHERE   mld_melding_key = meldingkey AND mld_statusopdr_key NOT IN (1, 2, 6, 7, 9);

          IF openopdrachten > 0
          THEN
             -- als melding geaccepteerd was wordt deze nu (vanwege open opdrachten) uitgegeven
             -- als melding al Uitgevoerd was wordt deze nu (met in behandeling opdrachten) NIET weer uitgegeven!
             setmeldingstatus (meldingkey, 7, user_key);
          ELSE
             -- Er zijn dus geen actieve opdrachten, maar er zijn wellicht wel dichte opdrachten
             -- Die hebben echter status 1 (Afgewezen), 6 (Afgemeld) of 7 (Verwerkt), 9 (Afgerond)
             -- De melding mag dan naar AV indien er louter 7 (minstens 1) en 1 opdrachten zijn
             SELECT   COUNT ( * )
               INTO   opdrachten
               FROM   mld_opdr
              WHERE   mld_melding_key = meldingkey;

             SELECT   COUNT ( * )
               INTO   nietavopdrachten
               FROM   mld_opdr
              WHERE   mld_melding_key = meldingkey AND mld_statusopdr_key <> 7;

             -- verwerkteopdrachten := opdrachten - nietavopdrachten;
             IF nietavopdrachten = 0 AND opdrachten > 0
             THEN
                IF autoav = 1
                THEN
                    -- There are only orders that are adm. closed, close the call (AV)
                    setmeldingstatus (meldingkey, 6, user_key);
                END IF;
             ELSE
                -- Er zijn alleen opdrachten met status 1 (Afgewezen) of 6/9 (Afgemeld/Afgerond),
                -- dan zetten we de Melding hier terug naar Geaccepteerd indien die Uitgegeven was
                -- Zodat die bij de FO weer onder Inbehandeling valt.
                setmeldingstatus (meldingkey, 4, user_key);
             END IF;
          END IF;
       END IF;
    END;

    -- Om helemaal compatible te blijven
    PROCEDURE updatemeldingstatus (meldingkey IN number, closeit IN number, user_key IN number)
    AS
    BEGIN
        updatemeldingstatusAV (meldingkey, closeit, user_key, 1);
    END;

    -- Geef de datum  waarop de melding op status pstatus is gezet
    -- Alleen bedoeld voor secundaire statussen (datum van registratie is bv wel
    -- direct te bepalen), dus alleen voor 1,4,5,6. Dit zijn tevens de
    -- actions die eenmalig zijn. reden voor deze functie: Ik wil niet dat iedereen die
    -- deze info wil zelf in de tracking moet gaan zoeken.
    FUNCTION getmeldingstatusdate (pmeldingkey IN number, pstatus IN number) RETURN date
    AS
     eventcode fac_srtnotificatie.fac_srtnotificatie_code%TYPE := NULL;
     retdatum date := NULL;
    BEGIN
    -- Welke tag hoort bij de gevraagde status?
       CASE pstatus
          WHEN 1  -- Afgewezen
          THEN
                eventcode :=  'MLDREJ';
          WHEN 4  -- Geaccepteerd (ongezien of gezien)
          THEN
                eventcode :=  'MLDACP';
          WHEN 5  -- Afgemeld
          THEN
                eventcode :=  'MLDAFM';
          WHEN 6  -- Verwerkt
          THEN
                eventcode :=  'MLDVER';
                ELSE NULL;
       END CASE;

       IF eventcode IS NOT NULL THEN
          retdatum := fac.gettrackingdate(eventcode, pmeldingkey);
       END IF;
       RETURN retdatum;
    END;

    -- Niet veel gebruikt, maar voor compatibility gedefinieerd
    -- wellicht nog uit te breiden tot de user per status, als wenselijk
    FUNCTION  getmeldinguser (pmeldingkey IN number) RETURN number
    AS
        perslid_key fac_tracking.prs_perslid_key%TYPE := NULL;
    BEGIN
       perslid_key := fac.gettrackinguserkey('MLDNEW', pmeldingkey);
       RETURN perslid_key;
    END;

    -- Geef meldingkey, gewenste status en userkey, en de status wordt
    -- gezet, waarbij zonodig (indien verandering) een trackrecord wordt gemaakt
    -- Als de status niet wijzigt, wordt ook geen trackrecord gemaakt
    -- ZIE schema StateDiagramOpdrachten.vsd
   -- Onderliggende childmeldingen krijgen dezelfde status, wat normaliter
   -- zou moeten lukken
   PROCEDURE setmeldingstatus (pmeldingkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER, pnotificeren IN NUMBER DEFAULT 1)
   AS
      currentstatus mld_melding.mld_melding_status%TYPE;
      activiteit_key mld_melding.fac_activiteit_key%TYPE;
      newstatus mld_melding.mld_melding_status%TYPE;
      conceptstatus mld_melding.mld_melding_conceptstatus%TYPE;
      eventcode VARCHAR2(10);  -- tabelsize is 6
      clear_on_close NUMBER(2);  -- +1 = Attentie, +2 = Behandelaar , +4 = Behandelteam, +8 = Actieve behandelaar
      actiecode mld_melding.mld_melding_actiecode%TYPE;
      behandelaar_key mld_melding.mld_melding_behandelaar_key%TYPE;
      discipline_key mld_melding.mld_ins_discipline_key%TYPE;
      behandelaar2_key mld_melding.mld_melding_behandelaar2_key%TYPE;

      CURSOR c_mldchilderen
      IS
         SELECT   mld_melding_key
           FROM   mld_melding
          WHERE   mld_melding_parentkey = pmeldingkey;
   BEGIN
      SELECT   mld_melding_status, fac_activiteit_key, mld_melding_actiecode,
               mld_melding_behandelaar_key, mld_ins_discipline_key, mld_melding_behandelaar2_key,
               mld_melding_conceptstatus
        INTO   currentstatus, activiteit_key, actiecode,
               behandelaar_key, discipline_key, behandelaar2_key,
               conceptstatus
        FROM   mld_melding
       WHERE   mld_melding_key = pmeldingkey;

      CASE pstatus
         WHEN 0                                                                                               -- Pending
         THEN
            IF currentstatus IS NULL
            THEN
               newstatus := pstatus;
               eventcode := 'MLDNEW';
            ELSIF currentstatus = 2 OR currentstatus = 4
            THEN
               newstatus := pstatus;
               eventcode := 'MLDBWD';
            END IF;
         WHEN 1                                                                                             -- Afgewezen
         THEN
            IF currentstatus IS NULL OR currentstatus = 0 OR currentstatus = 2 OR currentstatus = 4
            THEN
               newstatus := pstatus;
               eventcode := 'MLDREJ';
               clear_on_close := fac.getsetting('mld_clear_on_close');
               IF BITAND(clear_on_close, 1) = 1
               THEN
                  actiecode := 1;
               END IF;
               IF BITAND(clear_on_close, 2) = 2
               THEN
                  behandelaar_key := NULL;
               END IF;
               IF BITAND(clear_on_close, 4) = 4
               THEN
                  discipline_key := NULL;
               END IF;
               IF BITAND(clear_on_close, 8) = 8
               THEN
                  behandelaar2_key := NULL;
               END IF;
            END IF;
         WHEN 2                                                                                             -- Ingevoerd
         THEN
            IF currentstatus IS NULL OR currentstatus = 1 OR (currentstatus = 2 AND conceptstatus = 0)
            THEN
               newstatus := pstatus;
               IF conceptstatus = 0
               THEN
                  eventcode := 'MLDNEW';
               ELSE
                  eventcode := 'MLDCON';  -- eerst Concept
               END IF;
            ELSIF currentstatus = 0
            THEN
               newstatus := pstatus;
               eventcode := 'MLDDOO';
            ELSIF currentstatus = 4 OR currentstatus = 7 -- mld_disc_params_keten of mld_forward_if_active
            THEN
               newstatus := pstatus;
               eventcode := 'MLDFWD';
            END IF;
         WHEN 4                                                                     -- Geaccepteerd (ongezien of gezien)
         THEN
            IF currentstatus = 2
            THEN
               newstatus := pstatus;
               eventcode := 'MLDACP';
            ELSIF currentstatus = 7
            THEN
               newstatus := pstatus;
               eventcode := NULL;                                 -- Terug van uitgegeven is geen meldingstatuswijziging
            END IF;
         WHEN 5                                                                                              -- Afgemeld
         THEN
            IF currentstatus = 2 OR currentstatus = 0 OR currentstatus = 4 OR currentstatus = 7
            THEN
               newstatus := pstatus;
               eventcode := 'MLDAFM';
               clear_on_close := fac.getsetting('mld_clear_on_close');
               IF BITAND(clear_on_close, 1) = 1
               THEN
                  actiecode := 1;
               END IF;
               IF BITAND(clear_on_close, 2) = 2
               THEN
                  behandelaar_key := NULL;
               END IF;
               IF BITAND(clear_on_close, 4) = 4
               THEN
                  discipline_key := NULL;
               END IF;
               IF BITAND(clear_on_close, 8) = 8
               THEN
                  behandelaar2_key := NULL;
               END IF;
               -- Van actiecode bit 128 wissen indien gezet.
               IF BITAND(actiecode, 128) = 128
               THEN
                  actiecode := actiecode - 128;
               END IF;
            END IF;
         WHEN 6                                                                                              -- Verwerkt
         THEN
            IF currentstatus = 5
            THEN
               newstatus := pstatus;
               eventcode := 'MLDVER';
            END IF;
         WHEN 7                                                                                            -- Uitgegeven
         THEN
            IF currentstatus = 4
            THEN
               newstatus := pstatus;
               -- eventcode := 'MLDUIT';
            END IF;
         ELSE
            -- Invalid statuschange or no change
            newstatus := NULL;
      END CASE;

      IF newstatus IS NOT NULL
      THEN
         -- vooralsnog lopen de notificaties 1-op-1 met de tracking
         -- noticode := eventcode;
         UPDATE   mld_melding
            SET   mld_melding_status = newstatus,
                  mld_melding_actiecode = actiecode,
                  mld_melding_behandelaar_key = behandelaar_key,
                  mld_ins_discipline_key = discipline_key,
                  mld_melding_behandelaar2_key = behandelaar2_key
          WHERE   mld_melding_key = pmeldingkey;

         IF activiteit_key > 0
         THEN
             RETURN;
         END IF;

         IF eventcode = 'MLDAFM'
         THEN
              fac.createlikebookmark ('melding', pmeldingkey);
         ELSIF newstatus <> 0 AND newstatus <> 3 AND fac.getsetting('mld_notify_retract') = 1
         THEN
                fac.clrnotifications('MLDNW_', pmeldingkey, NULL, 'MLDACP');
         END IF;
         IF pnotificeren = 0 AND eventcode = 'MLDAFM'
         THEN
                eventcode := '#' || eventcode;
         END IF;

         -- We know that trackaction doesn't do tracking if eventcode is null
         fac.trackaction (eventcode, pmeldingkey, puserkey, NULL, NULL);

         -- Als het concept is moet altijd de insteming ingeschakeld worden.
         IF eventcode = 'MLDCON'
         THEN
            mld.notifyinstemmer(pmeldingkey);
         END IF;

         FOR r IN c_mldchilderen
         LOOP
            UPDATE   mld_melding
               SET   mld_melding_status = newstatus
             WHERE   mld_melding_key = r.mld_melding_key;
             IF eventcode = 'MLDAFM' OR eventcode = '#MLDAFM'
             THEN
                  fac.createlikebookmark ('melding', r.mld_melding_key);
             ELSIF newstatus <> 0 AND newstatus <> 3 AND fac.getsetting('mld_notify_retract') = 1
             THEN
                    fac.clrnotifications('MLDNW_', r.mld_melding_key, NULL, 'MLDACP');
             END IF;
            fac.trackaction (eventcode, r.mld_melding_key, puserkey, NULL, NULL);
         END LOOP;
      END IF;
   END;

    /* Deze functie is handig maar is amper toepasbaar bij intensieve queries */
    FUNCTION getopdrachtstatusdate (popdrkey IN number, pstatus IN number) RETURN date
    AS
         eventcode fac_srtnotificatie.fac_srtnotificatie_code%TYPE := NULL;
         retdatum date := NULL;
    BEGIN
        -- Welke tag hoort bij de gevraagde status?
           CASE pstatus
              WHEN 1
              THEN
                    eventcode :=  'ORDCAN';
              WHEN 2
              THEN
                    eventcode :=  'ORDFNO';  -- of ORDFNGO of ORDOOK
              WHEN 3
              THEN
                    eventcode :=  'ORDFIA';
              WHEN 4
              THEN
                    eventcode :=  'ORDFOK';
              WHEN 5
              THEN
                    eventcode :=  'ORDNEW';
              WHEN 6  -- Afgemeld
              THEN
                    eventcode :=  'ORDAFM';
              WHEN 7  -- Verwerkt
              THEN
                    eventcode :=  'ORDVER';
              WHEN 9  -- Kosten Afgemeld
              THEN
                    eventcode :=  'ORDAFR'; -- of ORDOOK
              WHEN 8
              THEN
                    eventcode :=  'ORDACP';
              WHEN 10  -- Ter goedkeuring
              THEN
                    eventcode :=  'ORDGOE';
              ELSE NULL;
           END CASE;

           IF eventcode IS NOT NULL THEN
             retdatum := fac.gettrackingdate(eventcode, popdrkey);
           END IF;
        RETURN retdatum;
    END;

    -- Geef opdrachtkey, gewenste status en userkey, en de status wortdt
    -- gezet, waarbij zonodig (indien verandering) een trackrecord wordt gemaakt
    -- Als de status niet wijzigt, wordt ook geen trackrecord gemaakt
    -- ZIE schema StateDiagramOpdrachten.vsd
    PROCEDURE setopdrachtstatus (popdrachtkey IN NUMBER,
                                 pstatus IN NUMBER,
                                 puserkey IN NUMBER,
                                 popdr_note_key IN NUMBER DEFAULT NULL,
                                 pnotificeren IN NUMBER DEFAULT 1)
    AS
       currentstatus mld_opdr.mld_statusopdr_key%TYPE;
       newstatus mld_opdr.mld_statusopdr_key%TYPE;
       teverzenden mld_opdr.mld_opdr_teverzenden%TYPE;
       eventcode VARCHAR2(10);  -- tabelsize is 6
       typeopdr_key mld_typeopdr.mld_typeopdr_key%TYPE;
       typeopdr_isofferte mld_typeopdr.mld_typeopdr_isofferte%TYPE;
       statusopdr_key_refiat mld_opdr.mld_statusopdr_key_refiat%TYPE;
       new_fac_tracking_key fac_tracking.fac_tracking_key%TYPE;
       l_notificeren NUMBER;
    BEGIN
       l_notificeren := pnotificeren;
       SELECT   mld_statusopdr_key, mld_typeopdr_key, mld_statusopdr_key_refiat, mld_opdr_teverzenden
         INTO   currentstatus, typeopdr_key, statusopdr_key_refiat, teverzenden
         FROM   mld_opdr
        WHERE   mld_opdr_key = popdrachtkey;
       CASE pstatus
          WHEN 1  -- Verworpen
          THEN
             IF currentstatus = 2
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDREJ';
             ELSIF currentstatus = 4 OR currentstatus = 5 OR currentstatus = 8  -- Verwerpen vanuit status Gefiatteerd(4) alleen door Putorders (fac.markorderassent).
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDCAN';
             END IF;
          WHEN 2  -- Niet gefiatteerd/niet goedgekeurd
          THEN
             IF currentstatus = 3
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDFNO';
             ELSIF currentstatus = 6
             THEN
                -- dit (van 6 naar 2) kan nu alleen igv offerte
                -- bij uitbreiding zonodig gaan kijken naar isofferte
                -- om het onderscheid te bepalen
                newstatus :=  pstatus;
                eventcode :=  'ORDONO';  -- Offerte afgewezen
             ELSIF currentstatus = 10
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDGNO';
             END IF;
          WHEN 3  -- Ter fiattering
          THEN
             IF currentstatus IS NULL OR currentstatus = 10 OR
                currentstatus = 5 OR currentstatus = 6 OR currentstatus = 8 OR currentstatus = 9  -- Hergoedkeuring/Herfiattering.
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDFIA';
             END IF;
          WHEN 4  -- Gefiatteerd
          THEN
             IF currentstatus = 3
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDFOK';
             END IF;
          WHEN 5  -- Uitgegeven
          THEN
             -- Eerste keer goedkeuren/fiateren komt van currentstatus NULL, 4 of 10.
             -- Terugkomen van hergoedkeuring/herfiattering/ komt van currentstatus 3 (afgewezen), 4 of 10.
             IF currentstatus IS NULL OR currentstatus = 3 OR currentstatus = 4 OR currentstatus = 10
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDNEW';
                IF l_notificeren = 1 AND (teverzenden IS NULL OR teverzenden = 0) -- gebruiker heeft aangegeven 'niet versturen'
                THEN
                   l_notificeren := 2; -- alleen niet naar technisch adres
                END IF;
             END IF;
          WHEN 6  -- Proces Technisch voltooid (TV) (Afgemeld)
          THEN
             -- Terugkomen van hergoedkeuring/herfiattering/ komt van currentstatus 3 (afgewezen), 4 of 10.
             IF currentstatus = 3 OR currentstatus = 4 OR currentstatus = 5 OR currentstatus = 8 OR currentstatus = 10
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDAFM';
             END IF;
          WHEN 7  -- Administratief voltooid (AV) (Verwerkt)
          THEN
             IF currentstatus = 6 OR currentstatus = 9
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDVER';
             END IF;
          WHEN 8  -- Geaccepteerd door de uitvoerder
          THEN
             -- Terugkomen van hergoedkeuring/herfiattering/ komt van currentstatus 3 (afgewezen), 4 of 10.
             IF currentstatus = 3 OR currentstatus = 4 OR currentstatus = 5 OR currentstatus = 10
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDACP';
             END IF;
          WHEN 9  -- Kosten Voltooid (Afgerond) of Offerte Ok
          THEN
             -- Terugkomen van hergoedkeuring/herfiattering/ komt van currentstatus 3 (afgewezen), 4 of 10.
             IF currentstatus = 3 OR currentstatus = 4 OR currentstatus = 6 OR currentstatus = 10
             THEN
                newstatus :=  pstatus;
                -- CHECK OP OFFERTEAANVRAAG
               SELECT mld_typeopdr_isofferte
                 INTO typeopdr_isofferte
                 FROM mld_typeopdr
                WHERE mld_typeopdr_key = typeopdr_key;
                -- exceptions? ik gok van niet.
                IF typeopdr_isofferte = 1
                THEN
                    eventcode :=  'ORDOOK';     -- offerte ok
                ELSE
                    eventcode :=  'ORDAFR';     -- kosten voltooid
                END IF;
             END IF;
          WHEN 10  -- Ter goedkeuring
          THEN
             IF currentstatus IS NULL OR
                currentstatus = 5 OR currentstatus = 6 OR currentstatus = 8 OR currentstatus = 9  -- Hergoedkeuring/Herfiattering.
             THEN
                newstatus :=  pstatus;
                eventcode :=  'ORDGOE';
             END IF;
          ELSE
             -- Invalid statuschange or no change
             newstatus :=  NULL;
       END CASE;
       IF newstatus IS NOT NULL
       THEN
          -- vooralsnog lopen de notificaties 1-op-1 met de tracking
          -- noticode :=  eventcode;
          UPDATE   mld_opdr
             SET   mld_statusopdr_key = newstatus
           WHERE   mld_opdr_key = popdrachtkey;
          -- We know that trackaction doesnt do tracking if eventcode is null
          -- Bij hergoedkeuring/herfiattering alleen het fiatteren en goedkeuren tracken.
          IF statusopdr_key_refiat IS NULL OR
             newstatus = 3 OR newstatus = 4 OR newstatus = 10
          THEN
             IF l_notificeren = 0 AND eventcode IS NOT NULL
             THEN
               eventcode := '#' || eventcode;
             END IF;
             IF l_notificeren = 2 AND eventcode IS NOT NULL
             THEN
               eventcode := '@' || eventcode; -- Niet naar technisch adres, wel naar personen
             END IF;
             fac.trackaction (eventcode, popdrachtkey, puserkey, NULL, NULL, new_fac_tracking_key);
             IF popdr_note_key IS NOT NULL
             THEN
                UPDATE mld_opdr_note
                   SET fac_tracking_key = new_fac_tracking_key
                 WHERE mld_opdr_note_key = popdr_note_key;
             END IF;
          END IF;
       END IF;
    END;

    -- Stuur alle mogelijke backofficemedewerkers een bericht als de
    -- melding NIEUW (niet-concept) is of geaccepteerd wordt door MLDBO3.
    -- Naar wie, wordt reversed opgezocht op basis van toegekende autorisaties
    -- (zoals bij de lijst van BO-behandelaars in suggest/persoonfilter.inc)
    -- pdisc_level: (1) Notificatie MLD2BO || MLD2B3.
    --                  Afhankelijk van notificatie, status en mld_disc_params_bonotify.
    --                  Discipline gelijk aan die van de standaard melding (mld_stdmelding.mld_ins_discipline_key).
    --              (2) Notificatie MLDBHG HOOFD behandelteam/behandelaar.
    --                  Als de status Nieuw/Ingevoerd(2) of Geaccepteerd(4) is.
    --                  Discipline gelijk aan die van de melding (mld_melding.mld_ins_discipline_key).
    --              (3) Notificatie MLDBHG BLOK behandelteam/behandelaar.
    --                  Als de status Geaccepteerd(4) of Uitgegeven(7) is.
    --                  Discipline gelijk aan de meegegeven discipline.
    PROCEDURE notifybackoffice (pmeldingkey IN NUMBER, pcode IN VARCHAR2, pdisc_level IN NUMBER DEFAULT 1, pdisckey IN NUMBER DEFAULT NULL)
    AS
        lloc_key       mld_melding.mld_alg_locatie_key%TYPE;
        lonrg_key      mld_melding.mld_alg_onroerendgoed_keys%TYPE;
        lalg_type      alg_v_onroerendgoed.alg_type%TYPE;
        lafd_key       prs_perslid.prs_afdeling_key%TYPE;
        ldisc_key      mld_disc_params.mld_ins_discipline_key%TYPE;
        lspoed         mld_melding.mld_melding_spoed%TYPE;
        lnotiprio      NUMBER (1);
        loms2bo        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        loms2b3        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        lomsbht        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        loms2bp        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        l2bomode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
        l2b3mode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
        lbhtmode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
        l2bpmode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE := 0;
        lbonotify      mld_disc_params.mld_disc_params_bonotify%TYPE;
        lbhgnotify     mld_disc_params.mld_disc_params_bhgnotify%TYPE;
        lfunctiecode   fac_functie.fac_functie_code%TYPE;
        lsrtnoticode   fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
        lstatus        mld_melding.mld_melding_status%TYPE;
        lbehandelaar   mld_melding.mld_melding_behandelaar2_key%TYPE;
        bericht        VARCHAR2 (4000);                   -- fac_srtnotificatie_oms%TYPE kan te kort zijn na substitutie
        priobericht    VARCHAR2 (4000);                   -- fac_srtnotificatie_oms%TYPE kan te kort zijn na substitutie
        lnrreceivers   NUMBER;
        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
        lnotifyooh     mld_disc_params.mld_disc_params_offhours%TYPE;
        lsender        mld_discipline.ins_discipline_email%TYPE;
        l_conceptstatus mld_melding.mld_melding_conceptstatus%TYPE;
    BEGIN
        BEGIN
            -- De vakgroep (discipline) setting MLD_DISC_PARAMS_BONOTIFY geeft aan of de notificatie moeten worden verstuurd.
            -- MLD_DISC_PARAMS_BONOTIFY: 0=niet, 1=bof, 2=bo3, 3=bo3 (aanmaak nieuwe melding) en dan bof (accepteren melding).
            -- Voor PRIO-Hoog meldingen wordt MLD2BP gestuurd (if there is no handler), ongeacht deze settings

            -- Sturing notificaties MLD2BO en MLD2B3 puur op basis van mld_disc_params_bonotify (Niet op de geconfigureerde WEB_MLDBO3 en WEB_MLDBOF rechten).
            -- Notificaties: MLD2BO: Er is een nieuwe melding XXX.
            --               MLD2B3: Voor melding XXX is uw acceptatie vereist.
            --                    | notificatie 1      | notificatie 2             |
            -- BONOTIFY           | (status Nieuw (2)) | (status Geaccepteerd (4)) | Te configureren WEB_MLDBO3 en WEB_MLDBOF rechten
            -- 0 (niet)           |       X            |         X                 |
            -- 1 (bof)            |       BOF(MLD2BO)  |         X                 | Alleen WEB_MLDBOF rechten zijn actief (niemand heeft WEB_MLDBO3 rechten).
            -- 2 (bo3)            |       BO3(MLD2B3)  |         X                 | Zowel de WEB_MLDBO3 als WEB_MLDBOF rechten zijn actief.
            -- 3 (bo3 en dan bof) |       BO3(MLD2B3)  |         BOF(MLD2BO)       | Zowel de WEB_MLDBO3 als WEB_MLDBOF rechten zijn actief.
            BEGIN
                SELECT DISTINCT m.mld_alg_locatie_key, -- DISTINCT omdat een melding met spoed zowel als spoed als als new/acp kan voorkomen?
                                m.mld_alg_onroerendgoed_keys,
                                onrg.alg_type,
                                p.prs_afdeling_key,
                                CASE
                                    WHEN pdisc_level = 1 THEN stdm.mld_ins_discipline_key
                                    WHEN pdisc_level = 2 THEN m.mld_ins_discipline_key
                                    WHEN pdisc_level = 3 THEN pdisckey
                                END,
                                m.mld_melding_spoed,
                                mdp.mld_disc_params_bonotify,
                                mdp.mld_disc_params_bhgnotify,
                                mdp.mld_disc_params_offhours,
                                m.mld_melding_status,
                                m.mld_melding_behandelaar2_key,
                                m.mld_melding_conceptstatus
                  INTO lloc_key,
                       lonrg_key,
                       lalg_type,
                       lafd_key,
                       ldisc_key,
                       lspoed,
                       lbonotify,
                       lbhgnotify,
                       lnotifyooh,
                       lstatus,
                       lbehandelaar,
                       l_conceptstatus
                  FROM mld_melding m,
                       prs_perslid p,
                       mld_stdmelding stdm,
                       mld_disc_params mdp,
                       alg_v_onroerendgoed onrg
                 WHERE m.prs_perslid_key = p.prs_perslid_key AND stdm.mld_stdmelding_key = m.mld_stdmelding_key
                       -- Eerste notificatie: Melding is nieuw (2).
                       --                     Naar BOF de MLD2BO notificatie: Alleen als bonotify = 1.
                       --                     Naar BO3 de MLD2B3 notificatie: Alleen als bonotify = 2 en 3.
                       --                     Tevens MLD2BP naar BOF indien het een spoed is and no handler is present
                       -- Tweede notificatie: Melding is net geaccepteerd (4).
                       --                     Naar BOF de MLD2BO notificatie: Alleen als bonotify = 3.
                       --
                       AND (   (pdisc_level = 1                                                               -- -- -- -- -- -- -- -- --
                                AND ((mld_melding_status = 2 OR mld_melding_status IS NULL)                   --                      --
                                     AND pcode != 'MLDACP'                                                    --                      --
                                     AND mdp.mld_disc_params_bonotify > 0)                                    --  > MLD2BO || MLD2B3  --
                            OR (mld_melding_status = 4                                                        --                      --
                                AND pcode = 'MLDACP'                                                          --                      --
                                AND mdp.mld_disc_params_bonotify = 3))                                        -- -- -- -- -- -- -- -- --
                            OR ((   (pdisc_level = 2 AND (mld_melding_status = 2 OR mld_melding_status = 4))  --                      --
                                 OR (pdisc_level = 3 AND (mld_melding_status = 4 OR mld_melding_status = 7))) --  > MLDBHG            --
                                AND mdp.mld_disc_params_bhgnotify > 0)                                        --                      --
                            OR mld_melding_spoed <= 2)                                                        -- -- -- -- -- -- -- -- --
                       AND (   (pdisc_level = 1 AND stdm.mld_ins_discipline_key = mdp.mld_ins_discipline_key)
                            OR (pdisc_level = 2 AND    m.mld_ins_discipline_key = mdp.mld_ins_discipline_key)
                            OR (pdisc_level = 3 AND                    pdisckey = mdp.mld_ins_discipline_key))
                       AND m.mld_alg_onroerendgoed_keys = onrg.alg_onroerendgoed_keys(+)
                       AND mld_melding_key = pmeldingkey;              -- op dit moment nog alleen voor NIEUWE meldingen

                -- Early exit als het nog een conceptmelding is
                IF l_conceptstatus <> 0
                THEN
                  RETURN;
                END IF;

                DBMS_OUTPUT.put_line ('melding zegt: hier moet genotificeerd worden');

                -- These notifications are now sent on behalf of the system, what might be the local FM organisation
                SELECT MAX (COALESCE(cd.ins_discipline_email, l.alg_locatie_email)) email
                  INTO lsender
                  FROM mld_melding m,
                       mld_stdmelding sm,
                       mld_discipline cd,
                       alg_locatie l
                 WHERE m.mld_stdmelding_key = sm.mld_stdmelding_key
                   AND sm.mld_ins_discipline_key = cd.ins_discipline_key
                   AND m.mld_alg_locatie_key = l.alg_locatie_key(+)
                   AND m.mld_melding_key = pmeldingkey;

                -- Als die melding/status er niet is, is er niks te doen en sprongen we al naar de exception
                -- Als die melding/status er wel is, gaan we verder

                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 = 'MLD2BO';

                SELECT lcl.x ('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms),
                       fac_srtnotificatie_mode
                  INTO loms2b3, l2b3mode
                  FROM fac_srtnotificatie
                 WHERE fac_srtnotificatie_code = 'MLD2B3';

                SELECT lcl.x ('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms),
                       fac_srtnotificatie_mode
                  INTO lomsbht, lbhtmode
                  FROM fac_srtnotificatie
                 WHERE fac_srtnotificatie_code = 'MLDBHG';

                -- Vertaal melding-spoed (1-4) met 3=normaal naar email-spoed (1-3), waarbij 1=hoog, 2=normaal, 3=laag
                IF lspoed <= 2
                THEN
                    lnotiprio := 1;
                ELSIF lspoed = 4
                THEN
                    lnotiprio := 3;
                ELSE
                    lnotiprio := 2;
                END IF;

                -- Igv spoed sturen we een extra-bericht (bedoeld als extra SMS) naar dezelfde BO-ers
                -- als die overdag een bericht krijgen. De eventuele achterwacht is verondersteld zelf op te letten.
                IF lnotiprio = 1 AND lbehandelaar IS NULL
                THEN
                    BEGIN
                        DBMS_OUTPUT.put_line ('Spoedje!');

                        SELECT lcl.x ('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms),
                               fac_srtnotificatie_mode
                          INTO loms2bp, l2bpmode
                          FROM fac_srtnotificatie
                         WHERE fac_srtnotificatie_code = 'MLD2BP' AND fac_srtnotificatie_mode > 0;

                        priobericht := mld.mldsprintf (loms2bp, pmeldingkey);
                    EXCEPTION
                        WHEN NO_DATA_FOUND
                        THEN
                            priobericht := NULL;
                            l2bpmode := 0;
                    END;
                    DBMS_OUTPUT.put_line ('Wordt evt genotificeerd met mode '||l2bpmode);
                END IF;

                -- Deze gaat alleen naar de prio mail van het behandelteam en valt dus buiten de aankomende if/else tak die naar alle BO'ers stuurt
                IF pdisc_level IN (2, 3) AND pcode = 'MLDBHG' AND BITAND(lbhgnotify, 2) = 2
                THEN
                    mld.notifyprio (pmeldingkey, lspoed, NULL, 2);
                END IF;

                -- Met alle varianten op mode 0 (dat is hier niet ongebruikelijk) zijn deze notificaties
                -- feitelijk uitgeschakeld en hoef ik dus ook niet duur te bepalen naar wie een notificatie niet gestuurd hoeft
                -- Sturing notificatie MLDBHG, MLD2BO of MLD2B3 (evt aangevuld met MLD2BP)
                IF (lbhtmode > 0 OR l2bpmode > 0) AND
                    pcode = 'MLDBHG' AND
                    BITAND(lbhgnotify, 1) = 1 AND
                    ((pdisc_level = 2 AND lstatus IN (2, 4)) OR (pdisc_level = 3 AND lstatus IN (4, 7)))
                THEN
                    lfunctiecode := 'WEB_MLDBOF';
                    lsrtnoticode := 'MLDBHG';
                    bericht := mld.mldsprintf (lomsbht, pmeldingkey);                          -- de variabelen invullen
                ELSIF (l2b3mode > 0 OR l2bpmode > 0) AND lstatus = 2 AND pcode != 'MLDACP' AND pcode != 'MLDBHG' AND (lbonotify = 2 OR lbonotify = 3)
                THEN
                    lfunctiecode := 'WEB_MLDBO3';
                    lsrtnoticode := 'MLD2B3';
                    bericht := mld.mldsprintf (loms2b3, pmeldingkey);                          -- de variabelen invullen
                ELSIF ((l2bomode > 0 OR l2bpmode > 0) AND (lstatus = 2 AND pcode != 'MLDACP' AND pcode != 'MLDBHG' AND lbonotify = 1)
                       OR (lstatus = 4 AND pcode = 'MLDACP' AND lbonotify = 3))
                THEN
                    lfunctiecode := 'WEB_MLDBOF';
                    lsrtnoticode := 'MLD2BO';
                    bericht := mld.mldsprintf (loms2bo, pmeldingkey);                          -- de variabelen invullen
                ELSE
                    DBMS_OUTPUT.put_line ('vakgroep zegt: hier hoeft niks genotificeerd te worden');
                    RETURN;
                END IF;
            EXCEPTION
                WHEN NO_DATA_FOUND
                THEN
                    DBMS_OUTPUT.put_line ('melding zegt: hier hoeft niks (meer) genotificeerd te worden');
                    -- hoeven we helemaal niets te doen
                    RETURN;
            END;

            DBMS_OUTPUT.put_line ('we gaan ' || lsrtnoticode || ': ' || bericht || ' sturen aan ' || lfunctiecode);
            DBMS_OUTPUT.put_line ('we gaan nu kijken wie dat zijn');

            lnrreceivers := 0;
            lreceivers := '';

            -- Buiten kantooruren naar de achterwacht melden.
            IF lnotifyooh = 1
            THEN
                IF ( (fac.iswerkdag (SYSDATE) = 0)                                               -- weekend of vrije dag
                                                  OR (fac.iswerktijd = 0)                          -- buiten kantoortijd
                                                                         )
                THEN
                    DBMS_OUTPUT.put_line ('Naar de achterwacht!');
                    lreceivers := fac.getsetting ('nightly_mld2bo_emailaddress');
                    lnrreceivers := lnrreceivers + 1;
                    fac.putnotificationsrtprio (NULL,
                                                NULL,
                                                lsrtnoticode,
                                                pmeldingkey,
                                                bericht,
                                                NULL,
                                                lreceivers,
                                                NULL,
                                                NULL,
                                                lnotiprio,                                                      -- 1,2,3
                                                lsender);
                    RETURN;                                       -- Dan doen we de rest van de gebruikers helemaal niet
                END IF;
            END IF;

            -- Hier gaan we berichten sturen naar de BO-ers
            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 = ldisc_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 = lafd_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 = lafd_key
                                                                       AND aa.niveau = g.fac_gebruiker_prs_level_write))))
                           -- in ASP:  if (params.loc_key>0, hier is lloc_key dan NULL en gaat het ook goed)
                           -- Afhankelijk op welk niveau de plaatsselector is ingevuld moet hier op dat niveau gechecked worden.
                           AND (g.fac_gebruiker_alg_level_write = -1
                                OR (g.fac_gebruiker_alg_level_write < 9
                                    AND (CASE
                                             WHEN lalg_type IS NULL
                                                  AND lloc_key IN
                                                             (SELECT alg_locatie_key
                                                                FROM fac_v_my_locations
                                                               WHERE prs_perslid_key = p.prs_perslid_key
                                                                     AND niveau = fac_gebruiker_alg_level_write)
                                             THEN
                                                 1
                                             WHEN lalg_type = 'T'
                                                  AND lonrg_key IN
                                                             (SELECT alg_terreinsector_key
                                                                FROM fac_v_my_locations l, alg_terreinsector t
                                                               WHERE t.alg_locatie_key = l.alg_locatie_key
                                                                     AND l.prs_perslid_key = p.prs_perslid_key
                                                                     AND l.niveau = fac_gebruiker_alg_level_write)
                                             THEN
                                                1
                                             WHEN lalg_type = 'G'
                                                  AND lonrg_key IN
                                                             (SELECT alg_gebouw_key
                                                                FROM fac_v_my_buildings
                                                               WHERE prs_perslid_key = p.prs_perslid_key
                                                                     AND niveau = fac_gebruiker_alg_level_write)
                                             THEN
                                                 1
                                             WHEN lalg_type = 'V'
                                                  AND lonrg_key IN
                                                             (SELECT alg_verdieping_key
                                                                FROM fac_v_my_floors
                                                               WHERE prs_perslid_key = p.prs_perslid_key
                                                                     AND niveau = fac_gebruiker_alg_level_write)
                                             THEN
                                                 1
                                             WHEN lalg_type = 'R'
                                                  AND lonrg_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)
                                             THEN
                                                 1
                                             ELSE
                                                 0
                                         END) = 1))
                           AND fac_functie_code = lfunctiecode)
            LOOP
                fac.putnotificationsrtprio (NULL,
                                            boer.prs_perslid_key,
                                            lsrtnoticode,
                                            pmeldingkey,
                                            bericht,
                                            NULL,
                                            NULL,
                                            NULL,
                                            NULL,
                                            lnotiprio,
                                            lsender);
                DBMS_OUTPUT.put_line ('bo-er: ' || boer.prs_perslid_key);

                -- Het kan zijn dat er ook een extra spoed bericht gestuurd moet worden
                IF l2bpmode > 0
                THEN
                    DBMS_OUTPUT.put_line ('Krijgt ook nog de prionotificatie');
                    fac.putnotificationsrtprio (NULL,
                                                boer.prs_perslid_key,
                                                'MLD2BP',                                                -- lsrtnoticode
                                                pmeldingkey,
                                                priobericht,
                                                NULL,
                                                NULL,
                                                NULL,
                                                NULL,
                                                1,                                                      -- spoed dus :-)
                                                lsender);
                END IF;

                IF lnrreceivers = 0
                THEN
                    SELECT prs_perslid_naam_friendly
                      INTO lreceivers
                      FROM prs_v_perslid_fullnames
                     WHERE prs_perslid_key = boer.prs_perslid_key;
                ELSE
                    SELECT prs_perslid_naam_friendly
                      INTO lreceivers1
                      FROM prs_v_perslid_fullnames
                     WHERE prs_perslid_key = boer.prs_perslid_key;

                    lreceivers := lreceivers || ', ' || lreceivers1;
                END IF;

                lnrreceivers := lnrreceivers + 1;
            END LOOP;

            IF lnrreceivers = 0
            THEN
                DBMS_OUTPUT.put_line ('no receivers');

                IF l2bpmode > 0
                THEN
                    -- er was een urgente melding, notificatie gewenst en niemand is als BO geconfigureerd
                    -- dan hoeven we niks te doen, maar toch sturen we de beheerder dan een signaal
                    fac.putsystemnotification (priobericht, 3);                              -- mode 3 is portal en mail
                    DBMS_OUTPUT.put_line ('inform admin: ' || priobericht);
                END IF;
            END IF;
        EXCEPTION
            WHEN NO_DATA_FOUND
            THEN
                RETURN;
        END;
    END;

    -- Handige variant van putnotificationsrtprio om een notificatie naar een individuele behandelaar te sturen
    -- Wordt typisch gebruikt voor MLDAB2 achtige notificaties, waar geen tracking bij is en die naar een
    -- specifiek iemand gestuurd moet worden.
    -- Is in wezen generieker dan naar alleen voor behandelaar
    PROCEDURE notifybehandelaar (pto IN NUMBER, pcode IN VARCHAR2, pmeldingkey IN NUMBER)
    AS
        lomschrijving           fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        lbericht                fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
    BEGIN

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

      lbericht := mld.mldsprintf (lomschrijving, pmeldingkey);
      fac.putnotificationsrtprio (NULL,
                                 pto,
                                 pcode,
                                 pmeldingkey,
                                 lbericht,
                                 NULL,
                                 NULL,
                                 NULL,
                                 NULL,
                                 2,
                                 NULL);
    END;

    -- Notificatie meldingen per prioriteit
    PROCEDURE notifyprio (pmeldingkey IN NUMBER, prio IN NUMBER, pperslid_key IN NUMBER, pdisc_level IN NUMBER DEFAULT 1)
    AS
        lnotiprio      NUMBER (1);
        lcode          fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
        loms           fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        lmode          fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
        bericht        VARCHAR2 (4000);                   -- fac_srtnotificatie_oms%TYPE kan te kort zijn na substitutie
        emailnw1       mld_disc_params.mld_disc_params_emailnw1%TYPE;
        emailnw2       mld_disc_params.mld_disc_params_emailnw2%TYPE;
        emailnw3       mld_disc_params.mld_disc_params_emailnw3%TYPE;
        emailnw4       mld_disc_params.mld_disc_params_emailnw4%TYPE;
        smsnw1         mld_disc_params.mld_disc_params_smsnw1%TYPE;
        smsnw2         mld_disc_params.mld_disc_params_smsnw2%TYPE;
        smsnw3         mld_disc_params.mld_disc_params_smsnw3%TYPE;
        smsnw4         mld_disc_params.mld_disc_params_smsnw4%TYPE;
    BEGIN
        IF pmeldingkey IS NULL
        THEN
            RETURN;
        END IF;

        SELECT mp.mld_disc_params_emailnw1,
               mp.mld_disc_params_emailnw2,
               mp.mld_disc_params_emailnw3,
               mp.mld_disc_params_emailnw4,
               mp.mld_disc_params_smsnw1,
               mp.mld_disc_params_smsnw2,
               mp.mld_disc_params_smsnw3,
               mp.mld_disc_params_smsnw4
          INTO emailnw1,
               emailnw2,
               emailnw3,
               emailnw4,
               smsnw1,
               smsnw2,
               smsnw3,
               smsnw4
          FROM mld_melding m,
               mld_stdmelding stdm,
               mld_disc_params mp
         WHERE stdm.mld_stdmelding_key = m.mld_stdmelding_key
           AND mp.mld_ins_discipline_key =
                  CASE
                     WHEN pdisc_level = 1 THEN stdm.mld_ins_discipline_key
                     WHEN pdisc_level = 2 THEN m.mld_ins_discipline_key
                  END
           AND m.mld_melding_key = pmeldingkey;

        -- Vertaal melding-spoed (1-4) met 3=normaal naar email-spoed (1-3), waarbij 1=hoog, 2=normaal, 3=laag
        IF prio <= 2
        THEN
            lcode := 'MLD2BP';
            lnotiprio := 1;
        ELSE
            lcode := 'MLDNW3';
            lnotiprio := prio - 1;
        END IF;

        IF pdisc_level = 2
        THEN
            lcode := 'MLDBHG';
        END IF;

        SELECT lcl.x('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms),
               fac_srtnotificatie_mode
          INTO loms,
               lmode
          FROM fac_srtnotificatie
         WHERE fac_srtnotificatie_code = lcode;

        bericht := mld.mldsprintf (loms, pmeldingkey);

        IF prio = 1 AND emailnw1 IS NOT NULL
        THEN
            fac.putnotificationsrtprio (pperslid_key,
                                            NULL,
                                            lcode,
                                            pmeldingkey,
                                            bericht,
                                            lmode,
                                            emailnw1,
                                            smsnw1,
                                            NULL,
                                            lnotiprio,
                                            NULL,
                                            NULL);
        ELSIF prio = 2 AND emailnw2 IS NOT NULL
        THEN
            fac.putnotificationsrtprio (pperslid_key,
                                            NULL,
                                            lcode,
                                            pmeldingkey,
                                            bericht,
                                            lmode,
                                            emailnw2,
                                            smsnw2,
                                            NULL,
                                            lnotiprio,
                                            NULL,
                                            NULL);
        ELSIF prio IN (3, 4) AND emailnw3 IS NOT NULL
        THEN
            fac.putnotificationsrtprio (pperslid_key,
                                            NULL,
                                            lcode,
                                            pmeldingkey,
                                            bericht,
                                            lmode,
                                            emailnw3,
                                            smsnw3,
                                            NULL,
                                            lnotiprio,
                                            NULL,
                                            NULL);
        ELSE
            RETURN;
        END IF;
    END;
   -- Stuur alle mogelijke opdracht goedkeurders een bericht als de opdracht status 10 heeft.
   -- Naar wie, wordt reversed opgezocht op basis van toegekende autorisaties.
   -- Lijkt heel erg sterk op bovenstaande notifybackoffice
   PROCEDURE notifyopdrgoedkeurders (popdrkey IN NUMBER)
   AS
      lloc_key mld_melding.mld_alg_locatie_key%TYPE;
      lafd_key prs_perslid.prs_afdeling_key%TYPE;
      lmld_key mld_melding.mld_melding_key%TYPE;
      lmld_opdr_disc_key mld_opdr.mld_opdr_discipline_key%TYPE;
      lspoed mld_melding.mld_melding_spoed%TYPE;
      loms fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
      lopdr_approved mld_opdr.mld_opdr_approved%TYPE;
      lopdr_kosten mld_opdr.mld_opdr_kosten%TYPE;
      lbestellimiet mld_disc_params.mld_disc_params_bestellimiet%TYPE;
      lbestellimiet2 mld_disc_params.mld_disc_params_bestellimiet2%TYPE;
      lbestellimiet3 mld_disc_params.mld_disc_params_bestellimiet3%TYPE;
      lbestellimiet4 mld_disc_params.mld_disc_params_bestellimiet4%TYPE;
      lbestellimiet5 mld_disc_params.mld_disc_params_bestellimiet5%TYPE;
      lgvs mld_typeopdr.mld_typeopdr_gvs%TYPE;
      lrefiat mld_opdr.mld_statusopdr_key_refiat%TYPE;
      lfunctiecode fac_functie.fac_functie_code%TYPE;
      lsender mld_discipline.ins_discipline_email%TYPE;
      bericht fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;                         -- kan te kort zijn na substitutie
      lnrreceivers   NUMBER;
      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
   BEGIN
      BEGIN
         SELECT   m.mld_alg_locatie_key,
                  p.prs_afdeling_key,
                  m.mld_melding_key,
                  o.mld_opdr_discipline_key,
                  m.mld_melding_spoed,
                  COALESCE(o.mld_opdr_approved, -1),
                  COALESCE(o.mld_opdr_kosten, 0),
                  COALESCE(mdp.mld_disc_params_bestellimiet, 0),
                  COALESCE(mdp.mld_disc_params_bestellimiet2, 0),
                  COALESCE(mdp.mld_disc_params_bestellimiet3, 0),
                  COALESCE(mdp.mld_disc_params_bestellimiet4, 0),
                  COALESCE(mdp.mld_disc_params_bestellimiet5, 0),
                  mto.mld_typeopdr_gvs,
                  COALESCE(o.mld_statusopdr_key_refiat, 0)
           INTO   lloc_key,
                  lafd_key,
                  lmld_key,
                  lmld_opdr_disc_key,
                  lspoed,
                  lopdr_approved,
                  lopdr_kosten,
                  lbestellimiet,
                  lbestellimiet2,
                  lbestellimiet3,
                  lbestellimiet4,
                  lbestellimiet5,
                  lgvs,
                  lrefiat
           FROM   mld_melding m,
                  prs_perslid p,
                  mld_opdr o,
                  mld_typeopdr mto,
                  mld_disc_params mdp
          WHERE   m.prs_perslid_key = p.prs_perslid_key
            AND   o.mld_opdr_discipline_key = mdp.mld_ins_discipline_key
            AND   o.mld_typeopdr_key = mto.mld_typeopdr_key
            AND   o.mld_statusopdr_key = 10
            AND   m.mld_melding_key = o.mld_melding_key
            AND   o.mld_opdr_key = popdrkey;
         IF (lopdr_kosten <= lbestellimiet AND lopdr_kosten < lgvs)  -- Dit eerst testen i.v.m. Ter goedkeuring. Verder moet sowieso goedgekeurd worden.
         THEN
           RETURN;   -- Het bedrag is lager als de eerste limiet. De opdracht hoeft niet goed gekeurd te worden, dus een lege fiatteurs array teruggeven.
         ELSIF (((fac.getsetting ('mld_opdr_approval_all') = 0 AND ((lopdr_kosten >= lbestellimiet) OR
                                                                    (lopdr_kosten >= lgvs AND lopdr_approved < 0))) OR
                 (fac.getsetting ('mld_opdr_approval_all') = 1 AND lopdr_kosten <= lbestellimiet2)) AND
                ((lrefiat = 0 AND lopdr_approved <= lbestellimiet) OR          -- Fiatteren volgens limieten.
                 (lrefiat > 0 AND lopdr_kosten >= lgvs AND lopdr_approved < 0))) -- Herfiatteren indien bedrag boven de GVS (lopdr_kosten >= lgvs) en het is de eerste goedkeuringsslag (lopdr_approved < 0).
         THEN
           lfunctiecode := 'WEB_ORDGOE';
         ELSIF ((fac.getsetting ('mld_opdr_approval_all') = 0 AND lopdr_kosten >= lbestellimiet2 AND lopdr_approved = lbestellimiet2) OR
                (fac.getsetting ('mld_opdr_approval_all') = 1 AND lopdr_kosten <= lbestellimiet3 AND ((lrefiat = 0 AND lopdr_approved <= lbestellimiet2) OR (lrefiat > 0 AND lopdr_kosten >= lgvs AND lopdr_approved < 0))))
         THEN
           lfunctiecode := 'WEB_ORDGO2';
         ELSIF ((fac.getsetting ('mld_opdr_approval_all') = 0 AND lopdr_kosten >= lbestellimiet3 AND lopdr_approved = lbestellimiet3) OR
                (fac.getsetting ('mld_opdr_approval_all') = 1 AND lopdr_kosten <= lbestellimiet4 AND ((lrefiat = 0 AND lopdr_approved <= lbestellimiet3) OR (lrefiat > 0 AND lopdr_kosten >= lgvs AND lopdr_approved < 0))))
         THEN
           lfunctiecode := 'WEB_ORDGO3';
         ELSIF ((fac.getsetting ('mld_opdr_approval_all') = 0 AND lopdr_kosten >= lbestellimiet4 AND lopdr_approved = lbestellimiet4) OR
                (fac.getsetting ('mld_opdr_approval_all') = 1 AND lopdr_kosten <= lbestellimiet5 AND ((lrefiat = 0 AND lopdr_approved <= lbestellimiet4) OR (lrefiat > 0 AND lopdr_kosten >= lgvs AND lopdr_approved < 0))))
         THEN
           lfunctiecode := 'WEB_ORDGO4';
         ELSIF ((fac.getsetting ('mld_opdr_approval_all') = 0 AND lopdr_kosten >= lbestellimiet5 AND lopdr_approved >= lbestellimiet5) OR
                (fac.getsetting ('mld_opdr_approval_all') = 1 AND lopdr_kosten > lbestellimiet5 AND ((lrefiat = 0 AND lopdr_approved <= lbestellimiet5) OR (lrefiat > 0 AND lopdr_kosten >= lgvs AND lopdr_approved < 0))))
         THEN
           lfunctiecode := 'WEB_ORDGO5';
         ELSE
           RETURN; -- Het goedgekeurde bedrag zit al boven de vijfde limiet. Geen approval meer nodig.
         END IF;
         -- These notifications are now sent on behalf of the system, what might be the local FM organisation
         SELECT MAX (COALESCE(cd.ins_discipline_email, l.alg_locatie_email)) email
           INTO lsender
           FROM mld_opdr o,
                mld_melding m,
                mld_discipline cd,
                alg_locatie l
          WHERE o.mld_melding_key = m.mld_melding_key
            AND cd.ins_discipline_key = lmld_opdr_disc_key
            AND m.mld_alg_locatie_key = l.alg_locatie_key(+)
            AND o.mld_opdr_key = popdrkey;
         -- Als die er niet is sprongen we al naar de exception
         -- Als die er wel is, gaan we verder
         SELECT   lcl.x('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms)
           INTO   loms
           FROM   fac_srtnotificatie
          WHERE   fac_srtnotificatie_code = 'ORD2GO'
            AND   fac_srtnotificatie_mode > 0;
         -- Die laatste conditie is optimalisatie. Met code 0 is de notificatie feitelijk uitgeschakeld en
         -- hoef ik dus ook niet duur te bepalen naar wie een notificatie niet gestuurd hoeft
         -- Als deze niets oplevert gaan we dus ook weer naar de exception
         -- Vertaal melding-spoed  (1-4) naar email-spoed (1-3), 3=normaal
         IF lspoed < 3
         THEN
            lspoed := 1;
         ELSIF lspoed = 4
         THEN
            lspoed := 3;
         ELSE
            lspoed := 2;
         END IF;
         bericht := mld.opdrsprintf (loms, popdrkey);                                        -- de variabelen invullen

         lnrreceivers := 0;
         lreceivers := '';
         FOR boer
            IN (SELECT g.prs_perslid_key
                  FROM fac_v_webgebruiker g,
                       fac_functie f,
                       prs_perslid p,
                       prs_v_afdeling d,
                       mld_melding m,
                       alg_v_allonroerendgoed onrg
                 WHERE g.fac_functie_key = f.fac_functie_key
                   AND g.prs_perslid_key = p.prs_perslid_key
                   AND d.prs_afdeling_key = p.prs_afdeling_key
                   AND g.ins_discipline_key = lmld_opdr_disc_key
                   AND m.mld_alg_onroerendgoed_keys = onrg.alg_onroerendgoed_keys(+)
                   AND m.mld_melding_key = lmld_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 = lafd_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 = lafd_key
                                                           AND aa.niveau = g.fac_gebruiker_prs_level_write))))
                   AND (g.fac_gebruiker_alg_level_write = -1
                        OR (g.fac_gebruiker_alg_level_write < 9
                            AND lloc_key IN
                                     (SELECT   alg_locatie_key
                                        FROM   fac_v_my_locations
                                       WHERE   prs_perslid_key = p.prs_perslid_key
                                               AND niveau = fac_gebruiker_alg_level_write)))
                   AND (g.fac_gebruiker_alg_level_write = -1
                     OR (g.fac_gebruiker_alg_level_write < 9
                     AND (CASE
                              WHEN m.mld_alg_onroerendgoed_keys IS NULL
                               AND m.mld_alg_locatie_key IN (SELECT alg_locatie_key
                                                               FROM fac_v_my_locations
                                                              WHERE prs_perslid_key = p.prs_perslid_key
                                                                AND niveau = g.fac_gebruiker_alg_level_write)
                              THEN
                                  1
                              WHEN onrg.alg_type = 'T'
                               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_terreinsector_key
                                                                      FROM fac_v_my_locations l, alg_terreinsector t
                                                                     WHERE t.alg_locatie_key = l.alg_locatie_key
                                                                       AND l.prs_perslid_key = p.prs_perslid_key
                                                                       AND l.niveau = g.fac_gebruiker_alg_level_write)
                              THEN
                                  1
                              WHEN onrg.alg_type = 'G'
                               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_gebouw_key
                                                                      FROM fac_v_my_buildings
                                                                     WHERE prs_perslid_key = p.prs_perslid_key
                                                                       AND niveau = g.fac_gebruiker_alg_level_write)
                              THEN
                                  1
                              WHEN onrg.alg_type = 'V'
                               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_verdieping_key
                                                                      FROM fac_v_my_floors
                                                                     WHERE prs_perslid_key = p.prs_perslid_key
                                                                       AND niveau = g.fac_gebruiker_alg_level_write)
                              THEN
                                  1
                              WHEN onrg.alg_type = 'R'
                               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_ruimte_key
                                                                      FROM fac_v_my_rooms
                                                                     WHERE prs_perslid_key = p.prs_perslid_key
                                                                       AND niveau = g.fac_gebruiker_alg_level_write)
                              THEN
                                  1
                              ELSE
                                  0
                          END) = 1))
                   AND fac_functie_code = lfunctiecode)
         LOOP
            fac.putnotificationsrtprio (NULL,
                                        boer.prs_perslid_key,
                                        'ORD2GO',
                                        popdrkey,
                                        bericht,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL,
                                        lspoed,                                                               -- 1,2,3,4
                                        lsender
                                       );
            IF lnrreceivers = 0 THEN
                SELECT prs_perslid_naam_friendly
                  INTO lreceivers
                  FROM prs_v_perslid_fullnames
                 WHERE prs_perslid_key = boer.prs_perslid_key;
            ELSE
                SELECT prs_perslid_naam_friendly
                  INTO lreceivers1
                  FROM prs_v_perslid_fullnames
                 WHERE prs_perslid_key = boer.prs_perslid_key;
               lreceivers := lreceivers||', '||lreceivers1;
            END IF;
            lnrreceivers := lnrreceivers+1;
         END LOOP;
         IF lnrreceivers > 0 THEN
             DBMS_OUTPUT.PUT_LINE(lnrreceivers);
             ltracking :=  lcl.l ('lcl_ord_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 ('#ORDMAI', popdrkey, NULL, NULL, SUBSTR(ltracking,1,2048));  -- maxlengte van fac_srtnotificatie_oms
        END IF;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            RETURN;
      END;
   END;

   -- Stuur notificatie psrtnotificatiekey naar diverse bedrijven
   -- in het bijzonder de uitvoerende maar het mag ook een
   -- ander 'subscribed' bedrijf zijn (bedrijfadres_type 'G').
   PROCEDURE notifyopdrbedrijven (popdrkey           NUMBER,
                                  ptrackingkey       NUMBER,
                                  pnotidelay         NUMBER DEFAULT NULL)
   AS
    BEGIN
        FOR bedrijfrec
            IN (SELECT o.mld_typeopdr_key,
                       o.mld_opdr_discipline_key,
                       b.prs_bedrijf_key,
                       CASE WHEN b.prs_bedrijf_key = o.mld_uitvoerende_keys THEN 'O' ELSE 'G' END bedrijfadres_type,
                       COALESCE (l1.alg_locatie_key, l2.alg_locatie_key)                          alg_locatie_key,
                       COALESCE (l1.alg_locatie_email, l2.alg_locatie_email)                      alg_locatie_email,
                       o.mld_melding_key || '/' || o.mld_opdr_bedrijfopdr_volgnr                  reference,
                       d.prs_bedrijf_key                                                          persoon_bedrijf_key -- van de melder, niet de uitvoerende
                  FROM mld_opdr        o,
                       mld_melding     m,
                       mld_adres       ma,
                       alg_locatie     l1,
                       alg_locatie     l2,
                       prs_perslid     p,
                       prs_v_afdeling  d,
                       prs_bedrijf     b
                 WHERE     o.mld_opdr_key = popdrkey
                       AND (   b.prs_bedrijf_key = o.mld_uitvoerende_keys
                            OR EXISTS
                                   (SELECT 1
                                      FROM prs_bedrijfadres ba
                                     WHERE ba.prs_bedrijf_key = b.prs_bedrijf_key
                                       AND ba.prs_bedrijfadres_startdatum <= SYSDATE
                                       AND ba.prs_bedrijfadres_type = 'G'))
                       AND o.mld_melding_key = m.mld_melding_key
                       AND m.mld_adres_key = ma.mld_adres_key(+)
                       AND ma.alg_locatie_key = l1.alg_locatie_key(+)
                       AND m.mld_alg_locatie_key = l2.alg_locatie_key(+)
                       AND d.prs_afdeling_key = p.prs_afdeling_key
                       AND p.prs_perslid_key = m.prs_perslid_key)
        LOOP
            fac.notifybedrijf (pbedrijf_key          => bedrijfrec.prs_bedrijf_key,
                               pbedrijfadres_type    => bedrijfrec.bedrijfadres_type,
                               prefkey               => popdrkey,
                               ptrackingkey          => ptrackingkey,
                               preference            => bedrijfrec.reference,
                               ptypeopdr_key         => bedrijfrec.mld_typeopdr_key,
                               plocatie_key          => bedrijfrec.alg_locatie_key,
                               pdiscipline_key       => bedrijfrec.mld_opdr_discipline_key,
                               psender               => bedrijfrec.alg_locatie_email,
                               pbedrijf_key2         => bedrijfrec.persoon_bedrijf_key,
                               pnotidelay            => pnotidelay);
        END LOOP;
    END;

   PROCEDURE notifymeldingbedrijven (pmldkey            NUMBER,
                                     ptrackingkey       NUMBER,
                                     pnotidelay         NUMBER DEFAULT NULL)
   AS
    BEGIN
        FOR bedrijfrec
            IN (SELECT b.prs_bedrijf_key,
                       'G' bedrijfadres_type, -- Meldingen generiek
                       COALESCE (l1.alg_locatie_key, l2.alg_locatie_key)      alg_locatie_key,
                       COALESCE (l1.alg_locatie_email, l2.alg_locatie_email)  alg_locatie_email,
                       m.mld_melding_key                                      reference,
                       m.mld_ins_discipline_key,
                       d.prs_bedrijf_key                                      persoon_bedrijf_key -- van de melder, niet de uitvoerende
                  FROM mld_melding     m,
                       mld_adres       ma,
                       alg_locatie     l1,
                       alg_locatie     l2,
                       prs_perslid     p,
                       prs_v_afdeling  d,
                       prs_bedrijf     b
                 WHERE     m.mld_melding_key = pmldkey
                       AND b.prs_bedrijf_intern = 2 -- 'G' is alleen voor systeembedrijven
                       AND EXISTS
                              (SELECT 1
                                 FROM prs_bedrijfadres ba
                                 WHERE ba.prs_bedrijf_key = b.prs_bedrijf_key
                                   AND ba.prs_bedrijfadres_startdatum <= SYSDATE
                                   AND ba.prs_bedrijfadres_type = 'G')
                       AND m.mld_adres_key = ma.mld_adres_key(+)
                       AND ma.alg_locatie_key = l1.alg_locatie_key(+)
                       AND m.mld_alg_locatie_key = l2.alg_locatie_key(+)
                       AND d.prs_afdeling_key = p.prs_afdeling_key
                       AND p.prs_perslid_key = m.prs_perslid_key)
        LOOP
            fac.notifybedrijf (pbedrijf_key          => bedrijfrec.prs_bedrijf_key,
                               pbedrijfadres_type    => bedrijfrec.bedrijfadres_type,
                               prefkey               => pmldkey,
                               ptrackingkey          => ptrackingkey,
                               preference            => bedrijfrec.reference,
                               plocatie_key          => bedrijfrec.alg_locatie_key,
                               pdiscipline_key       => bedrijfrec.mld_ins_discipline_key,
                               psender               => bedrijfrec.alg_locatie_email,
                               pbedrijf_key2         => bedrijfrec.persoon_bedrijf_key,
                               pnotidelay            => pnotidelay);
        END LOOP;
    END;

   -- Bepaal de instemmer van een conceptmelding conform de conceptstatus(bitcode)
   -- Levert NULL als die er niet is of niet bepaald kan worden
   FUNCTION getinstemmer (pmldkey IN NUMBER) RETURN NUMBER
   AS
        l_conceptstatus   mld_melding.mld_melding_conceptstatus%TYPE;
        l_kp_key          mld_melding.prs_kostenplaats_key%TYPE;
        l_melder_key      mld_melding.prs_perslid_key%TYPE;
        l_afd_key         mld_melding.prs_afdeling_key%TYPE;
        l_instemmer_key    NUMBER;
    BEGIN
        SELECT mld_melding_conceptstatus, prs_kostenplaats_key, prs_perslid_key
          INTO l_conceptstatus, l_kp_key, l_melder_key
          FROM mld_melding
         WHERE mld_melding_key = pmldkey;

        CASE l_conceptstatus                 -- ooit misschien nog BITAND voor meerlaagse instemming
            WHEN 0
            THEN
                l_instemmer_key := NULL;                                         -- dat wassie ook al
            WHEN 1
            THEN
                -- de budgetverantwoordelijke moet instemmen
                IF l_kp_key IS NOT NULL
                THEN
                    SELECT prs.getkpverantwoordelijke (l_kp_key, NULL, NULL)
                      INTO l_instemmer_key
                      FROM DUAL;

                    IF    l_instemmer_key IS NULL
                       OR l_instemmer_key < 0             -- kan misschien ook -1 opleveren ipv null
                       OR l_instemmer_key = l_melder_key                          -- dat ben ik zelf
                    THEN
                        l_instemmer_key := NULL;
                    END IF;
                ELSE
                    l_instemmer_key := NULL;                                     -- dat wassie ook al
                END IF;
            WHEN 2
            THEN
                --objectbeheerder, kies er maar een als er meer zijn..
                -- NB: UNSUPPORTED YET. Omdat de objecten pas later worden toegevoegd aan
                -- de nieuwe melding is deze flow onvoldoende voor deze case in deze opzet
                -- We verstoppen deze als optie in de GUI.
                BEGIN
                    SELECT MAX (d.prs_perslid_key_beh)
                      INTO l_instemmer_key
                      FROM mld_melding_object mo, ins_deel d
                     WHERE mo.ins_deel_key = d.ins_deel_key AND mo.mld_melding_key = pmldkey;
                EXCEPTION
                    WHEN NO_DATA_FOUND
                    THEN
                        l_instemmer_key := NULL;
                END;
            WHEN 4                                                                  --afdelingshoofd
            THEN
                SELECT d.prs_perslid_key_verantw
                  INTO l_instemmer_key
                  FROM prs_afdeling d, mld_melding m, prs_perslid p
                 WHERE     d.prs_afdeling_key = COALESCE (m.prs_afdeling_key, p.prs_afdeling_key)
                       AND m.prs_perslid_key = p.prs_perslid_key
                       AND mld_melding_key = pmldkey;
            WHEN 8                                               --een individuele verantwoordelijke
            THEN
                SELECT p.prs_perslid_key_verantw
                  INTO l_instemmer_key
                  FROM mld_melding m, prs_perslid p
                 WHERE m.prs_perslid_key = p.prs_perslid_key AND mld_melding_key = pmldkey;
            WHEN 16                                                     --gebouwverantwoordelijke(1)
            THEN
                SELECT g.prs_perslid_key_verantw
                  INTO l_instemmer_key
                  FROM mld_melding m, alg_v_onroerendgoed aog, alg_gebouw g
                 WHERE     aog.alg_gebouw_key = g.alg_gebouw_key(+)
                       AND m.mld_alg_onroerendgoed_keys = aog.alg_onroerendgoed_keys(+)
                       AND m.mld_melding_key = pmldkey;
        END CASE;

        RETURN l_instemmer_key;
    END;

    -- Notificeer de persoon die moet instemmen met de indiening van deze melding
    -- Als die er niet is, dan notificeren we niet, maar promoveren we de melding
    -- hier direct naar ingestemd, dus nieuw.
    PROCEDURE notifyinstemmer (pmldkey IN NUMBER)
    AS
        --l_melder_key      mld_melding.prs_perslid_key%TYPE;
        l_receiver_key    NUMBER;
        l_oms             fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        bericht           VARCHAR2 (4000); -- fac_srtnotificatie_oms%TYPE kan te kort zijn na substitutie
    BEGIN

        l_receiver_key := getinstemmer(pmldkey);

        IF l_receiver_key IS NOT NULL
        THEN
            SELECT lcl.x ('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms)
              INTO l_oms
              FROM fac_srtnotificatie
             WHERE fac_srtnotificatie_code = 'MLD2CO';

            bericht := mld.mldsprintf (l_oms, pmldkey);

            fac.putnotificationsrtprio (NULL,
                                        l_receiver_key,
                                        'MLD2CO',
                                        pmldkey,
                                        bericht,
                                        NULL,
                                        NULL,
                                        NULL,
                                        NULL,
                                        2,                                                   -- prio
                                        NULL);                                     -- sender (overweging l_melder_key)
        ELSE
            -- we kunnen niemand vinden; voor de voortgang zeggen we:
            -- dan is er dus geen expliciete instemming nodig en gaan we direct door
            UPDATE mld_melding
               SET mld_melding_conceptstatus = 0      -- bij BITAND alleen de beschouwde bits wissen
             WHERE mld_melding_key = pmldkey;

            fac.trackaction ('#MLDUPD', pmldkey, NULL, NULL, lcl.l('lcl_mld_defaultinstemming'));

            mld.setmeldingstatus (pmldkey,
                                  2,
                                  NULL,
                                  0);
        END IF;
    END;

   FUNCTION mld_besteed_budget_pgb (p_prs_key IN NUMBER, p_disc_key IN NUMBER)
      RETURN NUMBER
   AS
      l_budgetbesteld            NUMBER := 0;
   BEGIN
      -- Besteed budget van meegegeven persoon dit jaar voor de meegegeven discipline i.v.m. Persoons Gebonden Budget (PGB).
      -- Eventueel uitgezonderd (huidige) bestellingkey bes_key en meldingopdrachtkey opdr_key.
      -- De discipline instelling disc_params_pgb moet 1 of 3 zijn. Afhankelijk van deze instelling roep je de pgb of agb versie aan. Hier opnieuw controleren is niet nodig.
      -- Totaalbedrag van eerdere bestellingen en meldingopdrachten dit jaar van de besteller en behandelaar i.v.m. Persoons Gebonden Budget (PGB).
      SELECT COALESCE(SUM(totaalbedrag), 0) budgetbesteld   -- Korting en levkosten zijn 0.
        INTO l_budgetbesteld
        FROM (SELECT SUM (totaalbedrag) totaalbedrag
                FROM (SELECT SUM (o.mld_opdr_kosten) totaalbedrag
                           , o.mld_opdr_key
                        FROM mld_opdr o
                       WHERE o.prs_perslid_key = p_prs_key
                         AND o.mld_opdr_discipline_key = p_disc_key
                         -- Alleen meldingopdrachten in de actieve opdracht fase (Uitgegeven(5) en Geaccepteerd(8)),
                         -- in de afhandelings fase (Technisch voltooid(6) en Kosten voltooid(9)) en in de gereed fase (Verwerkt(7)).
                         AND o.mld_statusopdr_key IN (5, 6, 7, 8, 9)
                         AND o.mld_opdr_datumbegin >= TRUNC (SYSDATE, 'YEAR')
                      GROUP BY o.mld_opdr_key) tot
                   , mld_opdr o
               WHERE o.mld_opdr_key = tot.mld_opdr_key);
      RETURN l_budgetbesteld;
   END;

   FUNCTION mld_besteed_budget_agb (p_kp_key IN NUMBER)
      RETURN NUMBER
   AS
      l_budgetbesteld            NUMBER := 0;
      l_kp_limietperiode         NUMBER (1);
      l_periode                  VARCHAR2 (4);
   BEGIN
      -- Besteed budget van meegegeven persoon afgelopen periode i.v.m. Afdelings Gebonden Budget (AGB).
      -- Eventueel uitgezonderd (huidige) bestellingkey bes_key en meldingopdrachtkey opdr_key.
      -- De discipline instelling disc_params_pgb moet 1 of 3 zijn. Afhankelijk van deze instelling roep je de pgb of agb versie aan. Hier opnieuw controleren is niet nodig.
      -- Totaalbedrag van eerdere bestellingen en meldingopdrachten van afgelopen periode van de besteller en behandeaar i.v.m. Afdelings Gebonden Budget (AGB).

      -- Limietperiode kostenplaats (prs_kostenplaats_limietperiode): 0(of NULL)=geen(oneindig) (default), 1=maand, 2=jaar.
      IF p_kp_key > 0
      THEN
         -- Er is een kostenplaats gevonden.
         -- De limiet periode van de kostenplaatsgroep overruled die van de kostenplaats indien ingevuld.
         SELECT CASE COALESCE(kg.prs_kostenplaatsgrp_limperiode, 0)   -- Indien kostenplaats geen kostenplaatsgroep heeft dan ook "Geen" en eigen limietperiode van de kostenplaats nemen.
                WHEN 0    -- Geen.
                THEN k.prs_kostenplaats_limietperiode
                ELSE kg.prs_kostenplaatsgrp_limperiode   -- Maand of Jaar.
                END limietperiode
           INTO l_kp_limietperiode
           FROM prs_kostenplaats k
              , prs_kostenplaatsgrp kg
          WHERE k.prs_kostenplaatsgrp_key = kg.prs_kostenplaatsgrp_key(+)
            AND k.prs_kostenplaats_key = p_kp_key;

         IF l_kp_limietperiode = 1
         THEN
            l_periode := 'MM';     -- Maandelijks budget.
         ELSIF l_kp_limietperiode = 2
         THEN
            l_periode := 'YYYY';   -- Jaarlijks budget.
         ELSE
            l_periode := NULL;
         END IF;

        SELECT COALESCE(SUM(totaalbedrag), 0) budgetbesteld   -- Korting en levkosten zijn 0.
          INTO l_budgetbesteld
          FROM (SELECT SUM (totaalbedrag) totaalbedrag
                  FROM (SELECT SUM (o.mld_opdr_kosten) totaalbedrag
                             , o.mld_opdr_key
                          FROM mld_opdr o
                             , mld_disc_params mdp
                         WHERE o.mld_opdr_discipline_key = mdp.mld_ins_discipline_key
                           AND mdp.mld_disc_params_pgb IN (2,3)   -- Alleenn agb meetellen: 2 = Alleen agb, 3 = Beiden, pgb en agb.
                           AND o.prs_kostenplaats_key = p_kp_key
                           -- Alleen meldingopdrachten in de actieve opdracht fase (Uitgegeven(5) en Geaccepteerd(8)),
                           -- in de afhandelings fase (Technisch voltooid(6) en Kosten voltooid(9)) en in de gereed fase (Verwerkt(7)).
                           AND o.mld_statusopdr_key IN (5, 6, 7, 8, 9)
                           AND ((l_periode IS NOT NULL AND o.mld_opdr_datumbegin >= TRUNC (SYSDATE, l_periode))   -- De eerste van de deze maand of 1 januari dit jaar
                             OR (l_periode IS NULL))
                        GROUP BY o.mld_opdr_key) tot
                     , mld_opdr o
                 WHERE o.mld_opdr_key = tot.mld_opdr_key);
      END IF;

      RETURN l_budgetbesteld;
   END;

   -- Maak automatisch een opdracht aan bij een nieuwe melding als dat zo is geconfigureerd
   -- Doet niks als het (nog) een conceptmelding is.
   PROCEDURE mld_addautoorder (p_melding_key IN NUMBER)
   AS
      l_autoorder                        mld_stdmelding.mld_stdmelding_autoorder%TYPE;
      l_mld_autoorder                    prs_bedrijfdienstlocatie.mld_autoorder%TYPE;
      l_prs_perslid_key                  prs_perslid.prs_perslid_key%TYPE;
      l_mld_stdmelding_key               mld_stdmelding.mld_stdmelding_key%TYPE;
      l_mld_disc_params_opdr_kosten      NUMBER;
      l_mld_stdmelding_autoorderamnt     mld_stdmelding.mld_stdmelding_autoorderamount%TYPE;
      l_mld_disc_params_pgb              mld_disc_params.mld_disc_params_pgb%TYPE;
      l_prs_kostenplaats_key             prs_kostenplaats.prs_kostenplaats_key%TYPE;
      l_prs_kostensoort_key              prs_kostensoort.prs_kostensoort_key%TYPE;
      l_ins_discipline_key               mld_stdmelding.mld_ins_discipline_key%TYPE;
      l_bht_discipline_key               mld_melding.mld_ins_discipline_key%TYPE;
      l_opdr_discipline_key              mld_opdr.mld_opdr_discipline_key%TYPE;
      l_mld_melding_einddatum            mld_melding.mld_melding_einddatum%TYPE;
      l_conceptstatus                    mld_melding.mld_melding_conceptstatus%TYPE;
      l_mld_stdmelding_enddate_empty     mld_stdmelding.mld_stdmelding_enddate_empty%TYPE;
      l_mld_melding_omschrijving         mld_melding.mld_melding_omschrijving%TYPE;
      l_mld_melding_onderwerp            mld_melding.mld_melding_onderwerp%TYPE;
      l_prs_kostenplaats_fiat            prs_kostenplaats.prs_kostenplaats_fiat%TYPE;
      l_mld_disc_params_bestellimiet     mld_disc_params.mld_disc_params_bestellimiet%TYPE;
      l_mld_typeopdr_key                 mld_typeopdr.mld_typeopdr_key%TYPE;
      l_for_approval                     BOOLEAN;
      l_mld_typeopdr_fvs                 mld_typeopdr.mld_typeopdr_fvs%TYPE;
      l_mld_typeopdr_gvs                 mld_typeopdr.mld_typeopdr_gvs%TYPE;
      l_mld_typeopdr_isofferte           mld_typeopdr.mld_typeopdr_isofferte%TYPE;
      l_mld_typeopdr_kosten              mld_typeopdr.mld_typeopdr_kosten%TYPE;
      l_mld_typeopdr_kst_verplicht    NUMBER;
      l_mld_typeopdr_slamode             mld_typeopdr.mld_typeopdr_slamode%TYPE;
      l_exceeds_pgb                      BOOLEAN;
      l_exceeds_agb                      BOOLEAN;
      l_mld_adres_key                    mld_melding.mld_adres_key%TYPE;
      l_mld_alg_onroerendgoed_keys       mld_melding.mld_alg_onroerendgoed_keys%TYPE;
      l_mld_alg_locatie_key              mld_melding.mld_alg_locatie_key%TYPE;
      l_alg_gebouw_key                   alg_v_allonrgoed_gegevens.alg_gebouw_key%TYPE;
      l_alg_verdieping_key               alg_v_allonrgoed_gegevens.alg_verdieping_key %TYPE;
      l_alg_ruimte_key                   alg_v_allonrgoed_gegevens.alg_ruimte_key%TYPE;
      l_alg_type                         alg_v_allonrgoed_gegevens.alg_type%TYPE;
      l_prs_dienst_key                   NUMBER;
      l_prs_bedrijf_key                  prs_v_aanwezigbedrijf.prs_bedrijf_key%TYPE;
      l_cnt_contract_key                 cnt_contract.cnt_contract_key%TYPE;
      l_aantal                           NUMBER;
      l_bdl_tijdsduur                    prs_bedrijfdienstlocatie.prs_bdl_t_uitvoertijd.tijdsduur%TYPE;
      l_bdl_eenheid                      prs_bedrijfdienstlocatie.prs_bdl_t_uitvoertijd.eenheid%TYPE;
      l_prs_bedrijf_uurloon              prs_bedrijf.prs_bedrijf_uurloon%TYPE;
      l_mld_opdr_einddatum               mld_opdr.mld_opdr_einddatum%TYPE;
      l_mld_opdr_omschrijving            mld_opdr.mld_opdr_omschrijving%TYPE;
      l_prs_bedrijfadres_url             prs_bedrijfadres.prs_bedrijfadres_url%TYPE;
      l_haswrite                         NUMBER (1);
      l_new_opdr_key                     NUMBER (10);
      l_approver_key                     NUMBER (10);
      l_action                           VARCHAR2 (6);
   BEGIN
      BEGIN
         SELECT sm.mld_stdmelding_autoorder
              , m.prs_perslid_key
              , sm.mld_stdmelding_key
              , mdp.mld_disc_params_opdr_kosten
              , sm.mld_stdmelding_autoorderamount
              , mdp.mld_disc_params_pgb
              , m.prs_kostenplaats_key
              , sm.prs_kostensoort_key
              , sm.mld_ins_discipline_key
              , m.mld_ins_discipline_key
              , m.mld_melding_einddatum
              , sm.mld_stdmelding_enddate_empty
              , m.mld_melding_omschrijving
              , m.mld_melding_onderwerp
              , k.prs_kostenplaats_fiat
              , sm.prs_dienst_key
              , mdp.mld_disc_params_bestellimiet
              , m.mld_melding_conceptstatus
           INTO l_autoorder
              , l_prs_perslid_key
              , l_mld_stdmelding_key
              , l_mld_disc_params_opdr_kosten
              , l_mld_stdmelding_autoorderamnt
              , l_mld_disc_params_pgb
              , l_prs_kostenplaats_key
              , l_prs_kostensoort_key
              , l_ins_discipline_key
              , l_bht_discipline_key
              , l_mld_melding_einddatum
              , l_mld_stdmelding_enddate_empty
              , l_mld_melding_omschrijving
              , l_mld_melding_onderwerp
              , l_prs_kostenplaats_fiat
              , l_prs_dienst_key
              , l_mld_disc_params_bestellimiet
              , l_conceptstatus
           FROM mld_melding m
              , mld_stdmelding sm
              , ins_tab_discipline d
              , mld_disc_params mdp
              , prs_kostenplaats k
          WHERE m.mld_stdmelding_key = sm.mld_stdmelding_key
            AND sm.mld_ins_discipline_key = d.ins_discipline_key
            AND d.ins_discipline_key = mdp.mld_ins_discipline_key
            AND m.prs_kostenplaats_key = k.prs_kostenplaats_key(+)
            AND m.mld_melding_key = p_melding_key;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            -- Internal error; mld_melding must exist.
            RETURN;
      END;

      IF fac.getsetting('mld_opdr_discipline_mode') = '1'
      THEN
        l_opdr_discipline_key := l_ins_discipline_key;
      ELSE
        l_opdr_discipline_key := COALESCE(l_bht_discipline_key, l_ins_discipline_key);
     END IF;

      -- Moet er bij deze melding automatisch een opdracht worden aangemaakt?
      IF l_autoorder = 0 OR l_conceptstatus <> 0
      THEN
         -- No, done.
         RETURN;
      END IF;

      -- De behandelaar is initieel diegene die de opdracht aanmaakt (user). Hier nemen we dezelfde persoon als bij de (workflow) melding.
      -- Deze persoon moet wel MLDBOF en/of MLDBO3 schrijfrechten hebben omdat we anders niet kunnen bepalen of goedgekeurd of gefiatteerd moet worden.
      -- Als deze persoon geen MLDBOF en/of MLDBO3 schrijfrechten heeft dan maken we wel een opdracht aan, maar dan wordt hij niet als behandelaar ingevuld.
      SELECT CASE
             WHEN COALESCE(MIN(fac_gebruiker_prs_level_write), 9) < 9 OR COALESCE(MIN(fac_gebruiker_alg_level_write), 9) < 9
             THEN 1
             ELSE 0
             END
        INTO l_haswrite
        FROM fac_v_webgebruiker w,
             fac_functie f
       WHERE w.fac_functie_key = f.fac_functie_key
         AND w.prs_perslid_key = l_prs_perslid_key
         AND f.fac_functie_code IN ('WEB_MLDBOF', 'WEB_MLDBO3')
         AND ((l_ins_discipline_key IS NOT NULL AND ins_discipline_key = l_ins_discipline_key)
           OR l_ins_discipline_key IS NULL);

      BEGIN
         -- Bij automatische opdrachten pakken we per definitie de default opdracht type. We eisen dat die is ingevuld.
         SELECT sm.mld_typeopdr_key
              , mto.mld_typeopdr_fvs
              , mto.mld_typeopdr_gvs
              , mto.mld_typeopdr_isofferte
              , mto.mld_typeopdr_kosten
              , mto.mld_typeopdr_kosten_verplicht
              , mto.mld_typeopdr_slamode
           INTO l_mld_typeopdr_key
              , l_mld_typeopdr_fvs
              , l_mld_typeopdr_gvs
              , l_mld_typeopdr_isofferte
              , l_mld_typeopdr_kosten
              , l_mld_typeopdr_kst_verplicht
              , l_mld_typeopdr_slamode
           FROM mld_stdmelding sm
              , mld_typeopdr mto
          WHERE sm.mld_typeopdr_key = mto.mld_typeopdr_key
            AND sm.mld_typeopdr_key IS NOT NULL
            AND sm.mld_stdmelding_key = l_mld_stdmelding_key;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            -- Internal error; mld_typeopdr_key must exist.
            RETURN;
      END;

      IF l_mld_typeopdr_fvs IS NULL
      THEN
         l_mld_typeopdr_fvs := 0;
      END IF;

      -- Moet er gefiatteerd worden?
      IF l_mld_stdmelding_autoorderamnt < l_mld_typeopdr_fvs
      THEN
         l_for_approval := FALSE;
      ELSIF l_mld_disc_params_pgb > 0
      THEN
         -- Persoonlijk Gebonden Budget (PGB) en Afdeling Gebonden Budget (AGB) controle
         -- Fiatteringsproces moet gevolgd worden op de naam van de user
         -- var exceeds_pgb = mld.exceeds_pgb(tot_kosten, user_key, disc_key)
         l_exceeds_pgb := fac.exceeds_pgb(l_mld_stdmelding_autoorderamnt, l_prs_perslid_key, l_opdr_discipline_key, l_mld_disc_params_pgb);
         l_exceeds_agb := fac.exceeds_agb(l_mld_stdmelding_autoorderamnt, COALESCE(l_prs_kostenplaats_key, -1), l_opdr_discipline_key, l_mld_disc_params_pgb);
         IF l_exceeds_pgb OR l_exceeds_agb
         THEN
            -- Voor melding opdrachten heb je altijd BO rechten nodig.
            -- Een opdracht kan dus nooit van een FE komen. Aan de setting "mld_pgb_fe_fiat" (zoals bes_pgb_fe_fiat) heb je hier dan niets.
            IF fac.getsetting('mld_pgb_fiattering') = 1
            THEN
               -- Algemene fiatterings proces noodzakelijk naast PGB fiatering.
               l_for_approval := TRUE;
            ELSE
               -- Fiatteringsproces moet gevolgd worden op de naam van de user.
               -- Persoonlijk Gebonden Budget (PGB) en/of Afdeling Gebonden Budget (AGB) wordt overschreden.
               -- Opdracht kan dus niet aangemaakt worden.
               RETURN;
            END IF;
         END IF;

         -- Wel even checken of er een fiatteur gevonden kan worden.
         IF l_for_approval OR
            (fac.getsetting('mld_use_order_approval') = 1 AND
             l_mld_stdmelding_autoorderamnt > 0 AND
             (l_mld_stdmelding_autoorderamnt > fac.getsetting('can_selfapprove')))   -- Ik kan niet zelf fiatteren of kosten overschrijden het profiel.
         THEN
            l_for_approval := TRUE;
            -- Wie moet op verzoek goedkeuren voor deze kostenplaats, terwijl het bedrag wellicht onbekend is?
            -- Eerste fiatteur (pkey) mag niet fiatteren want het zit boven zijn profiel limiet.
            -- Alleen de melder van de melding mag niet zelf goedkeuren boven het bedrag can_selfapprove.
            -- Bij een kpg fiatteur moeten we de volgende hebben en niet de laatste, daarom (fiatbedrag >= 0) meegeven.
            -- prs.getfiatteur (pkostenplaats_key, pexcludekey, pondergrens, pdisckey, pfiatbedrag)
            SELECT prs.getfiatteur (COALESCE(l_prs_kostenplaats_key, -1), -1, l_mld_stdmelding_autoorderamnt, l_opdr_discipline_key, 0)
              INTO l_approver_key
              FROM DUAL;
         END IF;
      ELSE
         -- Standaard fiatteringscontrole
         -- De opdrachtaanmaker, Melder van de melding/BO-medewerker, contactpersoon enz, zijn allemaal de gelijk, namelijk de meldingaanmaker.
         IF (fac.getsetting('mld_use_order_approval') = 1 AND
             l_mld_stdmelding_autoorderamnt > 0 AND
             (l_mld_stdmelding_autoorderamnt > fac.getsetting('can_selfapprove') OR
              fac.exceeds_profiel(l_mld_stdmelding_autoorderamnt, l_prs_perslid_key, l_opdr_discipline_key)))   -- Ik kan niet zelf fiatteren of kosten overschrijden het profiel.
         THEN
            l_for_approval := TRUE;

            -- prs.getfiatteur (pkostenplaats_key, pexcludekey, pondergrens, pdisckey, pfiatbedrag)
            SELECT prs.getfiatteur (COALESCE(l_prs_kostenplaats_key, -1), -1, l_mld_stdmelding_autoorderamnt, l_opdr_discipline_key, 0)
              INTO l_approver_key
              FROM DUAL;
         END IF;
      END IF;

      IF l_for_approval AND l_prs_kostenplaats_fiat = 1
      THEN
         IF l_approver_key = -1
         THEN
            -- Internal error; approver must exist.
            RETURN;
         --ELSE
            -- Er is nu een altijd een eerste approver_key gevonden (met of zonder voldoende fiatteringsrechten). Anders al een abort.
            -- approver_key is oke of indien -1 dan is er geen approval meer nodig (is al geabort hierboven anders)
         END IF;
      END IF;

      -- Zetten van de status van de melding naar geaccepteerd en afhandelen van de tracking.
      mld.setmeldingstatus(p_melding_key, 4, NULL, 1);
      -- (re)calculate the conditionscores of the releated objects
      IF fac.getsetting('cnd_gebreken_srtdisc_key') > 0
      THEN
         cnd.process_mjb_score_effects(p_melding_key, NULL);
      END IF;

      -- Voor automatische opdrachten controleren of uitvoerende bepaald kan worden (niet voor offertes).
      IF l_mld_typeopdr_isofferte = 0
      THEN
         -- Daarvoor zijn plaatsgegevens relevant.
         -- Eerst kijken of er een locatie key bepaald kan worden.
         BEGIN
            SELECT mld_alg_locatie_key
                 , mld_adres_key
                 , mld_alg_onroerendgoed_keys
              INTO l_mld_alg_locatie_key
                 , l_mld_adres_key
                 , l_mld_alg_onroerendgoed_keys
              FROM mld_melding
             WHERE mld_melding_key = p_melding_key
               AND (mld_alg_locatie_key IS NOT NULL OR mld_adres_key IS NOT NULL);
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN -- Geen locatie of adres
               l_mld_alg_locatie_key := NULL;
               l_mld_adres_key := NULL;
               l_mld_alg_onroerendgoed_keys := NULL;
         END;

         IF l_mld_alg_locatie_key IS NULL AND l_mld_adres_key IS NOT NULL
         THEN
            -- Als we geen locatiekey hebben maar wel een afleveradres, kunnen we mogelijk ook een locatiekey bepalen.
            SELECT alg_locatie_key
              INTO l_mld_alg_locatie_key
              FROM mld_adres
             WHERE mld_adres_key = l_mld_adres_key;
         END IF;

         IF l_mld_alg_onroerendgoed_keys > 0
         THEN
            SELECT g.alg_gebouw_key
                 , g.alg_verdieping_key
                 , g.alg_ruimte_key
                 , g.alg_type
              INTO l_alg_gebouw_key
                 , l_alg_verdieping_key
                 , l_alg_ruimte_key
                 , l_alg_type
              FROM alg_v_allonrgoed_gegevens g
             WHERE g.alg_onroerendgoed_keys = l_mld_alg_onroerendgoed_keys;
         END IF;

         -- Dienst controle is bij het aanmaken van de start melding al gedaan.
         -- Voor de opdracht wordt namelijk uit gegaan van dezelfde mld_stdmelding, mld_alg_onroerendgoed_keys (locatie, gebouw en ruimte) en prs_perslid_voor.
         -- De controle zal dan dus hetzelfde zijn.
         -- Dienst controle: stdmelding -> prs_dienst_key -> prs_bedrijf_key.
         --                  Controles:
         --                  1) Er moet een bedrijf bij de dienst gevonden kunnen worden.
         --                  2) Als de melding onderdeel is van *een* dienstniveau dan moet bij de ruimte
         --                     een niveau ingevuld zijn waar deze melding onderdeel van is.
         --                  3) Als bij de melding is aangegeven dat hij alleen voor de eigen organisatie mag dan
         --                     moet die ruimte (via PRS_RUIMTEAFDELING) gehuurd worden door "eigen" afdeling
         --                     "eigen" is gedefinieerd als een afdeling die ons als parent heeft
         --                     of een afdeling die een parent van ons is.
         -- De controles kunnen hier overgeslagen worden en kan de prs bedrijf_key direct bepalen.

         IF l_prs_dienst_key IS NOT NULL
         THEN
            -- Controleer of er één bedrijf is dat deze dienst levert (op deze locatie/dit gebouw) via prs_bedrijfdienstlocatie
            IF l_alg_gebouw_key IS NOT NULL
            THEN
               SELECT MIN(bdl.prs_bedrijf_key) prs_bedrijf_key
                    , COUNT(DISTINCT bdl.prs_bedrijf_key) aantal
                    , MIN(bdl.prs_bdl_t_uitvoertijd.tijdsduur) tijdsduur
                    , MIN(bdl.prs_bdl_t_uitvoertijd.eenheid) eenheid
                 INTO l_prs_bedrijf_key
                    , l_aantal
                    , l_bdl_tijdsduur
                    , l_bdl_eenheid
                 FROM prs_bedrijfdienstlocatie bdl
                    , prs_v_aanwezigbedrijf b
                WHERE bdl.prs_bedrijf_key = b.prs_bedrijf_key
                  AND bdl.prs_dienst_key = l_prs_dienst_key
                  AND (   (  bdl.alg_gebouw_key = l_alg_gebouw_key
                          OR bdl.alg_gebouw_key IS NULL
                          )
                      AND (  bdl.alg_locatie_key = l_mld_alg_locatie_key
                          OR bdl.alg_locatie_key IS NULL
                          )
                      )
                  AND bdl.mld_autoorder = 1;
            ELSIF l_mld_alg_locatie_key IS NOT NULL
            THEN
               SELECT MIN(bdl.prs_bedrijf_key) prs_bedrijf_key
                    , COUNT(DISTINCT bdl.prs_bedrijf_key) aantal
                    , MIN(bdl.prs_bdl_t_uitvoertijd.tijdsduur)
                    , MIN(bdl.prs_bdl_t_uitvoertijd.eenheid) eenheid
                 INTO l_prs_bedrijf_key
                    , l_aantal
                    , l_bdl_tijdsduur
                    , l_bdl_eenheid
                 FROM prs_bedrijfdienstlocatie bdl
                    , prs_v_aanwezigbedrijf b
                WHERE bdl.prs_bedrijf_key = b.prs_bedrijf_key
                  AND bdl.prs_dienst_key = l_prs_dienst_key
                  AND (  bdl.alg_locatie_key = l_mld_alg_locatie_key
                      OR bdl.alg_locatie_key IS NULL
                      )
                  AND bdl.mld_autoorder = 1;
            ELSE
               SELECT MIN(bdl.prs_bedrijf_key) prs_bedrijf_key
                    , COUNT(DISTINCT bdl.prs_bedrijf_key) aantal
                    , MIN(bdl.prs_bdl_t_uitvoertijd.tijdsduur) tijdsduur
                    , MIN(bdl.prs_bdl_t_uitvoertijd.eenheid) eenheid
                 INTO l_prs_bedrijf_key
                    , l_aantal
                    , l_bdl_tijdsduur
                    , l_bdl_eenheid
                 FROM prs_bedrijfdienstlocatie bdl
                    , prs_v_aanwezigbedrijf b
                WHERE bdl.prs_bedrijf_key = b.prs_bedrijf_key
                  AND bdl.prs_dienst_key = l_prs_dienst_key
                  AND bdl.alg_gebouw_key IS NULL
                  AND bdl.alg_locatie_key IS NULL
                  AND bdl.mld_autoorder = 1; -- Bestaat er dan misschien maar 1 bedrijf voor deze dienst zonder loc/geb scope ?
            END IF;
            -- Indien dienst vereist en aantal is 0, dan is de dienst niet beschikbaar voor deze locatie/dit gebouw.
            -- Indien aantal groter is dan 0, dan kan ik geen goede keuze maken.
            IF l_aantal <> 1
            THEN
               l_prs_bedrijf_key := NULL;
            END IF;
            --
            -- Controleer of er één bedrijf is dat deze dienst levert (op deze locatie/dit gebouw) via cnt_contract_plaats
            IF l_aantal <> 1
            THEN
               IF l_mld_alg_onroerendgoed_keys IS NOT NULL
               THEN
                  SELECT MIN(c.cnt_prs_bedrijf_key) cnt_prs_bedrijf_key
                       , MIN(cp.cnt_contract_key) cnt_contract_key
                       , COUNT(DISTINCT c.cnt_prs_bedrijf_key) aantal
                    INTO l_prs_bedrijf_key
                       , l_cnt_contract_key
                       , l_aantal
                    FROM cnt_contract c
                       , cnt_contract_plaats cp
                       , cnt_disc_params cd
                   WHERE cp.cnt_contract_key = c.cnt_contract_key
                     AND cd.cnt_ins_discipline_key = c.ins_discipline_key
                     AND SYSDATE BETWEEN c.cnt_contract_looptijd_van
                                     AND c.cnt_contract_looptijd_tot
                     AND c.cnt_contract_verwijder IS NULL
                     AND cd.cnt_srtcontract_type IN (3,5)
                     AND cp.cnt_alg_plaats_key = l_mld_alg_onroerendgoed_keys
                     AND cp.cnt_alg_plaats_code = l_alg_type
                     AND c.prs_dienst_key = l_prs_dienst_key;
               ELSE
                  SELECT MIN(c.cnt_prs_bedrijf_key) cnt_prs_bedrijf_key
                       , MIN(cp.cnt_contract_key) cnt_contract_key
                       , COUNT(DISTINCT c.cnt_prs_bedrijf_key) aantal
                    INTO l_prs_bedrijf_key
                       , l_cnt_contract_key
                       , l_aantal
                    FROM cnt_contract c
                       , cnt_contract_plaats cp
                       , cnt_disc_params cd
                   WHERE cp.cnt_contract_key = c.cnt_contract_key
                     AND cd.cnt_ins_discipline_key = c.ins_discipline_key
                     AND SYSDATE BETWEEN c.cnt_contract_looptijd_van
                                     AND c.cnt_contract_looptijd_tot
                     AND c.cnt_contract_verwijder IS NULL
                     AND cd.cnt_srtcontract_type IN (3,5)
                     AND cp.cnt_alg_plaats_key = l_mld_alg_locatie_key
                     AND cp.cnt_alg_plaats_code = 'L'
                     AND c.prs_dienst_key = l_prs_dienst_key;
               END IF;
               IF l_aantal <> 1
               THEN
                  l_prs_bedrijf_key := NULL;
                  l_cnt_contract_key := NULL;
               END IF;
            END IF;
         END IF;
         IF l_prs_bedrijf_key IS NULL
         THEN
            -- Internal error; prs_bedrijf_key must exist.
            RETURN;
         END IF;
      END IF;

      -- Zijn de totale kosten verplicht en ingevuld? Hier gaat het om een nieuwe opdracht en moet dus gecontroleerd worden.
      -- Opdrachttype: mld_typeopdr_kosten_verplicht (typeopdr kosten): 0 = Niet verplicht, 1 = Save + 2 = Afmelden, 4 = Afronden.
      -- Vakgroep:     mld_disc_params_opdr_kosten (opdracht kosten):   0 = Niet verplicht, 7 = Aanmaak, 6 = Afmelden, 4 = Afronden.
      -- Nieuwe opdracht, dus ik hoef alleen te kijken naar Save (mld_typeopdr_kosten_verplicht) en Aanmaak (mld_disc_params_opdr_kosten).
      IF ((BITAND(l_mld_typeopdr_kst_verplicht, 1) = 1
        OR (l_mld_typeopdr_kst_verplicht = 0 AND BITAND(l_mld_disc_params_opdr_kosten, 1) = 1)) -- Zijn de kosten verplicht voor nieuwe opdracht?
      AND l_mld_stdmelding_autoorderamnt IS NULL)                                               -- Totale kosten bij autoorder.
      THEN
         -- Internal error; The costs must be filled in.
         RETURN;
      END IF;

      -- Als kosten meegerekend moeten worden ("Kosten meerekenen") dan moet er wel een kostenplaats bekend zijn.
      IF l_mld_typeopdr_kosten = 1 AND l_prs_kostenplaats_key IS NULL    -- Kosten meerekenen?
      THEN
         -- Internal error; prs_kostenplaats_key must exist.
         RETURN;
      END IF;

      -- Combinatievalidatie
      IF l_prs_kostenplaats_key IS NOT NULL AND NOT prs.combinatievalidatie(l_prs_kostenplaats_key, l_prs_kostensoort_key, l_opdr_discipline_key)
      THEN
         -- Internal error; Combinatievalidatie: Dit product is niet toegestaan voor deze kostenplaats.
         RETURN;
      END IF;

      -- mld_c_mld_uitvoerende_keys
      IF l_prs_bedrijf_key IS NULL
      THEN
         -- Internal error; prs_bedrijf_key must exist.
         RETURN;
      END IF;

      -- Uurloon
      SELECT b.prs_bedrijf_uurloon
        INTO l_prs_bedrijf_uurloon
        FROM prs_bedrijf b
       WHERE b.prs_bedrijf_key = l_prs_bedrijf_key;   -- Er is een geldige uitvoerder.

      -- Einddatum bepalen
      IF l_mld_typeopdr_slamode = 1
      THEN
         -- Uitvoertijd opdracht is bedrijf uitvoertijd.
         -- Als er een specifieke uitvoertijd voor ons gebouw is, dan zijn l_bdl_tijdsduur en l_bdl_eenheid hiermee gevuld.
         IF l_bdl_tijdsduur IS NULL
         THEN
            SELECT b.prs_bedrijf_t_uitvoertijd.tijdsduur
                 , b.prs_bedrijf_t_uitvoertijd.eenheid
              INTO l_bdl_tijdsduur
                 , l_bdl_eenheid
              FROM prs_bedrijf b
             WHERE b.prs_bedrijf_key = l_prs_bedrijf_key;   -- Er is een geldige uitvoerder.
         END IF;
      ELSIF l_mld_typeopdr_slamode = 2
      THEN
         -- Uitvoertijd opdracht is melding uitvoertijd.
         SELECT m.mld_melding_t_uitvoertijd.tijdsduur
              , m.mld_melding_t_uitvoertijd.eenheid
           INTO l_bdl_tijdsduur
              , l_bdl_eenheid
           FROM mld_melding m
          WHERE m.mld_melding_key = p_melding_key;
      -- ELSE l_mld_typeopdr_slamode = 3
      --   Dan blijft tijdsduur en eenheid NULL en wordt uiteindelijk de einddatum opdracht gelijk aan de einddatum melding.
      END IF;

      IF l_bdl_tijdsduur IS NOT NULL
      THEN
         -- Bepaal/Bereken de SLA-einddatum.
         IF l_mld_stdmelding_enddate_empty = 1
         THEN
            l_mld_opdr_einddatum := NULL;
         ELSE
            -- l_bdl_tijdsduur en l_bdl_eenheid hebben een waarde.
            SELECT mld.geteinddatum(p_melding_key,
                                    MLD_T_UITVOERTIJD(l_bdl_tijdsduur, l_bdl_eenheid),
                                    SYSDATE)
              INTO l_mld_opdr_einddatum
              FROM DUAL;

            -- Als setting mld_enforce_orderdates = 1, dan moeten de datums van de opdracht binnen de datums van de melding liggen.
            IF l_mld_typeopdr_slamode = 1 AND
               fac.getsetting('mld_enforce_orderdates') = 1 AND
               TRUNC(l_mld_melding_einddatum, 'DDD') < TRUNC(l_mld_opdr_einddatum, 'DDD')
            THEN
                l_mld_opdr_einddatum := l_mld_melding_einddatum;
            END IF;
         END IF;
      ELSE
         l_mld_opdr_einddatum := l_mld_melding_einddatum;   -- Einddatum melding;
      END IF;

      -- Opdracht omschrijving.
      IF l_mld_melding_onderwerp IS NOT NULL
      THEN
         l_mld_opdr_omschrijving := l_mld_melding_onderwerp;
         IF l_mld_melding_omschrijving IS NOT NULL
         THEN
            l_mld_opdr_omschrijving := l_mld_opdr_omschrijving || CHR(10);
         END IF;
      END IF;
      IF l_mld_melding_omschrijving IS NOT NULL
      THEN
         l_mld_opdr_omschrijving := l_mld_opdr_omschrijving || l_mld_melding_omschrijving;
      END IF;
      IF fac.getsetting('mld_ord_flexsummary') <> 0
      THEN
         l_mld_opdr_omschrijving := l_mld_opdr_omschrijving || mld.mldflexsummary(p_melding_key);
      END IF;

      SELECT mld_s_mld_opdr_key.NEXTVAL INTO l_new_opdr_key FROM DUAL;

      -- Merk op: voor sommige velden laten we bewust de default nemen
      INSERT INTO mld_opdr (mld_melding_key,
                            mld_opdr_key,
                            mld_opdr_bedrijfopdr_volgnr,
                            mld_typeopdr_key,
                            mld_uitvoerende_keys,
                            cnt_contract_key,
                            prs_perslid_key,
                            prs_kostenplaats_key,
                            prs_kostensoort_key,
                            mld_opdr_kosten,
                            mld_opdr_uurloon,
                            mld_opdr_uren,
                            mld_opdr_module,
                            mld_opdr_datumbegin,
                            mld_opdr_einddatum,
                            mld_opdr_omschrijving)
                    VALUES (p_melding_key,
                            l_new_opdr_key,
                            mld.bepaalopdrmeldingvolgnr(p_melding_key),
                            l_mld_typeopdr_key,
                            l_prs_bedrijf_key,
                            l_cnt_contract_key,
                            CASE
                            WHEN l_haswrite = 1
                            THEN l_prs_perslid_key
                            ELSE NULL
                            END,
                            l_prs_kostenplaats_key,
                            l_prs_kostensoort_key,
                            l_mld_stdmelding_autoorderamnt,
                            l_prs_bedrijf_uurloon,
                            0,
                            'MLD',
                            SYSDATE,                                      -- Begindatum opdracht gelijk aan de melding datum (SYSDATE voor workflow melding).
                            l_mld_opdr_einddatum,
                            l_mld_opdr_omschrijving);

      -- Status en tracking altijd met de functie setopdrachtstatus
      -- Zetten van de status van een nieuwe opdracht op nieuw en afhandelen van de tracking (status + uitvoerende tracking) en daarmee notificatie.
      IF l_mld_stdmelding_autoorderamnt > l_mld_disc_params_bestellimiet OR l_mld_stdmelding_autoorderamnt > l_mld_typeopdr_gvs
      THEN
        mld.setopdrachtstatus(l_new_opdr_key, 10, NULL);   -- Ter goedkeuring.
      ELSIF l_for_approval AND l_prs_kostenplaats_fiat = 1 AND l_mld_stdmelding_autoorderamnt > l_mld_typeopdr_fvs -- We moeten fiatteren en er is geen (of een te lage) fiatteringsvrijstelling
      THEN
           mld.setopdrachtstatus(l_new_opdr_key, 3, NULL);   -- Ter fiattering.
      ELSE
        -- Fiatteren niet nodig.
        mld.setopdrachtstatus(l_new_opdr_key, 5, NULL);   -- Uitgegeven.
        -- mld.trackuitvoerende(opdr_key, uitvoerende, opdr_status_key);
        SELECT CASE
               WHEN u.intern = 1
               THEN 'ORDMLI'
               ELSE 'ORDMLE'
               END
          INTO l_action
          FROM mld_v_uitvoerende u
         WHERE u.mld_uitvoerende_key = l_prs_bedrijf_key;
        -- Type "P" (persoon) is intern en type "B" (bedrijf) is afhankelijk van "prs_bedrijf_intern" intern of extern.
        fac.trackaction(l_action, l_new_opdr_key, NULL, NULL, NULL);
        -- In de database procedure doen we geen putorders.sendnotifications(pkey, paction). Dan moeten we maar iets langer wachten.
      END IF;

      -- Refresh meldingstatus zonodig als gevolg van een nieuw uitgegeven opdracht.
      -- Als er open opdrachten zijn wordt de melding op Uitgegeven gezet als dat al niet zo was.
      mld.updatemeldingstatus (p_melding_key, 0, NULL);
      -- (Re)calculate the conditionscores of the releated objects
      IF fac.getsetting('cnd_gebreken_srtdisc_key') > 0
      THEN
         cnd.process_mjb_score_effects(p_melding_key, NULL);
      END IF;

      -- Bij workflow meldingen worden de bijlagen niet gekopieerd.
      -- De bijlagen van de parent melding worden bij de onderliggende workflow melding weergegeven (in de show mode)
      -- als de instelling/setting "mld_show_parent_attachments" is gezet.
      -- Bij het automatisch aanmaken van de opdracht bij een workflowmelding hoeven dus ook geen bijlagen te worden gekopieerd.

      -- Bij het automatisch aanmaken van een opdracht bij een melding is alleen de melding_key doorgegeven en dus niet de melding kenmerken.
      -- Deze kenmerken zijn dus ook niet opgeslagen.
      -- De melding kenmerken die overeenkomen met de opdracht kenmerken (dezelfde omschrijving en srtkenmerk) ophalen en opslaan voor de nieuwe opdracht.
      INSERT INTO mld_kenmerkopdr (mld_opdr_key
                                 , mld_kenmerk_key
                                 , mld_kenmerkopdr_waarde)
         SELECT l_new_opdr_key mld_opdr_key
              , k.mld_kenmerk_key kenmerk_key
              , COALESCE((SELECT v.mld_kenmerkmelding_waarde
                            FROM mld_kenmerkmelding v
                               , mld_kenmerk vk
                               , mld_srtkenmerk vt
                           WHERE v.mld_melding_key = p_melding_key
                             AND vk.mld_srtkenmerk_key = vt.mld_srtkenmerk_key
                             AND vk.mld_srtkenmerk_key = k.mld_srtkenmerk_key
                             AND vk.mld_kenmerk_groep = k.mld_kenmerk_groep
                             AND v.mld_kenmerk_key = vk.mld_kenmerk_key
                             AND v.mld_kenmerkmelding_verwijder IS NULL
                             AND COALESCE(vk.mld_kenmerk_omschrijving, vt.mld_srtkenmerk_omschrijving) = COALESCE(k.mld_kenmerk_omschrijving, t.mld_srtkenmerk_omschrijving)),
                         k.mld_kenmerk_default) kenmerk_waarde
           FROM mld_srtkenmerk t
              , mld_kenmerk k
              , mld_typeopdr s
          WHERE (s.mld_typeopdr_key = l_mld_typeopdr_key OR s.mld_typeopdr_key IS NULL)
            AND k.mld_typeopdr_key = s.mld_typeopdr_key(+)
            AND k.mld_kenmerk_niveau IN ('P', 'O')
            AND k.mld_kenmerk_verwijder IS NULL
            AND k.mld_srtkenmerk_key = t.mld_srtkenmerk_key
            AND t.mld_srtkenmerk_verwijder IS NULL
            AND t.mld_srtkenmerk_kenmerktype <> 'M'
            AND BITAND(k.mld_kenmerk_rolcode, 5) > 0 -- Alleen bij of na afmelden mogen afmeld-kenmerken (x0x of x1x)
            AND COALESCE((SELECT v.mld_kenmerkmelding_waarde
                            FROM mld_kenmerkmelding v
                               , mld_kenmerk vk
                               , mld_srtkenmerk vt
                           WHERE v.mld_melding_key = p_melding_key
                             AND vk.mld_srtkenmerk_key = vt.mld_srtkenmerk_key
                             AND vk.mld_srtkenmerk_key = k.mld_srtkenmerk_key
                             AND vk.mld_kenmerk_groep = k.mld_kenmerk_groep
                             AND v.mld_kenmerk_key = vk.mld_kenmerk_key
                             AND v.mld_kenmerkmelding_verwijder IS NULL
                             AND COALESCE(vk.mld_kenmerk_omschrijving, vt.mld_srtkenmerk_omschrijving) = COALESCE(k.mld_kenmerk_omschrijving, t.mld_srtkenmerk_omschrijving)),
                         k.mld_kenmerk_default) IS NOT NULL
            AND COALESCE((SELECT v.mld_kenmerkmelding_waarde
                            FROM mld_kenmerkmelding v
                               , mld_kenmerk vk
                               , mld_srtkenmerk vt
                           WHERE v.mld_melding_key = p_melding_key
                             AND vk.mld_srtkenmerk_key = vt.mld_srtkenmerk_key
                             AND vk.mld_srtkenmerk_key = k.mld_srtkenmerk_key
                             AND vk.mld_kenmerk_groep = k.mld_kenmerk_groep
                             AND v.mld_kenmerk_key = vk.mld_kenmerk_key
                             AND v.mld_kenmerkmelding_verwijder IS NULL
                             AND COALESCE(vk.mld_kenmerk_omschrijving, vt.mld_srtkenmerk_omschrijving) = COALESCE(k.mld_kenmerk_omschrijving, t.mld_srtkenmerk_omschrijving)),
                         k.mld_kenmerk_default) NOT LIKE '%##EXPR##%';


      INSERT INTO fac_kenmwaarden(fac_kenmwaarden_module,
                                 fac_kenmwaarden_refkey,
                                 fac_kenmwaarden_kenmerk_key,
                                 fac_kenmwaarden_waarde,
                                 fac_kenmwaarden_kenmerktype,
                                 fac_kenmwaarden_kenmerklen,
                                 fac_kenmwaarden_kenmerkdec,
                                 fac_kenmwaarden_isexpr,
                                 prs_perslid_key)
         SELECT 'OPD',
                l_new_opdr_key,
                k.mld_kenmerk_key,
                COALESCE((SELECT v.mld_kenmerkmelding_waarde
                            FROM mld_kenmerkmelding v,
                                 mld_kenmerk vk,
                                 mld_srtkenmerk vt
                           WHERE v.mld_melding_key = p_melding_key
                             AND vk.mld_srtkenmerk_key = vt.mld_srtkenmerk_key
                             AND vk.mld_srtkenmerk_key = k.mld_srtkenmerk_key
                             AND vk.mld_kenmerk_groep = k.mld_kenmerk_groep
                             AND v.mld_kenmerk_key = vk.mld_kenmerk_key
                             AND v.mld_kenmerkmelding_verwijder IS NULL
                             AND COALESCE(vk.mld_kenmerk_omschrijving, vt.mld_srtkenmerk_omschrijving) = COALESCE(k.mld_kenmerk_omschrijving, t.mld_srtkenmerk_omschrijving)),
                         k.mld_kenmerk_default) kenmerk_waarde,
                t.mld_srtkenmerk_kenmerktype,
                t.mld_srtkenmerk_lengte,
                t.mld_srtkenmerk_dec,
                CASE
                WHEN k.mld_kenmerk_default LIKE '%##EXPR##%'
                THEN 1
                ELSE 0
                END fac_kenmwaarden_isexpr,
                l_prs_perslid_key
           FROM mld_srtkenmerk t
              , mld_kenmerk k
              , mld_typeopdr s
          WHERE (s.mld_typeopdr_key = l_mld_typeopdr_key OR s.mld_typeopdr_key IS NULL)
            AND k.mld_typeopdr_key = s.mld_typeopdr_key(+)
            AND k.mld_kenmerk_niveau IN ('P', 'O')
            AND k.mld_kenmerk_verwijder IS NULL
            AND k.mld_srtkenmerk_key = t.mld_srtkenmerk_key
            AND t.mld_srtkenmerk_verwijder IS NULL
            AND t.mld_srtkenmerk_kenmerktype <> 'M'
            AND BITAND(k.mld_kenmerk_rolcode, 5) > 0 -- Alleen bij of na afmelden mogen afmeld-kenmerken (x0x of x1x)
            AND COALESCE((SELECT MIN(v.mld_kenmerkmelding_waarde)
                            FROM mld_kenmerkmelding v
                               , mld_kenmerk vk
                               , mld_srtkenmerk vt
                           WHERE v.mld_melding_key = p_melding_key
                             AND vk.mld_srtkenmerk_key = vt.mld_srtkenmerk_key
                             AND vk.mld_srtkenmerk_key = k.mld_srtkenmerk_key
                             AND vk.mld_kenmerk_groep = k.mld_kenmerk_groep
                             AND v.mld_kenmerk_key = vk.mld_kenmerk_key
                             AND v.mld_kenmerkmelding_verwijder IS NULL),
                         k.mld_kenmerk_default) IS NOT NULL
        ORDER BY mld_kenmerk_volgnummer;

      -- Evaluate flex expressions.
      flx.evaluateflexexpressions('OPD', l_new_opdr_key, l_prs_perslid_key, 1);

      -- De nieuwe (offerte)opdracht door putorders laten oppikken (te verzenden veld zetten), zodat de opdracht verstuurd wordt.
      IF l_mld_typeopdr_isofferte = 1
      THEN
         -- Offerte.
         UPDATE mld_opdr
            SET mld_opdr_teverzenden = 1
          WHERE mld_opdr_key = l_new_opdr_key;
          fac.notifytrackingbedrijven ('ORDNEW', l_new_opdr_key);
      ELSE
         -- Alleen in geval van een uitvoerder, de opdracht door putorders laten oppikken.
         BEGIN
            SELECT prs_bedrijfadres_url
            INTO l_prs_bedrijfadres_url
            FROM (  SELECT prs_bedrijfadres_url
                      FROM prs_bedrijfadres
                     WHERE     prs_bedrijfadres_type = 'O'
                           AND prs_bedrijfadres_startdatum <= SYSDATE
                           AND (mld_typeopdr_key IS NULL OR mld_typeopdr_key = l_mld_typeopdr_key)
                           AND (alg_locatie_key = l_mld_alg_locatie_key OR alg_locatie_key IS NULL)
                           AND (   alg_district_key = (SELECT d.alg_district_key
                                                         FROM alg_locatie d
                                                        WHERE d.alg_locatie_key = l_mld_alg_locatie_key)
                                 OR alg_district_key IS NULL)
                           AND prs_bedrijf_key = l_prs_bedrijf_key
                  ORDER BY prs_bedrijfadres_startdatum DESC)
            WHERE ROWNUM = 1;

           UPDATE mld_opdr
              SET mld_opdr_teverzenden = 1
            WHERE mld_opdr_key = l_new_opdr_key;
            fac.notifytrackingbedrijven ('ORDNEW', l_new_opdr_key);
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN NULL;
         END;
      END IF;
   END mld_addautoorder;

   PROCEDURE mld_nextworkflowstep (p_melding_key IN NUMBER, p_success IN NUMBER, p_user_key IN NUMBER DEFAULT NULL)
   AS
      -- p_melding_key key of the call to be continued
      -- p_success gives state of the executed call:
      --  0 = rejected (reinstated since DB8)
      --  1 = completed
      -- -1 = initial (the originating call)
      l_melding_start_key        NUMBER (10);
      l_workflowstep_key         NUMBER (10);
      l_stdmelding_key           NUMBER (10);
      l_conceptstatus            mld_melding.mld_melding_conceptstatus%TYPE;
      l_workflowstep_next_key    NUMBER (10);
      l_new_melding_key          NUMBER (10);
      l_success                  NUMBER;
      l_nrofreadypredecessors    NUMBER;
      l_nrofactualpredecessors   NUMBER;
      l_nrofpossiblepredecessors NUMBER;
      l_nrofrequiredpredecessors NUMBER;
      l_prepredecessors          NUMBER;
      tmp                        NUMBER;
      createthisnextstep         BOOLEAN;
      rootregistered             BOOLEAN;
      l_nrstepsevaluatedtrue     NUMBER := 0;
      nrcase_a                   NUMBER := 0;
      nrcase_b                   NUMBER := 0;
      l_common_ancestor          mld_workflowrule.mld_workflowstep_key%TYPE;
      l_initmldstatus            mld_melding.mld_melding_status%TYPE;
      calculated_einddatum       mld_melding.mld_melding_einddatum%TYPE;
      root_einddatum             mld_melding.mld_melding_einddatum%TYPE;
      l_autoorder                mld_stdmelding.mld_stdmelding_autoorder%TYPE;
   BEGIN
      l_success := p_success;

      BEGIN
         SELECT mld_melding_start_key, mld_workflowstep_key, mld_stdmelding_key, mld_melding_conceptstatus
           INTO l_melding_start_key, l_workflowstep_key, l_stdmelding_key, l_conceptstatus
           FROM mld_melding
          WHERE mld_melding_key = p_melding_key;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            -- Internal error; mld_melding must exist
            RETURN;
      END;

      -- Early exit: conceptmeldingen vereisen eerst sowieso instemming
      IF l_conceptstatus <> 0
      THEN
         DBMS_OUTPUT.put_line ('Dit is een conceptmelding, geen workflowacties:' || p_melding_key);
         RETURN;
      END IF;

      IF p_success = -1
      THEN
         -- The first step of a workflow

         BEGIN
            SELECT ws.mld_workflowstep_key
              INTO l_workflowstep_key
              FROM mld_workflowstep ws
             WHERE ws.mld_stdmelding_key = l_stdmelding_key
                   AND ws.mld_workflowstep_start_key IS NULL;
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN
               -- No workflowsteps defined for this type of calls
               RETURN;
            WHEN TOO_MANY_ROWS
            THEN
               -- Workflow defined more than once, is erroneous; do not know what to do so
               RETURN;
         END;

         -- We must implicitly accept the initial call once, else we cannot complete it later
         -- and accepting in the end would be odd.
         mld.setmeldingstatus (p_melding_key, 4, p_user_key);
         rootregistered := FALSE;
         l_melding_start_key := p_melding_key;
         l_success := 1;                               -- we used the info, we continue like success
      END IF;

      -- Is this mld_melding part of a workflow?
      IF l_workflowstep_key IS NULL
      THEN
         -- No, done.
         RETURN;
      END IF;

      -- Als dit niet NULL waarden oplevert, dan is deze melding onderdeel van een workflow process
      -- Bepaal nu de vervolgstappen binnen deze workflow (zelfde start_key).
      -- Dit kunnen er meerdere zijn.
      DECLARE
         -- This cursor yields all the next workflowssteps as defined in this workflow
         -- That does not necessarily mean that all these steps will be created at this time!
         -- That actual creating depends on whether the condition evaluates to true and
         -- the state of dependent steps if any and as defined by jointype
         --
         -- TODO: think about the exact behaviour of mld_workflowrule_result
         CURSOR c_nextsteps
         IS
            SELECT ws.mld_workflowstep_key,
                   ws.mld_stdmelding_key,
                   stdm.mld_ins_discipline_key,
                   stdm.mld_stdmelding_default_disc,
                   disc.ins_srtdiscipline_key,
                   wr.mld_workflowrule_condition,
                   ws.mld_workflowstep_jointype,
                   ws.mld_workflowstep_eindtype,
                   COALESCE(stdm.mld_stdmelding_directklaar, dp.mld_disc_params_directklaar, 0) mld_directklaar
              FROM mld_workflowrule wr,                       -- alles wat begint op de huidige step
                   mld_workflowstep ws0,                       -- de huidige step, voor de start_key
                   mld_workflowstep ws,                                     -- alle volgende stappen
                   mld_stdmelding stdm,                          -- de melding van een volgende step
                   mld_discipline disc,
                   mld_disc_params dp
             WHERE     stdm.mld_stdmelding_key = ws.mld_stdmelding_key
                   AND stdm.mld_ins_discipline_key = disc.ins_discipline_key
                   AND stdm.mld_ins_discipline_key = dp.mld_ins_discipline_key
                   AND wr.mld_workflowstep_key = ws0.mld_workflowstep_key
                   AND ws.mld_workflowstep_start_key =
                         NVL (ws0.mld_workflowstep_start_key, ws.mld_workflowstep_start_key)
                   AND wr.mld_workflowstep_next_key = ws.mld_workflowstep_key
                   AND wr.mld_workflowrule_result = l_success
                   AND wr.mld_workflowstep_key = l_workflowstep_key;

         r_nextsteps   c_nextsteps%ROWTYPE;

         FUNCTION evaluatecondition (p_mld_key IN NUMBER, p_where IN VARCHAR2)
            RETURN BOOLEAN
         AS
            l_sql             VARCHAR2 (4000);
            l_rowsprocessed   NUMBER DEFAULT 0;
            l_cursor          INTEGER DEFAULT DBMS_SQL.open_cursor;
            l_cntbind         NUMBER;
            l_cnt             NUMBER;
            l_bvar            VARCHAR2 (1000);
            l_rflex           VARCHAR2 (1000) DEFAULT '(\:flex[0-9_]+)'; -- supports ':flex111 = ''538'''
            l_kenmerkwaarde   mld_kenmerkmelding.mld_kenmerkmelding_waarde%TYPE;
            l_kenmerk_key     mld_kenmerkmelding.mld_kenmerk_key%TYPE;
         BEGIN
            IF p_where IS NULL
            THEN
               RETURN TRUE;
            END IF;

            -- ook standaardondersteuning voor p.alg_gebouw_key, p.alg_verdieping_key, p.alg_ruimte_key en p.alg_terreinsector_key in de conditie
            l_sql := 'select 1 from mld_melding, alg_v_onroerendgoed p where mld_melding.mld_alg_onroerendgoed_keys = p.alg_onroerendgoed_keys(+) AND mld_melding_key = :mld_key AND (' || p_where ||')';
            DBMS_OUTPUT.put_line (l_sql);
            DBMS_SQL.parse (l_cursor, l_sql, DBMS_SQL.native);
            DBMS_SQL.bind_variable (l_cursor, ':mld_key', p_mld_key);
            l_cntbind :=
               REGEXP_COUNT (l_sql,
                             l_rflex,
                             1,
                             'i');
            DBMS_OUTPUT.put_line ('nBindvars: ' || TO_CHAR (l_cntbind));

            FOR l_cnt IN 1 .. l_cntbind LOOP
               l_bvar :=
                  REGEXP_SUBSTR (l_sql,
                                 l_rflex,
                                 1,
                                 l_cnt,
                                 'i');
               DBMS_OUTPUT.put_line ('Bindvar: ' || l_bvar);
               l_kenmerk_key := TO_NUMBER (SUBSTR (l_bvar, 6));
               DBMS_OUTPUT.put_line ('Bindvarkey: ' || l_kenmerk_key);

               BEGIN
                  SELECT mld_kenmerkmelding_waarde
                    INTO l_kenmerkwaarde
                    FROM mld_kenmerkmelding
                   WHERE mld_melding_key = p_mld_key AND mld_kenmerk_key = l_kenmerk_key;
               EXCEPTION
                  WHEN NO_DATA_FOUND
                  THEN
                     l_kenmerkwaarde := NULL;
               END;

               DBMS_SQL.bind_variable (l_cursor, l_bvar, l_kenmerkwaarde);
            END LOOP;

            l_rowsprocessed := DBMS_SQL.execute_and_fetch (l_cursor);
            DBMS_SQL.close_cursor(l_cursor);

            RETURN l_rowsprocessed = 1;
         END;
      BEGIN
         OPEN c_nextsteps;

         FETCH c_nextsteps INTO r_nextsteps;

         IF c_nextsteps%NOTFOUND
         THEN
            -- If no l_workflowstep_next_key was found, this workflow is done
            -- THEN, close the originating l_melding_start_key
            -- But only if there are no other threads open!
            SELECT COUNT (mld_melding_key)
              INTO tmp
              FROM mld_melding
             WHERE     mld_melding_start_key = l_melding_start_key
                   AND mld_workflowstep_key IS NOT NULL  -- tel toevallige adhoc vervolgmeldingen niet mee
                   AND mld_melding_status NOT IN (1, 5, 6)
                   AND mld_melding_key <> l_melding_start_key;

            -- Als er geen lopende parallelle meldingen zijn, OF DEZE (eenzame) STAP WORDT AFGEWEZEN
            -- Dan sluit de root. Overwogen dat de root niet Afgewezen wordt bij 0.
            IF tmp = 0 OR l_success = 0
            THEN
               DBMS_OUTPUT.put_line ('Closing parent:' || l_melding_start_key);
               mld.setmeldingstatus (l_melding_start_key, 5, p_user_key);
            --ELSE
            --DBMS_OUTPUT.PUT_LINE('no more steps, but still ' ||  tmp  || ' open calls in workflow');
            END IF;

            --More?
            RETURN;
         ELSE
            -- For each found l_workflowstep_next_key, create a new mld_melding
            -- if condition evaluates to true
            -- Using the basic properties of l_melding_start_key
            -- and the flexprops of p_melding_key if these match the mld_srtkenmerk_key
            LOOP

               DBMS_OUTPUT.put_line (   'startkey:'
                                    || l_melding_start_key
                                    || ' step key:'
                                    || r_nextsteps.mld_workflowstep_key);

               SELECT COUNT ( * )
                 INTO l_nrofpossiblepredecessors
                 FROM mld_workflowrule wr1, mld_workflowstep ws1
                WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                      AND wr1.mld_workflowstep_next_key = r_nextsteps.mld_workflowstep_key;

               DBMS_OUTPUT.put_line ('total nr of possible predecessors for next step: ' || l_nrofpossiblepredecessors);

               SELECT COUNT ( * )
                 INTO l_nrofactualpredecessors                             -- disregard status
                 FROM mld_melding m
                WHERE m.mld_workflowstep_key IN
                      (SELECT wr1.mld_workflowstep_key
                         FROM mld_workflowrule wr1, mld_workflowstep ws1
                        WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                          AND wr1.mld_workflowstep_next_key = r_nextsteps.mld_workflowstep_key
                      )
                    -- the step to be continued
                  AND m.mld_melding_start_key = l_melding_start_key;      -- for this thread

               DBMS_OUTPUT.put_line ('total nr of actual predecessors for next step: '
                                   || l_nrofactualpredecessors);

               l_nrofrequiredpredecessors := l_nrofactualpredecessors;

               -- If there is a difference between l_nrofpossiblepredecessors and l_nrofactualpredecessors there are
               -- a few possibilities:
               --   a. an actual predecessor has not been started yet (workflow branches are unequal length)
               --   b. an actual predecessor has not been started and will not start due to a condition
               -- In case a. the predecessor will start eventually and then trigger the next step.
               -- Then l_nrofreadypredecessors = l_nrofpossiblepredecessors
               -- In case b. the l_nrofreadypredecessors will never reach l_nrofpossiblepredecessors, the
               -- next step will be triggered when l_nrofreadypredecessors = l_nrofactualpredecessors
               -- The question is: how do we distinguish a and b?
               --
               -- Suggestion: backtracking the workflow for the step that is not (yet) there?
               IF l_nrofpossiblepredecessors > l_nrofactualpredecessors
               THEN
                  BEGIN
                     SELECT wr1.mld_workflowstep_key
                       INTO l_common_ancestor
                       FROM mld_workflowrule wr1, mld_workflowstep ws1
                      WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                        AND wr1.mld_workflowstep_next_key IN
                            (SELECT wr1.mld_workflowstep_key
                               FROM mld_workflowrule wr1, mld_workflowstep ws1
                              WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                                AND wr1.mld_workflowstep_next_key = r_nextsteps.mld_workflowstep_key
                            )
                      GROUP BY wr1.mld_workflowstep_key;
                  EXCEPTION
                     WHEN NO_DATA_FOUND OR TOO_MANY_ROWS
                     THEN
                        l_common_ancestor := -1;
                  END;

                  IF l_common_ancestor <> -1
                  THEN
                    DBMS_OUTPUT.put_line ('Common ancestor detected for all previous workflowsteps, so a condition not met (case b)');
                    l_nrofrequiredpredecessors := l_nrofactualpredecessors;
                  ELSE
                    -- determine case a or case b
                    FOR missingsteps
                       IN (SELECT wr1.mld_workflowstep_key
                             FROM mld_workflowrule wr1, mld_workflowstep ws1
                            WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                                  AND wr1.mld_workflowstep_next_key = r_nextsteps.mld_workflowstep_key
                           MINUS
                           SELECT mld_workflowstep_key
                             FROM mld_melding m
                            WHERE m.mld_workflowstep_key IN
                                  (SELECT wr1.mld_workflowstep_key
                                     FROM mld_workflowrule wr1, mld_workflowstep ws1
                                     WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                                       AND wr1.mld_workflowstep_next_key = r_nextsteps.mld_workflowstep_key
                                  )
                              AND mld_melding_start_key = l_melding_start_key
                          )
                    LOOP
                       -- This predecessing step missingsteps.mld_workflowstep_key is possible but not actual. How come?
                       -- Are some of its predecessor(s) not being the root actual in this workflow?
                       -- NOTE THAT THIS NEEDS ATTENTION IF WE NEED TO SUPPORT LONGER, UNBALANCED, CONDITIONAL WORKFLOWS
                       -- WE DO NOT SUPPORT THOSE HERE AND NOW, AND PROBABLY NO ONE WILL EVER NOTICE
                       SELECT COUNT ( * )
                         INTO l_prepredecessors
                         FROM mld_melding m
                        WHERE m.mld_workflowstep_key IN
                              (SELECT wr1.mld_workflowstep_key
                                 FROM mld_workflowrule wr1, mld_workflowstep ws1
                                WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                                  AND wr1.mld_workflowstep_next_key = missingsteps.mld_workflowstep_key
                              )
                          AND mld_melding_key <> l_melding_start_key
                          AND mld_melding_start_key = l_melding_start_key;

                       DBMS_OUTPUT.put_line ('Complex case! Total nr of actual prepredecessors for predecessor-step '
                                           || missingsteps.mld_workflowstep_key
                                           || ': '
                                           || l_prepredecessors);

                       IF l_prepredecessors = 0
                       THEN
                          -- Prepredecessor is presumably the root, so it must be a false condition that prevented
                          -- the step from being actual. It will never become existing, so case b
                          nrcase_b := nrcase_b + 1;                 -- we probably do not need this nr
                       ELSE
                          -- there are actual prepredecessors, case a
                          nrcase_a := nrcase_a + 1;
                       END IF;
                    END LOOP;

                    -- Now we checked all predecessors, which one do we choose?
                    -- If one case a exists, we should act like ...?
                    IF nrcase_a > 0
                    THEN
                       l_nrofrequiredpredecessors := l_nrofactualpredecessors + nrcase_a; --l_nrofpossiblepredecessors;
                    END IF;
                  END IF;
               ELSE
                  -- both are the same, just pick one to test against later
                  l_nrofrequiredpredecessors := l_nrofactualpredecessors;
               END IF;

               DBMS_OUTPUT.put_line ('total nr of required predecessors for next step: '
                                   || l_nrofrequiredpredecessors);

               SELECT COUNT ( * )
                 INTO l_nrofreadypredecessors
                 FROM mld_melding m
                WHERE m.mld_workflowstep_key IN
                      (SELECT wr1.mld_workflowstep_key
                         FROM mld_workflowrule wr1, mld_workflowstep ws1
                        WHERE wr1.mld_workflowstep_key = ws1.mld_workflowstep_key
                          AND wr1.mld_workflowstep_next_key = r_nextsteps.mld_workflowstep_key
                      )
                   -- the step to be continued
                  AND mld_melding_status IN (1, 5, 6) -- predecessor has been handled, no matter how
                  AND mld_melding_start_key = l_melding_start_key;            -- for this thread

               DBMS_OUTPUT.put_line ('total nr of READY predecessors for next step: '
                                   || l_nrofreadypredecessors);
               createthisnextstep := FALSE;

               -- What we do next depends on the jointype. We are one predecessor ourselves. Options are:
               ---- Exact one predecessor which is obviously ready (else we would not be called): start all next steps where that rule condition evaluates to true
               ---- Multiple predecessors:
               ------ jointype 0 (AND): all predecessors must be ready, if not do not start any next steps
               ------ jointype 1 (OR): at least one predecessor must be ready. Since we are called, this must be the case,
               ------                  unless that step has already been started by a previous call, then we should start
               ------                  these next steps again [next level: update flexprops of already started calls?]
               ------ jointype 2 (SYNC): all actually started predecessors must be ready. These predecessors are defined
               ------                    by the workflow but the actual runtime condition may have prevented that step to be created
               ------                    in which case that step should be neglected
               ---- if jointype is null is is treated as 0 (AND)
               ------ Note: i am not really sure if l_nrofpossiblepredecessors is always the right one to check against
               -- TE OVERWEGEN: NULL IS GEEN JOIN, DUS SEQUENCE OF SPLIT, DUS HOEF IK NIKS TE TELLEN, APARTE CASE ZONDER BOVENSTAANDE QUERIES?
               -- When p_success = -1 there is no predecessor, no jointype, so NULL/0
               CASE r_nextsteps.mld_workflowstep_jointype
                  WHEN 0
                  THEN                                                                        -- AND
                     createthisnextstep := l_nrofreadypredecessors >= l_nrofrequiredpredecessors OR p_success = -1;
                  WHEN 1
                  THEN                                                                         -- OR
                     createthisnextstep := l_nrofreadypredecessors = 1 OR p_success = -1;
                     -- if l_nrofreadypredecessors > 1 the creation has already taken place :-)
                  WHEN 2
                  THEN                                                                       -- SYNC
                     -- Wel nog een beetje raar in onze –naar mijn groeiende overtuiging slimmere- implementatie:
                     -- dit wil je altijd als je condities toepast, ook met een AND. Je wilt toch nooit wachten op een voorganger die niet bestaat?!?
                     -- Onze traditionele AND lijkt me een SYNC, en dan is deze mode toch niet nodig.
                     createthisnextstep := l_nrofreadypredecessors >= l_nrofrequiredpredecessors;
               END CASE;

               IF createthisnextstep
               THEN
                  DBMS_OUTPUT.put_line ('We GO for the next step ' || r_nextsteps.mld_workflowstep_key);

                  IF evaluatecondition (p_melding_key, r_nextsteps.mld_workflowrule_condition)
                  THEN
                     -- We mark the initial call as the workflow-root. We may only do this if at least one
                     -- nextstep-condition evaluates to true or we might end up with a root without steps
                     IF p_success = -1 AND NOT rootregistered
                     THEN
                        UPDATE mld_melding
                           SET mld_workflowstep_key = l_workflowstep_key,
                               mld_melding_start_key = p_melding_key -- do we need this or not? choose!
                         WHERE mld_melding_key = p_melding_key;

                        rootregistered := TRUE;
                     END IF;

                     DBMS_OUTPUT.put_line ('We actually start the next step ' || r_nextsteps.mld_workflowstep_key);
                     l_nrstepsevaluatedtrue := l_nrstepsevaluatedtrue + 1;

                     IF r_nextsteps.mld_directklaar = 2
                     THEN
                        l_initmldstatus := 0;
                     ELSE
                        -- zetten we expliciet achteraf, dan weten we ook of het een concept is
                        l_initmldstatus := NULL;
                     END IF;

                     SELECT mld_s_mld_melding_key.NEXTVAL INTO l_new_melding_key FROM DUAL;

                     -- Merk op: voor sommige velden laten we bewust de default nemen
                     INSERT INTO mld_melding (mld_melding_key,
                                              mld_melding_module,
                                              mld_meldbron_key,
                                              mld_alg_locatie_key,
                                              mld_alg_onroerendgoed_keys,
                                              mld_melding_datum,
                                              mld_melding_onderwerp,
                                              mld_melding_omschrijving,
                                              mld_stdmelding_key,
                                              mld_melding_status,
                                              mld_kosten_klant,
                                              mld_melding_document,
                                              prs_kostenplaats_key,
                                              prs_perslid_key,
                                              mld_adres_key,
                                              mld_workflowstep_key,
                                              mld_melding_start_key,
                                              mld_melding_ordernr,
                                              mld_melding_spoed,
                                              mld_ins_discipline_key)
                        SELECT l_new_melding_key,
                               mld_melding_module,
                               mld_meldbron_key,
                               mld_alg_locatie_key,
                               mld_alg_onroerendgoed_keys,
                               CASE
                               WHEN mld_melding_datum < SYSDATE
                               THEN SYSDATE
                               ELSE mld_melding_datum
                               END,
                               mld_melding_onderwerp,
                               mld_melding_omschrijving,
                               r_nextsteps.mld_stdmelding_key,
                               l_initmldstatus,   --- kan dus nog null zijn
                               mld_kosten_klant,
                               mld_melding_document,
                               m.prs_kostenplaats_key,
                               prs_perslid_key,
                               mld_adres_key,
                               r_nextsteps.mld_workflowstep_key,
                               l_melding_start_key,
                               mld_melding_ordernr,
                               mld_melding_spoed,
                               r_nextsteps.mld_stdmelding_default_disc
                          FROM mld_melding m,
                               mld_stdmelding msm
                         WHERE mld_melding_key = l_melding_start_key
                               AND msm.mld_stdmelding_key = r_nextsteps.mld_stdmelding_key;

                     IF r_nextsteps.mld_workflowstep_eindtype = 1
                     THEN
                        -- 1 = limit to the enddate of the root, if needed.
                        -- calculating the end date can be complex, we let the triggers do their job and
                        -- check afterwards whether we need to alter it
                        SELECT mld_melding_einddatum
                          INTO calculated_einddatum
                          FROM mld_melding
                         WHERE mld_melding_key = l_new_melding_key;
                        SELECT mld_melding_einddatum
                          INTO root_einddatum
                          FROM mld_melding
                         WHERE mld_melding_key = l_melding_start_key;
                         IF calculated_einddatum > root_einddatum
                         THEN
                            UPDATE mld_melding
                               SET mld_melding_einddatum = root_einddatum
                             WHERE mld_melding_key = l_new_melding_key;
                         END IF;
                     END IF;

                     -- De status zetten en de tracking genereren
                     IF l_initmldstatus IS NULL
                     THEN
                        l_initmldstatus := 2;
                     END IF;
                     mld.setmeldingstatus (l_new_melding_key, l_initmldstatus, NULL);

                     -- ook mld2bo notificatie, die weet ook dat-ie niks moet doen als
                     -- het nog concept is
                     IF r_nextsteps.mld_stdmelding_default_disc IS NOT NULL -- mldbhg notificatie
                     THEN
                        mld.notifybackoffice (l_new_melding_key, 'MLDBHG', 2);
                     END IF;

                     -- Kopieer nu de objecten mee als je dat wilt
                     IF fac.getsetting('mld_copy_objects_in_workflow') = 1
                     THEN
                        INSERT INTO mld_melding_object (mld_melding_key, ins_deel_key)
                           SELECT l_new_melding_key, ins_deel_key
                             FROM mld_melding_object
                            WHERE mld_melding_key = p_melding_key
                              AND mld_melding_object_verwijder is null;
                     END IF;
                     -- Kopieer nu de flexkenmerken voor zover deze bij oud-EN-nieuw bestaan
                     DECLARE
                        CURSOR c_mld_kenmerken
                        IS
                             -- VERRASSEND, SLIPGEVAAR, lastige materie
                             -- Dit zijn (nu) alle ingevulde kenmerken van de voorlopende meldingen,
                             -- per soortkenmerk gesorteerd zdd de LAATST AANGEMAAKTE MELDING (hogere key)
                             -- eerst komt.
                             -- Verderop wordt steeds alleen de eerste beschouwd.
                             -- Dat betekent de de kenmerken van de melding die later in een workflow
                             -- worden aangepast sterker zijn dan de eerdere.
                             -- Een echt hele goeie oplossing is niet mogelijk.
                             -- Pas ook op: bij de voorgaande meldingen kunnen ook zomaar de vervolgstappen
                             -- betrokken worden die hierboven net aangemaakt zijn. Dat vinden we niet erg
                             -- want die zijn dan immers zojuist ook op dezelfde manier bepaald.
                             -- Eerst de MAX van de meldingen bepalen en van die melding halen we de mld_kenmerkmelding_waarde op.
                             SELECT km.mld_kenmerkmelding_waarde,
                                    k.mld_srtkenmerk_key,
                                    mkm.mld_melding_key,
                                    k.mld_kenmerk_groep,
                                    COALESCE(k.mld_kenmerk_omschrijving, s.mld_srtkenmerk_omschrijving) mld_kenmerk_omschrijving
                               FROM mld_kenmerkmelding km,
                                    mld_kenmerk k,
                                    mld_melding m,
                                    mld_srtkenmerk s,
                                    (SELECT k1.mld_srtkenmerk_key,
                                            MAX(m1.mld_melding_key) mld_melding_key,
                                            k1.mld_kenmerk_groep,
                                            COALESCE(k1.mld_kenmerk_omschrijving, s1.mld_srtkenmerk_omschrijving) mld_kenmerk_omschrijving
                                       FROM mld_kenmerkmelding km1,
                                            mld_kenmerk k1,
                                            mld_melding m1,
                                            mld_srtkenmerk s1
                                      WHERE km1.mld_kenmerkmelding_verwijder IS NULL
                                        AND km1.mld_kenmerk_key = k1.mld_kenmerk_key
                                        AND km1.mld_melding_key = m1.mld_melding_key
                                        AND k1.mld_srtkenmerk_key = s1.mld_srtkenmerk_key
                                        AND s1.mld_srtkenmerk_kenmerktype NOT IN ('F', 'E')
                                        AND m1.mld_melding_start_key = l_melding_start_key
                                        AND m1.mld_melding_key < l_new_melding_key
                                        AND mld_workflowstep_key IS NOT NULL
                                     GROUP BY k1.mld_srtkenmerk_key,
                                              k1.mld_kenmerk_groep,
                                              k1.mld_kenmerk_omschrijving,
                                              s1.mld_srtkenmerk_omschrijving) mkm
                              WHERE km.mld_kenmerkmelding_verwijder IS NULL
                                AND km.mld_kenmerk_key = k.mld_kenmerk_key
                                AND km.mld_melding_key = m.mld_melding_key
                                AND k.mld_kenmerk_groep = mkm.mld_kenmerk_groep
                                AND km.mld_melding_key = mkm.mld_melding_key
                                AND k.mld_srtkenmerk_key = s.mld_srtkenmerk_key
                                AND s.mld_srtkenmerk_key = mkm.mld_srtkenmerk_key
                                AND s.mld_srtkenmerk_kenmerktype NOT IN ('F', 'E')
                                AND m.mld_melding_start_key = l_melding_start_key
                                AND m.mld_melding_key < l_new_melding_key
                                AND mld_workflowstep_key IS NOT NULL
                                AND COALESCE(k.mld_kenmerk_omschrijving, s.mld_srtkenmerk_omschrijving) = mkm.mld_kenmerk_omschrijving
                             ORDER BY 2,
                                      4,
                                      3 DESC,
                                      5;

                        r_mld_kenmerken         c_mld_kenmerken%ROWTYPE;
                        l_new_kenmerk_key       NUMBER (10);
                        wasbezigmetsrtkenmerk   NUMBER (10);
                        wasbezigmetgroep        NUMBER (10);
                        wasbezigmetomschrijving VARCHAR2 (50);
                        benbezigmetsrtkenmerk   NUMBER (10);
                        benbezigmetgroep        NUMBER (10);
                        benbezigmetomschrijving VARCHAR2 (50);
                     BEGIN
                        wasbezigmetsrtkenmerk := -1;
                        wasbezigmetgroep := -1;
                        wasbezigmetomschrijving := NULL;

                        FOR r_mld_kenmerken IN c_mld_kenmerken LOOP
                           -- Does the new (std)melding r_nextsteps.mld_stdmelding_key have this flexprop as well? THEN use it
                           BEGIN
                              --DBMS_OUTPUT.PUT_LINE ( 'SELECT kk.mld_kenmerk_key ..'  ||  r_mld_kenmerken.mld_srtkenmerk_key  ||  ' '  ||  r_nextsteps.mld_stdmelding_key);
                              benbezigmetsrtkenmerk := r_mld_kenmerken.mld_srtkenmerk_key;
                              benbezigmetgroep := r_mld_kenmerken.mld_kenmerk_groep;
                              benbezigmetomschrijving := r_mld_kenmerken.mld_kenmerk_omschrijving;

                              IF (benbezigmetsrtkenmerk <> wasbezigmetsrtkenmerk
                                  OR (benbezigmetsrtkenmerk = wasbezigmetsrtkenmerk
                                      AND benbezigmetgroep <> wasbezigmetgroep)
                                   OR (benbezigmetsrtkenmerk = wasbezigmetsrtkenmerk
                                       AND ((benbezigmetomschrijving IS NOT NULL AND wasbezigmetomschrijving IS NULL)
                                            OR (benbezigmetomschrijving IS NULL AND wasbezigmetomschrijving IS NOT NULL)
                                            OR (benbezigmetomschrijving IS NOT NULL AND wasbezigmetomschrijving IS NOT NULL AND benbezigmetomschrijving <> wasbezigmetomschrijving))))
                              THEN
                                 wasbezigmetsrtkenmerk := benbezigmetsrtkenmerk;
                                 wasbezigmetgroep := benbezigmetgroep;
                                 wasbezigmetomschrijving := benbezigmetomschrijving;

                                 --DBMS_OUTPUT.PUT_LINE ( 'EERSTE WAARDE VAN DIT KENMERK, van melding '||r_mld_kenmerken.mld_melding_key);
                                 SELECT mld_kenmerk_key
                                   INTO l_new_kenmerk_key
                                   FROM (SELECT kk.mld_kenmerk_key
                                           FROM mld_kenmerk kk,
                                                mld_srtkenmerk sk
                                          WHERE kk.mld_srtkenmerk_key = sk.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_verwijder IS NULL
                                            AND kk.mld_srtkenmerk_key = r_mld_kenmerken.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_groep = r_mld_kenmerken.mld_kenmerk_groep
                                            AND COALESCE(kk.mld_kenmerk_omschrijving, sk.mld_srtkenmerk_omschrijving) = r_mld_kenmerken.mld_kenmerk_omschrijving
                                            AND kk.mld_kenmerk_niveau = 'S'
                                            AND kk.mld_stdmelding_key = r_nextsteps.mld_stdmelding_key
                                         UNION
                                         SELECT kk.mld_kenmerk_key
                                           FROM mld_kenmerk kk,
                                                mld_srtkenmerk sk
                                          WHERE kk.mld_srtkenmerk_key = sk.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_verwijder IS NULL
                                            AND kk.mld_srtkenmerk_key = r_mld_kenmerken.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_groep = r_mld_kenmerken.mld_kenmerk_groep
                                            AND COALESCE(kk.mld_kenmerk_omschrijving, sk.mld_srtkenmerk_omschrijving) = r_mld_kenmerken.mld_kenmerk_omschrijving
                                            AND kk.mld_kenmerk_niveau = 'D'
                                            AND kk.mld_stdmelding_key = r_nextsteps.mld_ins_discipline_key
                                         UNION
                                         SELECT kk.mld_kenmerk_key
                                           FROM mld_kenmerk kk,
                                                mld_srtkenmerk sk
                                          WHERE kk.mld_srtkenmerk_key = sk.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_verwijder IS NULL
                                            AND kk.mld_srtkenmerk_key = r_mld_kenmerken.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_groep = r_mld_kenmerken.mld_kenmerk_groep
                                            AND COALESCE(kk.mld_kenmerk_omschrijving, sk.mld_srtkenmerk_omschrijving) = r_mld_kenmerken.mld_kenmerk_omschrijving
                                            AND kk.mld_kenmerk_niveau = 'T'
                                            AND kk.mld_stdmelding_key = r_nextsteps.ins_srtdiscipline_key
                                         UNION
                                         SELECT kk.mld_kenmerk_key
                                           FROM mld_kenmerk kk,
                                                mld_srtkenmerk sk
                                          WHERE kk.mld_srtkenmerk_key = sk.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_verwijder IS NULL
                                            AND kk.mld_srtkenmerk_key = r_mld_kenmerken.mld_srtkenmerk_key
                                            AND kk.mld_kenmerk_groep = r_mld_kenmerken.mld_kenmerk_groep
                                            AND COALESCE(kk.mld_kenmerk_omschrijving, sk.mld_srtkenmerk_omschrijving) = r_mld_kenmerken.mld_kenmerk_omschrijving
                                            AND kk.mld_kenmerk_niveau = 'A'
                                            AND kk.mld_stdmelding_key IS NULL) x;

                                 --DBMS_OUTPUT.PUT_LINE(r_mld_kenmerken.mld_melding_key||' '||r_mld_kenmerken.mld_srtkenmerk_key||' '||r_mld_kenmerken.mld_kenmerk_groep||'->'||l_new_melding_key||' '||l_new_kenmerk_key);
                                 --DBMS_OUTPUT.PUT_LINE('ook aanwezig bij de nieuwe, dus insert');
                                 --Controleer of dit kenmerk al is toegevoegd (meerdere voorliggende meldingen met zelfde kenmerk!)
                                 INSERT INTO mld_kenmerkmelding (mld_melding_key,
                                                                 mld_kenmerk_key,
                                                                 mld_kenmerkmelding_waarde)
                                      VALUES (l_new_melding_key,
                                              l_new_kenmerk_key,
                                              r_mld_kenmerken.mld_kenmerkmelding_waarde);
                              -- ELSE negeer dit record, we hebben deze al.
                              END IF;
                           EXCEPTION
                              WHEN NO_DATA_FOUND
                              THEN
                                 NULL;
                              --DBMS_OUTPUT.PUT_LINE('not found');
                              WHEN TOO_MANY_ROWS
                              THEN
                                 raise_application_error (
                                    -20001,
                                       'Soortkenmerk '
                                    || r_mld_kenmerken.mld_srtkenmerk_key
                                    || ' is op meerdere niveaus gedefinieerd');
                           --DBMS_OUTPUT.PUT_LINE('TOO MANY ROW');
                           END;
                        END LOOP;
                     END;
                     -- Vul nog lege flexkenmerken met een eventuele default waarde
                     IF fac.getsetting('mld_workflow_set_defaults') = 1
                     THEN
                         DECLARE
                            CURSOR def_mld_kenmerk
                                IS
                                    SELECT k.mld_kenmerk_key, k.mld_kenmerk_default
                                      FROM mld_kenmerk     k
                                           LEFT OUTER JOIN mld_kenmerkmelding km
                                               ON (    k.mld_kenmerk_key = km.mld_kenmerk_key
                                                   AND km.mld_melding_key = l_new_melding_key)
                                         , mld_srtkenmerk  s
                                     WHERE     mld_kenmerk_verwijder IS NULL
                                           AND k.mld_srtkenmerk_key = s.mld_srtkenmerk_key
                                           AND s.mld_srtkenmerk_kenmerktype NOT IN ('F', 'E')
                                           AND ((mld_kenmerk_niveau = 'A' AND mld_stdmelding_key IS NULL)
                                             OR (mld_kenmerk_niveau = 'S' AND mld_stdmelding_key = r_nextsteps.mld_stdmelding_key)
                                             OR (mld_kenmerk_niveau = 'D' AND mld_stdmelding_key = r_nextsteps.mld_ins_discipline_key)
                                             OR (mld_kenmerk_niveau = 'T' AND mld_stdmelding_key = r_nextsteps.ins_srtdiscipline_key))
                                           AND k.mld_kenmerk_default IS NOT NULL
                                           AND km.mld_kenmerkmelding_waarde IS NULL;
                                     this_mld_kenmerk         def_mld_kenmerk%ROWTYPE;
                         BEGIN
                             FOR this_mld_kenmerk IN def_mld_kenmerk LOOP
                                 BEGIN
                                     INSERT INTO mld_kenmerkmelding (mld_melding_key,
                                                                     mld_kenmerk_key,
                                                                     mld_kenmerkmelding_waarde)
                                         VALUES (l_new_melding_key,
                                                 this_mld_kenmerk.mld_kenmerk_key,
                                                 this_mld_kenmerk.mld_kenmerk_default);
                                 END;
                             END LOOP;
                         END;
                     END IF;

                     -- Controleer of er automatisch een opdracht aangemaakt moet worden en doe dat dan
                     -- Die checkt zelf of het een conceptmelding is en doet dat nu nog niks
                     mld.mld_addautoorder(l_new_melding_key);
                  END IF;                                                       -- evaluatecondition
               END IF;

               FETCH c_nextsteps INTO r_nextsteps;

               EXIT WHEN c_nextsteps%NOTFOUND;
            END LOOP;

            -- All nextsteps have been considered and started if the condition was true
            -- If none of the conditions were true, no next step is started and the workflow dies
            -- The previous step effectively was the/a last step so we should execute the corresponding
            -- routine: close the root if all others (if any) are done as well.
            IF l_nrstepsevaluatedtrue = 0
            THEN
               SELECT COUNT (mld_melding_key)
                 INTO tmp
                 FROM mld_melding
                WHERE     mld_melding_start_key = l_melding_start_key
                      AND mld_melding_status NOT IN (1, 5, 6)
                      AND mld_melding_key <> l_melding_start_key;

               -- Als er geen lopende parallelle meldingen zijn dan sluit de root.
               IF tmp = 0
               THEN
                  DBMS_OUTPUT.put_line (
                     'Closing parent due to all false conditions: ' || l_melding_start_key);
                  mld.setmeldingstatus (l_melding_start_key, 5, NULL);
               --ELSE
               --DBMS_OUTPUT.PUT_LINE('no more steps, but still ' ||  tmp  || ' open calls in workflow');
               END IF;
            END IF;

            CLOSE c_nextsteps;
         END IF;
      END;
   END mld_nextworkflowstep;

    -- Bereken van de melding het object met de laagste uitvoertijd.
    -- Levert NULL als er geen objecten zijn
    FUNCTION getlowestobjectuitvoer (p_melding_key IN NUMBER)
        RETURN NUMBER
    AS
        lnrins                      NUMBER;
        v_ins_key_min_uitvoertijd   NUMBER;
    BEGIN
      -- even kijken of er uberhaupt wel objecten zijn
      -- zonder de ins_deel tabel te raadplegen
      -- dat leidde nl tot een muating-error bij het verwerken van
      -- sensoroverschreiding, en het kan in veel gevallen directer
        SELECT COUNT (*)
          INTO lnrins
          FROM mld_melding_object m
         WHERE mld_melding_key = p_melding_key;

        IF lnrins = 0
        THEN
            v_ins_key_min_uitvoertijd := NULL;
        ELSIF lnrins = 1
        THEN
            SELECT ins_deel_key
              INTO v_ins_key_min_uitvoertijd
              FROM mld_melding_object m
             WHERE mld_melding_key = p_melding_key;
        ELSE
            SELECT MAX (d.ins_deel_key) ins_deel_key
              INTO v_ins_key_min_uitvoertijd
              FROM ins_deel d, mld_melding_object m
             WHERE     m.mld_melding_key = p_melding_key
                   AND d.ins_deel_key = m.ins_deel_key
                   AND (CASE
                            WHEN d.ins_deel_t_uitvoertijd.eenheid = 'U'
                            THEN
                                d.ins_deel_t_uitvoertijd.tijdsduur / 24
                            ELSE
                                d.ins_deel_t_uitvoertijd.tijdsduur
                        END) =
                       (SELECT MIN (
                                   CASE
                                       WHEN d1.ins_deel_t_uitvoertijd.eenheid = 'U'
                                       THEN
                                           d1.ins_deel_t_uitvoertijd.tijdsduur / 24
                                       ELSE
                                           d1.ins_deel_t_uitvoertijd.tijdsduur
                                   END)
                          FROM ins_deel d1, mld_melding_object m1
                         WHERE     m1.mld_melding_key = p_melding_key
                               AND d1.ins_deel_key = m1.ins_deel_key);
        END IF;

        RETURN v_ins_key_min_uitvoertijd;
    END;

    -- Dit is de tijd waarop afgerekend gaat worden. Respijt wordt er afgetrokken
    FUNCTION getactualuitvoer (p_melding_key IN NUMBER)
        RETURN MLD_T_UITVOERTIJD
    AS
       v_ins_key_min_uitvoertijd      NUMBER;
       v_actual_uitvoertijd_object    mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- constructor initialisatie;
    BEGIN
      -- Bepaal van de melding het object met de laagste uitvoertijd.
      v_ins_key_min_uitvoertijd := getlowestobjectuitvoer(p_melding_key);

      SELECT mld.getactualuitvoer(m.mld_melding_datum,
                                  COALESCE(fac.gettrackingdate('MLDAFM', m.mld_melding_key), fac.gettrackingdate('MLDREJ', m.mld_melding_key), SYSDATE),
                                  m.mld_stdmelding_key,
                                  m.mld_melding_spoed,
                                  m.mld_alg_onroerendgoed_keys,
                                  v_ins_key_min_uitvoertijd,
                                  m.mld_melding_t_uitvoertijd.eenheid
                            )
          INTO v_actual_uitvoertijd_object
          FROM mld_melding m
         WHERE mld_melding_key = p_melding_key;
      RETURN v_actual_uitvoertijd_object;
    END;

    FUNCTION getactualuitvoer (startdate   IN DATE,
                               enddate     IN DATE,
                               stdm_key    IN NUMBER,
                               prio        IN NUMBER,
                               alg_key     IN NUMBER, -- Altijd gebouw of hoger, locatie niet ondersteund
                               ins_key     IN NUMBER,  -- Object met de laagste uitvoertijd
                               eenheid     IN VARCHAR2 DEFAULT NULL
                              )
        RETURN MLD_T_UITVOERTIJD
    AS
       v_actual_uitvoertijd_object    mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- constructor initialisatie;
       v_actual_accepttijd            mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- constructor initialisatie;
       v_uitvoertijdtype              VARCHAR2(5);
       v_mld_stdmelding_regime        mld_stdmelding.mld_stdmelding_regime%TYPE;
       v_beginuur                     alg_gebouw.alg_gebouw_beginuur%TYPE;
       v_einduur                      alg_gebouw.alg_gebouw_einduur%TYPE;
       v_werkdagen                    alg_gebouw.alg_gebouw_werkdagen%TYPE;
    BEGIN
       getSLAparams(stdm_key, prio, alg_key, ins_key,
                    v_mld_stdmelding_regime, v_actual_uitvoertijd_object, v_actual_accepttijd, v_beginuur, v_einduur, v_werkdagen);

       IF COALESCE(eenheid, v_actual_uitvoertijd_object.eenheid) = 'D'
       THEN
           v_uitvoertijdtype := 'DAGEN';
       ELSE
           v_uitvoertijdtype := 'UREN';
       END IF;

       -- Als bij Openingstijden geen ruimte/gebouwopeningstijden zijn gevonden dan terugvallen op Kantoortijden.
       IF v_mld_stdmelding_regime = 1 OR (v_mld_stdmelding_regime = 2 AND (v_beginuur = -1 OR v_einduur = -1)) -- Kantoortijden: als in 5.1.2
       THEN
            v_actual_uitvoertijd_object :=
                FAC.datumtijdnaaruitvoertijd (startdate, enddate, v_uitvoertijdtype);
       ELSIF v_mld_stdmelding_regime = 2 --  Openingstijden: gebruik ruimte/gebouwopeningstijden
       THEN
            v_actual_uitvoertijd_object :=
                FAC.datumtijdnaaruitvoertijd (startdate,
                                              enddate,
                                              v_uitvoertijdtype,
                                              v_beginuur,
                                              v_einduur,
                                              v_werkdagen); -- Mode=0/1 resp. alle dagen/alleen werkdagen!
       ELSIF v_mld_stdmelding_regime = 3 --  24/7: negeert weekenden of vrije dagen
       THEN
            v_actual_uitvoertijd_object :=
                FAC.datumtijdnaaruitvoertijd (startdate,
                                              enddate,
                                              v_uitvoertijdtype,
                                              NULL, -- Don't care
                                              NULL, -- Don't care
                                              2); -- Mode=2 => 24/7
       END IF;

       -- Een negatieve actuele uitvoertijd niet toestaan. Minimale waarde is 0.
       IF v_actual_uitvoertijd_object.tijdsduur < 0
       THEN
           v_actual_uitvoertijd_object.tijdsduur := 0;
       END IF;

       RETURN v_actual_uitvoertijd_object;
    END;

    -- Dit is de tijd waarop afgerekend gaat worden.
    FUNCTION getactualaccept (p_melding_key IN NUMBER)
        RETURN MLD_T_UITVOERTIJD
    AS
       v_actual_accepttijd    mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- constructor initialisatie;
    BEGIN
      -- Objecten hebben geen acceptatietijd.
      SELECT mld.getactualaccept(m.mld_melding_datum,
                                  COALESCE(fac.gettrackingdate('MLDACP', m.mld_melding_key), fac.gettrackingdate('MLDAFM', m.mld_melding_key), fac.gettrackingdate('MLDREJ', m.mld_melding_key), SYSDATE),
                                  m.mld_stdmelding_key,
                                  m.mld_melding_spoed,
                                  m.mld_alg_onroerendgoed_keys,
                                  NULL,                               -- ins_key (Objecten hebben geen acceptatietijd).
                                  m.mld_melding_t_accepttijd.eenheid
                            )
          INTO v_actual_accepttijd
          FROM mld_melding m
         WHERE mld_melding_key = p_melding_key;
      RETURN v_actual_accepttijd;
    END;

    FUNCTION getactualaccept (startdate   IN DATE,
                               enddate     IN DATE,
                               stdm_key    IN NUMBER,
                               prio        IN NUMBER,
                               alg_key     IN NUMBER, -- Altijd gebouw of hoger, locatie niet ondersteund
                               ins_key     IN NUMBER,  -- Object met de laagste uitvoertijd
                               eenheid     IN VARCHAR2 DEFAULT NULL
                              )
        RETURN MLD_T_UITVOERTIJD
    AS
       v_actual_uitvoertijd_object    mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- constructor initialisatie;
       v_actual_accepttijd            mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- constructor initialisatie;
       v_uitvoertijdtype              VARCHAR2(5);
       v_mld_stdmelding_regime        mld_stdmelding.mld_stdmelding_regime%TYPE;
       v_beginuur                     alg_gebouw.alg_gebouw_beginuur%TYPE;
       v_einduur                      alg_gebouw.alg_gebouw_einduur%TYPE;
       v_werkdagen                    alg_gebouw.alg_gebouw_werkdagen%TYPE;
    BEGIN
       getSLAparams(stdm_key, prio, alg_key, ins_key,
                    v_mld_stdmelding_regime, v_actual_uitvoertijd_object, v_actual_accepttijd, v_beginuur, v_einduur, v_werkdagen);

       IF COALESCE(eenheid, v_actual_accepttijd.eenheid) = 'D'
       THEN
           v_uitvoertijdtype := 'DAGEN';
       ELSE
           v_uitvoertijdtype := 'UREN';
       END IF;

       -- Als bij Openingstijden geen ruimte/gebouwopeningstijden zijn gevonden dan terugvallen op Kantoortijden.
       IF v_mld_stdmelding_regime = 1 OR (v_mld_stdmelding_regime = 2 AND (v_beginuur = -1 OR v_einduur = -1)) -- Kantoortijden: als in 5.1.2
       THEN
            v_actual_accepttijd :=
                FAC.datumtijdnaaruitvoertijd (startdate, enddate, v_uitvoertijdtype);
       ELSIF v_mld_stdmelding_regime = 2 --  Openingstijden: gebruik ruimte/gebouwopeningstijden
       THEN
            v_actual_accepttijd :=
                FAC.datumtijdnaaruitvoertijd (startdate,
                                              enddate,
                                              v_uitvoertijdtype,
                                              v_beginuur,
                                              v_einduur,
                                              v_werkdagen); -- Mode=0/1 resp. alle dagen/alleen werkdagen!
       ELSIF v_mld_stdmelding_regime = 3 --  24/7: negeert weekenden of vrije dagen
       THEN
            v_actual_accepttijd :=
                FAC.datumtijdnaaruitvoertijd (startdate,
                                              enddate,
                                              v_uitvoertijdtype,
                                              NULL, -- Don't care
                                              NULL, -- Don't care
                                              2); -- Mode=2 => 24/7
       END IF;

       -- Een negatieve actuele uitvoertijd niet toestaan. Minimale waarde is 0.
       IF v_actual_accepttijd.tijdsduur < 0
       THEN
           v_actual_accepttijd.tijdsduur := 0;
       END IF;

       RETURN v_actual_accepttijd;
    END;

    FUNCTION uitvoertijd_to_char (uitvoertijd          IN MLD_T_UITVOERTIJD)
       RETURN VARCHAR
    AS BEGIN
       IF uitvoertijd IS NULL THEN
           RETURN NULL;
       END IF;
       RETURN '(' || uitvoertijd.tijdsduur || '; ' || uitvoertijd.eenheid || ')';
    END;

    FUNCTION uitvoertijd_to_unit (tijd MLD_T_UITVOERTIJD, eenheid VARCHAR2)
       RETURN NUMBER
    AS
       duur  NUMBER;
    BEGIN
       IF (tijd.tijdsduur IS NOT NULL AND tijd.tijdsduur != 0)
       THEN
          duur := tijd.tijdsduur;
          IF (eenheid = 'D' AND tijd.eenheid = 'U')
          THEN
             duur := tijd.tijdsduur / 24;
          END IF;
          IF (eenheid = 'U' AND tijd.eenheid = 'D')
          THEN
             duur := tijd.tijdsduur * 24;
          END IF;
       END IF;
       RETURN duur;
    END;

    -- bereken de SLA-einddatum gegeven onderstaande info
    FUNCTION geteinddatum (startdate            IN DATE,
                           stdm_key             IN NUMBER,
                           prio                 IN NUMBER,
                           alg_key              IN NUMBER, -- Altijd gebouw of hoger, locatie niet ondersteund
                           ins_key              IN NUMBER, -- Object met de laagste uitvoertijd
                           uitvoertijd_object   IN MLD_T_UITVOERTIJD DEFAULT MLD_T_UITVOERTIJD(NULL, NULL)) -- Als meegegeven dan wordt dit genomen als norm
       RETURN DATE                                                                  -- Handig voor (bevroren) mld_melding_uitvoertijd + respijt
    AS
       v_einddatum                    DATE;
       v_mld_stdmelding_regime        mld_stdmelding.mld_stdmelding_regime%TYPE;
       v_uitvoertijd_object           mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie;
       v_accepttijd                   mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie;
       v_uitvoertijdtype              VARCHAR2(5);
       v_beginuur                     alg_gebouw.alg_gebouw_beginuur%TYPE;
       v_einduur                      alg_gebouw.alg_gebouw_einduur%TYPE;
       v_werkdagen                    NUMBER;
    BEGIN
       getSLAparams(stdm_key, prio, alg_key, ins_key,
                    v_mld_stdmelding_regime, v_uitvoertijd_object, v_accepttijd, v_beginuur, v_einduur, v_werkdagen);

       IF uitvoertijd_object.eenheid IS NOT NULL
       THEN
          v_uitvoertijd_object := uitvoertijd_object;
       END IF;

       IF v_uitvoertijd_object.eenheid = 'D'
       THEN
          v_uitvoertijdtype := 'DAGEN';
       ELSE
          v_uitvoertijdtype := 'UREN';
       END IF;

       -- Als bij openingstijden geen ruimte/gebouwopeningstijden zijn gevonden dan terugvallen op kantoortijden.
       IF v_mld_stdmelding_regime = 1 OR (v_mld_stdmelding_regime = 2 AND (v_beginuur = -1 OR v_einduur = -1)) -- kantoortijden, als in 5.1.2
       THEN
            v_einddatum :=
                 FAC.DatumTijdPlusUitvoerTijd (startdate,
                                               v_uitvoertijd_object.tijdsduur,
                                               v_uitvoertijdtype);
       ELSIF v_mld_stdmelding_regime = 2 --  Openingstijden: gebruik ruimte/gebouwopeningstijden er bij
       THEN
            v_einddatum :=
                FAC.datumtijdplusuitvoertijd (startdate,
                                              v_uitvoertijd_object.tijdsduur,
                                              v_uitvoertijdtype,
                                              v_beginuur,
                                              v_einduur,
                                              v_werkdagen); -- Mode=0/1 resp. alle dagen/alleen werkdagen!
       ELSIF v_mld_stdmelding_regime = 3 --  24/7, negeert weekenden of vrije dagen
       THEN
            v_einddatum :=
                FAC.datumtijdplusuitvoertijd (startdate,
                                              v_uitvoertijd_object.tijdsduur,
                                              v_uitvoertijdtype,
                                              NULL, -- Don't care
                                              NULL, -- Don't care
                                              2); -- Mode=2 => 24/7
       END IF;

       RETURN v_einddatum;
    END;

    FUNCTION geteinddatum (p_melding_key        IN NUMBER,
                           p_uitvoertijd_object IN MLD_T_UITVOERTIJD DEFAULT MLD_T_UITVOERTIJD(NULL, NULL), -- Als meegegeven dan wordt dit genomen als norm
                           p_startdate          IN DATE DEFAULT NULL) -- Bereken einddatum met startdatum (voor opdrachten en meldingen verschillend)
       RETURN DATE
    AS
       v_ins_key_min_uitvoertijd      NUMBER := NULL;
       v_einddatum                    DATE;
    BEGIN
      -- Als p_uitvoertijd_object meegegeven is dan is object met de laagste uitvoertijd niet meer van belang
      IF p_uitvoertijd_object.eenheid IS NULL
      THEN
        -- Bepaal van de melding het object met de laagste uitvoertijd.
        v_ins_key_min_uitvoertijd := getlowestobjectuitvoer(p_melding_key);
      END IF;

      SELECT mld.geteinddatum(COALESCE(p_startdate, m.mld_melding_datum),
                              m.mld_stdmelding_key,
                              m.mld_melding_spoed,
                              m.mld_alg_onroerendgoed_keys,
                              v_ins_key_min_uitvoertijd, -- Object met de laagste uitvoertijd
                              p_uitvoertijd_object
                             )
          INTO v_einddatum
          FROM mld_melding m
         WHERE mld_melding_key = p_melding_key;
      RETURN v_einddatum;
    END;

    -- Bereken de standaard uitvoertijd
    FUNCTION getstduitvoer (stdm_key    IN NUMBER,
                            prio        IN NUMBER,
                            alg_key     IN NUMBER, -- Altijd gebouw of hoger, locatie niet ondersteund
                            ins_key     IN NUMBER) -- Object met de laagste uitvoertijd
       RETURN MLD_T_UITVOERTIJD
    AS
       v_uitvoertijd_object           mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       v_accepttijd                   mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       v_mld_stdmelding_regime        mld_stdmelding.mld_stdmelding_regime%TYPE;
       v_beginuur                     alg_gebouw.alg_gebouw_beginuur%TYPE;
       v_einduur                      alg_gebouw.alg_gebouw_einduur%TYPE;
       v_werkdagen                    NUMBER;
    BEGIN
       getSLAparams(stdm_key, prio, alg_key, ins_key,
                    v_mld_stdmelding_regime, v_uitvoertijd_object, v_accepttijd, v_beginuur, v_einduur, v_werkdagen);
      RETURN v_uitvoertijd_object;
    END;

    -- Bereken de standaard uitvoertijd
    FUNCTION getstduitvoer (p_melding_key IN NUMBER)
        RETURN MLD_T_UITVOERTIJD
    AS
       v_uitvoertijd_object                   mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       v_ins_key_min_uitvoertijd              NUMBER;
       v_ins_key_min_uitvoertijd_eenh         NUMBER;
       v_std_uitvoertijd                      NUMBER;
       v_std_uitvoertijd_eenheid              NUMBER;
    BEGIN
      -- Bepaal van de melding het object met de laagste uitvoertijd.
      v_ins_key_min_uitvoertijd := getlowestobjectuitvoer(p_melding_key);
      SELECT mld.getstduitvoer(m.mld_stdmelding_key,
                               m.mld_melding_spoed,
                               m.mld_alg_onroerendgoed_keys,
                               v_ins_key_min_uitvoertijd
                            )
        INTO v_uitvoertijd_object
        FROM mld_melding m
       WHERE mld_melding_key = p_melding_key;
      RETURN v_uitvoertijd_object;
    END;
    PROCEDURE getSLAparams (stdm_key    IN NUMBER,
                            prio        IN NUMBER,
                            alg_key     IN NUMBER, -- Altijd gebouw of hoger, locatie niet ondersteund
                            ins_key     IN NUMBER, -- Object met de laagste uitvoertijd
                            v_mld_stdmelding_regime OUT  NUMBER,
                            v_uitvoertijd_object    OUT  MLD_T_UITVOERTIJD,
                            v_accepttijd            OUT  MLD_T_UITVOERTIJD,
                            v_beginuur              OUT  NUMBER,
                            v_einduur               OUT  NUMBER,
                            v_werkdagen             OUT  NUMBER
                           )
    AS
       v_uitvoertijd_object_s           mld_stdmelding.mld_stdmelding_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       v_accepttijd_s                   mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       v_mld_stdmelding_afhankelijk     mld_stdmelding.mld_stdmelding_afhankelijk%TYPE;
       l_alg_type                       VARCHAR2(1);
       l_terreinsector_key              alg_terreinsector.alg_terreinsector_key%TYPE;
       l_gebouw_key                     alg_gebouw.alg_gebouw_key%TYPE;
       l_ruimte_key                     alg_ruimte.alg_ruimte_key%TYPE;
       l_insdeel_uitvoertijd_object     ins_deel.ins_deel_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_srtruimte_uitvoertijd_object   alg_srtruimte.alg_srtruimte_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_srtgebouw_uitvoertijd_object   alg_srtgebouw.alg_srtgebouw_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_srtterrein_uitvoertijd_object  alg_srtterreinsector.alg_srtterreinsec_t_uitvtijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_mldsrtruimte_uitvtijd_object   mld_stdmsrtruimte.mld_stdmsrtruimte_t_uitvtijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_mldsrtgebouw_uitvtijd_object   mld_stdmsrtgebouw.mld_stdmsrtgebouw_t_uitvtijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_mldsrtterrein_uitvtijd_object  mld_stdmsrtterrein.mld_stdmsrtterrein_t_uitvtijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_mldsrtterrein_acctijd          mld_stdmsrtterrein.mld_stdmsrtterrein_t_acctijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_mldsrtgebouw_accepttijd        mld_stdmsrtgebouw.mld_stdmsrtgebouw_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
       l_mldsrtruimte_accepttijd        mld_stdmsrtruimte.mld_stdmsrtruimte_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
    BEGIN
       SELECT mld_stdmelding_regime,
              CASE prio
                   WHEN 1 THEN mld_stdmelding_t_uitvtijd_pr1
                   WHEN 2 THEN mld_stdmelding_t_uitvtijd_pr2
                   WHEN 4 THEN mld_stdmelding_t_uitvtijd_pr4
                   ELSE mld_stdmelding_t_uitvoertijd
              END,                                         -- gegarandeerd gevuld
              mld_stdmelding_t_uitvoertijd,                -- standaard uitvoertijd
              CASE prio
                   WHEN 1 THEN mld_stdmelding_t_accept_pr1
                   WHEN 2 THEN mld_stdmelding_t_accept_pr2
                   WHEN 4 THEN mld_stdmelding_t_accept_pr4
                   ELSE mld_stdmelding_t_accepttijd
              END,                                         -- gegarandeerd gevuld
              mld_stdmelding_t_accepttijd,                 -- standaard acceptatietijd
              mld_stdmelding_afhankelijk
         INTO v_mld_stdmelding_regime,
              v_uitvoertijd_object,
              v_uitvoertijd_object_s,
              v_accepttijd,
              v_accepttijd_s,
              v_mld_stdmelding_afhankelijk
         FROM mld_stdmelding msm
        WHERE msm.mld_stdmelding_key = stdm_key;

       -- Als je geen afwijkende uitvoertijd voor de prio hebt, dan is het die van Normaal
       -- Dit is een vangnet, die prio had eigenlijk niet voor kunnen komen.
       IF prio <> 3 AND v_uitvoertijd_object.tijdsduur IS NULL
       THEN
          v_uitvoertijd_object := v_uitvoertijd_object_s;
       END IF;

       -- Als je geen afwijkende acceptatietijd voor de prio hebt, dan is het die van Normaal
       -- Dit is een vangnet, die prio had eigenlijk niet voor kunnen komen.
       IF prio <> 3 AND v_accepttijd.tijdsduur IS NULL
       THEN
          v_accepttijd := v_accepttijd_s;
       END IF;

       -- Acceptatietijd kent itt uitvoertijd geen objectafhankelijkheid.
       IF v_mld_stdmelding_afhankelijk = 1 AND ins_key IS NOT NULL
       THEN
         -- is er een objectafhankelijke SLA? Dan geldt die ongeacht de prio
          SELECT d.ins_deel_t_uitvoertijd
            INTO l_insdeel_uitvoertijd_object
            FROM ins_deel d
           WHERE d.ins_deel_key = ins_key;
          -- als er geen object-overrule gedefinieerd is, dan WERD de standaard-normaleprio-sla gebruikt,
          -- wat imho onjuist is, dat moet de standaard-betreffendeprio-sla zijn (een kritieke melding op
          -- een object waarvoor niks speciaals geldt is een normale kritieke melding)
          -- daarom aangepast, geen klachten over gehad, maar niettemin beter..
          -- mag weg: v_uitvoertijd_object.tijdsduur := COALESCE(l_insdeel_uitvoertijd_object.tijdsduur, v_uitvoertijd_object_s.tijdsduur);
          v_uitvoertijd_object.tijdsduur := COALESCE(l_insdeel_uitvoertijd_object.tijdsduur, v_uitvoertijd_object.tijdsduur);
          IF l_insdeel_uitvoertijd_object.tijdsduur IS NOT NULL
          THEN
             v_uitvoertijd_object.eenheid := l_insdeel_uitvoertijd_object.eenheid;
          ELSE
             -- mag weg: v_uitvoertijd_object.eenheid := v_uitvoertijd_object_s.eenheid;
             v_uitvoertijd_object.eenheid := v_uitvoertijd_object.eenheid;   -- en dat is dan op zich overbodig
          END IF;
       END IF;

       IF v_mld_stdmelding_afhankelijk = 1 AND l_insdeel_uitvoertijd_object.tijdsduur IS NULL AND alg_key IS NOT NULL
       THEN
          -- Als alg_srtruimte_uitvoertijd geen waarde heeft, dan terugvallen op standaard uitvoertijd die altijd een waarde heeft
          SELECT alg_type,
                 alg_terreinsector_key,
                 alg_gebouw_key,
                 alg_ruimte_key
            INTO l_alg_type,
                 l_terreinsector_key,
                 l_gebouw_key,
                 l_ruimte_key
            FROM alg_v_onroerendgoed
           WHERE alg_onroerendgoed_keys = alg_key;

          IF l_alg_type = 'T'
          THEN
             BEGIN
                SELECT DECODE (prio,
                               1, st.alg_srtterreinsec_t_uitv_pr1,
                               2, st.alg_srtterreinsec_t_uitv_pr2,
                               3, st.alg_srtterreinsec_t_uitvtijd,
                               4, st.alg_srtterreinsec_t_uitv_pr4),
                       DECODE (prio,
                               1, sst.mld_stdmsrtterrein_t_uitv_pr1,
                               2, sst.mld_stdmsrtterrein_t_uitv_pr2,
                               3, sst.mld_stdmsrtterrein_t_uitvtijd,
                               4, sst.mld_stdmsrtterrein_t_uitv_pr4),
                       COALESCE(sst.mld_stdmsrtterrein_regime, v_mld_stdmelding_regime) regime, -- geen srtterreinsector-afhankelijk afwijkend regime.
                       DECODE (prio,
                               1, sst.mld_stdmsrtterrein_t_acc_pr1,
                               2, sst.mld_stdmsrtterrein_t_acc_pr2,
                               3, sst.mld_stdmsrtterrein_t_acctijd,
                               4, sst.mld_stdmsrtterrein_t_acc_pr4)
                  INTO l_srtterrein_uitvoertijd_object,
                       l_mldsrtterrein_uitvtijd_object,
                       v_mld_stdmelding_regime,
                       l_mldsrtterrein_acctijd
                  FROM alg_terreinsector t,
                       alg_srtterreinsector st,
                       mld_stdmsrtterrein sst
                 WHERE t.alg_srtterreinsector_key = st.alg_srtterreinsector_key(+)
                   AND t.alg_srtterreinsector_key = sst.alg_srtterreinsector_key(+)
                   AND sst.mld_stdmelding_key(+) = stdm_key
                   AND t.alg_terreinsector_key = l_terreinsector_key;
              EXCEPTION
                 WHEN NO_DATA_FOUND
                 THEN NULL;
              END;
          ELSE
             BEGIN
                SELECT DECODE (prio,
                               1, sg.alg_srtgebouw_t_uitvoer_pr1,
                               2, sg.alg_srtgebouw_t_uitvoer_pr2,
                               3, sg.alg_srtgebouw_t_uitvoertijd,
                               4, sg.alg_srtgebouw_t_uitvoer_pr4),
                       DECODE (prio,
                               1, ssg.mld_stdmsrtgebouw_t_uitv_pr1,
                               2, ssg.mld_stdmsrtgebouw_t_uitv_pr2,
                               3, ssg.mld_stdmsrtgebouw_t_uitvtijd,
                               4, ssg.mld_stdmsrtgebouw_t_uitv_pr4),
                       COALESCE(ssg.mld_stdmsrtgebouw_regime, v_mld_stdmelding_regime) regime, -- geen srtgebouw-afhankelijk afwijkend regime.
                       DECODE (prio,
                               1, ssg.mld_stdmsrtgebouw_t_accept_pr1,
                               2, ssg.mld_stdmsrtgebouw_t_accept_pr2,
                               3, ssg.mld_stdmsrtgebouw_t_accepttijd,
                               4, ssg.mld_stdmsrtgebouw_t_accept_pr4)
                  INTO l_srtgebouw_uitvoertijd_object,
                       l_mldsrtgebouw_uitvtijd_object,
                       v_mld_stdmelding_regime,
                       l_mldsrtgebouw_accepttijd
                  FROM alg_gebouw g,
                       alg_srtgebouw sg,
                       mld_stdmsrtgebouw ssg
                 WHERE g.alg_srtgebouw_key = sg.alg_srtgebouw_key(+)
                   AND g.alg_srtgebouw_key = ssg.alg_srtgebouw_key(+)
                   AND ssg.mld_stdmelding_key(+) = stdm_key
                   AND g.alg_gebouw_key = l_gebouw_key;
             EXCEPTION
                WHEN NO_DATA_FOUND
                THEN NULL;
             END;

             IF l_alg_type = 'R'
             THEN
                BEGIN
                SELECT DECODE (prio,
                               1, sr.alg_srtruimte_t_uitvoer_pr1,
                               2, sr.alg_srtruimte_t_uitvoer_pr2,
                               3, sr.alg_srtruimte_t_uitvoertijd,
                               4, sr.alg_srtruimte_t_uitvoer_pr4),
                       DECODE (prio,
                               1, ssr.mld_stdmsrtruimte_t_uitv_pr1,
                               2, ssr.mld_stdmsrtruimte_t_uitv_pr2,
                               3, ssr.mld_stdmsrtruimte_t_uitvtijd,
                               4, ssr.mld_stdmsrtruimte_t_uitv_pr4),
                          COALESCE(ssr.mld_stdmsrtruimte_regime, v_mld_stdmelding_regime),  -- geen srtruimte-afhankelijk afwijkend regime.
                       DECODE (prio,
                               1, ssr.mld_stdmsrtruimte_t_accept_pr1,
                               2, ssr.mld_stdmsrtruimte_t_accept_pr2,
                               3, ssr.mld_stdmsrtruimte_t_accepttijd,
                               4, ssr.mld_stdmsrtruimte_t_accept_pr4)
                     INTO l_srtruimte_uitvoertijd_object,
                          l_mldsrtruimte_uitvtijd_object,
                          v_mld_stdmelding_regime,
                          l_mldsrtruimte_accepttijd
                     FROM alg_ruimte r,
                          alg_srtruimte sr,
                          mld_stdmsrtruimte ssr
                    WHERE r.alg_srtruimte_key = sr.alg_srtruimte_key(+)
                      AND r.alg_srtruimte_key = ssr.alg_srtruimte_key(+)
                      AND ssr.mld_stdmelding_key(+) = stdm_key
                      AND r.alg_ruimte_key = l_ruimte_key;
                EXCEPTION
                   WHEN NO_DATA_FOUND
                   THEN NULL;
                END;
             END IF;
          END IF;

          -- Uitvoertijd van de srtruimte, srtgebouw of srtterreinsector nemen.
          -- Als alg_srtruimte_t_uitvoertijd, alg_srtgebouw_t_uitvoertijd en alg_srtterreinsec_t_uitvtijd geen waarden hebben, dan terugvallen op standaard uitvoertijd die altijd een waarde heeft.
          IF l_alg_type = 'T'
          THEN
             v_uitvoertijd_object.tijdsduur := COALESCE(l_mldsrtterrein_uitvtijd_object.tijdsduur, l_srtterrein_uitvoertijd_object.tijdsduur, v_uitvoertijd_object.tijdsduur);
          ELSE
             v_uitvoertijd_object.tijdsduur := COALESCE(l_mldsrtruimte_uitvtijd_object.tijdsduur, l_srtruimte_uitvoertijd_object.tijdsduur,  -- eerst ruimte
                                                        l_mldsrtgebouw_uitvtijd_object.tijdsduur, l_srtgebouw_uitvoertijd_object.tijdsduur,  -- dan gebouw
                                                        v_uitvoertijd_object.tijdsduur);                                                   -- dan standaard.
          END IF;
          IF l_mldsrtruimte_uitvtijd_object.tijdsduur IS NOT NULL
          THEN
             v_uitvoertijd_object.eenheid := l_mldsrtruimte_uitvtijd_object.eenheid;
          ELSIF l_srtruimte_uitvoertijd_object.tijdsduur IS NOT NULL
          THEN
             v_uitvoertijd_object.eenheid := l_srtruimte_uitvoertijd_object.eenheid;
          ELSIF l_mldsrtgebouw_uitvtijd_object.tijdsduur IS NOT NULL
          THEN
             v_uitvoertijd_object.eenheid := l_mldsrtgebouw_uitvtijd_object.eenheid;
          ELSIF l_srtgebouw_uitvoertijd_object.tijdsduur IS NOT NULL
          THEN
             v_uitvoertijd_object.eenheid := l_srtgebouw_uitvoertijd_object.eenheid;
          ELSE
             v_uitvoertijd_object.eenheid := v_uitvoertijd_object.eenheid;
          END IF;

          -- Acceptatietijd van de mld_stdmsrtruimte, mld_stdmsrtgebouw of mld_stdmsrtterrein nemen.
          -- Als mld_stdmsrtruimte_t_accepttijd, mld_stdmsrtgebouw_t_accepttijd en mld_stdmsrtterrein_t_acctijd geen waarden hebben, dan terugvallen op standaard uitvoertijd die altijd een waarde heeft.
          IF l_alg_type = 'T'
          THEN
             v_accepttijd.tijdsduur := COALESCE(l_mldsrtterrein_acctijd.tijdsduur, v_accepttijd.tijdsduur);
          ELSE
             v_accepttijd.tijdsduur := COALESCE(l_mldsrtruimte_accepttijd.tijdsduur,  -- eerst ruimte
                                                l_mldsrtgebouw_accepttijd.tijdsduur,  -- dan gebouw
                                                v_accepttijd.tijdsduur);              -- dan standaard.
          END IF;
          IF l_mldsrtruimte_accepttijd.tijdsduur IS NOT NULL
          THEN
             v_accepttijd.eenheid := l_mldsrtruimte_accepttijd.eenheid;
          ELSIF l_mldsrtgebouw_accepttijd.tijdsduur IS NOT NULL
          THEN
             v_accepttijd.eenheid := l_mldsrtgebouw_accepttijd.eenheid;
          ELSE
             v_accepttijd.eenheid := v_accepttijd.eenheid;
          END IF;
       END IF;

       IF alg_key IS NULL AND v_mld_stdmelding_regime = 2
       THEN
          v_mld_stdmelding_regime := 1;                 --  dan terugvallen op algemene kantooruren
       END IF;
       IF v_mld_stdmelding_regime = 2 --  Openingstijden: zoek ruimte/gebouwopeningstijden er bij
       THEN
            SELECT MAX(alg_ruimte_key)
              INTO l_ruimte_key
              FROM alg_ruimte r
             WHERE r.alg_ruimte_key = alg_key;
            -- Minstens één van beide keys is gedefinieerd, zeker weten
            IF l_ruimte_key IS NOT NULL
            THEN
                -- de tijden van de ruimte of anders het gebouw gelden
                SELECT COALESCE (alg_ruimte_beginuur, alg_gebouw_beginuur, -1),
                       COALESCE (alg_ruimte_einduur, alg_gebouw_einduur, -1),
                       COALESCE (alg_ruimte_werkdagen, alg_gebouw_werkdagen)
                  INTO v_beginuur, v_einduur, v_werkdagen
                  FROM alg_ruimte r, alg_verdieping v, alg_gebouw g
                 WHERE r.alg_verdieping_key = v.alg_verdieping_key
                   AND v.alg_gebouw_key = g.alg_gebouw_key
                   AND r.alg_ruimte_key = l_ruimte_key;
            ELSE
               -- alg_key zal een gebouw, verdieping of terrein zijn.
               -- de tijden van het gebouw gelden of uren opleveren.
               SELECT beginuur,
                      einduur,
                      werkdagen
                 INTO v_beginuur,
                      v_einduur,
                      v_werkdagen
                 FROM (SELECT COALESCE(alg_gebouw_beginuur, -1) beginuur,
                              COALESCE(alg_gebouw_einduur, -1) einduur,
                              alg_gebouw_werkdagen werkdagen
                         FROM alg_gebouw g,
                              alg_v_allonroerendgoed aag
                        WHERE g.alg_gebouw_key = aag.alg_gebouw_key
                          AND aag.alg_onroerendgoed_keys = alg_key
                       UNION
                       SELECT -1 beginuur,
                              -1 einduur,
                              1 werkdagen
                         FROM alg_terreinsector t,
                              alg_v_allonroerendgoed aag
                        WHERE t.alg_terreinsector_key = aag.alg_terreinsector_key
                          AND aag.alg_onroerendgoed_keys = alg_key);
            END IF;
       END IF;
       RETURN;
    END;

    FUNCTION getacceptdatum (startdate IN DATE, stdm_key IN NUMBER, alg_key IN NUMBER, p_prio IN NUMBER DEFAULT 3)
        RETURN DATE
    IS
        l_accepttijdmld          mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie;
        l_accepttijdmldx         mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie;
        l_accepttijd_normaal     mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie;
        l_stdmelding_regime      mld_stdmelding.mld_stdmelding_regime%TYPE;
        l_stdmelding_regimex     mld_stdmelding.mld_stdmelding_regime%TYPE;
        l_stdmelding_afhankelijk mld_stdmelding.mld_stdmelding_afhankelijk%TYPE;
        l_alg_type               alg_v_allonroerendgoed.alg_type%TYPE;  -- kan dat op een view eigenlijk? anders VARCHAR2(1)
        l_ruimte_key             alg_ruimte.alg_ruimte_key%TYPE;
        l_terreinsector_key      alg_terreinsector.alg_terreinsector_key%TYPE;
        l_gebouw_key             alg_gebouw.alg_gebouw_key%TYPE;
        l_beginuur               alg_gebouw.alg_gebouw_beginuur%TYPE;
        l_einduur                alg_gebouw.alg_gebouw_einduur%TYPE;
        l_werkdagen              NUMBER;
    BEGIN
       -- Er is een hierarchie van SLA-tijden, van globaal tot specifiek, en kan overruled
       -- worden maar als dat niet gebeurt geldt de lagere waarde. Geldt ook voor regime.
       -- Het is hier zaak om de juiste waarde te bepalen
       --
       -- Volgorde is (object-sla kent geen acceptatietijd)
       -- x. mld_stdmelding_afhankelijk= 1 EN object-sla (ongeacht melding en prioriteit)
       -- 1. mld_stdmelding_afhankelijk= 1 EN plaats-sla-bij stdmelding voor de prioriteit
       -- 2. mld_stdmelding_afhankelijk= 1 EN plaats-sla voor de prioriteit
       -- 3. stdmelding-sla voor de prioriteit

       SELECT DECODE (p_prio,
                      1, mld_stdmelding_t_accept_pr1,
                      2, mld_stdmelding_t_accept_pr2,
                      3, mld_stdmelding_t_accepttijd,
                      4, mld_stdmelding_t_accept_pr4,
                      mld_stdmelding_t_accepttijd),
              mld_stdmelding_t_accepttijd,
              mld_stdmelding_regime,
              mld_stdmelding_afhankelijk
         INTO l_accepttijdmld, l_accepttijd_normaal, l_stdmelding_regime, l_stdmelding_afhankelijk
         FROM mld_stdmelding
        WHERE mld_stdmelding_key = stdm_key;

       -- Als je geen afwijkende acceptatietijd per prio hebt, dan is het die van Normaal
       -- Dit is een vangnet, als je het netjes deed had je overal dezelfde acceptatietijd ingevuld.
       IF p_prio <> 3 AND l_accepttijdmld.tijdsduur IS NULL
       THEN
          l_accepttijdmld := l_accepttijd_normaal;
       END IF;
       -- nu hebben we de standaardwaarde (3.)

       IF l_stdmelding_afhankelijk = 1 AND alg_key IS NOT NULL
       THEN
          -- Als alg_srtruimte_uitvoertijd geen waarde heeft, dan terugvallen op standaard uitvoertijd die altijd een waarde heeft
          SELECT alg_type,
                 alg_terreinsector_key,
                 alg_gebouw_key,
                 alg_ruimte_key
            INTO l_alg_type,
                 l_terreinsector_key,
                 l_gebouw_key,
                 l_ruimte_key
            FROM alg_v_onroerendgoed
           WHERE alg_onroerendgoed_keys = alg_key;

          -- deze ongebalanceerde constructie is bewust, omdat bij een ruimte (R) in een gebouw misschien
          -- geen srtruimtespecifieke overrule is, maar wel voor het hele gebouw
          IF l_alg_type = 'T'
          THEN
             BEGIN
                SELECT DECODE (p_prio,
                               1, sst.mld_stdmsrtterrein_t_acc_pr1,
                               2, sst.mld_stdmsrtterrein_t_acc_pr2,
                               3, sst.mld_stdmsrtterrein_t_acctijd,
                               4, sst.mld_stdmsrtterrein_t_acc_pr4), -- acceptie wordt niet per srtterreinsector overruled.
                       sst.mld_stdmsrtterrein_regime
                  INTO l_accepttijdmldx,
                       l_stdmelding_regimex
                  FROM alg_terreinsector t,
                       alg_srtterreinsector st,
                       mld_stdmsrtterrein sst
                 WHERE t.alg_srtterreinsector_key = st.alg_srtterreinsector_key
                   AND t.alg_srtterreinsector_key = sst.alg_srtterreinsector_key
                   AND sst.mld_stdmelding_key = stdm_key
                   AND t.alg_terreinsector_key = l_terreinsector_key;
              EXCEPTION
                 WHEN NO_DATA_FOUND
                 THEN NULL;
              END;
          ELSE -- G,V,R
             BEGIN
                SELECT DECODE (p_prio,
                               1, ssg.mld_stdmsrtgebouw_t_accept_pr1,
                               2, ssg.mld_stdmsrtgebouw_t_accept_pr2,
                               3, ssg.mld_stdmsrtgebouw_t_accepttijd,
                               4, ssg.mld_stdmsrtgebouw_t_accept_pr4), -- acceptie wordt niet per srtgebouw overruled.
                       ssg.mld_stdmsrtgebouw_regime
                  INTO l_accepttijdmldx,
                       l_stdmelding_regimex
                  FROM alg_gebouw g,
                       alg_srtgebouw sg,
                       mld_stdmsrtgebouw ssg
                 WHERE g.alg_srtgebouw_key = sg.alg_srtgebouw_key
                   AND g.alg_srtgebouw_key = ssg.alg_srtgebouw_key
                   AND ssg.mld_stdmelding_key = stdm_key
                   AND g.alg_gebouw_key = l_gebouw_key;
             EXCEPTION
                WHEN NO_DATA_FOUND
                THEN NULL;
             END;
          END IF;

          IF l_alg_type = 'R'
          THEN
             BEGIN
               SELECT DECODE (p_prio,
                            1, ssr.mld_stdmsrtruimte_t_accept_pr1,
                            2, ssr.mld_stdmsrtruimte_t_accept_pr2,
                            3, ssr.mld_stdmsrtruimte_t_accepttijd,
                            4, ssr.mld_stdmsrtruimte_t_accept_pr4), -- acceptie wordt niet per srtgebouw overruled.
                      ssr.mld_stdmsrtruimte_regime
                 INTO l_accepttijdmldx,
                      l_stdmelding_regimex
                FROM alg_ruimte r,
                      alg_srtruimte sr,
                      mld_stdmsrtruimte ssr
                WHERE r.alg_srtruimte_key = sr.alg_srtruimte_key
                   AND r.alg_srtruimte_key = ssr.alg_srtruimte_key
                   AND ssr.mld_stdmelding_key = stdm_key
                   AND r.alg_ruimte_key = l_ruimte_key;
             EXCEPTION
                WHEN NO_DATA_FOUND
                THEN NULL;
             END;
          END IF;

          IF l_accepttijdmldx.tijdsduur IS NOT NULL
          THEN
            l_accepttijdmld.tijdsduur := l_accepttijdmldx.tijdsduur;
            l_accepttijdmld.eenheid := l_accepttijdmldx.eenheid;
          END IF;
          -- is het raar als je dezelfde SLA-waarden met (alleen) een ander regime hebt?
          -- op zich mag het: binnen 4 uur maar in dit gebouw 24/7 ipv kantoortijden
          -- dan is er dus wel een record gevonden maar l_accepttijdmldx is leeg
          -- daarom hier onvoorwaardelijk
          l_stdmelding_regime := COALESCE(l_stdmelding_regimex, l_stdmelding_regime);

       END IF;

       -- we hebben nu de juiste acceptatietijd bepaald in l_accepttijdmld en het regime in l_stdmelding_regime
       -- nu is het nog een kwestie van rekenen waar dat ons brengt

       -- Regimes: 1) Kantoortijden regime
       --          2) Openingstijden regime
       --          3) 24/7 regime (negeert weekenden of vrije dagen)
       -- De functie fac.datumtijdplusuitvoertijd kan rekenen met zowel dagen als uren

       IF (l_stdmelding_regime = 1) OR (alg_key IS NULL AND l_stdmelding_regime = 2) -- Kantoortijdenregime of hierop terugvallen
       THEN
          RETURN fac.datumtijdplusuitvoertijd (startdate, l_accepttijdmld.tijdsduur, l_accepttijdmld.eenheid);
       END IF;

       IF l_stdmelding_regime = 2 -- Openingstijden: zoek ruimte/gebouwopeningstijden er bij
       THEN
         -- Minstens één van beide keys is gedefinieerd, zeker weten
         IF l_ruimte_key IS NOT NULL
         THEN
            -- de tijden van de ruimte of anders het gebouw gelden
            SELECT COALESCE (alg_ruimte_beginuur, alg_gebouw_beginuur, 0),
                   COALESCE (alg_ruimte_einduur, alg_gebouw_einduur, 24),
                   COALESCE (alg_ruimte_werkdagen, alg_gebouw_werkdagen)
              INTO l_beginuur, l_einduur, l_werkdagen
              FROM alg_ruimte r, alg_verdieping v, alg_gebouw g
             WHERE r.alg_verdieping_key = v.alg_verdieping_key
               AND v.alg_gebouw_key = g.alg_gebouw_key
               AND r.alg_ruimte_key = l_ruimte_key;
         ELSE
            -- alg_key zal een gebouw, verdieping of terrein zijn.
            -- de tijden van het gebouw gelden of 24 per dag alleen op werkdagen.
            SELECT beginuur,
                   einduur,
                   werkdagen
             INTO l_beginuur,
                  l_einduur,
                  l_werkdagen
             FROM (SELECT COALESCE(alg_gebouw_beginuur, 0) beginuur,
                          COALESCE(alg_gebouw_einduur, 24) einduur,
                          alg_gebouw_werkdagen werkdagen
                     FROM alg_gebouw g,
                          alg_v_allonroerendgoed aag
                    WHERE g.alg_gebouw_key = aag.alg_gebouw_key
                      AND aag.alg_onroerendgoed_keys = alg_key
                    UNION
                   SELECT 0 beginuur,
                          24 einduur,
                          1 werkdagen
                     FROM alg_terreinsector t,
                          alg_v_allonroerendgoed aag
                    WHERE t.alg_terreinsector_key = aag.alg_terreinsector_key
                      AND aag.alg_onroerendgoed_keys = alg_key);
         END IF;

         RETURN FAC.datumtijdplusuitvoertijd (startdate,
                                             l_accepttijdmld.tijdsduur,
                                             l_accepttijdmld.eenheid,
                                             l_beginuur,
                                             l_einduur,
                                             l_werkdagen); -- Mode=0/1 resp. alle dagen/alleen werkdagen!
       END IF;

       IF l_stdmelding_regime = 3 -- 24/7, negeert weekenden of vrije dagen
       THEN
         RETURN FAC.datumtijdplusuitvoertijd (startdate,
                                             l_accepttijdmld.tijdsduur,
                                             l_accepttijdmld.eenheid,
                                             NULL, -- Don't care
                                             NULL, -- Don't care
                                             2); -- Mode=2 => 24/7
       END IF;
    END;

   FUNCTION getnettotijdsbesteding (p_opdr_key IN NUMBER, p_prs_key IN NUMBER DEFAULT NULL) RETURN NUMBER
   AS
      l_netto_tijd                    NUMBER;
      l_fsn_code_last                 fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
      l_ft_datum_last                 fac_tracking.fac_tracking_datum%TYPE;
      l_ft_perslid_key                fac_tracking.prs_perslid_key%TYPE;
      l_mld_typeopdr_sequential       mld_typeopdr.mld_typeopdr_sequential%TYPE;
      CURSOR c_tracking
      IS
         SELECT st.fac_srtnotificatie_code,
                t.fac_tracking_datum,
                t.prs_perslid_key
           FROM fac_tracking t,
                fac_srtnotificatie st
          WHERE t.fac_srtnotificatie_key = st.fac_srtnotificatie_key
            AND st.fac_srtnotificatie_code IN ('ORDACP', 'ORDHLT', 'ORDRSM', 'ORDAFM')
            AND fac_tracking_refkey = p_opdr_key
         ORDER BY fac_tracking_datum;
   BEGIN
      l_netto_tijd := 0;
      l_fsn_code_last := NULL;
      l_ft_datum_last := NULL;
      l_ft_perslid_key := NULL;

      SELECT mto.mld_typeopdr_sequential
        INTO l_mld_typeopdr_sequential
        FROM mld_opdr o,
             mld_typeopdr mto
       WHERE o.mld_typeopdr_key = mto.mld_typeopdr_key
         AND o.mld_opdr_key = p_opdr_key;

      FOR r IN c_tracking
      LOOP
          -- Alleen als 'ORDAFM' of 'ORDHLT' getrackt is wordt er eventueel tijd bij de nettotijd opgeteld.
          -- Dan moet de vorige tracking wel 'ORDACP' of 'ORDRSM' zijn.
          -- Uitgezonderd als alleen de periode 'ORDACP-ORDAFM' is getrackt en "Onderbroken start" (mld_typeopdr.mld_typeopdr_sequential) aan staat.
         IF (r.fac_srtnotificatie_code = 'ORDAFM' OR r.fac_srtnotificatie_code = 'ORDHLT') AND
            (l_fsn_code_last = 'ORDACP' OR l_fsn_code_last = 'ORDRSM') AND
            l_ft_perslid_key = p_prs_key AND
            (l_fsn_code_last != 'ORDACP' OR r.fac_srtnotificatie_code != 'ORDAFM' OR BITAND(l_mld_typeopdr_sequential, 4) = 0)
         THEN
            l_netto_tijd := l_netto_tijd + (r.fac_tracking_datum - l_ft_datum_last);
         END IF;
         l_fsn_code_last := r.fac_srtnotificatie_code;
         l_ft_datum_last := r.fac_tracking_datum;
         l_ft_perslid_key := r.prs_perslid_key;
      END LOOP;
      -- Als de opdracht nog actief is en niet op hold staat, moet er nog tijd tot nu (SYSDATE) bij opgeteld worden.
      -- Uitgezonderd als 'ORDACP' als laatste is getrackt en "Onderbroken start" (mld_typeopdr.mld_typeopdr_sequential) aan staat.
      IF (l_fsn_code_last = 'ORDACP' OR l_fsn_code_last = 'ORDRSM') AND
         l_ft_perslid_key = p_prs_key AND
         (l_fsn_code_last != 'ORDACP' OR BITAND(l_mld_typeopdr_sequential, 4) = 0)
      THEN
         l_netto_tijd := l_netto_tijd + (SYSDATE - l_ft_datum_last);
      END IF;
      RETURN l_netto_tijd;
   END;

   FUNCTION BepaalOpdrMeldingVolgnr(p_melding_key IN NUMBER) RETURN NUMBER IS
     ReturnVal NUMBER;
   BEGIN
      SELECT COALESCE(MAX(mld_opdr_bedrijfopdr_volgnr),0) + 1
        INTO ReturnVal
        FROM mld_opdr
       WHERE mld_melding_key = p_melding_key;
      RETURN ReturnVal;
   END;

   FUNCTION BepaalOpdrContractVolgnr(p_contract_key IN NUMBER) RETURN NUMBER IS
     ReturnVal       NUMBER;
   BEGIN
      SELECT COALESCE(MAX(mld_opdr_bedrijfopdr_volgnr),0) + 1
        INTO ReturnVal
        FROM mld_opdr
       WHERE cnt_contract_key = p_contract_key;
      RETURN ReturnVal;
   END;

   FUNCTION mldsprintf (ps IN VARCHAR2, p_melding_key IN NUMBER)
      RETURN VARCHAR2
   IS
      s                      VARCHAR2 (2048 CHAR);
      varstdmld              mld_stdmelding.mld_stdmelding_omschrijving%TYPE;
      vardisc                ins_tab_discipline.ins_discipline_omschrijving%TYPE;
      varsrtdisc             ins_srtdiscipline.ins_srtdiscipline_prefix%TYPE;
      varonroerendgoedkeys   mld_melding.mld_alg_onroerendgoed_keys%TYPE;
      varplaats              VARCHAR2 (4000); -- Ook groot genoeg voor locatieomschrijving
      varonderwerp           mld_melding.mld_melding_onderwerp%TYPE;
      varmelder              VARCHAR2 (1000); -- Groot zat
      varspoed               mld_melding.mld_melding_spoed%TYPE;
      varextnr               mld_melding.mld_melding_externnr%TYPE;

   BEGIN
      s := ps;

      -- We do support substitution of placeholders in the messages
      -- ##DISC##    = ins_discipline_omschrijving
      -- ##STDMLD##  = mld_stdmelding_omschrijving
      -- ##KEY##     = ins_srtdiscipline_prefix+key
      -- ##PLAATS##  = plaatsaanduidig van plaats service
      -- ##SUBJECT## = mld_melding_onderwerp
      -- ##SPOED##   = 'SPOED' indien spoed, anders ''
      -- ##EXTNR##   = extern nummer
      -- ##MELDER##  = melder
      IF INSTR (s, '#') > 0
      THEN
         SELECT lcl.x ('mld_stdmelding_omschrijving',
                       stdm.mld_stdmelding_key,
                       stdm.mld_stdmelding_omschrijving),
                lcl.x ('ins_discipline_omschrijving',
                       d.ins_discipline_key,
                       d.ins_discipline_omschrijving),
                sd.ins_srtdiscipline_prefix,
                m.mld_alg_onroerendgoed_keys,
                m.mld_melding_spoed,
                m.mld_melding_onderwerp,
                pf.prs_perslid_naam_friendly,
                m.mld_melding_externnr
           INTO varstdmld,
                vardisc,
                varsrtdisc,
                varonroerendgoedkeys,
                varspoed,
                varonderwerp,
                varmelder,
                varextnr
           FROM mld_stdmelding stdm,
                ins_tab_discipline d,
                ins_srtdiscipline sd,
                mld_melding m,
                prs_v_perslid_fullnames_all pf
          WHERE     d.ins_srtdiscipline_key = sd.ins_srtdiscipline_key
                AND m.prs_perslid_key_voor = pf.prs_perslid_key  -- voor wie is evt relevanter
                AND stdm.mld_ins_discipline_key = d.ins_discipline_key
                AND stdm.mld_stdmelding_key = m.mld_stdmelding_key
                AND m.mld_melding_key = p_melding_key;

         s :=
            REPLACE (
               REPLACE (
                  REPLACE (REPLACE (REPLACE (REPLACE (s,
                  '##DISC##', vardisc),
                  '##STDMLD##', varstdmld),
                  '##KEY##', varsrtdisc || TO_CHAR (p_melding_key)),
                  '##EXTNR##', varextnr),
                  '##MELDER##', varmelder),
                  '##SUBJECT##', varonderwerp);

         IF varspoed <= 2
         THEN
            s :=
               REPLACE (s,
                        '##SPOED##',
                        '(' || lcl.l ('lcl_mld_spoed') || ')');
         ELSE
            s := REPLACE (s, '##SPOED##', '');
         END IF;

         IF varonroerendgoedkeys IS NOT NULL
         THEN
            -- Pas op: p.alg_onroerendgoed_keys is niet uniek, daarom alg_v_allonroerendgoed nodig.
            SELECT NVL (p.alg_plaatsaanduiding, '')
              INTO varplaats
              FROM alg_v_plaatsaanduiding_all p, alg_v_allonroerendgoed ao
             WHERE     p.alg_onroerendgoed_keys = ao.alg_onroerendgoed_keys
                   AND p.alg_onroerendgoed_type = ao.alg_type
                   AND ao.alg_onroerendgoed_keys = varonroerendgoedkeys;

            s := REPLACE (s, '##PLAATS##', varplaats);
         ELSE
            s := REPLACE (s, '##PLAATS##', '');
         END IF;
      END IF;

      RETURN s;
   END;

FUNCTION opdrsprintf (ps IN varchar2, p_opdr_key IN number)
   RETURN varchar2
IS
   s   VARCHAR2 (2048 CHAR);
   f   VARCHAR2 (2048 CHAR);
   d   NUMBER := 0;
   fmt VARCHAR2 (50 CHAR);
   lmld_melding_key mld_opdr.mld_melding_key%TYPE;
   lbedrijfopdr_volgnr mld_opdr.mld_opdr_bedrijfopdr_volgnr%TYPE;
   lopdr_omschrijving mld_opdr.mld_opdr_omschrijving%TYPE;
   lopdrstatus mld_opdr.mld_statusopdr_key%TYPE;
   lafmelderkey fac_tracking.prs_perslid_key%TYPE;
   lafmelder    prs_v_perslid_fullnames_all.prs_perslid_naam_full%TYPE;
   varstdmld mld_stdmelding.mld_stdmelding_omschrijving%TYPE;
   vardisc ins_tab_discipline.ins_discipline_omschrijving%TYPE;
   varsrtdisc ins_srtdiscipline.ins_srtdiscipline_prefix%TYPE;
   varspoed mld_melding.mld_melding_spoed%TYPE;
   varonroerendgoedkeys mld_melding.mld_alg_onroerendgoed_keys%TYPE;
   varalglocatiekey mld_melding.mld_alg_locatie_key%TYPE;
   varplaats VARCHAR2(4000); -- Ook groot genoeg voor locatieomschrijving
   varopdrtype mld_typeopdr.mld_typeopdr_omschrijving%TYPE;
   varextnr mld_opdr.mld_opdr_externnr%TYPE;
   varopdrid mld_opdr.mld_opdr_id%TYPE;
   varonderwerp mld_melding.mld_melding_onderwerp%TYPE;
BEGIN
   s := ps;

   -- We support substitution of placeholders in the messages
   -- ##OPDRKEYN## = voorloop+key+/+volgnr: kan $$x bevatten; x is hierin het aantal posities voor voorloop+key
   -- ##OPDRKEY## = ins_srtdiscipline_prefix+key+/+volgnr  (zie: RWSN#18845!)
   -- ##DISC##   = ins_discipline_omschrijving
   -- ##STDMLD## = mld_stdmelding_omschrijving
   -- ##DESC##   = mld_opdr_omschrijving (tbv SMS)
   -- ##SPOED##  = 'SPOED' indien spoed, anders ''
   -- ##PLAATS## = plaatsaanduidig van plaats service
   -- ##OPDRTYPE## = opdrachttype
   -- ##EXTNR## = extern nummer
   -- ##OPDRID## = mld_opdr_id
   -- ##SUBJECT## = mld_melding_onderwerp
    IF (instr2 (s, '#') > 0 AND instr2 (s, '$') > 0)
    THEN
        f := SUBSTR( s, INSTR2( s, '$$')+2);
        f := SUBSTR( f, 1, INSTR2( f, '##')-1);
        s := REPLACE( s, '$$'||f, '');
        IF f is not null
        THEN
            BEGIN
                d := TO_NUMBER(f);
            EXCEPTION
                WHEN OTHERS THEN d := 0;
            END;
            fmt := LPAD('0', d, '0');
        END IF;
    END IF;

    IF instr2 (s, '#') > 0
    THEN
        SELECT o.mld_melding_key,
               o.mld_opdr_bedrijfopdr_volgnr,
               o.mld_opdr_omschrijving,
               o.mld_statusopdr_key,
               o.mld_opdr_externnr,
               o.mld_opdr_id,
               lcl.x ('mld_typeopdr_omschrijving',
                      o.mld_typeopdr_key,
                      ot.mld_typeopdr_omschrijving)
          INTO lmld_melding_key,
               lbedrijfopdr_volgnr,
               lopdr_omschrijving,
               lopdrstatus,
               varextnr,
               varopdrid,
               varopdrtype
          FROM mld_opdr o, mld_typeopdr ot
         WHERE o.mld_typeopdr_key = ot.mld_typeopdr_key AND o.mld_opdr_key = p_opdr_key;

        -- Tijdens het tracken van het afmelden is de transactie nog niet
        -- afgelopen, en levert het zoeken naar de afmelder via tracking
        -- (nog) geen resultaat op. WE KUNNEN HIER DUS NIET NOTIFICEREN
        -- WIE ER HEEFT AFGEMELD.
        SELECT lcl.x ('mld_stdmelding_omschrijving',
                      stdm.mld_stdmelding_key,
                      stdm.mld_stdmelding_omschrijving),
               lcl.x ('ins_discipline_omschrijving',
                      d.ins_discipline_key,
                      d.ins_discipline_omschrijving),
               sd.ins_srtdiscipline_prefix,
               m.mld_melding_spoed,
               m.mld_alg_onroerendgoed_keys,
               m.mld_alg_locatie_key,
               m.mld_melding_onderwerp
          INTO varstdmld,
               vardisc,
               varsrtdisc,
               varspoed,
               varonroerendgoedkeys,
               varalglocatiekey,
               varonderwerp
          FROM mld_melding m,
               mld_stdmelding stdm,
               ins_tab_discipline d,
               ins_srtdiscipline sd
         WHERE d.ins_srtdiscipline_key = sd.ins_srtdiscipline_key
           AND stdm.mld_ins_discipline_key = d.ins_discipline_key
           AND stdm.mld_stdmelding_key = m.mld_stdmelding_key
           AND m.mld_melding_key = lmld_melding_key;

        IF varonroerendgoedkeys IS NOT NULL
        THEN
             -- Pas op: p.alg_onroerendgoed_keys is niet uniek, daarom alg_v_allonroerendgoed nodig.
             SELECT NVL (p.alg_plaatsaanduiding, '')
               INTO varplaats
               FROM alg_v_plaatsaanduiding_all p, alg_v_allonroerendgoed ao
              WHERE p.alg_onroerendgoed_keys = ao.alg_onroerendgoed_keys
                AND p.alg_onroerendgoed_type = ao.alg_type
                AND ao.alg_onroerendgoed_keys = varonroerendgoedkeys;
        ELSIF varalglocatiekey IS NOT NULL
        THEN
             SELECT NVL(l.alg_locatie_omschrijving, '')
               INTO varplaats
               FROM alg_locatie l
              WHERE l.alg_locatie_key = varalglocatiekey;
        ELSE
           varplaats := '';
        END IF;

        s := REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (REPLACE (s,
              '##OPDRKEYN##', CASE WHEN fmt IS NOT NULL THEN LTRIM(TO_CHAR (lmld_melding_key, fmt)) ELSE TO_CHAR (lmld_melding_key) END || '/' || TO_CHAR (lbedrijfopdr_volgnr)),
              '##OPDRKEY##',  varsrtdisc || TO_CHAR (lmld_melding_key) || '/' || TO_CHAR (lbedrijfopdr_volgnr)),
              '##DISC##',     vardisc),
              '##STDMLD##',   varstdmld),
              '##DESC##',     lopdr_omschrijving),
              '##OPDRTYPE##', varopdrtype),
              '##EXTNR##',    varextnr),
              '##OPDRID##',   varopdrid),
              '##SUBJECT##',  varonderwerp),
              '##PLAATS##',   varplaats);

        IF varspoed <= 2
        THEN
            s := REPLACE (s, '##SPOED##', '(' || lcl.l('lcl_mld_spoed') || ')');
        ELSE
            s := REPLACE (s, '##SPOED##', '');
        END IF;
    END IF;

    s := REPLACE (s, ' ()', '');
    RETURN s;
END;

PROCEDURE upsertmeldingkenmerk (p_kenmerk_key IN NUMBER, p_mld_key IN NUMBER, p_waarde IN VARCHAR2)
IS
    v_count    NUMBER;
    v_waarde   mld_kenmerkmelding.mld_kenmerkmelding_waarde%TYPE;
BEGIN
    SELECT COUNT ( * ), MIN (mld_kenmerkmelding_waarde)
      INTO v_count, v_waarde
      FROM mld_kenmerkmelding
     WHERE     mld_melding_key = p_mld_key
           AND mld_kenmerk_key = p_kenmerk_key
           AND mld_kenmerkmelding_verwijder IS NULL;

    IF v_count = 1
    THEN
        IF p_waarde IS NULL
        THEN
            DELETE mld_kenmerkmelding
             WHERE     mld_melding_key = p_mld_key
                   AND mld_kenmerk_key = p_kenmerk_key
                   AND mld_kenmerkmelding_verwijder IS NULL;
        ELSE
            IF (v_waarde <> p_waarde) THEN
                UPDATE mld_kenmerkmelding
                   SET mld_kenmerkmelding_waarde = p_waarde
                 WHERE     mld_melding_key = p_mld_key
                       AND mld_kenmerk_key = p_kenmerk_key
                       AND mld_kenmerkmelding_verwijder IS NULL;
            END IF;
        END IF;
    ELSE
        IF p_kenmerk_key IS NOT NULL AND p_waarde IS NOT NULL
        THEN
            INSERT INTO mld_kenmerkmelding (mld_kenmerk_key,
                                            mld_melding_key,
                                            mld_kenmerkmelding_waarde)
                VALUES (p_kenmerk_key, p_mld_key, p_waarde);
        END IF;
    END IF;
END;

-- Er wordt niet getrackt (wat eigenlijk niet zo goed is)
PROCEDURE upsertopdrachtkenmerk (p_kenmerk_key IN NUMBER, p_opdr_key IN NUMBER, p_waarde IN VARCHAR2)
IS
    v_count    NUMBER;
    v_waarde   mld_kenmerkopdr.mld_kenmerkopdr_waarde%TYPE;
BEGIN
    SELECT COUNT ( * ), MIN(mld_kenmerkopdr_waarde)
      INTO v_count, v_waarde
      FROM mld_kenmerkopdr
     WHERE     mld_opdr_key = p_opdr_key
           AND mld_kenmerk_key = p_kenmerk_key
           AND mld_kenmerkopdr_verwijder IS NULL;

    IF v_count = 1
    THEN
        IF p_waarde IS NULL
        THEN
            DELETE mld_kenmerkopdr
             WHERE     mld_opdr_key = p_opdr_key
                   AND mld_kenmerk_key = p_kenmerk_key
                   AND mld_kenmerkopdr_verwijder IS NULL;
        ELSE
            IF (v_waarde <> p_waarde) THEN
                UPDATE mld_kenmerkopdr
                   SET mld_kenmerkopdr_waarde = p_waarde
                 WHERE     mld_opdr_key = p_opdr_key
                       AND mld_kenmerk_key = p_kenmerk_key
                       AND mld_kenmerkopdr_verwijder IS NULL;
            END IF;
        END IF;
    ELSE
        IF p_kenmerk_key IS NOT NULL AND p_waarde IS NOT NULL
        THEN
            INSERT INTO mld_kenmerkopdr (mld_kenmerk_key,
                                         mld_opdr_key,
                                         mld_kenmerkopdr_waarde)
                VALUES (p_kenmerk_key, p_opdr_key, p_waarde);
        END IF;
    END IF;
END;


FUNCTION mldflexsummary (pmelding_key IN NUMBER)
   RETURN VARCHAR2
IS
   CURSOR c1
   IS
        SELECT k.mld_kenmerk_key,
               t.mld_srtkenmerk_kenmerktype,
               t.mld_srtkenmerk_nmin nmin,
               t.mld_srtkenmerk_nmax nmax,
               t.fac_kenmerkdomein_key,
               k.mld_kenmerk_volgnummer,
               COALESCE (
                   lcl.x ('mld_kenmerk_omschrijving', k.mld_kenmerk_key, k.mld_kenmerk_omschrijving),
                   lcl.x ('mld_srtkenmerk_omschrijving',
                          t.mld_srtkenmerk_key,
                          t.mld_srtkenmerk_omschrijving))
                   mld_kenmerk_omschrijving,
               v.mld_kenmerkmelding_waarde
          FROM mld_srtkenmerk t, mld_kenmerk k, mld_kenmerkmelding v
         WHERE     v.mld_kenmerk_key = k.mld_kenmerk_key
               AND k.mld_srtkenmerk_key = t.mld_srtkenmerk_key
               AND BITAND(t.mld_srtkenmerk_systeem,4) = 0  -- gewoon niet als vertrouwelijk
               AND k.mld_kenmerk_verwijder IS NULL
               AND t.mld_srtkenmerk_verwijder IS NULL
               AND NOT(  (   fac.getSetting('mld_ord_flexsummary') = 2
                         AND BITAND(k.mld_kenmerk_wissen, 4) = 4
                         )
                      OR fac.getSetting('mld_ord_flexsummary') = 0
                      )
               AND v.mld_melding_key = pmelding_key
      ORDER BY k.mld_kenmerk_volgnummer,
               UPPER(COALESCE(mld_kenmerk_omschrijving, mld_srtkenmerk_omschrijving));  --field-order always in native language order
   waarde    mld_kenmerkmelding.mld_kenmerkmelding_waarde%TYPE;
   builder   VARCHAR2 (4000 CHAR);
BEGIN
   FOR r IN c1 LOOP
      waarde := r.mld_kenmerkmelding_waarde;
      IF waarde IS NOT NULL AND waarde <> '-1'
      -- gevuld
      THEN
         IF r.mld_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 r.mld_srtkenmerk_kenmerktype = 'R' OR r.mld_srtkenmerk_kenmerktype = 'r' OR r.mld_srtkenmerk_kenmerktype = 'S'
         -- referentie
         THEN
            waarde := flx.getdomeinwaarde (r.fac_kenmerkdomein_key, 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(builder),0) + LENGTH(r.mld_kenmerk_omschrijving) + LENGTH(waarde) < 3990)
         THEN
            builder := builder || CHR(10) || r.mld_kenmerk_omschrijving || ': ' || waarde;
         END IF;
      END IF;
   END LOOP;
   RETURN builder;
END;

PROCEDURE remove(p_melding_key IN NUMBER)
IS
    CURSOR c_melding(p_melding_key IN NUMBER) IS
        SELECT mld_melding_key
          FROM mld_melding
         WHERE (mld_melding_start_key <> mld_melding_key AND mld_melding_start_key = p_melding_key)
            OR mld_melding_parentkey = p_melding_key;

    CURSOR c_opdracht(p_melding_key IN NUMBER) IS
        SELECT mld_opdr_key
          FROM mld_opdr
         WHERE mld_melding_key = p_melding_key
         ORDER BY mld_opdr_bedrijfopdr_volgnr DESC;

    CURSOR c_bijlagen(p_refkey IN NUMBER) IS
        SELECT fac_bijlagen_key
          FROM fac_bijlagen b
             , mld_melding r
             , (SELECT k.mld_kenmerk_key kenmerk_key
                  FROM mld_kenmerk k
                     , mld_srtkenmerk s
                 WHERE k.mld_srtkenmerk_key = s.mld_srtkenmerk_key
                   AND k.mld_kenmerk_niveau NOT IN ('O', 'P')
                   AND s.mld_srtkenmerk_kenmerktype IN ('F', 'M', 'E', 'X')
               ) k
         WHERE b.fac_bijlagen_kenmerk_key = k.kenmerk_key
           AND b.fac_bijlagen_refkey = r.mld_melding_key
           AND b.fac_bijlagen_module = 'MLD'
           AND b.fac_bijlagen_refkey = p_refkey;

BEGIN
    -- Ook alle child meldingen verwijderen.
    FOR ref_melding IN c_melding(p_melding_key)
    LOOP
        mld.remove(ref_melding.mld_melding_key);
    END LOOP;

    -- Alle opdrachten onder de melding verwijderen.
    FOR ref_opdracht IN c_opdracht(p_melding_key)
    LOOP
        mld.remove_opdr(ref_opdracht.mld_opdr_key);
    END LOOP;

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

    DELETE FROM mld_melding
     WHERE mld_melding_key = p_melding_key;

    -- Van de volgende tabellen worden de records die naar deze p_melding_key
    -- verwijzen met ON DELETE CASCADE ook verwijderd:
    --  mld_melding_note
    --  mld_kenmerkmelding
    --  mld_melding_object
    --  prj_scenario
    -- In de volgende tabel wordt mld_melding_key leeg gemaakt bij het verwijderen van p_melding_key:
    --  bes_bestelling

    fac.remove_tracking('melding', p_melding_key);
END;

PROCEDURE remove_opdr(p_mld_opdr_key IN NUMBER)
IS
    CURSOR c_factuur(p_opdracht_key IN NUMBER) IS
        SELECT fin_factuur_key
          FROM fin_factuur
         WHERE mld_opdr_key = p_opdracht_key;

    CURSOR c_afspraak(p_opdracht_key IN NUMBER) IS
        SELECT bez_afspraak_key
          FROM bez_afspraak
         WHERE mld_opdr_key = p_opdracht_key;

    CURSOR c_bijlagen(p_refkey IN NUMBER) IS
        SELECT fac_bijlagen_key
          FROM fac_bijlagen b
             , mld_opdr r
             , (SELECT k.mld_kenmerk_key kenmerk_key
                  FROM mld_kenmerk k
                     , mld_srtkenmerk s
                 WHERE k.mld_srtkenmerk_key = s.mld_srtkenmerk_key
                   AND k.mld_kenmerk_niveau IN ('O', 'P')
                   AND s.mld_srtkenmerk_kenmerktype IN ('F', 'M', 'E', 'X')
               ) k
         WHERE b.fac_bijlagen_refkey = r.mld_opdr_key
           AND b.fac_bijlagen_module = 'MLD'
           AND b.fac_bijlagen_refkey = p_refkey;

BEGIN
    FOR ref_factuur IN c_factuur(p_mld_opdr_key)
    LOOP
        fin.remove(ref_factuur.fin_factuur_key);
    END LOOP;

    FOR ref_afspraak IN c_afspraak(p_mld_opdr_key)
    LOOP
        bez.remove(ref_afspraak.bez_afspraak_key);
    END LOOP;

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

    DELETE FROM mld_opdr
     WHERE mld_opdr_key = p_mld_opdr_key;

    -- Van de volgende tabellen worden de records die naar deze mld_opdr_key
    -- verwijzen met ON DELETE CASCADE ook verwijderd:
    --  mld_opdr_note
    --  mld_kenmerkopdr
    --  mld_opdr_materiaal
    --  mld_opdr_uitvoeren
    --  mld_opdr_uren
    -- Hierdoor worden de afhankelijkheden in de volgende tabel ook verwijderd:
    --  mld_opdruren_kosten

    fac.remove_tracking('opdracht', p_mld_opdr_key);
END;

-- Deze functie reset (gegarandeerd) de p_actiecode-bits van mld_melding_actiecode voor meldingen
-- die langer dan p_days dagen geleden zijn afgemeld
-- Als meer bits worden meegeven (bv 6 = 4+2) dan zijn beide bits na aanroep gereset
-- als dat voor de aanroep niet het geval was, dus zowel 2,4 als 6 worden dan 0
-- voor meldingen die aan de conditie voldoen.
-- Aanleiding voor deze functie is het resetten van de Actie-bij-melder na x dagen.
PROCEDURE resetpostafmeldactie (p_actiecode IN NUMBER DEFAULT 2, p_days IN NUMBER DEFAULT 7)
IS
BEGIN
   UPDATE mld_melding m
      SET m.mld_melding_actiecode = m.mld_melding_actiecode - BITAND (m.mld_melding_actiecode, p_actiecode)
   WHERE     m.mld_melding_status = 5  -- afgemeld
         AND BITAND (m.mld_melding_actiecode, p_actiecode) > 0
         AND fac.gettrackingdate ('MLDAFM', m.mld_melding_key) < (SYSDATE - p_days);

   -- Willen we nog iets tracken of zo? Ik denk zelf van niet
END;

END mld;
/

REGISTERRUN('$Id$')

#endif // MLD
