#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);
  FUNCTION  getopdrachtstatusdate (popdrkey IN number, pstatus IN number) RETURN date;
  PROCEDURE setopdrachtstatus (popdrachtkey IN NUMBER, pstatus IN NUMBER, puserkey IN NUMBER);
  PROCEDURE notifybackoffice (pmeldingkey IN NUMBER, pcode IN VARCHAR2);
  PROCEDURE notifyprio (pmeldingkey IN NUMBER, prio IN NUMBER, pperslid_key IN NUMBER);
  PROCEDURE notifyopdrgoedkeurders (popdrkey IN NUMBER);

  PROCEDURE mld_nextworkflowstep     (p_melding_key        IN NUMBER
                                     ,p_success            IN NUMBER);
  FUNCTION getlowestobjectuitvoer    (p_melding_key        IN NUMBER) RETURN NUMBER;
  FUNCTION uitvoertijd_to_char       (uitvoertijd          IN MLD_T_UITVOERTIJD) RETURN VARCHAR;
  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 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_beginuur              OUT  NUMBER,
                          v_einduur               OUT  NUMBER,
                          v_werkdagen             OUT  NUMBER
                        );
  FUNCTION getacceptdatum            (startdate IN DATE, stdm_key IN NUMBER, alg_key IN NUMBER)  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;
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)
   AS
      currentstatus mld_melding.mld_melding_status%TYPE;
      newstatus mld_melding.mld_melding_status%TYPE;
      eventcode fac_srtnotificatie.fac_srtnotificatie_code%TYPE;

      CURSOR c_mldchilderen
      IS
         SELECT   mld_melding_key
           FROM   mld_melding
          WHERE   mld_melding_parentkey = pmeldingkey;
   BEGIN
      SELECT   mld_melding_status
        INTO   currentstatus
        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 = 3 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 = 3
            THEN
               newstatus := pstatus;
               eventcode := 'MLDREJ';
            END IF;
         WHEN 2                                                                                             -- Ingevoerd
         THEN
            IF currentstatus IS NULL OR currentstatus = 1
            THEN
               newstatus := pstatus;
               eventcode := 'MLDNEW';
            ELSIF currentstatus = 0
            THEN
               newstatus := pstatus;
               eventcode := 'MLDDOO';
            ELSIF currentstatus = 3 OR currentstatus = 4 OR currentstatus = 7 -- mld_disc_params_keten of mld_forward_if_active
            THEN
               newstatus := pstatus;
               eventcode := 'MLDFWD';
            END IF;
         WHEN 3                                                    -- Ingezien (voor de eerste keer, voordat acceptatie)
         THEN
            IF currentstatus = 2
            THEN
               newstatus := pstatus;
               eventcode := 'MLDING';
            END IF;
         WHEN 4                                                                     -- Geaccepteerd (ongezien of gezien)
         THEN
            IF currentstatus = 2 OR currentstatus = 3
            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 = 3 OR currentstatus = 4 OR currentstatus = 7
            THEN
               newstatus := pstatus;
               eventcode := 'MLDAFM';
            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
          WHERE   mld_melding_key = pmeldingkey;
         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, 'MLDACP');
         END IF;

         -- We know that trackaction doesn't do tracking if eventcode is null
         fac.trackaction (eventcode, pmeldingkey, puserkey, NULL, NULL);
         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'
             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, '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)
    AS
       currentstatus mld_opdr.mld_statusopdr_key%TYPE;
       newstatus mld_opdr.mld_statusopdr_key%TYPE;
       eventcode fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
       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;
    BEGIN
       SELECT   mld_statusopdr_key, mld_typeopdr_key, mld_statusopdr_key_refiat
         INTO   currentstatus, typeopdr_key, statusopdr_key_refiat
         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';
             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
             fac.trackaction (eventcode, popdrachtkey, puserkey, NULL, NULL);
          END IF;
       END IF;
    END;

   -- Stuur alle mogelijke backofficemedewerkers een bericht als de
   -- melding NIEUW 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)
    PROCEDURE notifybackoffice (pmeldingkey IN NUMBER, pcode IN VARCHAR2)
    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_stdmelding.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;
        loms2bp        fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        l2bomode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
        l2b3mode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE;
        l2bpmode       fac_srtnotificatie.fac_srtnotificatie_mode%TYPE := 0;
        lbonotify      mld_disc_params.mld_disc_params_bonotify%TYPE;
        lfunctiecode   fac_functie.fac_functie_code%TYPE;
        lsrtnoticode   fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
        lstatus        mld_melding.mld_melding_status%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;
    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, 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 speod als als new/acp kan voorkomen?
                                m.mld_alg_onroerendgoed_keys,
                                onrg.alg_type,
                                p.prs_afdeling_key,
                                stdm.mld_ins_discipline_key,
                                m.mld_melding_spoed,
                                mdp.mld_disc_params_bonotify,
                                mdp.mld_disc_params_offhours,
                                m.mld_melding_status
                  INTO lloc_key,
                       lonrg_key,
                       lalg_type,
                       lafd_key,
                       ldisc_key,
                       lspoed,
                       lbonotify,
                       lnotifyooh,
                       lstatus
                  FROM mld_melding m,
                       prs_perslid p,
                       mld_stdmelding stdm,
                       ins_tab_discipline d,
                       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
                       -- Tweede notificatie: Melding is net geaccepteerd (4).
                       --                     Naar BOF de MLD2BO notificatie: Alleen als bonotify = 3.
                       --
                       AND ( (    (mld_melding_status = 2 OR mld_melding_status IS NULL)
                              AND pcode != 'MLDACP'
                              AND mdp.mld_disc_params_bonotify > 0)
                            OR (mld_melding_status = 4 AND pcode = 'MLDACP' AND mdp.mld_disc_params_bonotify = 3)
                            OR mld_melding_spoed <= 2)
                       AND stdm.mld_ins_discipline_key = d.ins_discipline_key
                       AND d.ins_discipline_key = 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

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

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

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

                -- 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 MLD2BO of MLD2B3 (evt aangevuld met MLD2BP)
                IF (l2b3mode > 0 OR l2bpmode > 0)AND lstatus = 2 AND pcode != 'MLDACP' 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 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
                END IF;
            EXCEPTION
                WHEN NO_DATA_FOUND
                THEN
                    DBMS_OUTPUT.put_line ('melding zegt: hier hoeft niks 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
                                                NULL);
                    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 = '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,
                                            NULL);
                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 :-)
                                                NULL);
                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 (lnrreceivers);
                ltracking := lcl.l ('lcl_mld_notification_sent_to');
                --ltracking := 'Notitificatie ''{0}'' verstuurd aan {1}';
                DBMS_OUTPUT.put_line (ltracking);
                ltracking := REPLACE (ltracking, '{0}', bericht);
                ltracking := REPLACE (ltracking, '{1}', lreceivers);
                IF l2bpmode > 0
                THEN
                    -- as a modest sign that we (also) issued a priority notification we add an exclamation mark
                    ltracking := '! '||ltracking;
                END IF;
                DBMS_OUTPUT.put_line (ltracking);
                fac.trackaction ('#MLDMAI',
                                 pmeldingkey,
                                 NULL,
                                 NULL,
                                 SUBSTR (ltracking, 1, 2048));                   -- maxlengte van fac_srtnotificatie_oms
            ELSE
                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;
    -- Notificatie meldingen per prioriteit
    PROCEDURE notifyprio (pmeldingkey IN NUMBER, prio IN NUMBER, pperslid_key IN NUMBER)
    AS
        lnotiprio      NUMBER (1);
        lcode          fac_srtnotificatie.fac_srtnotificatie_code%TYPE;
        loms           fac_srtnotificatie.fac_srtnotificatie_oms%TYPE;
        lstatus        mld_melding.mld_melding_status%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 m.mld_melding_status,
               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 lstatus,
               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 = stdm.mld_ins_discipline_key
           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;

        SELECT lcl.x('fac_srtnotificatie_oms', fac_srtnotificatie_key, fac_srtnotificatie_oms)
          INTO loms
          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,
                                            lstatus,
                                            emailnw1,
                                            smsnw1,
                                            NULL,
                                            lnotiprio,
                                            NULL,
                                            NULL);
        ELSIF prio = 2 AND emailnw2 IS NOT NULL
        THEN
            fac.putnotificationsrtprio (pperslid_key,
                                            NULL,
                                            lcode,
                                            pmeldingkey,
                                            bericht,
                                            lstatus,
                                            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,
                                            lstatus,
                                            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;
      ldisc_key mld_stdmelding.mld_ins_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,
                  stdm.mld_ins_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,
                  ldisc_key,
                  lspoed,
                  lopdr_approved,
                  lopdr_kosten,
                  lbestellimiet,
                  lbestellimiet2,
                  lbestellimiet3,
                  lbestellimiet4,
                  lbestellimiet5,
                  lgvs,
                  lrefiat
           FROM   mld_melding m,
                  prs_perslid p,
                  mld_stdmelding stdm,
                  mld_opdr o,
                  mld_typeopdr mto,
                  ins_tab_discipline d,
                  mld_disc_params mdp
          WHERE   m.prs_perslid_key = p.prs_perslid_key
            AND   stdm.mld_stdmelding_key = m.mld_stdmelding_key
            AND   stdm.mld_ins_discipline_key = d.ins_discipline_key
            AND   d.ins_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_stdmelding sm,
                mld_discipline cd,
                alg_locatie l
          WHERE o.mld_melding_key = m.mld_melding_key
            AND 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 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
                 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))))
                         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 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;

   PROCEDURE mld_nextworkflowstep (p_melding_key IN NUMBER, p_success IN NUMBER)
   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_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_initmldstatus            mld_melding.mld_melding_status%TYPE;
   BEGIN
      l_success := p_success;

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

      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, NULL);
         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,
                   disc.ins_srtdiscipline_key,
                   wr.mld_workflowrule_condition,
                   ws.mld_workflowstep_jointype,
                   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;

            l_sql := 'select 1 from mld_melding where 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, NULL);
            --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 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
                -- 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;
             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;
                  -- 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
                        l_initmldstatus := 2;
                     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_melding_opmerking,
                                              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)
                        SELECT l_new_melding_key,
                               mld_melding_module,
                               mld_meldbron_key,
                               mld_alg_locatie_key,
                               mld_alg_onroerendgoed_keys,
                               SYSDATE,
                               mld_melding_onderwerp,
                               mld_melding_omschrijving,
                                  lcl.l ('lcl_mld_wf_generated_by')
                               || p_melding_key
                               || '. '
                               || mld_melding_opmerking,
                               r_nextsteps.mld_stdmelding_key,
                               l_initmldstatus,
                               mld_kosten_klant,
                               mld_melding_document,
                               prs_kostenplaats_key,
                               prs_perslid_key,
                               mld_adres_key,
                               r_nextsteps.mld_workflowstep_key,
                               l_melding_start_key,
                               mld_melding_ordernr,
                               mld_melding_spoed
                          FROM mld_melding, mld_stdmelding msm
                         WHERE mld_melding_key = l_melding_start_key
                               AND msm.mld_stdmelding_key = r_nextsteps.mld_stdmelding_key;

                     fac.trackaction ('MLDNEW',
                                      l_new_melding_key,
                                      NULL,
                                      NULL,
                                      NULL);                               -- ook mld2bo notificatie

                     -- 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.
                             SELECT km.mld_kenmerkmelding_waarde,
                                    k.mld_srtkenmerk_key,
                                    m.mld_melding_key,
                                    k.mld_kenmerk_groep
                               FROM mld_kenmerkmelding km,
                                    mld_kenmerk k,
                                    mld_melding m,
                                    mld_srtkenmerk s
                              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_srtkenmerk_key = s.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
                           ORDER BY 2, 4, 3 DESC;

                        r_mld_kenmerken         c_mld_kenmerken%ROWTYPE;
                        l_new_kenmerk_key       NUMBER (10);
                        wasbezigmetsrtkenmerk   NUMBER (10);
                        wasbezigmetgroep        NUMBER (10);
                        benbezigmetsrtkenmerk   NUMBER (10);
                        benbezigmetgroep        NUMBER (10);
                     BEGIN
                        wasbezigmetsrtkenmerk := -1;
                        wasbezigmetgroep := -1;

                        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;

                              IF (benbezigmetsrtkenmerk <> wasbezigmetsrtkenmerk
                                  OR (benbezigmetsrtkenmerk = wasbezigmetsrtkenmerk
                                      AND benbezigmetgroep <> wasbezigmetgroep))
                              THEN
                                 wasbezigmetsrtkenmerk := benbezigmetsrtkenmerk;
                                 wasbezigmetgroep := benbezigmetgroep;

                                 --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
                                          WHERE 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 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
                                          WHERE 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 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
                                          WHERE 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 kk.mld_kenmerk_niveau = 'T'
                                                AND kk.mld_stdmelding_key =
                                                      r_nextsteps.ins_srtdiscipline_key) x;

                                 --DBMS_OUTPUT.PUT_LINE('ook aanwezig bij de nieuwe, met kenmerk_key');
                                 --DBMS_OUTPUT.PUT_LINE(l_new_kenmerk_key);
                                 --DBMS_OUTPUT.PUT_LINE('dus insert');
                                 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 (
                                    -20000,
                                       '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 = '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;
                  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.
    FUNCTION getlowestobjectuitvoer (p_melding_key IN NUMBER)
        RETURN NUMBER
    AS
       v_ins_key_min_uitvoertijd      NUMBER;
    BEGIN
      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);

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

    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;

    -- 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_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_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_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_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_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_mld_stdmelding_afhankelijk     mld_stdmelding.mld_stdmelding_afhankelijk%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_mldsrtruimte_uitvtijd_object   alg_srtruimte.alg_srtruimte_t_uitvoertijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie
    BEGIN
       SELECT mld_stdmelding_regime,
              COALESCE(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, mld_stdmelding_t_uitvoertijd), -- gegarandeerd gevuld
              mld_stdmelding_t_uitvoertijd,                -- standaard uitvoertijd
              mld_stdmelding_afhankelijk
         INTO v_mld_stdmelding_regime,
              v_uitvoertijd_object,
              v_uitvoertijd_object_s,
              v_mld_stdmelding_afhankelijk
         FROM mld_stdmelding msm
        WHERE msm.mld_stdmelding_key = stdm_key;

       IF v_mld_stdmelding_afhankelijk = 1 AND ins_key IS NOT NULL
       THEN
          SELECT d.ins_deel_t_uitvoertijd
            INTO l_insdeel_uitvoertijd_object
            FROM ins_deel d
           WHERE d.ins_deel_key = ins_key;
          v_uitvoertijd_object.tijdsduur := COALESCE(l_insdeel_uitvoertijd_object.tijdsduur, v_uitvoertijd_object_s.tijdsduur);
          IF l_insdeel_uitvoertijd_object.tijdsduur IS NOT NULL
          THEN
             v_uitvoertijd_object.eenheid := l_insdeel_uitvoertijd_object.eenheid;
          ELSE
             v_uitvoertijd_object.eenheid := v_uitvoertijd_object_s.eenheid;
          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 sr.alg_srtruimte_t_uitvoertijd,
                 ssr.mld_stdmsrtruimte_t_uitvtijd,
                 COALESCE(ssr.mld_stdmsrtruimte_regime, v_mld_stdmelding_regime)  -- optioneel nog srtruimte-afhankelijk afwijkend regime
            INTO l_srtruimte_uitvoertijd_object,
                 l_mldsrtruimte_uitvtijd_object,
                 v_mld_stdmelding_regime
            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 = alg_key;

           -- Uitvoertijd van de srtruimte nemen.
          v_uitvoertijd_object.tijdsduur := COALESCE(l_mldsrtruimte_uitvtijd_object.tijdsduur, l_srtruimte_uitvoertijd_object.tijdsduur, v_uitvoertijd_object_s.tijdsduur);
          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;
          ELSE
             v_uitvoertijd_object.eenheid := v_uitvoertijd_object_s.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 of een verdieping zijn
                -- de tijden van het gebouw gelden
                SELECT alg_gebouw_beginuur, alg_gebouw_einduur, alg_gebouw_werkdagen
                  INTO v_beginuur, v_einduur, v_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;
            END IF;
       END IF;
       RETURN;
    END;

    FUNCTION getacceptdatum (startdate IN DATE, stdm_key IN NUMBER, alg_key IN NUMBER)
        RETURN DATE
    IS
        l_accepttijd_object     mld_stdmelding.mld_stdmelding_t_accepttijd%TYPE := MLD_T_UITVOERTIJD(NULL, NULL); -- contructor initialisatie;
        l_stdmelding_regime     mld_stdmelding.mld_stdmelding_regime%TYPE;
        l_ruimte_key            alg_ruimte.alg_ruimte_key%TYPE;
        l_beginuur              alg_gebouw.alg_gebouw_beginuur%TYPE;
        l_einduur               alg_gebouw.alg_gebouw_einduur%TYPE;
        l_werkdagen             NUMBER;
        l_uitvoertijdtype       VARCHAR2(5);
    BEGIN
       SELECT mld_stdmelding_t_accepttijd,
              mld_stdmelding_regime
         INTO l_accepttijd_object,
              l_stdmelding_regime
         FROM mld_stdmelding
        WHERE mld_stdmelding_key = stdm_key;

       -- mld_stdmelding_regime: 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_accepttijd_object.eenheid = 'D'
       THEN
          l_uitvoertijdtype := 'DAGEN';
       ELSE
          l_uitvoertijdtype := 'UREN';
       END IF;

       -- Hier wordt verder gehandeld obv regime. Ik zou verwachten dat mld_stdmelding_afhankelijk mede bepalend is
       -- Regime kan nu per srtruimte afwijken dus moeten we daar eerst naar toe. De rest van de flow kan dan intact blijven.
       IF (alg_key IS NOT NULL)
       THEN
          -- Als het een ruimte-key is maken we dat hier expliciet
          SELECT MAX(alg_ruimte_key)
            INTO l_ruimte_key
            FROM alg_ruimte r
           WHERE r.alg_ruimte_key = alg_key;

          -- Dan kunnen we met de srtruimte evt afwijkend regime bepalen
          IF l_ruimte_key IS NOT NULL
          THEN
              SELECT COALESCE(ssr.mld_stdmsrtruimte_regime, l_stdmelding_regime)
                INTO l_stdmelding_regime
                FROM alg_ruimte r, mld_stdmsrtruimte ssr
               WHERE r.alg_srtruimte_key = ssr.alg_srtruimte_key(+)
                 AND ssr.mld_stdmelding_key(+) = stdm_key
                 AND r.alg_ruimte_key = l_ruimte_key;
          END IF;
       END IF;
       -- nu weten we het geldende regime

       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_accepttijd_object.tijdsduur, l_uitvoertijdtype);
       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 of een verdieping zijn
             -- de tijden van het gebouw gelden
             SELECT COALESCE (alg_gebouw_beginuur, 0),
                    COALESCE (alg_gebouw_einduur, 24),
                    alg_gebouw_werkdagen
               INTO l_beginuur, l_einduur, l_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;
          END IF;

          RETURN FAC.datumtijdplusuitvoertijd (startdate,
                                               l_accepttijd_object.tijdsduur,
                                               l_uitvoertijdtype,
                                               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_accepttijd_object.tijdsduur,
                                              l_accepttijd_object.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;
      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;
      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.
         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
         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.
      IF (l_fsn_code_last = 'ORDACP' OR l_fsn_code_last = 'ORDRSM') AND
         l_ft_perslid_key = p_prs_key
      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;
      varspoed               mld_melding.mld_melding_spoed%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 ''
      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
           INTO varstdmld,
                vardisc,
                varsrtdisc,
                varonroerendgoedkeys,
                varspoed,
                varonderwerp
           FROM mld_stdmelding stdm,
                ins_tab_discipline d,
                ins_srtdiscipline sd,
                mld_melding m
          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 = p_melding_key;

         s :=
            REPLACE (
               REPLACE (
                  REPLACE (REPLACE (s, '##DISC##', vardisc),
                           '##STDMLD##',
                           varstdmld),
                  '##KEY##',
                  varsrtdisc || TO_CHAR (p_melding_key)),
               '##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);
   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;
BEGIN
   s := ps;

   -- We support substitution of placeholders in the messages
   -- ##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
    IF instr2 (s, '#') > 0
    THEN
        SELECT o.mld_melding_key,
               o.mld_opdr_bedrijfopdr_volgnr,
               o.mld_opdr_omschrijving,
               o.mld_statusopdr_key,
               lcl.x ('mld_typeopdr_omschrijving',
                      o.mld_typeopdr_key,
                      ot.mld_typeopdr_omschrijving)
          INTO lmld_melding_key,
               lbedrijfopdr_volgnr,
               lopdr_omschrijving,
               lopdrstatus,
               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
          INTO varstdmld,
               vardisc,
               varsrtdisc,
               varspoed,
               varonroerendgoedkeys,
               varalglocatiekey
          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 (
                                    s,
                                    '##OPDRKEY##',
                                       varsrtdisc
                                    || TO_CHAR (lmld_melding_key)
                                    || '/'
                                    || TO_CHAR (lbedrijfopdr_volgnr)),
                                '##DISC##',
                                vardisc),
                            '##STDMLD##',
                            varstdmld),
                        '##DESC##',
                        lopdr_omschrijving),
                    '##OPDRTYPE##',
                    varopdrtype),
                '##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,
               mld_srtkenmerk_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 v.mld_melding_key = pmelding_key
      ORDER BY k.mld_kenmerk_volgnummer,
               UPPER(lcl.x ('t.mld_srtkenmerk_omschrijving',
                            t.mld_srtkenmerk_key,
                            mld_srtkenmerk_omschrijving));
   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 IN ('N', 'B') AND r.nmin = 0 AND r.nmax = 1
         -- 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 = 'S'
         -- referentie
         THEN
            waarde := fac.getdomeinwaarde (r.fac_kenmerkdomein_key, TO_NUMBER (waarde));
         END IF;
         -- In het zeldzame geval dat de tekst te lang zou worden slaan we sommige
         -- kenmerken gewoon silent over. Niet ideaal maar toch vrij theoretisch
         IF (COALESCE(LENGTH(builder),0) + LENGTH(r.mld_srtkenmerk_omschrijving) + LENGTH(waarde) < 3990)
         THEN
            builder := builder || CHR(10) || r.mld_srtkenmerk_omschrijving || ': ' || waarde;
         END IF;
      END IF;
   END LOOP;
   RETURN builder;
END;

END mld;
/

REGISTERRUN('$Id$')

#endif // MLD
