<% /*
     $Revision$
     $Id$
*/ %>

<!-- #include file="../Shared/budget.inc" -->
<!-- #include file="../prs/prs.inc" -->

<%
mld = {
        setmeldingstatus:
            function (mld_key, mld_status_key, noti_caller)
            {
                noti_caller = typeof noti_caller == "undefined" ? 1 : (noti_caller ? 1 : 0);
                var sql = "BEGIN mld.setmeldingstatus(" + mld_key + ", " + mld_status_key + ", " + user_key + ", " + noti_caller + "); END;"
                Oracle.Execute(sql);
                // Deze zet de status en doet dan bijpassende tracking en notificatie
                // zou leuk zijn om true of false op te leveren naar gelang de status echt anders is geworden
                mld.process_mjb_score_effects(mld_key);
            },

        setopdrachtstatus:
            function (opdr_key, opdr_status_key, uitvoerende, opdr_note_key, pnotificeren) // een eventuele fac_tracking_key wordt in opdr_note(_key) geregistreerd
            {
              if (typeof pnotificeren == 'undefined')
                pnotificeren = true;
              // Deze zet de status en doet dan bijpassende tracking en notificatie
              var sql = "BEGIN mld.setopdrachtstatus(" + opdr_key + ", "
                                                       + opdr_status_key + ", "
                                                       + user_key + ", "
                                                       + (opdr_note_key>0?opdr_note_key:"NULL") + ","
                                                       + (pnotificeren?1:0)
                                                       + "); END;"
              Oracle.Execute(sql);
              // Nu nog "ORDMLI" (interne uitvoerder) of "ORDMLE" (externe uitvoerder) tracking indien status op uitgegeven (5) wordt gezet
              // Of anders "ORDCAI" (interne uitvoerder) of "ORDCAE" (externe uitvoerder) tracking indien status op annuleren (1) wordt gezet.
              if ((opdr_status_key == 5 || opdr_status_key == 1) && uitvoerende > 0) // Status wordt op 5 gezet indien opdracht niet ter fiattering wordt aangeboden
                mld.trackuitvoerende(opdr_key, uitvoerende, opdr_status_key);
            },

        updatemeldingstatus:
            function (mld_key, closeit)
            {
                 // Functie MLD.updatemeldingstatus(mld_key, close_call, user_key) moet aangeroepen worden na veranderingen in mld_opdr
                 // en als de melding nog niet wordt afgemeld. We weten nog niet of de melding wordt afgemeld of al is afgemeld
                 // 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
                var  sql = "BEGIN mld.updatemeldingstatus (" + mld_key + ", "+closeit+", " + user_key + "); END;";
                Oracle.Execute(sql);
                mld.process_mjb_score_effects(mld_key);
            },

        process_mjb_score_effects:
            function (mld_key)
            {
                // (re)calculate the conditionscores of the releated objects
                if (S("cnd_gebreken_srtdisc_key") > 0) {
                    var cndsql = "BEGIN cnd.process_mjb_score_effects(" + mld_key  + ", " + (user_key>0?user_key:"NULL") + "); END;";
                    Oracle.Execute(cndsql);
                }
            },

        autoapprovefactuur:
            function (opdr_key)
            { // Zijn er bijbehorende facturen die al zijn ingevoerd met de status "Ingevoerd(2)" die nog geapproved moeten worden?
              sql = "SELECT f.fin_factuur_key"
                  + "  FROM fin_factuur f"
                  + " WHERE f.mld_opdr_key = " + opdr_key
                  + "   AND f.fin_factuur_statuses_key = 2"
                  + "   AND f.fin_factuur_verwijder IS NULL" // Verwijderde facturen niet auto approven (VGLD#60654).
                  + " ORDER BY f.fin_factuur_key";
              var oRs = Oracle.Execute(sql);
              while (!oRs.eof)
              { // Autofiatteer de facturen als dat zo ingesteld is.
                // Functie kijkt zelf of autofiatteren aanstaat.
                sql = "BEGIN fin.autoapprovefactuur(" + oRs("fin_factuur_key").Value + "); END;";
                Oracle.Execute(sql);
                oRs.MoveNext();
              }
              oRs.Close();
            },

        // levert de key van de eventuele instemmer van een melding
        // kan ook null zijn, dan is er geen (te bepalen)
        getinstemmer_key:
          function (mld_key)
          {
            var retval;
            var sqlt = "SELECT mld.getinstemmer("+mld_key+") FROM DUAL";
            var oRst = Oracle.Execute(sqlt);
            if (oRst(0).Value)
            {
              retval = oRst(0).Value;
            }
            oRst.close();
            return retval;
          },

        getchildmeldingen:
            function (mld_key)
            { // Als er child meldingen zijn, dan volgen het behandelteam en de behandelaar2 van de child die van de parent.
              // Array child_arr_cont is alleen gevuld bij het opslaan van een vervolgmelding. Dan hier maar een nieuwe array vullen/bepalen.
              var child_arr = [];
              var sql_c = "SELECT mld_melding_key"
                        + "  FROM mld_melding"
                        + " WHERE mld_melding_parentkey = " + mld_key;
              var oRs_c = Oracle.Execute(sql_c);
              while (!oRs_c.eof)
              {
                var child = {mld_key:          oRs_c("mld_melding_key").Value
                            }
                child_arr.push(child);
                oRs_c.MoveNext();
              }
              oRs_c.close();
              return child_arr;
            },

        updatechildren:
            function (child_arr, parentparams)
            { // Zijn er wel child meldingen en is er wel een veld aan te passen?
              var saveBehandelteam = parentparams.saveBehandelteam;
              var saveBehandelaar2 = parentparams.saveBehandelaar2;
              if (child_arr.length == 0 || !(saveBehandelteam || saveBehandelaar2))
                return;

              var setLines = [];
              if (saveBehandelteam)
                setLines.push("mld_ins_discipline_key = " + (parentparams.behandelteam_key > 0? parentparams.behandelteam_key : "NULL"));
              if (saveBehandelaar2)
                setLines.push("mld_melding_behandelaar2_key = " + (parentparams.behandelaar2_key > 0? parentparams.behandelaar2_key : "NULL"));
              var updateSetSql = "UPDATE mld_melding SET " + setLines.join(", ");

              // Behandelaars2 en Behandelteams van de child meldingen moeten die van de parent volgen.
              for (var i = 0; i < child_arr.length; i++)
              {
                if (setLines.length > 0)
                { // Behandelteam en/of behandelaar2 aanpassen.
                  var behsql = updateSetSql
                           + " WHERE mld_melding_key = " + child_arr[i].mld_key;
                  Oracle.Execute(behsql);
                }

                // Na de update nu alleen nog de tracking en/of notificaties.
                if (saveBehandelteam)
                  mld.trackAndNotifyBehandelteam(child_arr[i].mld_key, parentparams.behandelteam_key, true); // Tracking en notificatie child. Wijziging gedaan door _SYSTEM
                if (saveBehandelaar2)
                  mld.trackbehandelaar2(child_arr[i].mld_key, parentparams.behandelaar2_key, false); // Tracking child. Een child kan geen gekoppelde atie zijn.
              }
            },

        acceptmelding:
            function (mld_key, params)
            { // Accepteren van een melding.
              var saveBehandelaar = params.saveBehandelaar;
              var saveBehandelaar2 = params.saveBehandelaar2;
              var saveBehandelteam = params.saveBehandelteam;
              var remark = params.remark;
              var behandelaar_key = params.handler;
              var behandelaar2_key = params.processor;
              var behandelteam_key = params.treatmentteam;
              var canFOwrite = params.canFOwrite;
              var canBOwrite = params.canBOwrite;
              var noValidateToken = params.noValidateToken;
              var fields = myJSON.parse(JSON.stringify(params.datefields)); // Clone datefields without reference (Deep copy).

              if (saveBehandelaar)
                fields.push({ dbs: "mld_melding_behandelaar_key", typ: "key", val: behandelaar_key /* afzonderlijke tracking */ });
              if (saveBehandelteam)
                fields.push({ dbs: "mld_ins_discipline_key", typ: "key", val: behandelteam_key, foreign: "mld_discipline" /* afzonderlijke tracking */ });
              if (saveBehandelaar2)
                fields.push({ dbs: "mld_melding_behandelaar2_key", typ: "key", val: behandelaar2_key /* afzonderlijke tracking */ });

              if (fields.length)
              {
                var mldUpd = buildTrackingUpdate("mld_melding", " mld_melding_key = " + mld_key, fields, { noValidateToken: noValidateToken });

                // Opslaan van de gewijzigde data.
                var err = Oracle.Execute(mldUpd.sql, true);
                if (err.friendlyMsg)
                  abort_with_warning(err.friendlyMsg);

                if (mldUpd.trackarray.length)
                  mld.trackmeldingupdate(mld_key, L("lcl_mld_is_mldupd") + "\n" + mldUpd.trackarray.join("\n"));
              }


              // Alleen als behandelaar, behandelaar2 en/of behandelteam zijn opgeslagen dit tracken.
              // Als behandelaar_key == user_key dan wel tracking maar geen notificatie
              if (saveBehandelaar)
                  mld.trackbehandelaar(mld_key, behandelaar_key, behandelaar_key == user_key);
              if (saveBehandelaar2)
                  mld.trackbehandelaar2(mld_key, behandelaar2_key, behandelaar2_key == user_key);
              if (saveBehandelteam)
                  mld.trackAndNotifyBehandelteam(mld_key, behandelteam_key);

              if (remark)
              {
                mld_note_save(mld_key,
                              remark,
                              {    isFE: false,
                                zichtFE: true, /* altijd */
                                noValidateToken: noValidateToken
                              });
              }

              if (canBOwrite)
              {
                // Zetten van de status op geaccepteerd.
                mld.setmeldingstatus(mld_key, 4);
                // Geen message "De melding PXXX/Y is geaccepteerd" meer geven (AADS#20339)
              }
              else if (canFOwrite)
              {
                mld.setmeldingstatus(mld_key, 0);
              }

              // Het behandelteam en de behandelaar2 van het child zijn gelijk aan die van de parent. Ze zijn gelijk gezet bij het koppelen.
              // Als die van de parent aangepast moeten worden geldt dat dus ook voor het child.
              if (saveBehandelaar2 || saveBehandelteam)
              {
                // Als er child meldingen zijn, dan volgen het behandelteam en de behandelaar2 van de child die van de parent.
                var child_arr = mld.getchildmeldingen(mld_key);
                var parentparams = {saveBehandelteam: saveBehandelteam,
                                    saveBehandelaar2: saveBehandelaar2,
                                    behandelteam_key: behandelteam_key,
                                    behandelaar2_key: behandelaar2_key
                                   };
                mld.updatechildren(child_arr, parentparams);
              }
            },

        // Afronden insert/update van een melding.
        finishmeldingiu:
            function (mld_key)
            { // Eventuele (gewijzigde) objecten zijn nu ook opgeslagen.
              // Nu kan de definitieve mld_melding.mld_melding_einddatum_std en mld_melding.mld_melding_t_uitvoertijd bepaald en gezet worden.

              // 1) Eerst de mld_melding_einddatum_std
              // In update mag database functie mld.geteinddatum() zelf niet gebruikt worden omdat deze ook in de trigger wordt aangeroepen.
              // De foutmelding is dan: ORA-04091: table UWVA.MLD_MELDING is mutating, trigger/function may not see it, ORA-06512: at "UWVA.MLD", line 966
              // Daarom eerst bepalen en dan zetten.
              var sql = "SELECT mld.geteinddatum(mld_melding_key) einddatum"
                      + "     , mld_melding_einddatum_std"
                      + "  FROM mld_melding"
                      + " WHERE mld_melding_key = " + mld_key;
              var oRs = Oracle.Execute(sql);
              var einddatum = new Date(oRs("einddatum").Value);
              oRs.Close();

              sql = "UPDATE mld_melding"
                  + "   SET mld_melding_einddatum_std = " + einddatum.toSQL(true)
                  + " WHERE mld_melding_key = " + mld_key;
              Oracle.Execute(sql);

              // 2) Nu de mld_melding_t_uitvoertijd
              sql = "SELECT uitv.std_uitv_type.tijdsduur std_tijdsduur"
                  + "     , uitv.std_uitv_type.eenheid std_eenheid"
                  + "     , uitv.uitv_type.tijdsduur old_tijdsduur"
                  + "     , uitv.uitv_type.eenheid old_eenheid"
                  + "  FROM (SELECT mld.getstduitvoer (mld_melding_key) std_uitv_type"
                  + "             , mld_melding_t_uitvoertijd uitv_type"
                  + "          FROM mld_melding"
                  + "         WHERE mld_melding_key = " + mld_key + ") uitv";
              oRs = Oracle.Execute(sql);
              var std_uitvoertijd = oRs("std_tijdsduur").Value;
              var std_uitvoertijd_eenheid = oRs("std_eenheid").Value;
              var old_uitvoertijd = oRs("old_tijdsduur").Value;
              var old_uitvoertijd_eenheid = oRs("old_eenheid").Value;
              oRs.Close();

              sql = "UPDATE mld_melding m"
                  + "   SET m.mld_melding_t_uitvoertijd.tijdsduur = " + std_uitvoertijd
                  + "     , m.mld_melding_t_uitvoertijd.eenheid = " + safe.quoted_sql(std_uitvoertijd_eenheid)
                  + " WHERE m.mld_melding_key = " + mld_key;
              Oracle.Execute(sql);
            },

        trackAndNotifyBehandelteam:
            function (mld_key, behandelteam_key, as_system)
            {
                var as_system = (typeof as_system == 'undefined' ? false : as_system)

                var sql = "SELECT ins_discipline_omschrijving"
                        + "  FROM mld_discipline"
                        + " WHERE ins_discipline_key = " + behandelteam_key;
                var loRs = Oracle.Execute(sql);
                if ( !loRs.eof )
                    var behandelteam_str = L("lcl_mld_is_mldbhg_to").format(loRs("ins_discipline_omschrijving").Value);
                else // Komt niet voor?
                    var behandelteam_str = L("lcl_mld_is_mldbhg_none");
                loRs.close();
                // Met '#' want melder hoort geen MLDBHG te krijgen, die is voor BOF
                shared.trackaction("#MLDBHG", mld_key, behandelteam_str, behandelteam_key, as_system);  //MLDBHG=ins_discipline_key
                mld.notifybehandelteam(mld_key, behandelteam_key);
            },

        notifybehandelteam:
            function (mld_key, mld_ins_discipline_key, use_disc)
            { // Notificeer BO medewerkers van het behandelteam over een behandelteam wijziging
                if (mld_ins_discipline_key > 0)
                    Oracle.Execute("BEGIN mld.notifybackoffice (" + mld_key + ", 'MLDBHG', " + (use_disc? "3, " + mld_ins_discipline_key : "2") + "); END;");
            },

        trackbehandelaar:
            function (mld_key, behandelaar_key, nonoti) // Nonoti onderdrukt notificatie
            {
                var sql = "SELECT pf.prs_perslid_naam_full FROM prs_v_perslid_fullnames_all pf "
                        + "WHERE prs_perslid_key = " + behandelaar_key;
                var loRs = Oracle.Execute(sql);
                if (!loRs.eof)
                    var behandelaar_str = L("lcl_mld_is_mldbeh_to").format(loRs(0).Value);
                else
                    var behandelaar_str = L("lcl_mld_is_mldbeh_none");
                loRs.close();
                shared.trackaction((nonoti?"#":"") + "MLDBEH", mld_key, behandelaar_str, behandelaar_key); //MLDBEH=prs_perslid_key
            },

        trackbehandelaar2:
            function (mld_key, behandelaar2_key, nonoti) // Nonoti onderdrukt notificatie
            {
                var sql = "SELECT pf.prs_perslid_naam_full FROM prs_v_perslid_fullnames_all pf"
                        + " WHERE prs_perslid_key = " + behandelaar2_key;
                var loRs = Oracle.Execute(sql);
                if (!loRs.eof)
                    var behandelaar2_str = L("lcl_mld_is_mldabh_to").format(loRs(0).Value);
                else
                    var behandelaar2_str = L("lcl_mld_is_mldabh_none");
                loRs.close();
                shared.trackaction((nonoti?"#":"") + "MLDABH", mld_key, behandelaar2_str, behandelaar2_key); //MLDABH=prs_perslid_key
            },

        notifybehandelaar2:
            function (mld_key, behandelaar2_key) // Geen tracking, alleen notificeren (zoals met tracking gebeurt in fac.notifytracking())
            {
                if (behandelaar2_key > 0)
                    Oracle.Execute("BEGIN mld.notifybehandelaar (" + behandelaar2_key + ", 'MLDAB2', " + mld_key + "); END;");
            },

        trackmeldingupdate:
            // Let op: dit moet wellicht niet altijd (aangeroepen na save)
            function (mld_key, ptxt)
            {
                return shared.trackaction("MLDUPD", mld_key, ptxt);
            },

        trackmeldingforward:
            function (mld_key)
            {
                return shared.trackaction("MLDFWD", mld_key);
            },

        trackmeldingaddnote:
            // Let op: dit moet wellicht niet altijd (aangeroepen na save)
            function (mld_key, ptxt)
            {
                return shared.trackaction("MLDNOT", mld_key, ptxt);
            },

        trackopdrachtaddnote:
            // Let op: dit moet wellicht niet altijd (aangeroepen na save)
            function (mld_key, ptxt)
            {
                return shared.trackaction("ORDNOB", mld_key, ptxt);
            },

        trackuitvoerende:
            function (opdr_key, uitvoerende_key, status)
            {
              // Is uitvoerende intern of extern?
              sql = "SELECT u.intern"
                  + " FROM mld_v_uitvoerende u"
                  + " WHERE u.mld_uitvoerende_key = " + uitvoerende_key
              var oRs = Oracle.Execute(sql);
              // type "P" (persoon) is intern en type "B" (bedrijf) is afhankelijk van "prs_bedrijf_intern" intern of extern.
              var intern = (oRs("intern").Value);
              oRs.close();

              if (status == 5)
                  shared.trackaction((intern? "ORDMLI" : "ORDMLE"), opdr_key, null, uitvoerende_key);  //ORDMLI=prs_perslid_key, ORDMLE=prs_bedrijf_key
              else if (status == 1)
                  shared.trackaction((intern? "ORDCAI" : "ORDCAE"), opdr_key, null, uitvoerende_key);  //ORDCAI=prs_perslid_key, ORDCAE=prs_bedrijf_key
            },

        trackopdrachtupdate:
            function (opdr_key, ptxt)
            {
               return shared.trackaction("ORDUPD", opdr_key, ptxt);
            },

        trackopdrplandatumupdate:
            function (opdr_key, ptxt)
            {
               return shared.trackaction("ORDPLD", opdr_key, ptxt);
            },

        trackopdrplandatum2update:
            function (opdr_key, ptxt)
            {
               return shared.trackaction("ORDPL2", opdr_key, ptxt);
            },

        trackopdreinddatumupdate:
            function (opdr_key, ptxt)
            {
               return shared.trackaction("ORDDAT", opdr_key, ptxt);
            },

        trackmeldingafronden:
            function (mld_key, ptxt)
            {
              return shared.trackaction("MLDAFR", mld_key, ptxt);
            },

        trackmeldingverwerken:
            function (mld_key, ptxt)
            {
              return shared.trackaction("MLDVER", mld_key, ptxt);
            },

        opdr_hltrsm:
            function (opdr_key, params)
            {
              if (params.resume)
              { // Als er kenmerken verplicht zijn bij het onderbreken, dan moeten deze weer leeg gemaakt worden bij het hervatten.
                var kenmSql = " SELECT k.mld_kenmerk_key"
                            + "      , ko.mld_kenmerkopdr_key"
                            + "   FROM mld_kenmerkopdr ko"
                            + "      , mld_kenmerk k"
                            + "  WHERE k.mld_kenmerk_key = ko.mld_kenmerk_key"
                            + "    AND mld_kenmerkopdr_verwijder IS NULL"
                            + "    AND k.mld_kenmerk_onderbreken = 2" // Onderbreken kenmerken wissen bij hervatten.
                            + "    AND mld_opdr_key = " + opdr_key;
                var oRs = Oracle.Execute(kenmSql);
                while (!oRs.eof)
                { // Kenmerk weer leeg maken (verwijderen).
                  var delSql = "DELETE"
                             + "  FROM mld_kenmerkopdr"
                             + " WHERE mld_opdr_key = " + opdr_key
                             + "   AND mld_kenmerk_key = " + oRs("mld_kenmerk_key").Value
                             + "   AND mld_kenmerkopdr_key = " + oRs("mld_kenmerkopdr_key").Value;
                  Oracle.Execute(delSql);
                  oRs.MoveNext();
                }
                oRs.Close();

                // Als er al een opdracht actief is en sequentieel&2, dan moet de actieve opdracht onderbroken worden.
                // Als de opdrachten niet sequentieel uitgevoerd moeten worden, dan wordt er ook geen actieve opdracht gevonden.
                var activeopdr = mld.getactiveopdracht(opdr_key);
                if (activeopdr.opdr_key > 0)
                { // De actieve opdracht onderbreken.
                  shared.trackaction("ORDHLT", activeopdr.opdr_key);
                  Oracle.Execute("UPDATE mld_opdr SET mld_opdr_halted = 1 WHERE mld_opdr_key = " + activeopdr.opdr_key);
                }
              }

              var sql = "SELECT mld_opdr_halted"
                      + "  FROM mld_opdr"
                      + " WHERE mld_opdr_key = " + opdr_key;
              var oRs = Oracle.Execute(sql);
              var halted = oRs("mld_opdr_halted").Value == 1;
              oRs.Close();

              if (params.halt && (!halted || params.forcetracking))
              {
                Oracle.Execute("UPDATE mld_opdr SET mld_opdr_halted = 1 WHERE mld_opdr_key = " + opdr_key);
                var tracking_key = shared.trackaction("ORDHLT", opdr_key);
              }
              if (params.resume && (halted || params.forcetracking))
              {
                Oracle.Execute("UPDATE mld_opdr SET mld_opdr_halted = 0 WHERE mld_opdr_key = " + opdr_key);
                var tracking_key = shared.trackaction("ORDRSM", opdr_key);
              }
              return tracking_key;
            },

        saveobjects:
            function (mld_key, obj_arr, deelsrtcont_key)
            { // Objecten die worden verwijderd bepalen i.v.m. tracking.
              var plaatsaanduiding = (S("prs_wpprefix_objectid") == 1
                                     ? " CASE"
                                       + " WHEN o.prs_werkplek_omschrijving IS NOT NULL"
                                       + " THEN ' ' || o.prs_werkplek_omschrijving"
                                       + " ELSE ''"
                                       + " END"
                                     : "''");
              var sql = "SELECT ins_deel_omschrijving || " + plaatsaanduiding + " || ' (' || " + lcl.xsql('s.ins_srtdeel_omschrijving', 's.ins_srtdeel_key') + " || ')' deel "
                      + "  FROM mld_melding_object mo"
                      + "     , ins_deel d"
                      + "     , ins_srtdeel s"
                      + "     , ins_v_alg_overzicht o"
                      + " WHERE mo.ins_deel_key = d.ins_deel_key"
                      + "   AND d.ins_srtdeel_key = s.ins_srtdeel_key"
                      + "   AND d.ins_alg_ruimte_key = o.alg_onroerendgoed_keys(+)"
                      + "   AND d.ins_alg_ruimte_type = o.alg_onroerendgoed_type(+)"
                      + "   AND d.ins_alg_locatie_key = o.alg_locatie_key(+)"
                      + "   AND mo.mld_melding_key = " + mld_key
                      + (obj_arr.length > 0
                        ? " AND d.ins_deel_key NOT IN (" + obj_arr.join(",") + ")"
                        : "");
              var oRs = Oracle.Execute(sql);
              var first = true;
              var deleted_objects = "";
              while(!oRs.eof)
              {
                if (first)
                {
                  deleted_objects = L("lcl_mld_del_obj") + ": ";
                  first = false;
                }
                else
                  deleted_objects += ",\n";
                deleted_objects += oRs("deel").Value;

                oRs.MoveNext();
              }
              oRs.Close();

              var added_objects = "";
              if (obj_arr.length > 0)
              {
                // Objecten die worden toegevoegd bepalen i.v.m. tracking.
                sql = "SELECT ins_deel_omschrijving || " + plaatsaanduiding + " || ' (' || " + lcl.xsql('s.ins_srtdeel_omschrijving', 's.ins_srtdeel_key') + " || ')' deel "
                    + "  FROM ins_deel d"
                    + "     , ins_srtdeel s"
                    + "     , ins_v_alg_overzicht o"
                    + " WHERE d.ins_srtdeel_key = s.ins_srtdeel_key"
                    + "   AND d.ins_deel_key NOT IN (SELECT mo.ins_deel_key FROM mld_melding_object mo WHERE mo.mld_melding_key = " + mld_key + ")"
                    + "   AND d.ins_alg_ruimte_key = o.alg_onroerendgoed_keys(+)"
                    + "   AND d.ins_alg_ruimte_type = o.alg_onroerendgoed_type(+)"
                    + "   AND d.ins_alg_locatie_key = o.alg_locatie_key(+)"
                    + (obj_arr.length > 0
                      ? " AND d.ins_deel_key IN (" + obj_arr.join(",") + ")"
                      : "");
                oRs = Oracle.Execute(sql);
                first = true;
                while(!oRs.eof)
                {
                  if (first)
                  {
                    added_objects = L("lcl_mld_add_obj") + ": ";
                    first = false;
                  }
                  else
                    added_objects += ",\n";
                  added_objects += oRs("deel").Value;

                  oRs.MoveNext();
                }
                oRs.Close();
              }

              // Voor MJOB taken geldt:
              // Als de verwijderde objecten taken hebben, dan moet de status van die taken van "Ter uitvoering(3)" teruggezet worden naar "Gaccepteerd(2)".
              // Taken die gereed gemeld en voltooid zijn, worden niet in status terug gezet. Deze zijn al afgerond.
              sql = " SELECT mo.ins_deel_key"
                  + "      , mo.ins_deelsrtcontrole_key"
                  + "   FROM mld_melding m"
                  + "      , mld_melding_object mo"
                  + "      , ins_deelsrtcontrole idsc"
                  + "      , ins_srtcontrole isc"
                  + "      , ctr_disc_params cdp"
                  + "  WHERE m.mld_melding_key = mo.mld_melding_key"
                  + "    AND mo.ins_deelsrtcontrole_key = idsc.ins_deelsrtcontrole_key"
                  + "    AND idsc.ins_srtcontrole_key = isc.ins_srtcontrole_key"
                  + "    AND isc.ctr_discipline_key = cdp.ctr_ins_discipline_key"
                  + "    AND mo.mld_melding_key = " + mld_key
                  + "    AND mo.ins_deelsrtcontrole_key IS NOT NULL" // Alleen de objecten met taken.
                  + "    AND idsc.ins_deelsrtcontrole_status = 3"    // Alleen taken met status "Ter uitvoering(3)".
                  + "    AND cdp.ctr_disc_params_ismjob = 1"         // Alleen MJOB taken.
                  + (obj_arr.length != 0
                    ? "  AND mo.ins_deel_key NOT IN (" + obj_arr.join(",") + ")" // Uitgezonderd de objecten die niet zijn verwijderd.
                    : "");
              oRs = Oracle.Execute(sql);
              while(!oRs.eof)
              { // Het is MJOB en de taak heeft de status "Ter uitvoering(3)".
                // Status terugzetten van "Ter uitvoering(3)" naar "Gaccepteerd(2)" en geef de bijpassende tracking en notificatie.
                // I.p.v. ins.setinspectstatus aan te roepen, roepen we zelf de database procedure aan.
                // Dan hoeven we hier het bestand ins.inc niet te includen.
                //ins.setinspectstatus(oRs("ins_deelsrtcontrole_key").Value, 2); // Geaccordeerd(2).
                var sql = "BEGIN ins.setinspectstatus(" + oRs("ins_deelsrtcontrole_key").Value + ", 2, " + user_key + "); END;"
                Oracle.Execute(sql);

                oRs.MoveNext();
              }
              oRs.Close();

              // Objecten verwijderen uit de melding.
              sql = " DELETE mld_melding_object"
                  + "  WHERE mld_melding_key = " + mld_key
                  + (obj_arr.length != 0
                    ? "    AND ins_deel_key NOT IN (" + obj_arr.join(",") + ")"
                    : "");
              Oracle.Execute(sql);

              // Objecten opslaan.
              if (obj_arr.length != 0)
              {
                sql = "INSERT INTO mld_melding_object (mld_melding_key"
                    + (deelsrtcont_key > 0
                      ? "            , ins_deelsrtcontrole_key"
                      : "")
                    + "                              , ins_deel_key)"
                    + " SELECT " + mld_key
                    + (deelsrtcont_key > 0
                      ? "    , " + deelsrtcont_key
                      : "")
                    + "      , ins_deel_key"
                    + "   FROM ins_deel"
                    + "  WHERE ins_deel_verwijder IS NULL"
                    + "    AND ins_deel_key IN (" + obj_arr.join(",") + ")"
                    + "    AND (ins_deel_vervaldatum IS NULL OR ins_deel_vervaldatum > TRUNC(SYSDATE))"
                    + "    AND ins_deel_key NOT IN"
                      + " (SELECT ins_deel_key FROM mld_v_aanwezigmelding_object WHERE mld_melding_key = " + mld_key + ")";
                Oracle.Execute(sql);
              }
              // Track tekst teruggeven.
              return (deleted_objects != ""? deleted_objects + "\n" : "") + added_objects;
            },

        notifyopdrachtgoedkeuren:
            function (opdr_key)
            { // Alle goedkeurders een notificatie (ORD2GO) sturen voor de volgend goedkeuring.
              Oracle.Execute("BEGIN mld.notifyopdrgoedkeurders(" + opdr_key + "); END;");
            },

        addautoorder:
            // Trap automatische opdrachten af bij een nieuwe melding als dat zo geconfigureerd is
            // We weten dat deze niks doet als de melding (nog) concept is
            function (p_mld_key)
            {
                  var sql = "BEGIN mld.mld_addautoorder(" + p_mld_key + "); END;";
                  Oracle.Execute(sql);
            },

        nextworkflowstep:
            // Proceed with the next step of the workflow
            // p_mld_key: key of the call to be continued
            // p_success gives state of the executed call:
            //  0 = rejected (deprecated since 4.70)
            //  1 = completed
            // -1 = initial (the originating call)
            function (p_mld_key, p_success, p_has_user_key)
            {
              if (S("mld_enable_workflow") == 1) {
                var sql = "BEGIN mld.mld_nextworkflowstep (" + p_mld_key + ", " + p_success + ", " + (p_has_user_key ? user_key : "NULL") + "); END;";
                Oracle.Execute(sql);
              }
            },

        executedworkflowsteps:
            // Haal alle mld_melding keys op van de workflow tot deze melding.
            // Met include_self wordt de huidige melding ook toegevoegd aan het array.
            function (p_mld_key, include_self)
            {
                function set_label(p_key)
                {
                    return shared.mld_prefix(p_key) + p_key + " ({0})";
                }

                function workflowchain_reverse(pstart_key, current_workflowstep_key, pkeylist)
                {
                    // Doorloop directe voorgangers van current_workflowstep_key
                    var sql_b = "SELECT m.mld_melding_key"
                              + "     , r.mld_workflowstep_key previous_step"
                              + "  FROM mld_melding m"
                              + "     , mld_workflowrule r"
                              + " WHERE m.mld_workflowstep_key = r.mld_workflowstep_key"
                              + "   AND m.mld_melding_start_key = " + pstart_key
                              + "   AND r.mld_workflowstep_next_key = " + current_workflowstep_key;
                    var oRs_b = Oracle.Execute(sql_b);
                    while (!oRs_b.eof)
                    {
                        var mkey = oRs_b("mld_melding_key").Value;
                        if (!(mkey in pkeylist))
                        {
                            pkeylist[mkey] = set_label(mkey);
                            workflowchain_reverse(pstart_key, oRs_b("previous_step").Value, pkeylist);
                        }
                        oRs_b.MoveNext();
                    }
                    oRs_b.Close();
                }

                function workflow_attachments(pmld_key)
                {
                    var kenmerken = [];
                    var sql_b = "SELECT k.mld_kenmerk_key"
                              + "     , k.mld_srtkenmerk_key"
                              + "     , COALESCE(k.mld_kenmerk_omschrijving, sk.mld_srtkenmerk_omschrijving) k_desc"
                              + "  FROM mld_kenmerk k"
                              + "     , mld_srtkenmerk sk"
                              + " WHERE k.mld_srtkenmerk_key = sk.mld_srtkenmerk_key"
                              + "   AND EXISTS (SELECT 'x'"
                              + "                 FROM fac_bijlagen"
                              + "                WHERE fac_bijlagen_kenmerk_key = k.mld_kenmerk_key"
                              + "                  AND fac_bijlagen_module = 'MLD'"
                              + "                  AND fac_bijlagen_verwijder IS NULL"
                              + "                  AND fac_bijlagen_refkey = " + pmld_key + ")";
                    var oRs_b = Oracle.Execute(sql_b);
                    while (!oRs_b.eof)
                    {
                        kenmerken.push({ km_key:    oRs_b("mld_kenmerk_key").Value
                                       , srtkm_key: oRs_b("mld_srtkenmerk_key").Value
                                       , k_desc:    oRs_b("k_desc").Value
                                       });
                        oRs_b.MoveNext();
                    }
                    oRs_b.Close();
                    return kenmerken;
                }

                //
                var parent_list = []; // Ook knoppen met bijlagen van de 'parent'-chain
                if (include_self)
                {
                    parent_list.push ( { label: set_label(p_mld_key)
                                       , module: "MLD"
                                       , key: p_mld_key
                                       }
                                     );
                }
                if (S("mld_show_parent_attachments"))
                {
                    var sql = "SELECT w.mld_workflowstep_attachments"
                            + "     , m.mld_workflowstep_key"
                            + "     , m.mld_melding_start_key"
                            + "  FROM mld_melding m"
                            + "     , mld_workflowstep w"
                            + " WHERE m.mld_melding_key = " + p_mld_key
                            + "   AND m.mld_workflowstep_key = w.mld_workflowstep_key";
                    var oRs = Oracle.Execute(sql);
                    if (!oRs.eof)
                    {
                        var start_key = oRs("mld_melding_start_key").Value;
                        var show_attach  = oRs("mld_workflowstep_attachments").Value;
                        var cur_step_key = oRs("mld_workflowstep_key").Value;

                        if (show_attach > 0)
                        {
                            if (show_attach == 2)
                            {   // .. en alle voorgaande meldingen.
                                var pkeylist = {};
                                workflowchain_reverse(start_key, cur_step_key, pkeylist); // pkeylist is een object en dus by-reference parameter
                                for (mkey in pkeylist)
                                {
                                    parent_list.push ( { label:  pkeylist[mkey]
                                                       , module: "MLD"
                                                       , key: mkey
                                                       , kenmerken:  workflow_attachments(mkey)
                                                       }
                                                     );
                                }
                            }
                            else
                            {
                                if (show_attach == 1)
                                {   // .. en startmelding
                                    var sql_a = "SELECT mld_melding_key"
                                              + "  FROM mld_melding"
                                              + " WHERE mld_melding_key = " + start_key
                                              + "   AND mld_melding_key <> " + p_mld_key;
                                }
                                else if (show_attach == 3)
                                {   // .. en alle meldingen van de workflow
                                    var sql_a = "SELECT mld_melding_key"
                                              + "  FROM mld_melding"
                                              + " WHERE mld_melding_start_key = " + start_key
                                              + "   AND mld_melding_key <> " + p_mld_key;
                                }
                                var oRs_a = Oracle.Execute(sql_a);
                                while (!oRs_a.eof)
                                {
                                    var mkey = oRs_a("mld_melding_key").Value;
                                    parent_list.push ( { label:  set_label(mkey)
                                                       , module:  "MLD"
                                                       , key: mkey
                                                       , kenmerken: workflow_attachments(mkey)
                                                       }
                                                     );
                                    oRs_a.MoveNext();
                                }
                                oRs_a.Close();
                            }
                        }
                    }
                    oRs.Close();
                }
                return parent_list;
            },

        notifyprio:
            function (mld_key, prio)
            { // Notify relevant to prio;
              // mld_disc_params.mld_disc_params_emailnwX where X in [1-4]
              Oracle.Execute("BEGIN mld.notifyprio(" + mld_key + ", " + prio + ", " + user_key + "); END;");
            },

        gettrackdate_sql:
            function (tcode)
            {
              return "(SELECT t.fac_tracking_datum "
                     + " FROM fac_tracking t, fac_srtnotificatie st"
                     + " WHERE t.fac_srtnotificatie_key = st.fac_srtnotificatie_key"
                     + " AND t.fac_tracking_refkey = m.mld_melding_key"
                     + " AND st.fac_srtnotificatie_code = " + safe.quoted_sql(tcode) + ")";
            },

        gettrackuser_sql:
            function (tcode)
            {
              return " (SELECT t.prs_perslid_key "
                     + "  FROM fac_tracking t, fac_srtnotificatie st"
                     + " WHERE t.fac_srtnotificatie_key = st.fac_srtnotificatie_key"
                     + "   AND t.fac_tracking_refkey = m.mld_melding_key"
                     + "   AND st.fac_srtnotificatie_code = " + safe.quoted_sql(tcode) + ")";
            },

        getFwdType:
            function (mld_key, this_mld, mld_melding)
            {
              this_mld    = this_mld    || mld.func_enabled_melding(mld_key);
              mld_melding = mld_melding || mld.mld_melding_info(mld_key);

              // Let op; dit is geen rechten check
              // Hier wordt slechts status-afhankelijk bekeken welke types doorsturen er evt. mogelijk zijn;
              // fwdType & 1 -> Vakgroep wijzigen (= Corrigeren)
              // fwdType & 2 -> Behandelteam wijzigen (= Doorsturen)

              var fwdInfo = { "fwdType": 0 };

              function hasProcInDisc(vakgroep, behandelteam)
              { // Andere vakgroepen waar hetzelfde behandelteam ingezet kan worden zijn:
                // 1) De vakgroepen met het hetzelfde bahandelteam.
                // 2) De vakgroepen met alle behandelteams (geen enkel mld_discipline_discipline record).
                var sql = "SELECT mld_discipline_key1 ins_discipline_key" // 1)
                        + "  FROM mld_discipline_discipline"
                        + " WHERE mld_discipline_key2 = " + behandelteam
                        + "   AND mld_discipline_key1 != " + vakgroep
                        + " UNION"
                        + "  SELECT ins_discipline_key" // 2)
                        + "    FROM ins_tab_discipline"
                        + "       , mld_disc_params"
                        + "   WHERE ins_tab_discipline.ins_discipline_key = mld_disc_params.mld_ins_discipline_key(+)"
                        + "     AND mld_disc_params.mld_disc_params_srtgroep IN (5, 7)"
                        + "     AND ins_tab_discipline.ins_discipline_module = 'MLD'"
                        + "     AND ins_discipline_verwijder IS NULL"
                        + "     AND NOT EXISTS (SELECT mld_discipline_key1"
                        + "                       FROM mld_discipline_discipline"
                        + "                      WHERE mld_discipline_key1 = ins_discipline_key)"
                        + "ORDER BY ins_discipline_key";
                var oRs = Oracle.Execute(sql);
                hasProcInDisc = !oRs.eof;
                oRs.Close();
                return hasProcInDisc;
              }

              switch (mld_melding.mld_status)
              {
                case 0: // Pending
                case 1: // Afgewezen
                case 6: // Verwerkt                                      // [canForward = false && canForwardTeam = false && canFixMelding = false]
                  break;
                case 2: // Nieuw
                case 3: // Te accepteren
                  // Ik mag alleen corrigeren of doorsturen als er andere vakgroepen zijn waar hetzelfde behandelteam ingezet kan worden.
                  if (mld_melding.mld_ins_discipline_key > 0 && !hasProcInDisc(mld_melding.disc_key, mld_melding.mld_ins_discipline_key))            // Doorsturen  (Behandelteam doorsturen)   [canForwardTeam = true]
                    fwdInfo = { "fwdType": 2 }; // fwdType & 2 heeft altijd label L("lcl_mld_forward_team");
                  else
                  {                                                      // Corrigeren  (Operationeel corrigeren)   [canForward = true]
                    fwdInfo = { "fwdType": 1, "fwdLabel": L("lcl_mld_correct_before"), "fwdHint": L("lcl_mld_correct_before_hint") };
                    if (mld_melding.srtgroep & 4)
                      fwdInfo.fwdType += 2;                              // Corrigeren of Doorsturen kan allebei    [canForward = true && canForwardTeam = true]
                  }
                  break;
                case 4: // In behandeling
                case 7: // Uitgegeven
                  // Ik mag alleen corrigeren of doorsturen als er andere vakgroepen zijn waar hetzelfde behandelteam ingezet kan worden.
                  if (mld_melding.mld_ins_discipline_key > 0 && !hasProcInDisc(mld_melding.disc_key, mld_melding.mld_ins_discipline_key))            // Doorsturen  (Behandelteam doorsturen)   [canForwardTeam = true]
                    fwdInfo = { "fwdType": 2 }; // fwdType & 2 heeft altijd label L("lcl_mld_forward_team")
                  else
                    fwdInfo = { "fwdType":  (mld_melding.srtgroep & 4
                                             ? 3                         // Corrigeren of Doorsturen kan allebei    [canForward = true && canForwardTeam = true]
                                             : 1),                       // Behandelteam doorsturen kan niet als de vakgroep geen teams heeft
                                "fwdLabel": this_mld.canForwardKeten
                                            ? L("lcl_keten_forward")     // Corrigeren  (Vervolgen, GOTO)           [canForwardKeten = true]
                                            : L("lcl_active_forward"),   // Corrigeren  (Vervolgen, GOSUB)          [S("mld_forward_if_active") == 1]   /* Uitfaseren tot 2020.1 */
                                "fwdHint":  this_mld.canForwardKeten
                                            ? L("lcl_keten_forward_hint")
                                            : L("lcl_active_forward_hint") };
                  break;
                case 5: // Afgemeld                                      // Corrigeren  (Administratief corrigeren) [canFixMelding = true]
                  fwdInfo = { "fwdType": 1, "fwdLabel": L("lcl_mld_correct_after"), "fwdHint": L("lcl_mld_correct_after_hint") };
                  break;
              }
              return fwdInfo;
            },

        getFirstApprover:
            function (mld_info, mld_opdr)
            {
              // Bepalen eerste persoon om te fiatteren.
              var approver_key = -1;
              var prsname = "";
              var pkey = -1;
              var for_approval = false;
              // Als de kostenplaats bij de opdracht overruled is dan wordt altijd tegen het profiel van de BO-medewerker getest.
              if (mld_info.mld_kk == 1 && mld_info.kostenpl_key == mld_opdr.kp_key && S("mld_opdr_ignore_caller_profile") == 0)
                pkey = mld_info.melder_key;  // Melder van de melding.
              else
              { // Terugzoeken wie *oorspronkelijk* de opdrachtaanmaker was (De user op dat moment).

                // Opdracht -Als nieuw fiatteren-.
                var asNew = S("mld_opdr_refiat_preference") == 1 && // Bij herfiattering opnieuw fiatteren, 1=goedkeurder kan aangeven of dat moet.
                            mld_opdr.opdr_status_refiat > 0 &&      // Herfiattering (refiat).
                            mld_opdr.kp_fiat == 1;                  // Opdrachten fiatteren 1=Ja.

                if (mld_opdr.opdr_key < 0 ||             // Nieuwe opdracht.
                   (asNew && mld_opdr.opdr_status != 3)) // Als nieuw fiatteren en de status moet nog naar "Ter fiattering(3)".
                  pkey = user_key; // De opdrachtaanmaker is de user.
                else
                {
                  var opdrachtaanmaker = -1;
                  // Bij -Als nieuw fiatteren- niet naar de tracking kijken. De status is al "Ter fiattering(3)".
                  if (!asNew)
                  {
                    var sql = "SELECT fac.gettrackinguserkey('ORDNEW', " + mld_opdr.opdr_key + ") opdrachtaanmaker FROM DUAL";
                    var oRs = Oracle.Execute(sql);
                    opdrachtaanmaker = oRs("opdrachtaanmaker").Value;
                    oRs.Close();
                  }

                  // De opdrachtaanmaker is de verantwoordelijke van de ORDNEW tracking of anders de user bij aanmaak van de opdracht (die nog gefiatteerd moet worden).
                  // De user bij aanmaak van de opdracht is de verantwoordelijke van de ORDGOE tracking/notificatie of anders de ORDFIA tracking/notificatie.
                  // Eerst de ORDGOE controleren want die komt voor de ORDFIA.
                  if (opdrachtaanmaker)
                    pkey = opdrachtaanmaker;
                  else
                  { // Dan is de opdrachtaanmaker wellicht de verantwoordelijke van de ORDGOE tracking/notificatie.
                    var sql = "SELECT fac.gettrackinguserkey('ORDGOE', " + mld_opdr.opdr_key + ") opdrachtaanmaker FROM DUAL";
                    var oRs = Oracle.Execute(sql);
                    opdrachtaanmaker = oRs("opdrachtaanmaker").Value;
                    oRs.Close();
                    pkey = opdrachtaanmaker;

                    if (opdrachtaanmaker)
                      pkey = opdrachtaanmaker; // Verantwoordelijke van de ORDGOE tracking/notificatie
                    else
                    { // Dan moet de opdrachtaanmaker de verantwoordelijke zijn van de ORDFIA tracking/notificatie.
                      var sql = "SELECT fac.gettrackinguserkey('ORDFIA', " + mld_opdr.opdr_key + ") opdrachtaanmaker FROM DUAL";
                      var oRs = Oracle.Execute(sql);
                      opdrachtaanmaker = oRs("opdrachtaanmaker").Value;
                      oRs.Close();
                      pkey = opdrachtaanmaker; // Verantwoordelijke van de ORDFIA tracking/notificatie.
                    }
                  }
                }
              }

              if (mld_opdr.opdr_handfiat || // Vrijwillig. Wel even checken of er een fiatteur gevonden kan worden.
                  (S("mld_use_order_approval") &&
                   mld_opdr.t_cost > 0 &&
                   (mld_opdr.t_cost > S("can_selfapprove") || budget.exceeds_profiel(mld_opdr.t_cost, pkey, mld_opdr.opdr_disc_key))) // Ik kan niet zelf fiatteren of kosten overschrijden het profiel
                   )
              {
                // Niet automatisch fiat(!)teren.
                // Profiel wordt overschreden of we moeten het mandaat van de melder negeren.
                for_approval = true;

                // Wie moet op verzoek goedkeuren voor deze kostenplaats, terwijl het bedrag wellicht onbekend is?
                // Wanneer pkey uitsluiten voor het bepalen van de volgende fiatteur?
                // Niet als: 1) het mandaat van de melder wordt genegeerd (mld_opdr_ignore_caller_profile).
                //           2) het bestelde bedrag boven de profiel-limiet van de melder of opdracht aanmaker van de melding komt.
                // Wel als: 1) de melder of de opdracht aanmaker van de melding (pkey) niet zelf mag goedkeuren.
                // Bij een kpg fiatteur moeten we de volgende hebben en niet de laatste, daarom (fiatbedrag >= 0) meegeven.
                approver_key = prs.getFiatteur(mld_opdr.kp_key, (mld_opdr.t_cost > S("can_selfapprove"))? pkey : -1, mld_opdr.t_cost, mld_opdr.opdr_disc_key, mld_opdr.fiatbedrag);

                if (approver_key > -1)
                {
                  var sql = "SELECT prs_perslid_naam_full FROM prs_v_perslid_fullnames_all WHERE prs_perslid_key = " + approver_key;
                  var oRs = Oracle.Execute(sql);
                  var prsname = oRs("prs_perslid_naam_full").Value;
                  oRs.Close();
                }
              }
              return {for_approval: for_approval, approver_key: approver_key, approver_name: prsname}
            },

        getrefmoduletext:
            // Lever de string behorend bij kanverwijzen bit
            function (p)
            {
              var ps = "??";
              p = parseInt(p, 10);
              switch (p) {
                  case 1:   { ps = L("lcl_mld_stdmelding_own"); break; } // Melding (M)
                  case 2:   { ps = L("lcl_opdr_info"); break; }          // Opdracht [O]
                  case 4:   { ps = L("lcl_res_reservation"); break; }    // Reservering (R)
                  case 8:   { ps = L("lcl_bes_bestelling"); break; }     // Bestelling (B)
                  case 16:  { ps = L("lcl_bes_bestelopdracht"); break; } // Bestelopdr [X] /* reserved for future use */
                  case 32:  { ps = L("lcl_contract"); break; }           // Contract [C]   /* reserved for future use */
                  case 64:  { ps = L("lcl_fin_invoice"); break; }        // Factuur [F]    /* reserved for future use */
                  case 128: { ps = L("lcl_mld_stdmelding_all"); break; } // Alle meldingen [M]
              }
              return ps;
            },

        getpriotext:
            // Lever de string behorend bij prioriteit p
            function (p)
            {
              var ps = "??";
              p = parseInt(p, 10);
              switch (p) {
                  case 1: { ps = L("lcl_mld_urg_kritiek"); break; }
                  case 2: { ps = L("lcl_mld_urg_hoog"); break; }
                  case 3: { ps = L("lcl_mld_urg_normaal"); break; }
                  case 4: { ps = L("lcl_mld_urg_laag"); break; }
                  case 5: { ps = L("lcl_mld_onderbroken"); break; }  // denk ik, pseudoprio of zo?
              }
              return ps;
            },

        getpriocon:
            // Lever de icon op behorend bij prioriteit p
            function (p)
            {
              var displ = "";
              p = parseInt(p, 10);
              switch (p)
              {
                    case 1:  displ = "fa-triangle-exclamation"; break;
                    case 2:  displ = "fa-diamond-exclamation"; break;
                    case 3:  displ = ""; break;
                    case 4:  displ = "fa-arrow-circle-down"; break;
                    case 5:  displ = "fa-pause-circle"; break;
              }
              return displ;
            },

        getregimetext:
            // Lever de string behorend bij mld_stdmelding_regime p
            function (p)
            {
              var ps = "??";
              p = parseInt(p, 10);
              switch (p) {
                  case 1: { ps = L("lcl_mld_office_hours"); break; }
                  case 2: { ps = L("lcl_mld_opening_hours"); break; }
                  case 3: { ps = L("lcl_mld_24_7"); break; }
              }
              return ps;
            },

        getimpacttext:
            // Lever de string behorend bij impact p
            function (p)
            {
              var impacttext = ( p ? L("lcl_mld_impact" + p) : L("lcl_trackfromempty") );
              return impacttext;
            },

        geturgentietext:
            // Lever de string behorend bij urgentie p
            function (p)
            {
              var urgentietext = ( p ? L("lcl_mld_urgentie" + p) : L("lcl_trackfromempty") );
              return urgentietext;
            },

        getmldstatustext:
            function (p, pconceptstatus)
            {
              var statustekst = "??";
              var s = parseInt(p, 10);
              switch (s) {
                  case 0: { statustekst = L("lcl_mld_pending"); break; }
                  case 1: { statustekst = L("lcl_mld_afgewezen"); break; }
                  case 2: {
                      if ((pconceptstatus||0) == 0)
                      {
                        statustekst = L("lcl_mld_ingevoerd");
                      }
                      else
                      {
                        statustekst = L("lcl_mld_conceptstatus_{0}".format(pconceptstatus));
                      }
                      break;
                  }
                  case 3: { statustekst = L("lcl_mld_ingezien"); break; }
                  case 4: { statustekst = L("lcl_mld_geaccepteerd"); break; }
                  case 5: { statustekst = L("lcl_mld_afgemeld"); break; }
                  case 6: { statustekst = L("lcl_mld_verwerkt"); break; }
                  case 7: { statustekst = L("lcl_mld_uitgegeven"); break; }
                  case 99: { statustekst = L("lcl_mld_not_solved"); break; }
                  case 991: { statustekst = L("lcl_mld_offerte_accept"); break; }
                  case 992: { statustekst = L("lcl_mld_offerte_is_accept"); break; }
              }
              if (Session("logging")>0)
                statustekst += " ("+String(p)+")";
              return statustekst;
           },

        // Geeft de meldingstatus terug, maar checkt bij
        // 1) status 4 of dat de status nieuw(4) of oud(99) is.
        // 2) status 5 met de setting "mld_assume_ok_days" is gezet of dat de status afgemeld(5) of niet opgelost(99) is.
        // mld_key geef ik mee omdat ik die toch altijd al weet; ik had daarmee de status natuurlijk
        // hier ook zelf kunnen bepalen.
        getextendedmldstatus:
            function (s, pmld_key)
            {
              var result = s;
              if (s == 4)
              { // Status is nu 4 (Geaccepteerd). Als er opdrachten zijn maar geen open opdrachten, dan wordt de status 99 (Niet opgelost).
                var result = 4;
                var sql = "SELECT COUNT(mld_opdr_key) nrOrders FROM mld_opdr WHERE mld_melding_key = " + pmld_key;
                var oRs = Oracle.Execute(sql);
                var nrOrders = oRs("nrOrders").Value;
                oRs.Close();
                if (nrOrders > 0)
                { // Aantal lopende opdrachten
                  sql = "SELECT COUNT(mld_opdr_key) nrOpen"
                      + "  FROM mld_opdr o"
                      + " WHERE mld_melding_key = " + pmld_key
                      + "   AND o.mld_statusopdr_key NOT IN (1, 2, 6, 7, 9)";
                  oRs = Oracle.Execute(sql);
                  var nrOpen = oRs("nrOpen").Value;
                  oRs.Close();

                  if (nrOpen == 0)
                  { // Status is nu 99 (Niet opgelost).
                    // Als de laatste opdrachten een offerte is dan wordt de status 991 of 992 (Offerte acceptatie of Offerte geaccepteerd).
                    // De status is dan afhankelijk van het aantal geaccepteerde offertes.
                    result = 99;
                    sql = "SELECT mo.mld_typeopdr_isofferte"
                        + "  FROM mld_opdr o1"
                        + "     , mld_typeopdr mo"
                        + " WHERE o1.mld_typeopdr_key = mo.mld_typeopdr_key"
                        + "   AND o1.mld_opdr_key = (SELECT MAX(o2.mld_opdr_key)"
                        + "                            FROM mld_opdr o2"
                        + "                           WHERE o2.mld_melding_key = " + pmld_key + ")";
                    oRs = Oracle.Execute(sql);
                    var lastOpdrIsOff = oRs("mld_typeopdr_isofferte").Value == 1;
                    oRs.Close();
                    if (lastOpdrIsOff)
                    { //  99 = Niet opgelost
                      // 991 = Offerte acceptatie
                      // 992 = Offerte geaccepteerd
                      // Voorbeeld status van de melding met twee offerte opdrachten:
                      //                        Statussen
                      // Offerte 1:        6     6     2     2
                      // Offerte 2:        6     9     9     2
                      // nrToAccept:       2     1     0     0
                      // nrAccept:         0     1     1     0
                      // Melding status: 991   992   992    99
                      // Aantal te accepteren offertes
                      sql = "SELECT COUNT(o.mld_statusopdr_key) nrToAccept"
                          + "  FROM mld_opdr o"
                          + " WHERE mld_melding_key = " + pmld_key
                          + "   AND o.mld_statusopdr_key = 6"
                          + "   AND o.mld_opdr_key > COALESCE((SELECT MAX (o1.mld_opdr_key)"
                          + "                                   FROM mld_opdr o1"
                          + "                                      , mld_typeopdr mo1"
                          + "                                  WHERE o1.mld_typeopdr_key = mo1.mld_typeopdr_key"
                          + "                                    AND mo1.mld_typeopdr_isofferte = 0"
                          + "                                    AND o1.mld_melding_key = " + pmld_key + "), 0)"
                      oRs = Oracle.Execute(sql);
                      var nrToAccept = oRs("nrToAccept").Value;
                      oRs.Close();

                      // Aantal geaccepteerde offertes
                      sql = "SELECT COUNT(o.mld_statusopdr_key) nrAccept"
                          + "  FROM mld_opdr o"
                          + " WHERE mld_melding_key = " + pmld_key
                          + "   AND o.mld_statusopdr_key = 9"
                          + "   AND o.mld_opdr_key > COALESCE((SELECT MAX (o1.mld_opdr_key)"
                          + "                                   FROM mld_opdr o1"
                          + "                                      , mld_typeopdr mo1"
                          + "                                  WHERE o1.mld_typeopdr_key = mo1.mld_typeopdr_key"
                          + "                                    AND mo1.mld_typeopdr_isofferte = 0"
                          + "                                    AND o1.mld_melding_key = " + pmld_key + "), 0)"
                      oRs = Oracle.Execute(sql);
                      var nrAccept = oRs("nrAccept").Value;
                      oRs.Close();
                      // Als een offerte is geaccepteerd dan status 992.
                      // Als er geen offerte is geaccepteerd dan kijken of er nog offerte afgemeld zijn die geaccepteerd/afgewezen kunnen worden, dan status 991 anders 99
                      result = (nrAccept == 1? 992 : (nrToAccept > 0? 991 : 99));
                    }
                  }
                }
              }
              else if (s == 5 && S("mld_assume_ok_days") > 0)
              {
                var sql = "SELECT mld_melding_actiecode"
                        + "  FROM mld_melding"
                        + " WHERE mld_melding_key = " + pmld_key;
                var oRs = Oracle.Execute(sql);
                var actiecode = oRs("mld_melding_actiecode").Value;
                oRs.Close();
                if (actiecode & 128) // Afgemeld en attentie op de BO/FO(128).
                  result = 99; // Niet opgelost.
              }
              return result;
            },

        getextendedmldstatustext:
            function (pstatus, pmld_key)
            {
              var xstatus = mld.getextendedmldstatus(pstatus, pmld_key);
              return mld.getmldstatustext(xstatus);
            },

        // Geeft de opdrachtstatus terug, maar checkt bij status 5 en 8, of de behandeling onderbroken/hervat is (ORDHLT/ORDRSM).
        // De opdr_key geef ik mee omdat ik die toch altijd al weet; ik had daarmee de status natuurlijk hier ook zelf kunnen bepalen.
        getextendedopdrstatus:
            function (pstatus, popdr_key)
            {
              var result = pstatus;
              if (pstatus == 8)
              {
                var sql = "SELECT fac.gettrackingdate ('ORDHLT', " + popdr_key + ") trackdatehlt"
                        + "     , fac.gettrackingdate ('ORDRSM', " + popdr_key + ") trackdatersm"
                        + "  FROM DUAL";
                var oRs = Oracle.Execute(sql);
                var trackdateHLT = oRs("trackdatehlt").Value != null? new Date(oRs("trackdatehlt").Value) : null;
                var trackdateRSM = oRs("trackdatersm").Value != null? new Date(oRs("trackdatersm").Value) : null;
                oRs.Close();

                if (trackdateHLT != null && (trackdateRSM == null || trackdateHLT > trackdateRSM))
                  result = 81; // Onderbroken.
                if (trackdateRSM != null && trackdateHLT < trackdateRSM)
                  result = 82; // Hervat.
              }

              return result;
            },

        getextendedopdrstatustext:
            function (pstatus, popdr_key)
            {
              var xstatus = mld.getextendedopdrstatus(pstatus, popdr_key);
              return status.getopdrstatustext(xstatus);
            },

        // bereken de SLA-einddatum gegeven onderstaande info
        geteinddatum:
            function (startdate, stdm_key, prio, geb_key, ruimte_key, obj_key)
            {
              var alg_key = 'NULL';
              if (ruimte_key > 0)
                  alg_key = ruimte_key;
              else
              {
                  if (geb_key > 0)
                      alg_key = geb_key;
              }
              var sql = "SELECT mld.geteinddatum(" + startdate.toSQL(true) + ", " + stdm_key + ", " + prio + "," + alg_key + "," + (obj_key > 0? obj_key : "NULL") + ")"
                      + "  FROM DUAL";
              var oRs = Oracle.Execute(sql);
              var einddatum = new Date(oRs(0).Value);
              oRs.Close();
              return einddatum;
            },

        // bereken de SLA-einddatum gegeven onderstaande info
        geteinddatumopdracht:
            function _geteinddatumopdracht(mld_key, uitvoertijd, startdatum, sla_mode)
            { // Deze functie wordt alleen aangeroepen voor Leverancier-SLA (SLA-mode = 1) of Melding-SLA (SLA-mode = 2).
              // Voor Melding-Einddatum (SLA-mode = 3) wordt deze functie nooit aangeroepen omdat altijd uitgegaan wordt van de melding einddatum.
              var sql = "SELECT m.mld_melding_einddatum"
                      + "     , sm.mld_stdmelding_enddate_empty"
                      + "     , sm.mld_stdmelding_autoorder"
                      + "  FROM mld_melding m"
                      + "     , mld_stdmelding sm"
                      + " WHERE m.mld_stdmelding_key = sm.mld_stdmelding_key"
                      + "   AND m.mld_melding_key = " + mld_key;
              var oRs = Oracle.Execute(sql);
              var mld_einddatum = new Date(oRs("mld_melding_einddatum").Value);
              var enddateempty = oRs("mld_stdmelding_enddate_empty").Value == 1;
              var autoorder = oRs("mld_stdmelding_autoorder").Value == 1;
              oRs.Close();

              if ((!autoorder && enddateempty) || (autoorder && enddateempty))
                einddatum = null;
              else if (uitvoertijd)
              {
                  var sql = "SELECT mld.geteinddatum(" + mld_key + ", MLD_T_UITVOERTIJD(" + uitvoertijd.tijdsduur + ", " + safe.quoted_sql(uitvoertijd.eenheid) + "), " + startdatum.toSQL(true) + ")"
                          + "  FROM DUAL";
                  var oRs = Oracle.Execute(sql);
                  var einddatum = new Date(oRs(0).Value);
                  oRs.Close();
                  if (sla_mode == 1)
                  {
                      // Als setting mld_enforce_orderdates = 1, dan moeten de datums van de opdracht binnen de datums van de melding liggen.
                      if (S("mld_enforce_orderdates") == 1 && mld_einddatum.midnight() < einddatum.midnight())
                          einddatum = mld_einddatum;
                  }
              }
              else
              { // Uitvoerdatum is null of 0.
                var einddatum = mld_einddatum; // De einddatum van de opdracht ligt nu binnen de datums van de melding.
                // Voor nieuwe opdrachten is de default Einddatum gelijk aan de einddatum van de melding,
                // tenzij die in het verleden ligt, dan is het de opdrachtstartdatum.
                // Als setting mld_enforce_orderdates = 1, dan moeten de datums van de opdracht binnen de datums van de melding liggen.
                if (S("mld_enforce_orderdates") != 1 && mld_einddatum.midnight() < new Date(startdatum).midnight())
                  einddatum = new Date(startdatum);
              }
              return einddatum;
            },

        hasAlgUitvoertijd: -1, // unknown
        getbedrijfuitvoertijd:
            function _getbedrijfuitvoertijd(bedrijf_key, melding_key, dienst_key)
            {
              if (mld.hasAlgUitvoertijd == -1)  // Zijn er specifieke uitvoertijden voor gebouwen?
              {
                  var sql = "SELECT COUNT(*) cnt"
                          + "  FROM prs_bedrijfdienstlocatie bdl"
                          + " WHERE bdl.prs_bdl_t_uitvoertijd.tijdsduur IS NOT NULL";
                  var oRs = Oracle.Execute(sql)
                  mld.hasAlgUitvoertijd = oRs("cnt").Value;
                  oRs.Close()
              }

              var sql, oRs, uitvoertijd;
              var hasSpecifiek = false;
              if (mld.hasAlgUitvoertijd > 0) // Kijken of er een specifieke uitvoertijd voor ons gebouw is
              {
                  var result = mld.mld_melding_info(melding_key); // deze is 'duur' dus zo weinig mogelijk uitvoeren
                  // Als er geen dienst_key is meegegeven dan de dienst_key van de stdmeldingen gebruiken.
                  if (dienst_key == null)
                    dienst_key = result.dienst_key;

                  sql = "SELECT bdl.prs_bdl_t_uitvoertijd.tijdsduur tijdsduur, bdl.prs_bdl_t_uitvoertijd.eenheid eenheid"
                      + "  FROM prs_bedrijfdienstlocatie bdl"
                      + " WHERE bdl.prs_bedrijf_key = " + bedrijf_key
                      + "   AND bdl.prs_dienst_key = " + dienst_key;
                  // Als in de tabel de alg_gebouw_key en/of alg_locatie_key NULL is dan levert het bedrijf de dienst op ALLE gebouwen en/of locaties.
                  if (result.bld_key > 0)
                  {
                      sql += " AND ((bdl.alg_gebouw_key = " + result.bld_key + " OR bdl.alg_gebouw_key IS NULL) AND"
                           + "      (bdl.alg_locatie_key = " + result.loc_key + " OR bdl.alg_locatie_key IS NULL)" + ")";
                  }
                  else if (result.loc_key > 0) // überhaupt plaatsgegevens?
                  {
                       sql += " AND (bdl.alg_locatie_key = " + result.loc_key + " OR bdl.alg_locatie_key IS NULL)";
                  }
                  sql += " AND bdl.prs_bdl_t_uitvoertijd.tijdsduur > 0";
                  oRs = Oracle.Execute(sql);
                  var hasSpecifiek = !oRs.Eof;
                  if (!hasSpecifiek) // dan moet deze vast dicht
                      oRs.Close();
              }

              if (!hasSpecifiek)
              {
                sql = "SELECT b.prs_bedrijf_t_uitvoertijd.tijdsduur tijdsduur"
                    + "     , b.prs_bedrijf_t_uitvoertijd.eenheid eenheid"
                    + "  FROM prs_bedrijf b"
                    + " WHERE b.prs_bedrijf_key = " + bedrijf_key;
                oRs = Oracle.Execute(sql);
              }
              if (oRs.Eof || oRs("tijdsduur").Value == null) // oRs.Eof: Waarschijnlijk persoon
                uitvoertijd = null;
              else
                uitvoertijd = {tijdsduur: oRs("tijdsduur").Value, eenheid: oRs("eenheid").Value};
              oRs.Close();
              return uitvoertijd;
            },

        getmeldinguitvoertijd:
            function (mld_key)
            {
              var sql = "SELECT m.mld_melding_t_uitvoertijd.tijdsduur tijdsduur"
                      + "     , m.mld_melding_t_uitvoertijd.eenheid eenheid"
                      + "  FROM mld_melding m"
                      + " WHERE m.mld_melding_key = " + mld_key;
              var oRs = Oracle.Execute(sql);
              if (oRs.eof || oRs("tijdsduur").Value == null)
                var uitvoertijd = null;
              else
                var uitvoertijd = {tijdsduur: oRs("tijdsduur").Value, eenheid: oRs("eenheid").Value};
              oRs.Close();
              return uitvoertijd;
            },

        getstartdatesave:
            function (mld_key, params_startdate)
            { // Er zijn twee situaties te onderscheiden voor startdatum:
              // 1) Als startdatum zichtbaar/wijzigbaar (vakgroep setting "Startdatum te bepalen" (mld_disc_params_startdatum))
              //    De tijd van de startdatum is altijd de begintijd van de dag (setting "fac_t_startofworkday" bijvoorbeeld 8:00 uur)
              //    => Startdatum = TRUNC(startdatum) + 8:00 uur
              //    Uitzondering: Echter als de startdatum de registratiedatum (bij nieuwe melding dus sysdate) is moet wel voor de begintijd de registratietijd (registratiedatum) genomen worden tijdens het opslaan.
              //                  Anders geldt de acceptatietijd (in uren) onterecht al vanaf het begin van de dag.
              // 2) Startdatum is niet zichtbaar/wijzigbaar
              //    De tijd van de startdatum is de tijd van de huidige waarde of van de sysdate, COALESCE(huidige waarde, sysdate).
              //    => Startdatum = COALESCE(huidige waarde, sysdate)

              // Startdatum:
              if (params_startdate.startdate)
                var startdate = params_startdate.startdate;
              else
                var startdate = getFQParamDate("startdate", new Date); // Indien niet meegegeven, neem dan sysdate.

              var startwerkdag = parseFloat(S("fac_t_startofworkday"));
              var startwerkdag_uur = Math.floor(startwerkdag);
              var startwerkdag_min = (startwerkdag - Math.floor(startwerkdag)) * 60;
              var startdatebegin = new Date(startdate.getFullYear(), startdate.getMonth(), startdate.getDate(), startwerkdag_uur, startwerkdag_min);
              var sysdate = new Date();

              if (params_startdate.disc_with_startdatum)
              { // Situatie 1: Einddatum = TRUNC(startdatum) + 8:00 uur + SLA
                // LET OP!!!: Als setting "mld_disc_params_startdatum" is gezet dan wordt eigenlijk verondersteld dat de SLA in dagen is en niet in uren.
                //            Echter als de startdatum de registratiedatum (bij nieuwe melding dus sysdate) is moet wel voor de begintijd de registratietijd (registratiedatum) genomen worden tijdens het opslaan.
                //            Anders geldt de acceptatietijd (in uren) onterecht al vanaf het begin van de dag.
                if (mld_key < 0)
                { // Nieuwe melding.
                  // Startdatum is vandaag: starttijd is huidige tijd.
                  // Startdatum is niet vandaag: starttijd is begin werkdag.
                  var startdate_is_today = (startdate.midnight().getTime() == sysdate.midnight().getTime());
                  startdate = (startdate_is_today? sysdate : startdatebegin);
                }
                else
                { // Bestaande melding
                  sql = "SELECT mld_melding_datum"
                      + "  FROM mld_melding"
                      + " WHERE mld_melding_key = " + mld_key;
                  oRs = Oracle.Execute(sql);
                  var oldstartdate = new Date(oRs("mld_melding_datum").Value);

                  // Alleen als datum veranderd is moet de starttijd worden aangepast.
                  if (startdate.midnight().getTime() != oldstartdate.midnight().getTime())
                  { // Startdatum is aangepast.
                    // Als de startdatum is aangepast in registratiedatum, dan wel weer de registratietijd (registratiedatum) pakken.
                    // In alle andere gevallen begin van de werkdag pakken.
                    sql = "SELECT fac.gettrackingdate('MLDNEW', " + mld_key + ") registratiedatum FROM DUAL"
                    oRs_1 = Oracle.Execute(sql);
                    var registratiedatum = new Date(oRs_1("registratiedatum").Value);
                    oRs_1.Close();

                    var startdatum_is_registratiedatum = (startdate.midnight().getTime() == registratiedatum.midnight().getTime());
                    startdate = (startdatum_is_registratiedatum? registratiedatum : startdatebegin);
                  }
                  else
                  { // else startdatum niet aanpassen.
                    startdate = oldstartdate;
                  }
                  oRs.Close();
                }
                return {startdate: startdate, startfield: { dbs: "mld_melding_datum", typ: "datetime", val: startdate, track: L("lcl_mld_startdate") }}; // Begin werkdag.
              }
              else
              { // Situatie 2: Einddatum = COALESCE(huidige waarde, sysdate) + SLA
                if (mld_key < 0)
                {
                  startdate = new Date();
                  return {startdate: new Date(), startfield: { dbs: "mld_melding_datum", typ: "sql", val: "SYSDATE" }}; // Nieuwe melding, nu/sysdate.
                }
                else
                { // Wijziging melding, huidige opgeslagen waarde.
                  if (params_startdate.startdate == undefined)
                    return {startdate: startdate, startfield: { dbs: "mld_melding_datum", typ: "datetime", frm: "startdate", track: L("lcl_mld_startdate") }};
                  else
                    // params_startdate.startdate was meegegeven. Dan deze waarde opslaan.
                    return {startdate: startdate, startfield: { dbs: "mld_melding_datum", typ: "datetime", val: params_startdate.startdate, track: L("lcl_mld_startdate") }};
                }
              }
            },

        getactivehltopdracht:
            function (popdr_key, mode, pprs_key, puitv_key)
            {
              // Is er een actieve opdracht of zijn er onderbroken opdrachten die sequentieel uigevoerd moeten worden.
              var sql = "SELECT MAX(mld_opdr_key) mld_opdr_key"
                      + "     , MAX(sd.ins_srtdiscipline_prefix || o.mld_melding_key || '/' || o.mld_opdr_bedrijfopdr_volgnr) opdracht"
                      + "     , COUNT(mld_opdr_key) aantalopdr"
                      + "  FROM mld_opdr o"
                      + "     , mld_melding m"
                      + "     , mld_stdmelding s"
                      + "     , mld_discipline md"
                      + "     , ins_srtdiscipline sd"
                      + "     , mld_typeopdr top"
                      + "     , mld_v_uitvoerende mu"
                      + " WHERE o.mld_melding_key = m.mld_melding_key"
                      + "   AND m.mld_stdmelding_key = s.mld_stdmelding_key"
                      + "   AND s.mld_ins_discipline_key = md.ins_discipline_key"
                      + "   AND md.ins_srtdiscipline_key = sd.ins_srtdiscipline_key"
                      + "   AND o.mld_typeopdr_key = top.mld_typeopdr_key"
                      + "   AND o.mld_uitvoerende_keys = mu.mld_uitvoerende_key"
                      + "   AND o.prs_perslid_key = " + (pprs_key > 0? pprs_key : "(SELECT o2.prs_perslid_key FROM mld_opdr o2 WHERE o2.mld_opdr_key = " + popdr_key + ")")
                      + "   AND o.mld_uitvoerende_keys = " + (puitv_key > 0? puitv_key : "(SELECT o2.mld_uitvoerende_keys FROM mld_opdr o2 WHERE o2.mld_opdr_key = " + popdr_key + ")")
                      + "   AND o.mld_statusopdr_key = 8" // Alleen Actieve (Status Geaccepteerd(8)) opdrachten.
                      + "   AND BITAND(top.mld_typeopdr_sequential, 2) = 2" // Alleen opdrachten die sequentieel uitgevoerd moeten worden.
                      + (mode == "A"
                        ? " AND o.mld_opdr_halted = 0"
                        : " AND o.mld_opdr_halted = 1")
                      + "   AND mu.intern = 1" // Alleen interne uitvoerders.
                      + "   AND mld_opdr_key != " + popdr_key;
              var oRs = Oracle.Execute(sql);
              var result = { opdr_key: oRs("mld_opdr_key").Value? oRs("mld_opdr_key").Value : -1,
                             opdracht: oRs("opdracht").Value? oRs("opdracht").Value : "",
                             aantal: oRs("aantalopdr").Value };
              oRs.Close();
              return result;
            },

        getactiveopdracht:
            function (popdr_key)
            {
              return mld.getactivehltopdracht(popdr_key, "A"); // Mode "Actief"
            },

        getactiveopdracht:
            function (popdr_key, pprs_key, puitv_key)
            {
              return mld.getactivehltopdracht(popdr_key, "A", pprs_key, puitv_key); // Mode "Actief"
            },

        gethltopdrachten:
            function (popdr_key)
            {
              return mld.getactivehltopdracht(popdr_key, "H"); // Mode "Onderbroken"
            },

        keepFlexDocuments:
         function(mld_key, old_stdm, stdmelding)
         {
           /* Match de srtkenmerk_key-s van de oude en nieuwe mld_stdmelding */
           if (old_stdm != stdmelding)
           {
             __Log("Old MLD_STDMELDING_KEY: " + old_stdm + " New: " + stdmelding);
             // pas op dat zelfs de vakgroep (mld_ins_discipline_key) gewijzigd kan zijn
             var flexsql = "SELECT k_old.mld_kenmerk_key k_old"
                         + "     , k_new.mld_kenmerk_key k_new"
                         + "  FROM mld_srtkenmerk t_old"
                         + "     , mld_srtkenmerk t_new"
                         + "     , mld_kenmerk    k_old"
                         + "     , mld_kenmerk    k_new"
                         + "     , mld_stdmelding s_old"
                         + "     , mld_stdmelding s_new"
                         + "     , mld_discipline d_new"
                         + "     , mld_discipline d_old"
                         + " WHERE s_old.mld_stdmelding_key = " + old_stdm
                         + "   AND s_new.mld_stdmelding_key = " + stdmelding
                         + "   AND k_old.mld_srtkenmerk_key = t_old.mld_srtkenmerk_key"
                         + "   AND k_new.mld_srtkenmerk_key = t_new.mld_srtkenmerk_key"
                         + "   AND s_old.mld_ins_discipline_key = d_old.ins_discipline_key"
                         + "   AND s_new.mld_ins_discipline_key = d_new.ins_discipline_key"
                         + "   AND t_old.mld_srtkenmerk_kenmerktype IN ('F', 'E', 'M')"
                         + "   AND t_new.mld_srtkenmerk_kenmerktype IN ('F', 'E', 'M')"
                         + "   AND ((k_old.mld_stdmelding_key IS NULL                        AND k_old.mld_kenmerk_niveau = 'A')"
                         + "     OR (k_old.mld_stdmelding_key = s_old.mld_stdmelding_key     AND k_old.mld_kenmerk_niveau = 'S')"
                         + "     OR (k_old.mld_stdmelding_key = s_old.mld_ins_discipline_key AND k_old.mld_kenmerk_niveau = 'D')"
                         + "     OR (k_old.mld_stdmelding_key = d_old.ins_srtdiscipline_key  AND k_old.mld_kenmerk_niveau = 'T'))"
                         + "   AND ((k_new.mld_stdmelding_key IS NULL                        AND k_new.mld_kenmerk_niveau = 'A')"
                         + "     OR (k_new.mld_stdmelding_key = s_new.mld_stdmelding_key     AND k_new.mld_kenmerk_niveau = 'S')"
                         + "     OR (k_new.mld_stdmelding_key = s_new.mld_ins_discipline_key AND k_new.mld_kenmerk_niveau = 'D')"
                         + "     OR (k_new.mld_stdmelding_key = d_new.ins_srtdiscipline_key  AND k_new.mld_kenmerk_niveau = 'T'))"
                         + "   AND k_old.mld_kenmerk_verwijder IS NULL"
                         + "   AND k_new.mld_kenmerk_verwijder IS NULL"
                         + "   AND t_old.mld_srtkenmerk_verwijder IS NULL"
                         + "   AND t_new.mld_srtkenmerk_verwijder IS NULL"
                         + "   AND k_new.mld_kenmerk_rolcode > 0"  // hetzelfde als BITAND(k_new.mld_kenmerk_rolcode, 255) > 0
                         //+ "   AND k_new.mld_kenmerk_volgnummer > 0"
                         + "   AND k_old.mld_kenmerk_groep = k_new.mld_kenmerk_groep"
                         + "   AND ((k_old.mld_kenmerk_niveau = 'A' AND k_new.mld_kenmerk_niveau = 'A')"
                         + "     OR (k_old.mld_kenmerk_niveau NOT IN ('A') AND k_new.mld_kenmerk_niveau NOT IN ('A')))"
                         + "   AND COALESCE(k_old.mld_kenmerk_omschrijving, t_old.mld_srtkenmerk_omschrijving) = "
                         + "       COALESCE(k_new.mld_kenmerk_omschrijving, t_new.mld_srtkenmerk_omschrijving)";

             var subfolder = "MLD/" + subfolderKey("M", mld_key)
             RenameFlexFolders(flexsql, "MLD", "M", mld_key);
           }
         },

        moveFlexStdmelding:
         function(mld_key, old_stdm, stdmelding)
         {
           /* Match de kenmerk_key-s van de oude en nieuwe mld_stdmelding */
           var trackarray = []; // Eventuele tracking
           if (old_stdm != stdmelding)
           {
             __Log("Old MLD_STDMELDING_KEY: " + old_stdm + " New: " + stdmelding);
             // pas op dat zelfs de vakgroep (mld_ins_discipline_key) gewijzigd kan zijn
             var flexsql = "SELECT mk.mld_kenmerk_key kenm_key_old"
                         +"      , sk.mld_srtkenmerk_kenmerktype"
                         + "     , kenm_new.mld_kenmerk_key kenm_key_new"
                         + "     , mld_kenmerkmelding_key"
                         + "     , COALESCE (" + lcl.xsql("mk.mld_kenmerk_omschrijving", "mk.mld_kenmerk_key")
                         + "              ,  " + lcl.xsql("sk.mld_srtkenmerk_omschrijving", "sk.mld_srtkenmerk_key") + ") mld_kenmerk_omschrijving"
                         + "     , mkm.mld_kenmerkmelding_waarde"
                         + "     , sk.mld_srtkenmerk_systeem"
                         + "     , sk.fac_kenmerkdomein_key"
                         + "  FROM mld_kenmerkmelding mkm"
                         + "     , mld_kenmerk mk"
                         + "     , mld_srtkenmerk sk"
                         + "     , mld_stdmelding s"
                         + "     , mld_discipline d"
                         + "     , (SELECT mkn.mld_kenmerk_key"
                         + "             , mkn.mld_srtkenmerk_key"
                         + "             , COALESCE (mkn.mld_kenmerk_omschrijving, skn.mld_srtkenmerk_omschrijving) omschrijving"
                         + "          FROM mld_kenmerk mkn"
                         + "             , mld_srtkenmerk skn"
                         + "             , mld_stdmelding sn"
                         + "             , mld_discipline dn"
                         + "         WHERE sn.mld_ins_discipline_key = dn.ins_discipline_key"
                         + "           AND mkn.mld_srtkenmerk_key = skn.mld_srtkenmerk_key"
                         + "           AND ((mkn.mld_stdmelding_key IS NULL AND mkn.mld_kenmerk_niveau = 'A')"
                         + "             OR (mkn.mld_stdmelding_key = sn.mld_stdmelding_key AND mkn.mld_kenmerk_niveau = 'S')"
                         + "             OR (mkn.mld_stdmelding_key = sn.mld_ins_discipline_key AND mkn.mld_kenmerk_niveau = 'D')"
                         + "             OR (mkn.mld_stdmelding_key = dn.ins_srtdiscipline_key AND mkn.mld_kenmerk_niveau = 'T'))"
                         + "           AND mkn.mld_kenmerk_verwijder IS NULL"
                         + "           AND (sn.mld_stdmelding_key = " + stdmelding + " OR sn.mld_stdmelding_key IS NULL)) kenm_new"
                         + " WHERE mkm.mld_kenmerk_key = mk.mld_kenmerk_key"
                         + "   AND s.mld_ins_discipline_key = d.ins_discipline_key"
                         + "   AND mk.mld_srtkenmerk_key = sk.mld_srtkenmerk_key"
                         + "   AND sk.mld_srtkenmerk_kenmerktype NOT IN ('M')"
                         + "   AND ((mk.mld_stdmelding_key IS NULL AND mk.mld_kenmerk_niveau = 'A')"
                         + "     OR (mk.mld_stdmelding_key = s.mld_stdmelding_key AND mk.mld_kenmerk_niveau = 'S')"
                         + "     OR (mk.mld_stdmelding_key = s.mld_ins_discipline_key AND mk.mld_kenmerk_niveau = 'D')"
                         + "     OR (mk.mld_stdmelding_key = d.ins_srtdiscipline_key AND mk.mld_kenmerk_niveau = 'T'))"
                         + "   AND mk.mld_srtkenmerk_key = kenm_new.mld_srtkenmerk_key(+)"
                         // Bij meerdere dezelfde kenemerken moeten de omschrijvingen overeenkomen. Anders krijg je teveel (kruislingse) resultaten.
                         + "   AND COALESCE (mk.mld_kenmerk_omschrijving, sk.mld_srtkenmerk_omschrijving) = kenm_new.omschrijving(+)"
                         + "   AND mk.mld_kenmerk_verwijder IS NULL"
                         + "   AND mkm.mld_melding_key = " + mld_key
                         + "   AND (s.mld_stdmelding_key = " + old_stdm + " OR s.mld_stdmelding_key IS NULL)"
                         + " ORDER BY mk.mld_kenmerk_key";

             var oRs = Oracle.Execute(flexsql);
             while (!oRs.eof)
             {
               var kenm_key_new = oRs("kenm_key_new").Value;
               if (kenm_key_new)
               { // Overeenkomende flexkenmerken van de oude naar de nieuwe stdmelding overzetten.
                 // De waarde veranderd niet, dus geen tracking nodig.
                 sql = "UPDATE mld_kenmerkmelding"
                     + "   SET mld_kenmerk_key = " + kenm_key_new
                     + " WHERE mld_kenmerkmelding_key = " + oRs("mld_kenmerkmelding_key").Value;
                 Oracle.Execute(sql);
               }
               else
               { // Nieuwe stdmelding heeft het flexkenmerk niet. Track dat dit flexkenmerk verloren gaat.
                 var kenmerktype = oRs("mld_srtkenmerk_kenmerktype").Value;
                 var kmwaarde = oRs("mld_kenmerkmelding_waarde").Value;
                 var kdomein_key = oRs("fac_kenmerkdomein_key").Value;
                 var confidential = oRs("mld_srtkenmerk_systeem").Value & 4;
                 if (confidential)
                 {
                   kmwaarde = L("lcl_confidential_mask");
                 }
                 else
                 {
                   if (kenmerktype == "S" || kenmerktype == "r" || kenmerktype == "R")
                   {
                     var oRsd = Oracle.Execute("SELECT fac.getdomeinwaarde(" + kdomein_key + ", " + safe.quoted_sql(kmwaarde) + ") domeinwaarde FROM DUAL");
                     kmwaarde = oRsd("domeinwaarde").Value;
                     oRsd.Close();
                   }
                 }
                 trackarray.push(L("lcl_mld_prop_not_exist").format(oRs("mld_kenmerk_omschrijving").Value, kmwaarde) + L("lcl_trackto") + L("lcl_tracktoempty"));
               }
               oRs.MoveNext();
             }
             oRs.Close();
           }
           return trackarray;
         },

        saveFlexBlokKenmerken:
            function(mld_key, flex_blok, params)
            { // Behandelbare bloktitel kenmerken afhandelen tijdens het opslaan van de melding.
              // Deze kenmerken komen alleen in de MLD module voor. Daarom is de code hier in mld.inc gedefinieerd.
              var mldtrackarray = []; // eventuele tracking
              var kenmerk_key = flex_blok.id;
              var new_disc_key = flex_blok.team;
              var new_prs_key = flex_blok.prs;
              var new_complete = flex_blok.complete == 1;

              var sql = "SELECT mld_melding_status FROM MLD_melding WHERE mld_melding_key = " + mld_key;
              var oRs = Oracle.Execute(sql);
              var mld_status = oRs("mld_melding_status").Value;
              oRs.Close();

              var sql = "SELECT mld_kenmerkblokmelding_key"
                      + "     , kbm.ins_discipline_key"
                      + "     , kbm.prs_perslid_key"
                      + "     , CASE WHEN kbm.mld_kenmerkblokmelding_afmelddatum IS NOT NULL THEN 1 ELSE 0 END complete"
                      + "     , COALESCE (" + lcl.xsql("k.mld_kenmerk_omschrijving", "k.mld_kenmerk_key")
                      + "              ,  " + lcl.xsql("t.mld_srtkenmerk_omschrijving", "t.mld_srtkenmerk_key") + ") kenmerk_omschrijving"
                      + "  FROM mld_kenmerkblokmelding kbm"
                      + "     , mld_kenmerk k"
                      + "     , mld_srtkenmerk t"
                      + " WHERE k.mld_srtkenmerk_key = t.mld_srtkenmerk_key"
                      + "   AND k.mld_kenmerk_key = kbm.mld_kenmerk_key"
                      + "   AND kbm.mld_melding_key = " + mld_key
                      + "   AND kbm.mld_kenmerk_key = " + kenmerk_key;

              oRsb = Oracle.Execute(sql);
              if (!oRsb.eof)
              { // mld_kenmerkblokmelding record aanwezig.
                var old_disc_key = oRsb("ins_discipline_key").Value || -1;
                var old_prs_key = oRsb("prs_perslid_key").Value || -1;
                var old_complete = oRsb("complete").Value == 1;
                var label = oRsb("kenmerk_omschrijving").Value;  // For tracking only.

                // Notificeren en tracken van mld_kenmerkblokmelding behandelteam en behandelaar gebeurt pas als de melding is geaccepteerd (FCLT#86882).
                // Dan is de status "Gaccepteerd(4)" of "Uitgegeven(7)"
                if ((new_disc_key != old_disc_key || new_prs_key != old_prs_key || new_complete != old_complete) && (mld_status == 4 || mld_status == 7))
                {
                  sql = "UPDATE mld_kenmerkblokmelding"
                      + "   SET ins_discipline_key = " + (new_disc_key > 0? new_disc_key : "NULL")
                      + "     , prs_perslid_key = " + (new_prs_key > 0? new_prs_key : "NULL")
                      + "     , mld_kenmerkblokmelding_afmelddatum = " + (new_complete? "SYSDATE" : "NULL")
                      + " WHERE mld_melding_key = " + mld_key
                      + "   AND mld_kenmerk_key = " + kenmerk_key;
                  Oracle.Execute(sql);

                  // notificeer als iemand anders aan de bak moet,
                  if (!new_complete && new_prs_key != old_prs_key && new_prs_key > 0)
                  {
                    // Niet tracken, want dat verwart met de behandeling van de hoofdmeldingen.
                    // De behandeling van het blok wordt toegewezen, niet de behandeling van de melding immmers.
                    mld.notifybehandelaar2(mld_key, new_prs_key); // Notificatie behandelaar blok.
                  }
                  else if (!new_complete && new_disc_key != old_disc_key && new_prs_key == -1 && new_disc_key > 0)
                  {
                    // Wel MLDBHG notificatie, geen MLDBHG tracking want dat zou verwarrend zijn voor het hoofdbehandelteam.
                    mld.notifybehandelteam(mld_key, new_disc_key, true); // Notificatie hoofdbehandelteam.
                  }

                  // En dan wil ik deze aanpassing(en) tracken als een gewone wijziging (MLDUPD)
                  // Deze komt niet met de andere tracking mee, omdat de waarden niet bij de gewonen kenmerken zitten
                  // en daar de verschillen dus niet opgemerkt worden. Daarom hier.
                  if (!new_complete && new_disc_key != old_disc_key)
                  {
                    mldtrackarray.push(label + ": " + buildTrackText("key", (old_disc_key > -1? old_disc_key : null), (new_disc_key > -1 ? new_disc_key : ""), {foreign: "MLD_DISCIPLINE"}));
                  }
                  if (!new_complete && new_prs_key != old_prs_key)
                  {
                    mldtrackarray.push(label + ": " + buildTrackText("key", (old_prs_key > -1? old_prs_key : null), (new_prs_key > -1 ? new_prs_key : ""), {foreign: "PRS_PERSLID"}));
                  }
                  // een eventuele completering ook tracken
                  if (new_complete && !old_complete)  // is dat ook bij de undo?
                  {
                    mldtrackarray.push(label + ": " + buildTrackText("varchar", "", L("lcl_mld_is_blokafm"), {nodiff: true}));  // Hoe track je dat netter?
                  }
                }
              }
              else
              { // Er is geen mld_kenmerkblokmelding record aanwezig. Dat hoeft niet alleen bij een nieuwe melding zo te zijn. Dat kan o.a. ook bij een nieuw kenmerk "Bloktitel met behandelaar".
                // Behandelteam (ins_discipline_key), behandelaar (prs_perslid_key) en gereed (mld_kenmerkblokmelding_afmelddatum) zijn niet verplicht,.
                sql = "INSERT INTO mld_kenmerkblokmelding"
                    + "           (mld_melding_key"
                    + "          , mld_kenmerk_key"
                    + "          , ins_discipline_key"
                    + "          , prs_perslid_key"
                    + "          , mld_kenmerkblokmelding_afmelddatum"
                    + "           )"
                    + "    VALUES (" + mld_key
                    + "          , " + kenmerk_key
                    + "          , " + (new_disc_key > 0? new_disc_key : "NULL")
                    + "          , " + (new_prs_key > 0? new_prs_key : "NULL")
                    + "          , " + (new_complete > 0? "SYSDATE" : "NULL")
                    + "           )";
                Oracle.Execute(sql);

                // Notificeren en tracken van default mld_kenmerkblokmelding behandelteam en behandelaar gebeurt pas bij het accepteren van de melding (FCLT#86882).
                // Dan is de status "Gaccepteerd(4)" of "Uitgegeven(7)"
                if (mld_status == 4 || mld_status == 7)
                {
                  if (!new_complete && new_prs_key > 0)
                  {
                    // Niet tracken, want dat verwart met de behandeling van de hoofdmeldingen.
                    // De behandeling van het blok wordt toegewezen, niet de behandeling van de melding immmers.
                    mld.notifybehandelaar2(mld_key, new_prs_key); // Notificatie behandelaar blok.
                  }
                  else if (!new_complete && new_disc_key > 0)
                  {
                    // Wel MLDBHG notificatie, geen MLDBHG tracking want dat zou verwarrend zijn voor het hoofdbehandelteam.
                    mld.notifybehandelteam(mld_key, new_disc_key, true); // Notificatie hoofdbehandelteam.
                  }

                  // Er zijn geen oude waardes, want het mld_kenmerkblokmelding was niet aanwezig. Er is ook nog geen kenmerk omschrijving (label).
                  sql = "SELECT COALESCE (" + lcl.xsql("k.mld_kenmerk_omschrijving", "k.mld_kenmerk_key")
                     + "               ,  " + lcl.xsql("sk.mld_srtkenmerk_omschrijving", "sk.mld_srtkenmerk_key") + ") kenmerk_omschrijving"
                     + "   FROM mld_kenmerk k"
                     + "      , mld_srtkenmerk sk"
                     + "  WHERE k.mld_srtkenmerk_key = sk.mld_srtkenmerk_key"
                     + "    AND k.mld_kenmerk_key = " + kenmerk_key;
                  oRsk = Oracle.Execute(sql);
                  var label = oRsk("kenmerk_omschrijving").Value; // For tracking only.
                  oRsk.Close();
                  if (!params.isNew && !new_complete && new_disc_key > 0)
                  {
                    mldtrackarray.push(label + ": " + buildTrackText("key", null, new_disc_key, {foreign: "MLD_DISCIPLINE"}));
                  }
                  if (!params.isNew && !new_complete && new_prs_key > 0)
                  {
                    mldtrackarray.push(label + ": " + buildTrackText("key", null, new_prs_key, {foreign: "PRS_PERSLID"}));
                  }
                  if (!params.isNew && new_complete)
                  {
                    mldtrackarray.push(label + ": " + buildTrackText("varchar", "", L("lcl_mld_is_blokafm")), {nodiff: true});  // Hoe track je dat netter?
                  }
                }
              }
              oRsb.Close();

              return mldtrackarray;
            },

        deleteOldFlexBlocks: // Geef onderwerp, omschrijving en notities terug als JSON object
            function(mld_key, blokkenmerk_key_arr)
            { // Als een melding is doorgestuurd kunnen er mld_kenmerkblokmelding van de oude stdmelding zijn die verwijderd moeten worden.
              sql = "DELETE FROM mld_kenmerkblokmelding"
                  + " WHERE mld_kenmerkblokmelding_key IN"
                  + "           (SELECT kbm.mld_kenmerkblokmelding_key"
                  + "              FROM mld_kenmerkblokmelding kbm"
                  + "             WHERE kbm.mld_melding_key = " + mld_key
                  + (blokkenmerk_key_arr.length
                    ? "               AND kbm.mld_kenmerk_key NOT IN (" + blokkenmerk_key_arr.join(",") + ")"
                    : "")
                  + "           )";
              Oracle.Execute(sql);
            },

        getmldjson: // Geef onderwerp, omschrijving en notities terug als JSON object
            function(mld_key)
            {
              var json_result = {
                notities: []
              };
              var sql = "SELECT m.mld_melding_onderwerp,"
                      + "       TO_CHAR (SUBSTR (m.mld_melding_omschrijving, 1, 4000))"
                      + "           mld_melding_omschrijving,"
                      + "       s.mld_stdmelding_omschrijving,"
                      + "       d.ins_discipline_omschrijving,"
                      + "       t.ins_srtdiscipline_omschrijving"
                      + "  FROM mld_melding        m,"
                      + "       mld_stdmelding     s,"
                      + "       mld_discipline     d,"
                      + "       ins_srtdiscipline  t"
                      + " WHERE m.mld_melding_key = " + mld_key
                      + "   AND m.mld_stdmelding_key = s.mld_stdmelding_key"
                      + "   AND s.mld_ins_discipline_key = d.ins_discipline_key"
                      + "   AND d.ins_srtdiscipline_key = t.ins_srtdiscipline_key";
              var oRs = Oracle.Execute(sql);
              if (!oRs.EoF) {
                json_result.type = oRs("ins_srtdiscipline_omschrijving").Value;
                json_result.categorie = oRs("ins_discipline_omschrijving").Value;
                json_result.melding = oRs("mld_stdmelding_omschrijving").Value;
                json_result.onderwerp = oRs("mld_melding_onderwerp").Value;
                json_result.omschrijving = oRs("mld_melding_omschrijving").Value;
              }
              oRs.Close();
              sql = "SELECT COALESCE (mld_melding_note_wijzigdatum, mld_melding_note_aanmaak) datum,"
                  + "       mn.mld_melding_note_omschrijving,"
                  + "       p.prs_perslid_naam_friendly"
                  + "  FROM mld_melding_note mn"
                  + "     , prs_v_perslid_fullnames_all p"
                  + " WHERE mn.prs_perslid_key = p.prs_perslid_key" // Geen outer-join want we willen hier geen tracking
                  + "   AND mld_melding_key = " + mld_key
                  + " ORDER BY mld_melding_note_aanmaak ASC";
              oRs = Oracle.Execute(sql);
              while (!oRs.EoF) {
                json_result.notities.push({
                  datum: new Date(oRs("datum").Value),
                  omschrijving: shared.stripbbcodes(oRs("mld_melding_note_omschrijving").Value),
                  naam: oRs("prs_perslid_naam_friendly").Value
                });
                oRs.MoveNext();
              }
              oRs.Close();
              return json_result;
            },

        getStatusSql:
            function(mldstatus_str, alias)
            {
              var sql = "";
              alias = alias || "mld_melding";
              mldstatus_str = String(mldstatus_str);
              if (mldstatus_str)
              {
                // Aantal openstaande opdrachten of offertes
                // Openstaande opdrachten hebben de status 10, 3, 4 of 5.
                // Openstaande offertes hebben de status 10, 3, 4, 5 of 6.
                // Offerte Acceptatie: offerte met een opdracht status 6 ook als open zien.
                var sql_opdr_be_open = " CASE (SELECT COUNT(o.mld_opdr_key)"
                                       + " FROM mld_opdr o"
                                       + " WHERE mld_melding_key = " + alias + ".mld_melding_key)"
                                     + " WHEN 0"
                                     + " THEN -1"
                                     + " ELSE (SELECT COUNT (o.mld_statusopdr_key)"
                                     + "         FROM mld_opdr o"
                                      + "       WHERE mld_melding_key = " + alias + ".mld_melding_key"
                                      + "         AND o.mld_statusopdr_key NOT IN (1, 2, 6, 7, 9))"
                                     + " END";

                // Aantal offertes niet in de status Afgewezen(1), Afgekeurd(2), Afgemeld(6) of Verwerkt(7).
                // Omdat de sql_offertes_afgerond en sql_offertes_toaccept altijd worden gebruikt
                // in combinatie met "AND sql_opdr_be_open  = 0" en/of "AND m.mld_melding_status = 4" is "o.mld_statusopdr_key = 9"
                // ook mogelijk i.p.v. o.mld_statusopdr_key NOT IN (1, 2, 6, 7). De statusen voor open opdrachten vallen er dan toch buiten.
                // Een offerte die afgemeld, afgekeurd, afgewezen of verwerkt wordt, veranderd de status van de melding niet.
                // Een offerte die afgerond(9) wordt veranderd de status van de melding van "Offerte acceptatie" naar "Offerte geaccepteerd".
                // a) Aantal afgeronde(9) offertes (die niet status 1, 2, 6 en/of 7 hebben)
                //   (Er zijn geen opdrachten) => AND mld_opdr_key > 0
                // b) Aantal afgeronde(9) offertes/opdrachten (die geen status 1, 2, 6 en/of 7 hebben)
                //    (Er zijn opdrachten van eerdere offertes) => AND mld_opdr_key > MAX(o1.mld_opdr_key)
                var sql_offertes_afgerond = " (SELECT COUNT(o.mld_statusopdr_key)"
                                          + "         FROM mld_opdr o"
                                          + "            , mld_typeopdr mo"
                                          + "        WHERE o.mld_typeopdr_key = mo.mld_typeopdr_key"
                                          + "          AND o.mld_melding_key = " + alias + ".mld_melding_key"
                                          + "          AND mo.mld_typeopdr_isofferte = 1"
                                          + "          AND o.mld_statusopdr_key = 9" // AND o.mld_statusopdr_key NOT IN (1, 2, 6, 7)
                                          + "          AND o.mld_opdr_key > COALESCE ((SELECT MAX(o1.mld_opdr_key)"
                                          + "                                            FROM mld_opdr o1"
                                          + "                                               , mld_typeopdr mo1"
                                          + "                                           WHERE o1.mld_typeopdr_key = mo1.mld_typeopdr_key"
                                          + "                                             AND mo1.mld_typeopdr_isofferte = 0"
                                          + "                                             AND o1.mld_melding_key = " + alias + ".mld_melding_key), 0))";
                // Als alle offertes zijn afgewezen of afgekeurd en er zijn geen te accepteren offertes meer dan is de melding status "Niet opgelost"
                var sql_offertes_toaccept = " (SELECT COUNT(o.mld_statusopdr_key)"
                                          + "         FROM mld_opdr o"
                                          + "            , mld_typeopdr mo"
                                          + "        WHERE o.mld_typeopdr_key = mo.mld_typeopdr_key"
                                          + "          AND o.mld_melding_key = " + alias + ".mld_melding_key"
                                          + "          AND mo.mld_typeopdr_isofferte = 1"
                                          + "          AND o.mld_statusopdr_key = 6" // AND o.mld_statusopdr_key NOT IN (1, 2, 6, 7)
                                          + "          AND o.mld_opdr_key > COALESCE ((SELECT MAX(o1.mld_opdr_key)"
                                          + "                                            FROM mld_opdr o1"
                                          + "                                               , mld_typeopdr mo1"
                                          + "                                           WHERE o1.mld_typeopdr_key = mo1.mld_typeopdr_key"
                                          + "                                             AND mo1.mld_typeopdr_isofferte = 0"
                                          + "                                             AND o1.mld_melding_key = " + alias + ".mld_melding_key), 0))";

                // Is de laatste opdracht bij de melding een offerte?
                var sql_last_is_offertes = " COALESCE((SELECT 1"
                                         + "             FROM mld_opdr o"
                                         + "                , mld_typeopdr mo"
                                         + "            WHERE o.mld_typeopdr_key = mo.mld_typeopdr_key"
                                         + "              AND mo.mld_typeopdr_isofferte = 1"
                                         + "              AND o.mld_melding_key = " + alias + ".mld_melding_key"
                                         + "              AND o.mld_opdr_key = (SELECT MAX(o1.mld_opdr_key)"
                                         + "                                      FROM mld_opdr o1"
                                         + "                                     WHERE o1.mld_melding_key = " + alias + ".mld_melding_key)), 0)";

                // In mldstatus_str kan de waarde 99 "Niet opgelost" voorkomen. Dit is geen bestaande status.
                if (mldstatus_str.indexOf("-1") == -1)
                { // Als alle(-1) niet is geselecteerd
                  // status         | aantal opdrachten | aantal open opdrachten | status key
                  // ____________________________________________________________________________
                  // geaccepteerd   |        0          |           0            |     4
                  // niet opgelost  |        >0         |           0            |     4 (99)
                  // uitgegeven     |        >0         |           >0           |     7
                  // Alleen bij niet opgelost en uitgegeven moet er gekeken worden naar het aantal (open) opdrachten
                  // sql_opdr_be_open is -1 als aantal opdrachten 0 is
                  // sql_opdr_be_open is 0 als aantal opdrachten > 0 waarvan 0 open
                  // sql_opdr_be_open is >0 als aantal opdrachten > 0 waarvan >0 open
                  // Voor status 4 komen twee statussen voor geaccepteerd(4) en niet opgelost(99).
                  // Voor status 5 komen twee statussen voor afgemeld(5) en niet opgelost(99).

                  // Mogelijkheden statussen 4, 5 en 99 in de mldstatus_str die vertaald moeten worden naar de goed status voorwaarde:
                  // 1) Geen van de statussen 4, 5 en 99.
                  // 2) Status 4, 5 en 99.
                  // 3) Status 4 en 5.
                  // 4) Status 4 en 99.
                  // 5) Status 5 en 99.
                  // 6) Status 4.
                  // 7) Status 5.
                  // 8) Status 99.
                  if ((mldstatus_str.indexOf("4") == -1 && mldstatus_str.indexOf("5") == -1 && mldstatus_str.indexOf("99") == -1) ||   // Geen status 4, 5 en 99. (1)
                      (mldstatus_str.indexOf("4") != -1 && mldstatus_str.indexOf("99") != -1))                                         // Status 4 en 99 of stutus 4, 5 en 99. (2) en (4)
                  { // Als geaccepteerd(4), afgemeld(5) en niet opgelost(99) samen wel of niet zijn geselecteerd of
                    // als geaccepteerd(4) en niet opgelost(99) zijn geselecteerd zonder afgemeld(5).
                    var status_split = mldstatus_str.split(',');
                    if ((mldstatus_str.indexOf("4") != -1) && mldstatus_str.indexOf("99") != -1)
                    { // Verwijder 99 uit de mldstatus_str. Niet alleen 99 is aanwezig, ook 4 is aanwezig.
                      mldstatus_str = "";
                      for (i = 0; i < status_split.length; i++)
                      {
                        if (status_split[i] != "99")
                          mldstatus_str += (mldstatus_str == ""? "" : ", ") + status_split[i];
                      }
                    }
                    sql = " (" + alias + ".mld_melding_status IN (" + mldstatus_str + ")"
                        + (mldstatus_str.indexOf("5") == -1 && S("mld_assume_ok_days") > 0 // Geen afgemeld(5) aanwezig en setting "mld_assume_ok_days" is niet gezet.
                          ? " OR (" + alias + ".mld_melding_status IN (5) AND BITAND(" + alias + ".mld_melding_actiecode, 128) = 128)" // Niet opgelost(99) is afgemeld(5) met attentie BO/FO (actiecode 128).
                          : "")
                        + ")";
                  }
                  else if (mldstatus_str.indexOf("99") != -1 && mldstatus_str.indexOf("4") == -1)                                      // Status 99 of status 5 en 99 (Geen 4). (5) en (8)
                  { // Als niet opgelost(99) is geselecteerd en geaccepteerd(4) is niet geselecteerd => Als Te behandelen (99) is aangevinkt.
                    var status_split = mldstatus_str.split(',');

                    if (status_split.length > 1)
                    { // Verwijder 99 uit de mldstatus_str. Niet alleen 99 is aanwezig.
                      mldstatus_str = "";
                      for (i = 0; i < status_split.length; i++)
                      {
                        if (status_split[i] != "99")
                          mldstatus_str += (mldstatus_str == ""? "" : ", ") + status_split[i];
                      }
                      sql = " (" + alias + ".mld_melding_status IN (" + mldstatus_str + ")"
                          + (mldstatus_str.indexOf("5") == -1 && S("mld_assume_ok_days") > 0 // Geen afgemeld(5) aanwezig en setting "mld_assume_ok_days" is niet gezet.
                            ? " OR (" + alias + ".mld_melding_status IN (5) AND BITAND(" + alias + ".mld_melding_actiecode, 128) = 128)" // Niet opgelost(99) is afgemeld(5) met attentie BO/FO (actiecode 128).
                            : "")
                           // Voor meldingstatus 4 geldt dat er geen open opdrachten zijn.
                           // En daarnaast geldt:
                           // Opdrachten: De laatste opdracht is geen offerte.
                           // Offertes: Offertes met niet afgemelde (6) offertes niet tonen (laatste opdracht is een offerte).
                           + " OR ((" + sql_opdr_be_open + " = 0 AND (" + sql_offertes_afgerond + " != 0 OR " + sql_offertes_toaccept + " = 0 OR " + sql_last_is_offertes + " = 0))"
                           + " AND (" + alias + ".mld_melding_status = 4)))";
                    }
                    else
                    { // Alleen 99 is aanwezig.
                      // Voor meldingstatus 4 geldt dat er geen open opdrachten zijn.
                      // En daarnaast geldt:
                      // Opdrachten: De laatste opdracht is geen offerte.
                      // Offertes: Offertes met niet afgemelde (6) offertes niet tonen (laatste opdracht is een offerte).
                      sql = " ((" + sql_opdr_be_open + " = 0 AND (" + sql_offertes_afgerond + " != 0 OR " + sql_offertes_toaccept + " = 0 OR " + sql_last_is_offertes + " = 0))"
                          + " AND (" + alias + ".mld_melding_status = 4))";
                    }
                  }
                  else if (mldstatus_str.indexOf("4") != -1)                                                                           // Status 4 of status 4 en 5. (3) en (6)
                  { // Als geaccepteerd(4) is geselecteerd en niet opgelost(99) is niet geselecteerd => Als In behandeling (4) is aangevinkt.
                    var status_split = mldstatus_str.split(',');
                    if (status_split.length > 1)
                    { // verwijder 4 uit de mldstatus_str. Niet alleen 4 is aanwezig.
                      mldstatus_str = "";
                      for (i = 0; i < status_split.length; i++)
                      {
                        if (status_split[i] != "4")
                          mldstatus_str += (mldstatus_str == ""? "" : ", ") + status_split[i];
                      }
                      sql = " (" + alias + ".mld_melding_status IN (" + mldstatus_str + ")"
                          // Voor meldingstatus 4 geldt.
                          // Opdrachten: Er zijn geen opdrachten.
                          // Offertes: Alle offertes staan ter acceptatie (zijn afgemeld (6)) (laatste opdracht is een offerte)
                          + " OR ((" + sql_opdr_be_open + " = -1 OR (" + sql_offertes_afgerond + " = 0 AND " + sql_offertes_toaccept + " > 0 AND " + sql_last_is_offertes + " = 1))"
                          + " AND (" + alias + ".mld_melding_status = 4)))";
                    }
                    else
                    { // Alleen 4 is aanwezig.
                      // Voor meldingstatus 4 geldt.
                      // Opdrachten: Er zijn geen opdrachten.
                      // Offertes: Alle offertes staan ter acceptatie (zijn afgemeld (6)) (laatste opdracht is een offerte)
                      sql = " ((" + sql_opdr_be_open + " = -1 OR (" + sql_offertes_afgerond + " = 0 AND " + sql_offertes_toaccept + " > 0 AND " + sql_last_is_offertes + " = 1))"
                          + " AND (" + alias + ".mld_melding_status = 4))";
                    }
                  }
                  else if (mldstatus_str.indexOf("5") != -1)                                                                           // Status 5. (7)
                  { // Als afgemeld(5) is geselecteerd en geaccepteerd(4) en niet opgelost(99) zijn niet geselecteerd.
                    sql = " " + alias + ".mld_melding_status IN (" + mldstatus_str + ")";
                  }
                  //
                  // Als meldingstatus Te behandelen(2) is aangevinkt EN spoedmeldingen moeten bij Te behandelen worden getoond,
                  // voeg dan de spoedmeldingen toe.
                  // Ook als de melding in Uitgegeven(7) en er is een opdracht Toegekend(5).
                  if (S("mld_show_urgent_as_new") && mldstatus_str.indexOf("2") != -1)
                  {
                      var add_spoed = " OR (   (" + alias + ".mld_melding_spoed < 3)"
                                    +    " AND (  (" + alias + ".mld_melding_status IN (2, 4))"
                                    +        " OR (   (" + alias + ".mld_melding_status = 7)"
                                    +           " AND ( (SELECT COUNT (o.mld_statusopdr_key)"
                                                      + "  FROM mld_opdr o"
                                                      + " WHERE mld_melding_key = " + alias + ".mld_melding_key"
                                                      + "   AND o.mld_statusopdr_key = 5"
                                                      + ") > 0)"
                                    +           " )"
                                    +        " )"
                                    +    " )";
                    sql = " (" + sql + add_spoed + ")";
                  }
                }
              }
              return sql;
            },

        // Meldingen worden soms niet geaccepteerd maar direct afgewezen of afgemeld.
        // Als dit binnen de acceptatietijd gebeurd dan is die melding niet te laat geaccepteerd.
        getwhere_to_late_accept_sql:
            function(mtable)
            {
              var sql = " CASE WHEN " + mtable + ".mld_melding_acceptdatum_std"
                                            + " < COALESCE(fac.gettrackingdate ('MLDACP', " + mtable + ".mld_melding_key)," // Geaccepteerde meldingen
                                            + "            fac.gettrackingdate ('MLDREJ', " + mtable + ".mld_melding_key)," // Direct afgewezen meldingen
                                            + "            fac.gettrackingdate ('MLDAFM', " + mtable + ".mld_melding_key)," // Direct afgemelde meldingen
                                            + "            SYSDATE)"
                      + " THEN 1"
                      + " ELSE 0"
                      + " END";
              return sql;
            },
        sql_on_time_run_sla:
            function()
            {
              var sql_on_time_run_sla = " CASE"
                                        + " WHEN std.mld_stdmelding_slabewaken = 0 OR m.mld_melding_indult = 1 THEN " + mld.sql_on_time_run_afspraak()
                                        + " ELSE CASE WHEN gau.actualuitvoertijd.tijdsduur / CASE"
                                        + "                                                  WHEN gau.actualuitvoertijd.eenheid = 'U'"
                                        + "                                                  THEN 24"
                                        + "                                                  ELSE 1"
                                        + "                                                  END"
                                        + "                <= "
                                        + "                (CASE"
                                        + "                WHEN m.mld_melding_t_uitvoertijd.eenheid = 'U'"
                                        + "                THEN m.mld_melding_t_uitvoertijd.tijdsduur / 24"
                                        + "                ELSE m.mld_melding_t_uitvoertijd.tijdsduur"
                                        + "                END + CASE"
                                        + "                      WHEN m.mld_melding_t_respijt.tijdsduur IS NULL"
                                        + "                      THEN 0"
                                        + "                      WHEN m.mld_melding_t_respijt.eenheid = 'U'"
                                        + "                      THEN m.mld_melding_t_respijt.tijdsduur / 24"
                                        + "                      ELSE m.mld_melding_t_respijt.tijdsduur"
                                        + "                      END)"
                                        + "           THEN 1"     // op tijd
                                        + "           ELSE 0"
                                        + "      END"
                                        + " END";
              return sql_on_time_run_sla
            },
        sql_on_time_run_afspraak:
            function()
            {
                  var sql_on_time_run_afspraak = " CASE WHEN m.mld_melding_einddatum >="
                                    + "      COALESCE(fac.gettrackingdate('MLDAFM', m.mld_melding_key), fac.gettrackingdate('MLDREJ', m.mld_melding_key), sysdate)"
                                    + "       THEN 1"    // op tijd
                                    + "       ELSE 0"
                                    + " END";
                  return sql_on_time_run_afspraak;
            },

        // Meldingen worden soms niet geaccepteerd maar direct afgewezen of afgemeld.
        // Als dit binnen de acceptatietijd gebeurd dan is die melding niet te laat geaccepteerd.
        getwhere_to_late_run_sql:
            function(mtable, stdtable, MorO)
            { // Ook meldingen waarvoor geldt dat mld_stdmelding_slabewaken = 0 of mld_melding_indult = 1,
              // moeten worden meegenomen in de query omdat in hetzelfde overzicht de 'Uitvoering op tijd (Afspraak) (%)' ook wordt weergegeven.
              // Deze meldingen worden dan niet meegenomen in de berekening van 'Uitvoering op tijd (SLA) (%)'.
              var sql = " CASE"
                      + " WHEN fac.gettrackingdate('MLDAFM', " + mtable + ".mld_melding_key) IS NULL"
                      + " THEN CASE"
                           + " WHEN(CASE "
                           + "      WHEN " + stdtable + ".mld_stdmelding_slabewaken = 1"
                           + "             AND NOT " + mtable + ".mld_melding_indult = 1"
                           // Als de respijtdatum null(0) is dan direct de einddatum nemen (anders wordt de stdmelding uitvoertijd er nog een keer bij opgeteld).
                           + "             AND " + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".tijdsduur IS NOT NULL"
                           + "             AND " + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".eenheid IS NOT NULL"
                           + "      THEN mld.geteinddatum(" + mtable + ".mld_melding_einddatum_std,"
                           +                              stdtable + ".mld_stdmelding_key,"
                           +                              mtable + ".mld_melding_spoed,"
                           + "                            NULL,"
                           + "                            NULL,"
                           + "                            MLD_T_UITVOERTIJD(COALESCE(" + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".tijdsduur, 0), " + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".eenheid))" // Rekening houden met respijt dagen.
                           + "      WHEN " + stdtable + ".mld_stdmelding_slabewaken = 1"
                           + "      THEN mld.geteinddatum(" + mtable + ".mld_melding_key)" // Geen rekening houden met respijt. Einddatum is aanmeldingsdatum/begindatum + SLA tijd.
                           + "      ELSE " + mtable + ".mld_melding_einddatum" // Geen rekening houden met respijt. Einddatum is ingevoerde einddatum.
                           + "      END) < COALESCE(fac.gettrackingdate('MLDREJ', " + mtable + ".mld_melding_key), SYSDATE)"
                                + " THEN 1"
                                + " ELSE 0"
                                + " END"
                      + " ELSE CASE WHEN(CASE "
                           + "           WHEN " + stdtable + ".mld_stdmelding_slabewaken = 1"
                           + "                  AND NOT " + mtable + ".mld_melding_indult = 1"
                           // Als de respijtdatum null(0) is dan direct de einddatum nemen (anders wordt de stdmelding uitvoertijd er nog een keer bij opgeteld).
                           + "                  AND " + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".tijdsduur IS NOT NULL"
                           + "                  AND " + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".eenheid IS NOT NULL"
                           + "           THEN mld.geteinddatum(" + mtable + ".mld_melding_einddatum_std,"
                           +                                   stdtable + ".mld_stdmelding_key,"
                           +                                   mtable + ".mld_melding_spoed,"
                           + "                                 NULL,"
                           + "                                 NULL,"
                           + "                                 MLD_T_UITVOERTIJD(COALESCE(" + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".tijdsduur, 0), " + mtable + (MorO == "M"? ".mld_melding_t_respijt" : "") + ".eenheid))" // Rekening houden met respijt dagen.
                           + "           WHEN " + stdtable + ".mld_stdmelding_slabewaken = 1"
                           + "           THEN mld.geteinddatum(" + mtable + ".mld_melding_key)" // Geen rekening houden met respijt. Einddatum is aanmeldingsdatum/begindatum + SLA tijd.
                           + "           ELSE " + mtable + ".mld_melding_einddatum" // Geen rekening houden met respijt. Einddatum is ingevoerde einddatum.
                           + "           END) < fac.gettrackingdate('MLDAFM', " + mtable + ".mld_melding_key)"
                           + " THEN 1"
                           + " ELSE 0"
                           + " END"
                      + " END";
              return sql;
            },

        getwhereSrttracking:
            function(params)
            {
              var datefrom = params.actiondatefrom;
              var dateto = params.actiondateto;
              var sqln = "";

              if (datefrom && dateto)
              {
                var ora_date1 = datefrom.beginToSQL();
                var ora_date2 = dateto.endToSQL();
                sqln = " AND fac_tracking_datum BETWEEN " + ora_date1 + " AND " + ora_date2;
              }
              else if (datefrom)
              {
                var ora_date1 = datefrom.beginToSQL();
                sqln = " AND fac_tracking_datum >= " + ora_date1;
              }
              else if (dateto)
              {
                var ora_date2 = dateto.endToSQL();
                sqln = " AND fac_tracking_datum < " + ora_date2;
              }

              var sql = "";
              if (params.srt_tracking && params.srt_tracking != "-1")
              {
                var xmlnode_arr = { melding: [], opdracht: [] };
                var ssql = "SELECT fac_srtnotificatie_xmlnode, "
                         + "       fac_srtnotificatie_key"
                         + "  FROM fac_srtnotificatie"
                         + " WHERE fac_srtnotificatie_code IN (" + safe.quoted_sql_join(params.srt_tracking, false) + ")";
                var oRs = Oracle.Execute(ssql);
                while (!oRs.eof)
                {
                    var xmlnode = oRs("fac_srtnotificatie_xmlnode").Value;
                    var srtnoti_key = oRs("fac_srtnotificatie_key").Value;
                    var fac_srtnotificatie_key = oRs("fac_srtnotificatie_key").Value;
                    xmlnode_arr[xmlnode].push(srtnoti_key);
                    oRs.MoveNext();
                }
                oRs.Close();

                var groep_opdr = (params.groepering_key == 2 || params.groepering_key == 16);
                sql += " AND ("
                     +     ( xmlnode_arr.melding.length > 0
                           ? "  EXISTS (SELECT 1"
                           + "            FROM fac_tracking ft"
                           + "           WHERE ft.fac_srtnotificatie_key IN (" + xmlnode_arr.melding.join(",") + ")"
                           + "             AND ft.fac_tracking_refkey = m.mld_melding_key"
                           +             sqln
                           +             (params.prs_tracking > 0?"       AND ft.prs_perslid_key = " + params.prs_tracking:"")
                           + "         )"
                           : "(1=0)"
                           )
                     + "     OR"
                     +     ( xmlnode_arr.opdracht.length > 0
                           ? "  EXISTS (SELECT 1"
                           + "            FROM fac_tracking ft"
                           +             (!groep_opdr?" , mld_opdr o":"")
                           + "           WHERE ft.fac_srtnotificatie_key IN (" + xmlnode_arr.opdracht.join(",") + ")"
                           + "             AND ft.fac_tracking_refkey = o.mld_opdr_key"
                           +             sqln
                           +             (params.prs_tracking > 0?"       AND ft.prs_perslid_key = " + params.prs_tracking:"")
                           +             (!groep_opdr?" AND o.mld_melding_key = m.mld_melding_key":"")
                           + "         )"
                           : "(1=0)"
                           )
                     + "     )";
              }
              return sql;
            },

        getwherePrstracking:
            function(params)
            {
              var sql = "";
              if (params.prs_tracking > 0 && params.srt_tracking == "-1")
              {
                sql += " AND (EXISTS"
                    + "   (SELECT 1"
                    + "      FROM fac_tracking ft, fac_srtnotificatie sn"
                    + "     WHERE ft.fac_tracking_refkey = m.mld_melding_key"
                    + "       AND ft.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                    + "       AND sn.fac_srtnotificatie_xmlnode = 'melding'"
                    + "       AND ft.prs_perslid_key = " + params.prs_tracking + ")"
                    + " OR EXISTS"
                    + "   (SELECT 1"
                    + "      FROM fac_tracking ft, mld_opdr o, fac_srtnotificatie sn"
                    + "     WHERE ft.fac_tracking_refkey = o.mld_opdr_key"
                    + "       AND ft.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                    + "       AND sn.fac_srtnotificatie_xmlnode = 'opdracht'"
                    + "       AND ft.prs_perslid_key = " + params.prs_tracking
                    + "       AND o.mld_melding_key = m.mld_melding_key" + "))";
              }
              return sql;
            },

        getfromwherelist_sql:
            function(pautfunction, params)
            {
              var treat          = params.treat;
              var mld_key        = params.mld_key;
              var mld_key_arr    = params.mld_key_arr || [];
              var opdr_key       = params.opdr_key; // de zichtbare opdrachtkey (eigenlijk meldingkey)
              var intopdr_key    = params.intopdr_key;  // de technische echte mld_opdr_key
              var mldstatus_arr  = params.mldstatus_arr;
              var opdrstatus_arr = params.opdrstatus_arr;
              var caller_key     = params.caller_key;
              var comp_key       = params.comp_key;
              var org_key        = params.org_key;
              var ref_key        = params.ref_key;
              var ref_type       = params.ref_type;
              var reg_key_arr    = params.reg_key_arr || [];
              var dist_key_arr   = params.dist_key_arr || [];
              var loc_key_arr    = params.loc_key_arr || [];
              var bld_key_arr    = params.bld_key_arr || [];
              var flr_key_arr    = params.flr_key_arr || [];
              var room_key_arr   = params.room_key_arr || [];
              var disc_type      = params.disc_type || 1;
              var mld_ins_discipline_key_arr = params.mld_ins_discipline_key_arr || [];
              var behandel_key     = params.behandel_key; // wordt nog bij mobile gebruikt
              var behandel_key_arr = params.behandel_key_arr || [];
              var behandel2_key    = params.behandel2_key; // wordt nog bij mobile gebruikt
              var behandel2_key_arr= params.behandel2_key_arr || [];
              // Dit is de "relevante" behandelaar;
              // dus bij vakgroepen met teams -> actieve behandelaar
              // en bij vakgroepen zonder teams -> primaire behandelaar
              var behandel3_key    = params.behandel3_key; // wordt nog bij mobile gebruikt
              //var behandel3_key_arr= params.behandel3_key_arr || []; // Komt alleen in dit bestand nog voor. De parameter is dus altijd leeg en doet niets (meer).
              var srtdisc_key_arr  = params.srtdisc_key_arr || [];
              var disc_key_arr     = params.disc_key_arr || [];
              var meldinggrp_key   = params.meldinggrp_key;
              var behandelgrp_key  = params.behandelgrp_key;
              var stdm_key_arr     = params.stdm_key_arr || [];
              var kpgrp_key_arr    = params.kpgrp_key_arr || [];
              var kp_key_arr       = params.kp_key_arr || [];
              var tag_key_arr      = params.tag_key_arr || [];
              var handler_key      = params.handler_key;
              var uitvopdr_key     = params.uitvopdr_key;
              var contact_key      = params.contact_key;
              var opdrtype_key     = params.opdrtype_key;
              var chkSearchOR      = params.chkSearchOR;
              var searchtekst      = params.searchtekst;
              var omschr           = params.omschr;
              var disc_key         = params.disc_key;
              var insgroup_key     = params.insgroup_key;
              var objsrt_key_arr   = params.objsrt_key_arr || [];
              var objectoms        = params.objectoms;
              var chkAcceptEx      = params.chkAcceptEx;
              var chkRunEx         = params.chkRunEx;
              var chkSpoed         = params.chkSpoed;
              var chkAfgerond      = params.chkAfgerond;
              var showRespijt      = params.respijt;
              var showIndult       = params.indult;
              var onlyConcepts     = params.onlyConcepts;
              var inclConcepts     = params.inclConcepts;
              var datefrom         = params.datefrom;
              var dateto           = params.dateto;
              var enddatefrom      = params.enddatefrom;
              var enddateto        = params.enddateto;
              var groepering_key   = params.groepering_key;
              // JGL: Volgens mij komen 2 en 16 hier nooit, die zijn naar opdr_list geleid
              var toon_opdr_overz  = (groepering_key == 2 || groepering_key == 10 || groepering_key == 11 || groepering_key == 16 || groepering_key == 17);
              var offertes         = params.offertes;
              var meldbron_key     = params.meldbron_key;
              var ingevoerd        = params.ingevoerd;
              var verantw_key      = params.verantw_key;
              var vervolgmld       = params.vervolgmld; // null, 1 or 2
              var completed        = params.completed; // null, 1 or 2
              var priority_arr     = params.priority_arr || [];   // 1,2,3 or 4
              var public           = (params.public==1);

              //var dienst_key     = params.dienst_key;
              var deel_key         = params.deel_key;
              var deelsrtcont_key  = params.deelsrtcont_key;
              var rsv_ruimte_key   = params.rsv_ruimte_key;
              var referencetype    = params.referencetype;
              //var stdm_key = params.stdm_key; // Ondersteunen we dit nog
              var mldstpen = params.mldstpen;
              var mldstnew = params.mldstnew;
              var mldstacc = params.mldstacc;
              var mldstuit = params.mldstuit;
              var mldstrej = params.mldstrej;
              var mldstafm = params.mldstafm;
              var mldstver = params.mldstver;
              var mldnieto = params.mldnieto;

              // Dit lijkt me om te kunnen bepalen of ik uberhaupt naar de PRS-autorisatie hoef te kijken
              var add_prs_restrict = prshasrestrict(pautfunction);

              var sqln = "";
              sqln += " FROM mld_melding m"
                    + ", mld_discipline md"
                    + (disc_type == 2
                      ? ", mld_discipline md2"
                      : "")
                    + ", mld_disc_params mdp"
                    + ", alg_v_allonrgoed_gegevens v"
                    + ", alg_locatie l"
                    + ", alg_district di"
                    + ((verantw_key || groepering_key == 23)
                      ? ", alg_gebouw g, alg_terreinsector t"
                      : "")
                    + ", (SELECT m1.mld_melding_key"
                      + "      , mld.getactualuitvoer (m1.mld_melding_key) actualuitvoertijd"
                      + "   FROM mld_melding m1) gau"
                    + ", prs_perslid p"
                    + (kpgrp_key_arr.length
                      ? ", prs_kostenplaats k"
                      : "")
                    + ", mld_stdmelding std"
                    + ", mld_stdmeldinggroep stdg"
                    + ((add_prs_restrict)? ", prs_v_afdeling_boom b" : "")
                    + ((perform && srtdisc_key_arr.length) || !perform  || treat
                      ? ", ins_srtdiscipline sd"
                      : "")
                    + (treat
                      ? ", mld_kenmerk k"
                      + ", mld_srtkenmerk sk"
                      + ", mld_kenmerkblokmelding kbm"
                      : "")
                    + (true
                      ? ", mld_melding_tag mmt"
                      : "")
                    + (toon_opdr_overz
                      ? ", mld_opdr o"
                      : "")
                    + (offertes
                      ? ",   (SELECT o1.mld_melding_key" // Meldingen met zijn aantal offertes
                        + "        , COUNT (o1.mld_opdr_key) aantal_offertes"
                        + "        , MAX(o1.mld_opdr_bedrijfopdr_volgnr) lastoffertevolgnr"
                        + "     FROM mld_opdr o1"
                        + "        , mld_typeopdr mto"
                        + "    WHERE o1.mld_typeopdr_key = mto.mld_typeopdr_key"
                        + "      AND mto.mld_typeopdr_isofferte = 1"
                        + "   GROUP BY o1.mld_melding_key) offerte"
                        // Nodig om extra class orderready toe te kunnen toevoegen dat aangeeft dat er actie nodig is (uitvoeringsopdracht aanmaken, nieuwe offerte aanmaken of melding afmelden).
                        + ", (SELECT o2.mld_melding_key" // Meldingen met aantal offertes met de status Afgewezen (1), Afgekeurd (2) en/of Technisch Voltooid/Afgemeld (6)
                        + "        , COUNT (o2.mld_opdr_key) aantal_offready"
                        + "     FROM mld_opdr o2"
                        + "        , mld_typeopdr mto"
                        + "    WHERE o2.mld_typeopdr_key = mto.mld_typeopdr_key"
                        + "      AND mto.mld_typeopdr_isofferte = 1"
                        + "      AND o2.mld_statusopdr_key IN (1, 2, 6)"
                        + "   GROUP BY o2.mld_melding_key) offready"
                        // Nodig om meldingen met alleen afgewezen en afgekeurde opdrachten niet meer te tonen als melding in offerte traject
                        + ", (SELECT o3.mld_melding_key" // Meldingen met aantal offertes met de status Afgewezen (1) en/of Afgekeurd (2).
                        + "        , COUNT (o3.mld_opdr_key) aantal_offallnok"
                        + "     FROM mld_opdr o3"
                        + "        , mld_typeopdr mto"
                        + "    WHERE o3.mld_typeopdr_key = mto.mld_typeopdr_key"
                        + "      AND mto.mld_typeopdr_isofferte = 1"
                        + "      AND o3.mld_statusopdr_key IN (1, 2)"
                        + "   GROUP BY o3.mld_melding_key) offallnok"
                        + ", (SELECT o4.mld_melding_key" // Meldingen zonder opdrachten
                        + "        , COUNT (o4.mld_opdr_key) aantal_opdrachten"
                        + "        , MAX(o4.mld_opdr_bedrijfopdr_volgnr) lastopdrachtvolgnr"
                        + "     FROM mld_opdr o4"
                        + "        , mld_typeopdr mto"
                        + "    WHERE o4.mld_typeopdr_key = mto.mld_typeopdr_key"
                        + "      AND mto.mld_typeopdr_isofferte = 0"
                        + "   GROUP BY o4.mld_melding_key) opdracht"
                      : "")
                    + (deelsrtcont_key
                      ? ", mld_melding_object mo"
                      : "");

              if (ingevoerd)
              {
                  sqln += " , (SELECT prs_perslid_key"
                            + " , fac_tracking_refkey mld_melding_key"
                            + " FROM fac_tracking t"
                            + " , fac_srtnotificatie sn"
                            + " WHERE t.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                            + " AND sn.fac_srtnotificatie_code = 'MLDNEW') invoerder";
              }

              if (params.kaarten && ("mldbordColumn" in params) && params.mldbordColumn > 0) {
                  var srtkenmerk_key = params.mldbordColumn;
                  var kenmerk_omschrijving = params.mldbordColumnDescr;
                  sqln += ", (SELECT km.mld_melding_key"
                        + "        , k.mld_kenmerk_key"
                        + "        , km.mld_kenmerkmelding_waarde"
                        + "        , flx.getdomeinwaarde (skm.fac_kenmerkdomein_key, km.mld_kenmerkmelding_waarde) waardetext"
                        + "     FROM mld_srtkenmerk skm, mld_kenmerk k, mld_kenmerkmelding km"
                        + "    WHERE k.mld_kenmerk_key = km.mld_kenmerk_key"
                        + "      AND skm.mld_srtkenmerk_key = k.mld_srtkenmerk_key"
                        + "      AND skm.mld_srtkenmerk_verwijder IS NULL"
                        + "      AND skm.mld_srtkenmerk_key = " + srtkenmerk_key
                        + "      AND COALESCE (k.mld_kenmerk_omschrijving, skm.mld_srtkenmerk_omschrijving) = " + safe.quoted_sql(kenmerk_omschrijving) + ") kmv";
              }

              sqln += " WHERE m.mld_alg_locatie_key = l.alg_locatie_key(+)"
                    + " AND l.alg_district_key = di.alg_district_key(+)"
                    + " AND m.mld_alg_onroerendgoed_keys = v.alg_onroerendgoed_keys(+)"
                    + " AND m.prs_perslid_key = p.prs_perslid_key"
                    + " AND md.ins_discipline_key = mdp.mld_ins_discipline_key"
                    + " AND md.ins_discipline_key = std.mld_ins_discipline_key"
                    + (public ? " AND m.mld_melding_publiek = 1" : "")
                    + (disc_type == 2
                      ? " AND m.mld_ins_discipline_key = md2.ins_discipline_key(+)"
                      : "")
                    + ((add_prs_restrict)
                      ? " AND b.prs_afdeling_key = COALESCE(m.prs_afdeling_key, p.prs_afdeling_key)"
                      : "")
                    + " AND std.mld_stdmelding_key = m.mld_stdmelding_key"
                    + " AND std.mld_stdmeldinggroep_key = stdg.mld_stdmeldinggroep_key(+)"
                    + " AND m.mld_melding_key = gau.mld_melding_key"
                    + ((perform && srtdisc_key_arr.length) || !perform || treat
                      ? " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
                      : "")
                    + (!perform
                      ? " AND m.fac_activiteit_key IS NULL"
                      : "")
                    + (treat
                      ? " AND m.mld_melding_key = kbm.mld_melding_key"
                        + " AND k.mld_kenmerk_key = kbm.mld_kenmerk_key"
                        + " AND k.mld_srtkenmerk_key = sk.mld_srtkenmerk_key"
                        + " AND ((k.mld_stdmelding_key IS NULL"
                        + "   AND k.mld_kenmerk_niveau = 'A')"
                        + "   OR (k.mld_stdmelding_key = std.mld_stdmelding_key"
                        + "   AND k.mld_kenmerk_niveau = 'S')"
                        + "   OR (k.mld_stdmelding_key = std.mld_ins_discipline_key"
                        + "   AND k.mld_kenmerk_niveau = 'D')"
                        + "   OR (k.mld_stdmelding_key = md.ins_srtdiscipline_key"
                        + "   AND k.mld_kenmerk_niveau = 'T'))"
                        + " AND sk.mld_srtkenmerk_verwijder IS NULL"
                        + " AND k.mld_kenmerk_verwijder IS NULL"
                        + " AND sk.mld_srtkenmerk_kenmerktype = 'b'"
                      : "")
                    + (true // todo?
                      ? " AND m.mld_melding_tag_key = mmt.mld_melding_tag_key(+)"
                      : "")
                    + (toon_opdr_overz
                      ? " AND m.mld_melding_key = o.mld_melding_key(+)"
                      : "")
                    + (offertes
                      ? " AND offerte.mld_melding_key = m.mld_melding_key"
                        + " AND offerte.mld_melding_key = opdracht.mld_melding_key(+)"
                        + " AND offerte.mld_melding_key = offready.mld_melding_key(+)"
                        + " AND offerte.mld_melding_key = offallnok.mld_melding_key(+)"
                        + " AND offerte.aantal_offertes > 0"
                        + " AND offerte.aantal_offertes != COALESCE(offallnok.aantal_offallnok , 0)" // offertes met alleen afgekeurde/afgewezen opdrachten niet tonen
                        + " AND (opdracht.aantal_opdrachten IS NULL"
                        + "      OR opdracht.lastopdrachtvolgnr < offerte.lastoffertevolgnr)"
                      : "")
                    + (ingevoerd
                      ? " AND m.mld_melding_key = invoerder.mld_melding_key"
                      : "")
                    + (showRespijt
                      ? ""
                      : " AND m.mld_melding_t_respijt.tijdsduur IS NULL")
                    + (showIndult
                      ? ""
                      : " AND m.mld_melding_indult = 0")
                    + (onlyConcepts ? " AND m.mld_melding_conceptstatus <> 0"                   // Speciaal en uniek voor de &concept=1 pagina
                                    : (inclConcepts ? ""                                        // Frontend mag al zijn eigen meldingen zien, ook waar nog instemming vereist is
                                                    : " AND m.mld_melding_conceptstatus = 0")); // Default laten we geen conceptmeldingen zien

              if (handler_key || opdrtype_key || contact_key || uitvopdr_key || opdr_key || opdrstatus_arr || intopdr_key)
              { // meldingen filter je op 'die een opdracht hebben met xxxxxx'
                // opdrachten filter je rechtstreeks
                var opdr_prs_key = [];
                if (contact_key)  opdr_prs_key.push(contact_key);
                if (uitvopdr_key) opdr_prs_key.push(uitvopdr_key);

                if (!toon_opdr_overz)
                    sqln += " AND EXISTS"
                          + " (SELECT o.mld_opdr_key"
                          + "    FROM mld_opdr o"
                          + "   WHERE m.mld_melding_key = o.mld_melding_key(+)"
                sqln += (handler_key
                        ? "   AND o.mld_uitvoerende_keys = " + handler_key
                        : "")
                      + (opdrtype_key
                        ? "   AND o.mld_typeopdr_key = " + opdrtype_key
                        : "")
                      + (contact_key || uitvopdr_key
                        ? "   AND o.prs_perslid_key IN (" + opdr_prs_key.join(",") + ")"
                        : "")
                      + (opdr_key // Selectie op nummer negeert alle andere filters (Andere waarde zijn niet doorgegeven
                        ? "   AND o.mld_melding_key = " + opdr_key  // seems odd, but is right -PF
                        : "")
                      + (intopdr_key // de interne (echte) opdrachtkey
                        ? "   AND o.mld_opdr_key = " + intopdr_key
                        : "")
                      + (opdrstatus_arr
                        ? "   AND o.mld_statusopdr_key IN (" + opdrstatus_arr.join(",") + ")"
                        : "")
                if (!toon_opdr_overz)
                      sqln += ")"
              }

              // -2: Primaire behandelaar
              // -3: Behandelteam
              // -4: Actieve behandelaar
              // >0: Kenmerk
              if (params.kaarten && "mldbordColumn" in params) {
                if (params.mldbordColumn === -2) { // Dan willen we geen meldingen zien die niets met behandelaren doen
                  sqln += " AND mdp.mld_disc_params_primairbeh <> 0";
                } else if (params.mldbordColumn === -3 || params.mldbordColumn === -4) { // Dan willen we geen meldingen zien die niets met behandelteams doen
                  sqln += " AND BITAND(mdp.mld_disc_params_srtgroep, 5) = 5";
                }
                if (params.mldbordColumn === -4) { // Dan moet het behandelteam minstens gevuld zijn
                  sqln += " AND m.mld_ins_discipline_key IS NOT NULL";
                }
                if (params.mldbordColumn > 0) {
                  sqln += " AND kmv.mld_melding_key(+) = m.mld_melding_key";
                }
              }

              no_old_closed_calls = ((S("mld_max_history") > 0) && (mldstrej || mldstafm || mldstver));

              // Apply the selections onto the query
              if (mld_key)
              { // Selectie op nummer negeert alle andere filters
                sqln += " AND m.mld_melding_key = " + mld_key;
              }
              else if (mld_key_arr.length)
              { // Selectie op nummer negeert alle andere filters
                sqln += " AND m.mld_melding_key IN (" + mld_key_arr.join(",") + ")";
              }

              if (params.mldgroup_key > 0)
              {
                sqln += " AND m.mld_melding_mldgroup_key = " + params.mldgroup_key;
              }

              if (rsv_ruimte_key)
              { // Selectie op nummer negeert alle andere filters
                sqln += " AND m.res_rsv_ruimte_key = " + rsv_ruimte_key;
              }

              var showstatus = "";
              if (mldstpen)  showstatus = (showstatus == ""? "" : showstatus + ",") + "0";
              if (mldstrej)  showstatus = (showstatus == ""? "" : showstatus + ",") + "1";
              if (mldstnew)  showstatus = (showstatus == ""? "" : showstatus + ",") + "2";
              if (mldstacc)  showstatus = (showstatus == ""? "" : showstatus + ",") + "4";
              if (mldstafm)  showstatus = (showstatus == ""? "" : showstatus + ",") + "5";
              if (mldstver)  showstatus = (showstatus == ""? "" : showstatus + ",") + "6";
              if (mldstuit)  showstatus = (showstatus == ""? "" : showstatus + ",") + "7";
              if (mldnieto)  showstatus = (showstatus == ""? "" : showstatus + ",") + "99";

              // PF: ik was meer een voorstander van dit, maar kennelijk kan er ook
              //     een kantenklare string meekomen
              //if (showstatus != "")
              //   sqln += " AND m.mld_melding_status IN (" + showstatus + ")";
              if (mldstatus_arr)
                mldstatus_arr = mldstatus_arr.join(",")
              else
                mldstatus_arr = showstatus;

              var sql_status = mld.getStatusSql(mldstatus_arr, "m");

              var bits = 0;
              if (params.actiecodeBO)
                 bits |= 1;
              if (params.actiecodeFE)
                 bits |= 2;
              if (bits > 0)
                 sqln += " AND BITAND(m.mld_melding_actiecode, " + bits + ") > 0";

              if (params.actiecodeATT)
                 sqln += " AND BITAND(m.mld_melding_actiecode, 128) = 128";

              if (params.flags && params.flags.length > 0 && params.flags.length < S('mld_melding_flags'))
              {
                var filterNull = false;

                for (var i=0; i< params.flags.length; i++)
                {
                 if (params.flags[i] === 0)
                 {
                   filterNull = true;
                 }
                }

                sqln += " AND (m.mld_melding_flag IN (" + params.flags.join(",") + ")";

                if (filterNull)
                  sqln += " or m.mld_melding_flag is null";
                sqln += ")";
              }

              if (deel_key)
              { // selectie op nummer negeert alle andere filters
                sqln += " AND m.mld_melding_key IN (SELECT mld_melding_key FROM mld_melding_object WHERE ins_deel_key = " + deel_key + ")";
              }

              if (deelsrtcont_key)
              { // Alle meldingen die gekoppeld zijn aan de periodieke inspectie.
                sqln += " AND m.mld_melding_key = mo.mld_melding_key(+)"
                      + " AND mo.ins_deelsrtcontrole_key = " + deelsrtcont_key;
              }

              if (no_old_closed_calls)
                sqln += " AND (m.mld_melding_datum >= SYSDATE - " + S("mld_max_history") + ")";

              // Hier wordt gezocht in de omschrijving, opmerking, de notities en de eventuele (tekst-)kenmerken
              // Dit is een potentieel en onvermijdelijk dure zoekactie.
              function zoek_woord(woord)
              {
                return  "(    UPPER(mld_melding_omschrijving) LIKE " + safe.quoted_sql_wild("%" + woord + "%")
                     +  "  OR UPPER(mld_melding_onderwerp) LIKE " + safe.quoted_sql_wild("%" + woord + "%")
                     +  "  OR UPPER(mld_melding_opmerking) LIKE " + safe.quoted_sql_wild("%" + woord + "%")
                     +  "  OR UPPER(mld_melding_externnr) LIKE " + safe.quoted_sql_wild(woord)  // wildcards doe je zelf maar.
                     +  "  OR EXISTS (SELECT mld_melding_key"
                     +  "               FROM mld_kenmerkmelding km"
                     +  "              WHERE km.mld_melding_key = m.mld_melding_key"
                     +  "                AND km.mld_kenmerkmelding_verwijder IS NULL"
                     +  "                AND UPPER(km.mld_kenmerkmelding_waarde) LIKE " + safe.quoted_sql_wild("%" + woord + "%") + ")"
                     +  "  OR EXISTS (SELECT mld_melding_key"
                     +  "               FROM mld_melding_note n"
                     +  "              WHERE n.mld_melding_key = m.mld_melding_key "
                     +  (params.urole == "fe" ? " AND n.mld_melding_note_flag <> 0" : "")
                     +  "                AND UPPER(n.mld_melding_note_omschrijving) LIKE " + safe.quoted_sql_wild("%" + woord + "%") + ")"
                     +  ")"
              }
              if (searchtekst)
              {
                var woorden = searchtekst.split(" "); // ook komma en zo?
                var zoekwoorden = [];
                for (var i = 0; i < woorden.length; i++)
                {
                     zoekwoorden.push(zoek_woord(woorden[i]));
                }
                sqln += " AND (" + zoekwoorden.join( (chkSearchOR ? " OR " : " AND ") ) + ")";
              }

              if (omschr)
              {
                sqln += " AND UPPER(mld_melding_omschrijving) LIKE "+ safe.quoted_sql_wild("%" + omschr + "%");
              }

              if (verantw_key || groepering_key == 23)
              {
                 sqln += " AND v.alg_gebouw_key = g.alg_gebouw_key(+)"
                       + " AND v.alg_terreinsector_key = t.alg_terreinsector_key(+)";
                 if (verantw_key)
                     sqln += " AND (  g.prs_perslid_key_verantw = "  + verantw_key
                           + "     OR g.prs_perslid_key_verantw2 = " + verantw_key
                           + "     OR t.prs_perslid_key_verantw = "  + verantw_key
                           + "     OR t.prs_perslid_key_verantw2 = " + verantw_key
                           + "     )";
              }

              if (caller_key)
                sqln += " AND m.prs_perslid_key = " + caller_key;

              if (vervolgmld == 1)  // geen (ad hoc) vervolgmeldingen = alleen hoofdmeldingen of normale meldingen
              {                     // ook van workflow
                sqln += " AND (  ((m.mld_melding_start_key IS NULL)     AND (m.mld_workflowstep_key IS NULL))"
                      + "     OR ((m.mld_melding_start_key IS NOT NULL) AND (m.mld_melding_key = m.mld_melding_start_key))"
                      + "     )";
              }

              if (vervolgmld == 2)  // alleen (ad hoc) vervolgmeldingen
              {
                sqln += " AND ((m.mld_melding_start_key IS NOT NULL) AND (m.mld_melding_key <> m.mld_melding_start_key))";
                if (!S("mld_show_workflowstep_as_followup"))
                  sqln += " AND m.mld_workflowstep_key IS NULL";      // workflowsteps are not included
              }

              if (completed)
              {
                sqln += " AND m.mld_melding_afgerond = " + (completed == 1? "1" : "0");
              }

              if (priority_arr.length)
              {
                sqln += " AND m.mld_melding_spoed IN (" + priority_arr.join(",") + ")";
              }

              var behandel2 = "";
              var behandel3 = "";
              if (mld_ins_discipline_key_arr.length)
              {
                if (mld_ins_discipline_key_arr.length == 1 && mld_ins_discipline_key_arr[0] == -2)
                  behandel2 += " AND m.mld_ins_discipline_key IS NULL";
                else if (inArray(-2, mld_ins_discipline_key_arr))
                  behandel2 += " AND (m.mld_ins_discipline_key IS NULL OR m.mld_ins_discipline_key IN (" + mld_ins_discipline_key_arr.join(", ") + "))";
                else
                  behandel2 += " AND m.mld_ins_discipline_key IN (" + mld_ins_discipline_key_arr.join(", ") + ")";
              }

              if (behandel_key_arr.length)
              {
                if (behandel_key_arr.length == 1 && behandel_key_arr[0] == -2)
                  sqln += " AND m.mld_melding_behandelaar_key IS NULL";
                else if (inArray(-2, behandel_key_arr))
                  sqln += " AND (m.mld_melding_behandelaar_key IS NULL OR m.mld_melding_behandelaar_key IN (" + behandel_key_arr.join(", ") + "))";
                else
                  sqln += " AND m.mld_melding_behandelaar_key IN (" + behandel_key_arr.join(", ") + ")";
              }
              else if (behandel_key > 0)
                sqln += " AND m.mld_melding_behandelaar_key = " + behandel_key;
              else if (behandel_key == -2)
                sqln += " AND m.mld_melding_behandelaar_key IS NULL";

              if (behandel2_key_arr.length)
              {
                if (behandel2_key_arr.length == 1 && behandel2_key_arr[0] == -2)
                  behandel2 += " AND m.mld_melding_behandelaar2_key IS NULL";
                else if (inArray(-2, behandel2_key_arr))
                  behandel2 += " AND (m.mld_melding_behandelaar2_key IS NULL OR m.mld_melding_behandelaar2_key IN (" + behandel2_key_arr.join(", ") + "))";
                else
                  behandel2 += " AND m.mld_melding_behandelaar2_key IN (" + behandel2_key_arr.join(", ") + ")";
              }
              else if (behandel2_key > 0)
                behandel2 += " AND m.mld_melding_behandelaar2_key = " + behandel2_key;
              else if (behandel2_key == -2)
                behandel2 += " AND m.mld_melding_behandelaar2_key IS NULL";

              var beh3sql = " CASE"
                          + "     WHEN BITAND (mdp.mld_disc_params_srtgroep, 4) = 4" // 'Met teams'
                          + "     THEN m.mld_melding_behandelaar2_key"
                          + "     ELSE m.mld_melding_behandelaar_key"
                          + " END";
              if (behandel3_key > 0)
                behandel3 += " AND " + beh3sql + " = " + behandel3_key;
              else if (behandel3_key == -2)
                behandel3 += " AND " + beh3sql + " IS NULL";

              if (ref_key && ref_type)
                sqln += " AND m.mld_melding_kto_key = " + ref_key
                      + " AND m.mld_melding_kto_type LIKE " + safe.quoted_sql(ref_type);

              if (room_key_arr.length)
                sqln += " AND v.alg_ruimte_key IN (" + room_key_arr.join(",") + ")";
              else if (flr_key_arr.length)
                sqln += " AND v.alg_verdieping_key IN (" + flr_key_arr.join(",") + ")";
              else if (bld_key_arr.length)
                sqln += " AND (v.alg_gebouw_key IN (" + bld_key_arr.join(",") + ") OR v.alg_terreinsector_key IN (" + bld_key_arr.join(",") + ")) ";
              else if (loc_key_arr.length)
                sqln += " AND m.mld_alg_locatie_key IN (" + loc_key_arr.join(",") + ")";
              else if (dist_key_arr.length)
                sqln +=  " AND di.alg_district_key IN (" + dist_key_arr.join(",") + ")";
              else if (reg_key_arr.length)
                sqln +=  " AND di.alg_regio_key IN (" + reg_key_arr.join(",") + ")";

              if (meldbron_key)
                sqln += " AND m.mld_meldbron_key = " + meldbron_key;

              if (referencetype)
                sqln += " AND m.mld_melding_kto_type = " + safe.quoted_sql(referencetype == "ME"? "M" : referencetype);

              if (kpgrp_key_arr.length)
                sqln += (toon_opdr_overz
                        ? " AND o.prs_kostenplaats_key = k.prs_kostenplaats_key(+)"
                        : " AND m.prs_kostenplaats_key = k.prs_kostenplaats_key(+)")
                      + " AND k.prs_kostenplaatsgrp_key IN (" + kpgrp_key_arr.join(",") + ")";

              if (kp_key_arr.length) // PCHD#40076
                sqln += (toon_opdr_overz
                        ? " AND o.prs_kostenplaats_key IN ("
                        : " AND m.prs_kostenplaats_key IN (")
                          + kp_key_arr.join(",") + ")";

              if (tag_key_arr.length)
              {
                sqln += " AND (m.mld_melding_tag_key IN (" + tag_key_arr.join(",")+ ")"
                      + (inArray(-2, tag_key_arr) ? " OR m.mld_melding_tag_key IS NULL)" : ")");
              }

              if (org_key)
                sqln += " AND COALESCE(m.prs_afdeling_key, p.prs_afdeling_key) IN"
                      + " (SELECT a.prs_afdeling_key"
                      + " FROM prs_v_afdeling_familie a"
                      + " WHERE a.prs_afdeling_elder_key = " + org_key + ")";
              else if (comp_key)
                sqln += " AND COALESCE(m.prs_afdeling_key, p.prs_afdeling_key) IN"
                      + " (SELECT a.prs_afdeling_key"
                      + " FROM prs_v_afdeling a"
                      + " WHERE a.prs_bedrijf_key = " + comp_key + ")";

              // Soort melding, productgroep, meldinggroep, melding
              if (stdm_key_arr.length || meldinggrp_key)
              {
                if (stdm_key_arr.length)
                  sqln += " AND m.mld_stdmelding_key IN (" + stdm_key_arr.join(",") + ")";
                if (meldinggrp_key)
                  sqln += " AND std.mld_stdmeldinggroep_key IN (" + meldinggrp_key + ")";
              }
              else if (disc_key_arr.length)
                sqln += " AND std.mld_ins_discipline_key IN (" + disc_key_arr.join(",") + ")";
              else if (srtdisc_key_arr.length)
                sqln += " AND sd.ins_srtdiscipline_key IN (" + srtdisc_key_arr.join(",") + ") ";

              // Behandelgroep
              if (behandelgrp_key)
                sqln += " AND mdp.mld_behandelgroep_key = " + behandelgrp_key;

              // Discipline, group, objectsoort
              if (disc_key || insgroup_key || objsrt_key_arr.length)
              {
                sqln += " AND m.mld_melding_key IN"
                        + " (SELECT mld_melding_key"
                        + " FROM mld_melding_object"
                        + " WHERE ins_deel_key IN"
                          + " (SELECT ins_deel_key"
                          + " FROM ins_deel WHERE";
                if (objsrt_key_arr.length)
                  sqln += " ins_srtdeel_key IN"
                        + " (SELECT ins_srtdeel_key"
                        + " FROM ins_srtdeel"
                        + " WHERE ins_srtdeel_key IN (" + objsrt_key_arr.join(",") + "))";
                else if (insgroup_key)
                  sqln += " ins_srtdeel_key IN"
                        + " (SELECT ins_srtdeel_key"
                        + " FROM ins_srtdeel"
                        + " WHERE ins_srtgroep_key = " + insgroup_key + ")";
                else if (disc_key)
                  sqln += " ins_discipline_key = " + disc_key;
                sqln += ") AND mld_melding_object_verwijder IS NULL)";
              }

              if (objectoms)
              {
                sqln += " AND m.mld_melding_key IN"
                        + " (SELECT mld_melding_key"
                        + " FROM mld_melding_object mo"
                          + "  , ins_deel d"
                          + "  , ins_srtdeel sd"
                        + " WHERE mo.ins_deel_key = d.ins_deel_key"
                          + " AND d.ins_srtdeel_key = sd.ins_srtdeel_key"
                          + " AND (ins_srtdeel_upper LIKE " + safe.quoted_sql_wild("%" + objectoms + "%")
                          + "   OR ins_deel_upper LIKE " + safe.quoted_sql_wild("%" + objectoms + "%") + ")"
                          + " AND mo.mld_melding_object_verwijder IS NULL)";
              }

              // Meldingen worden soms niet geaccepteerd maar direct afgewezen of afgemeld.
              // Als dit binnen de acceptatietijd gebeurd dan is die melding niet te laat geaccepteerd.
              if (chkAcceptEx)
              {
                sqln += " AND " + mld.getwhere_to_late_accept_sql("m") + " = 1";
              }


              if (chkRunEx)
              {
                sqln += " AND " + mld.sql_on_time_run_sla() + " <> 1";
              }

              if (chkSpoed)
              {
                sqln += " AND m.mld_melding_spoed < 3";
              }

              if (chkAfgerond)
              {
                sqln += " AND m.mld_melding_afgerond = 1";
              }

              if (datefrom && dateto)
              {
                var ora_date1 = datefrom.toSQL(true);
                var ora_date2 = dateto.toSQL(true);
                if (toon_opdr_overz)
                  sqln += " AND o.mld_opdr_datumbegin BETWEEN " + ora_date1 + " AND " + ora_date2;
                else
                  sqln += " AND m.mld_melding_datum BETWEEN " + ora_date1 + " AND " + ora_date2;
              }
              else if (datefrom)
              {
                var ora_date1 = datefrom.beginToSQL();
                if (toon_opdr_overz)
                  sqln += " AND o.mld_opdr_datumbegin >= " + ora_date1;
                else
                  sqln += " AND m.mld_melding_datum >= " + ora_date1;
              }
              else if (dateto)
              {
                var ora_date2 = dateto.endToSQL();
                if (toon_opdr_overz)
                  sqln += " AND o.mld_opdr_datumbegin < " + ora_date2;
                else
                  sqln += " AND m.mld_melding_datum  < " + ora_date2;
              }

              if (enddatefrom && enddateto)
              {
                var ora_date1 = enddatefrom.toSQL(true);
                var ora_date2 = enddateto.toSQL(true);
                if (toon_opdr_overz)
                  sqln += " AND o.mld_opdr_einddatum BETWEEN " + ora_date1 + " AND " + ora_date2;
                else
                  sqln += " AND m.mld_melding_einddatum BETWEEN " + ora_date1 + " AND " + ora_date2;
              }
              else if (enddatefrom)
              {
                var ora_date1 = enddatefrom.beginToSQL();
                if (toon_opdr_overz)
                  sqln += " AND o.mld_opdr_einddatum >= " + ora_date1;
                else
                  sqln += " AND m.mld_melding_einddatum >= " + ora_date1;
              }
              else if (enddateto)
              {
                var ora_date2 = enddateto.endToSQL();
                if (toon_opdr_overz)
                  sqln += " AND o.mld_opdr_einddatum < " + ora_date2;
                else
                  sqln += " AND m.mld_melding_einddatum  < " + ora_date2;
              }

              // check for web_mlduse rights on discipline when public
              if (public == 1)
              {
                sqln += "   AND EXISTS (SELECT fw.ins_discipline_key"
                      + "                 FROM fac_v_webgebruiker fw"
                      + "                    , fac_functie ff"
                      + "                WHERE std.mld_ins_discipline_key = fw.ins_discipline_key"
                      + "                  AND fw.fac_functie_key = ff.fac_functie_key"
                      + "                  AND ff.fac_functie_code IN ('WEB_MLDFOF', 'WEB_MLDUSE')"
                      + "                  AND ((ff.fac_functie_code = 'WEB_MLDUSE'"
                      + "                    AND std.mld_stdmelding_notfrontend = 0)"
                      + "                    OR ff.fac_functie_code = 'WEB_MLDFOF')"
                      + "                  AND fw.fac_gebruiker_alg_level_read < 9"
                      + "                  AND fw.fac_gebruiker_prs_level_read < 9"
                      + "                  AND fw.prs_perslid_key = " + user_key + ")";
              }
              else if (frontend) // dit niet hier, als je dit wilt moet je zorgen niet met fe aan te roepen: && !rsv_ruimte_key)
              {
                var prsKeys = user.collegakeylist();
                sqln += " AND m.prs_perslid_key IN (" + prsKeys + ")"
              }

              sqln += mld.getwhereSrttracking(params);
              sqln += mld.getwherePrstracking(params);

              if (mld_key == null)
              {
                if (!params.minfo || groepering_key == 1 || (groepering_key > 2 && groepering_key < 16) || groepering_key >= 18)
                { // Meldingen
                   sqln += getKenmerkSql("MLD", "m.mld_melding_key", true);
                }
                else if (groepering_key == 2 || groepering_key == 17 || groepering_key == 16)
                { // Opdrachten JGL: Volgens mij kom je hier nooit, dit gebeurt via ins_list
                  sqln += getKenmerkSql("OPD", "o.mld_opdr_key", true);
                }
              }

              if (params.minfo)
              {
                sqln += (params.ingevoerd == "fe"? " AND m.prs_perslid_key = invoerder.prs_perslid_key" : "");
                sqln += (params.ingevoerd == "fo"? " AND m.prs_perslid_key <> invoerder.prs_perslid_key" : "");
              } // minfo only

              var sql_afd = "(SELECT p.prs_afdeling_key FROM prs_perslid p WHERE p.prs_perslid_key = m.prs_perslid_key)";
              var sqln_arr = [];
              sqln_arr[0] = sqln
                          + (sql_status ? " AND" + sql_status : "")
                          + behandel2
                          + behandel3;
              // Tertiate behandelaren die rechten hebben op behandelbare blokken.
              // Alleen in de statussen Geaccepteerd(4) en Uitgegeven(7) mag tertiare behandelaar de melding aanpassen (canChangeKenmerkBlok).
              // Alleen tertiare behandelaren met "WEB_MLDBOF" rechten kunnen gekozen worden in de blok header (zie o.a. ook in de functie BLOCK_START_HTML in Shared\iface.inc).
              sql_status = " AND (   " + (sql_status ? sql_status : " 1 = 1 ")
                         + (mldstafm
                              ? " OR kbm.mld_kenmerkblokmelding_afmelddatum IS NOT NULL" // Indien aangevinkt, toon ook kenmerkblokken met status afgemeld
                              : " AND kbm.mld_kenmerkblokmelding_afmelddatum IS NULL") // Indien uitgevinkt, toon geen afgemelde kenmerkblokken
                         + "     )";
              sqln_arr[1] = sqln
                          + " AND (m.mld_melding_key IN (SELECT DISTINCT kbm.mld_melding_key"
                          + "                              FROM prs_perslid p"
                          + "                                 , mld_kenmerkblokmelding kbm"
                          + "                                 , mld_discipline d"
                          + "                             WHERE m.mld_melding_status IN (4, 7)" // Statussen Geaccepteerd(4) en Uitgegeven(7)
                          + "                               AND (p.prs_perslid_key = kbm.prs_perslid_key"
                          + "                                 OR (kbm.prs_perslid_key IS NULL"
                          + "                                 AND p.prs_perslid_key IN"
                          + "                                         (SELECT p.prs_perslid_key"
                          + "                                            FROM prs_perslid p"
                          + "                                               , prs_v_afdeling d1"
                          + "                                           WHERE p.prs_perslid_key IN"
                          + "                                                     (SELECT prs_perslid_key"
                          + "                                                        FROM fac_v_webgebruiker g"
                          + "                                                       WHERE g.fac_functie_key = (SELECT fac_functie_key "
                          + "                                                                                    FROM fac_functie"
                          + "                                                                                   WHERE fac_functie_code = 'WEB_MLDBOF')"
                          + "                                                         AND g.ins_discipline_key = kbm.ins_discipline_key"
                          + "                                                         AND (g.fac_gebruiker_prs_level_write = -1"
                          + "                                                           OR (g.fac_gebruiker_prs_level_write = 0"
                          + "                                                           AND d1.prs_bedrijf_key ="
                          + "                                                               (SELECT aa.prs_bedrijf_key"
                          + "                                                                  FROM prs_v_afdeling aa"
                          + "                                                                 WHERE aa.prs_afdeling_key = " + sql_afd + "))"
                          + "                                                           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 = " + sql_afd
                          + "                                                                                   AND aa.niveau = g.fac_gebruiker_prs_level_write))))"
                          + "                                                         AND prs_perslid_verwijder IS NULL"
                          + "                                                         AND p.prs_afdeling_key = d1.prs_afdeling_key"
                          + "                                                         AND (prs_perslid_oslogin IS NULL"
                          + "                                                           OR prs_perslid_oslogin NOT LIKE '\\_%' ESCAPE '\\')"
                          + "                                                         AND BITAND( prs_perslid_flags, 2) = 0))))"
                          + "                               AND kbm.ins_discipline_key = d.ins_discipline_key"
                          + "                               AND p.prs_perslid_key = " + user_key
                          + sql_status
                          + "                           )"
                          + "     )";
              return sqln_arr;
            },

        // Lever tekstueel alle flexkenmerken van een melding op.
        // Dat gaat als default in de omschrijving van de opdrachten
        getFlexSummary:
            function(melding_key)
            {
              var sql = "SELECT mld.mldflexsummary("+melding_key+") FROM DUAL";
              var oRs = Oracle.Execute(sql);
              var summarystring = oRs(0).Value||"";
              oRs.Close();
              return summarystring;
            },

        // Levert een veld (label + waarde) met een klikbare verwijzing naar een gerefereerde entiteit
        // Dat is de entiteit waarop deze melding betrekking heeft, bijvoorbeeld bij klachten of KTO.
        referentielink:
            function (ptype, pkey, plabel, pparams)
            {
              pparams = pparams || {};
              var lbl = mld.referentielabel(ptype, pkey); // 'Reservering 1234'
              var params = null;
              var refUrole = (typeof urole != "undefined" && (  (ptype != "M" && ptype != "O" && urole == "b2")   // bo2 bestaat alleen bij MLD en ORD
                                                             || (ptype == "C" && urole == "fo"))) ? "bo" : urole; // fo bestaat niet bij CNT
              switch(ptype)
              {
                case "R":
                  var params = { infoPointer: { Url: "appl/res/res_reservering.asp?urole="+refUrole+"&rsv_ruimte_key=" + pkey }};
                  break;
                case "M":
                  var params = { infoPointer: { Url: "appl/mld/mld_melding.asp?urole="+refUrole+"&mld_key=" + pkey}};
                  if (pparams.tooltip)
                  {
                      var TOOLTIP_MAXLENGTH = 50;
                      var sql = "SELECT mld_melding_onderwerp"
                              + "  FROM mld_melding"
                              + " WHERE mld_melding_key = " + pkey;
                      var oRs = Oracle.Execute(sql);
                      var subject = oRs("mld_melding_onderwerp").Value;
                      oRs.Close();
                      params.title = subject;
                      if (subject && subject.length > TOOLTIP_MAXLENGTH) subject = subject.substr(0, TOOLTIP_MAXLENGTH - 3) + "...";
                      params.tooltip = subject;
                  }
                  break;
                case "B":
                  var params = { infoPointer: { Url: "appl/bes/bes_bestelling.asp?urole="+refUrole+"&bes_key=" + pkey}};
                  break;
                case "X":
                  var params = { infoPointer: { Url: "appl/bes/bes_opdr.asp?urole="+refUrole+"&ordernr=" + pkey}};
                  break;
                case "O":
                  var params = { infoPointer: { Url: "appl/mld/mld_opdr.asp?urole="+refUrole+"&opdr_key=" + pkey}};
                  break;
                case "C":
                  var params = { infoPointer: { Url: "appl/cnt/cnt_contract.asp?urole="+refUrole+"&cnt_key=" + pkey}};
                  break;
                case "F":
                  var params = { infoPointer: { Url: "appl/fin/fin_factuur.asp?urole="+refUrole+"&fin_key=" + pkey}};
                  break;
              }
              if (params)
                ROFIELDTR("fld", plabel, lbl, params);
            },

        // Levert een label op voor een bepaald referentie type
        referentielabel:
            function (ptype, pkey)
            {
              switch(ptype)
              {
                case "R":
                  var sql = "SELECT res_reservering_key, res_rsv_ruimte_volgnr, res_rsv_ruimte_omschrijving"
                          + "  FROM res_rsv_ruimte"
                          + " WHERE res_rsv_ruimte_key = " + pkey;
                  var oRs = Oracle.Execute(sql);
                  var txt = L("lcl_reservation") + " " + oRs("res_reservering_key").Value + "/" + oRs("res_rsv_ruimte_volgnr").Value + (oRs("res_rsv_ruimte_omschrijving").Value ? " "+oRs("res_rsv_ruimte_omschrijving").Value : "");
                  oRs.Close();
                  return txt;
                  break;
                case "M":
                  var stored_dialect = lcl.get_dialect(); // Get the current dialect.
                  mld.mld_set_dialect(pkey);
                  var txt = L("lcl_complain") + " " + shared.mld_prefix(pkey) + pkey; // String buildup using the referenced dialect.
                  lcl.set_dialect(stored_dialect.selector_key, stored_dialect.selector_id); // Re-set the dialect back to the previous one
                  return txt;
                  break;
                case "B":
                  return L("lcl_bes_bestelling") + " " + S("bes_bestelling_prefix") + pkey;
                  break;
                case "X":
                  return L("lcl_bes_bestelopdracht") + " " + S("bes_bestelling_prefix") + pkey;
                  break;
                case "O":
                  var sql = "SELECT mld_melding_key, mld_opdr_bedrijfopdr_volgnr"
                          + "  FROM mld_opdr"
                          + " WHERE mld_opdr_key = " + pkey;
                  var oRs = Oracle.Execute(sql);
                  var txt = L("lcl_shared_order") + " " + oRs("mld_melding_key").Value + "/" + oRs("mld_opdr_bedrijfopdr_volgnr").Value;
                  oRs.Close();
                  return txt;
                  break;
                case "C":
                  var sql = "SELECT COALESCE(cnt_contract_nummer, cnt_contract_nummer_intern, TO_CHAR(cnt_contract_key))"
                          + "       || CASE WHEN cnt_contract_versie IS NOT NULL"
                          + "               THEN '.'||cnt_contract_versie"
                          + "          END cnt_nr"
                          + "     , cnt_contract_omschrijving"
                          + "  FROM cnt_contract"
                          + " WHERE cnt_contract_key = " + pkey;
                  var oRs = Oracle.Execute(sql);
                  var txt = L("lcl_contract") + " " + oRs("cnt_nr").Value +" "+ oRs("cnt_contract_omschrijving").Value;
                  oRs.Close();
                  return txt;
                  break;
                case "F":
                  var sql = "SELECT COALESCE(fin_factuur_nr, TO_CHAR(fin_factuur_key)) fact_nr"
                          + "  FROM fin_factuur"
                          + " WHERE fin_factuur_key = " + pkey;
                  var oRs = Oracle.Execute(sql);
                  var txt = L("lcl_fin_invoice") + " " + oRs("fact_nr").Value;
                  oRs.Close();
                  return txt;
                  break;
              }
            },

        mld_prefix: shared.mld_prefix,  // for compatibility

        mld_melding_info:
           function _mld_melding_info(mld_key)
           {
             _DetectMultipleCalls("mld.mld_melding_info", mld_key);

             // TODO: mld_melding_info bevat ook heel veel std_melding/discipline info
             //       Dat kan beter opgehaald worden met:
             //       var mld_info = mld.mld_melding_info(mld_key);
             //       var stdm_info = mld.mld_stdmeldinginfo(mld_info.stdm_key);
             //       of desnoods mld_info.stdm_info = mld.mld_stdmeldinginfo(mld_info.stdm_key)
             //       Dan kan deze functie veel compacter

             // INITIALISATIE MET DE INITIEEL WEER TE GEVEN GEGEVENS
             sql = "SELECT mld_melding_omschrijving"
                 + "     , mld_melding_onderwerp"
                 + "     , mld_melding_onderwerp_ai"
                 + "     , mld_melding_datum"
                 + "     , mld_melding_actiedatum"
                 + "     , fac.gettrackingdate('MLDAFM', mld_melding_key) afmelddatum"
                 + "     , s.mld_ins_discipline_key stdm_ins_discipline_key"
                 + "     , s.prs_dienst_key"
                 + "     , m.mld_stdmelding_key"
                 + "     , m.mld_alg_onroerendgoed_keys"
                 + "     , m.mld_melding_t_uitvoertijd.tijdsduur uitvoertijd_tijdsduur"
                 + "     , m.mld_melding_t_uitvoertijd.eenheid uitvoertijd_eenheid"
                 + "     , m.mld_melding_einddatum"
                 + "     , m.mld_melding_einddatum_std"
                 + "     , au.actualuitvoertijd.tijdsduur actualuitvoertijd_tijdsduur"
                 + "     , au.actualuitvoertijd.eenheid actualuitvoertijd_eenheid"
                 + "     , m.mld_kosten_klant"
                 + "     , m.prs_kostenplaats_key"
                 + "     , s.prs_kostensoort_key"
                 + "     , COALESCE(m.prs_afdeling_key, p.prs_afdeling_key) prs_afdeling_key"
                 + "     , d.prs_afdeling_naam"
                 + "     , m.mld_melding_opmerking"
                 + "     , m.prs_perslid_key"
                 + "     , p.prs_perslid_telefoonnr"
                 + "     , m.prs_perslid_key_voor"
                 + "     , m.mld_melding_status"
                 + "     , m.mld_melding_conceptstatus"
                 + "     , m.mld_melding_t_respijt.tijdsduur respijt_tijdsduur"
                 + "     , m.mld_melding_t_respijt.eenheid respijt_eenheid"
                 + "     , m.mld_meldbron_key"
                 + "     , m.mld_meldbron_nr"
                 + "     , m.mld_melding_externnr"
                 + "     , sd.ins_srtdiscipline_prefix"
                 + "     , sd2.ins_srtdiscipline_prefix mld_srtins_prefix"
                 + "     , md.ins_srtdiscipline_key"
                 + "     , m.mld_adres_key"
                 + "     , m.mld_melding_publiek"
                 + "     , m.mld_melding_spoed"
                 + "     , m.mld_melding_impact"
                 + "     , m.mld_melding_urgentie"
                 + "     , m.mld_melding_ordernr"
                 + "     , m.mld_melding_parentkey"
                 + "     , sd.ins_srtdiscipline_alg"
                 + "     , sd.ins_srtdiscipline_ins"
                 + "     , sd.ins_srtdiscipline_bes"
                 + "     , sd.ins_srtdiscipline_res"
                 + "     , " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
                 + "     , " + lcl.xsql('sd2.ins_srtdiscipline_omschrijving', 'sd2.ins_srtdiscipline_key') + " mld_ins_srtdiscipline_oms"
                 + "     , COALESCE(m.mld_alg_locatie_key, -1) alg_locatie_key"
                 + "     , COALESCE(g.alg_gebouw_key, g.alg_terreinsector_key, -1) alg_gebouw_key"
                 + "     , COALESCE(g.alg_verdieping_key, -1) alg_verdieping_key"
                 + "     , COALESCE(g.alg_ruimte_key, -1) alg_ruimte_key"
                 + "     , (SELECT 'B'"
                 + "          FROM alg_gebouw"
                 + "         WHERE alg_gebouw_key = g.alg_gebouw_key"
                 + "        UNION"
                 + "        SELECT 'T'"
                 + "          FROM alg_terreinsector"
                 + "         WHERE alg_terreinsector_key = g.alg_terreinsector_key) bttype"
                 + "     , m.mld_workflowstep_key workflow"
                 + "     , m.mld_melding_start_key"
                 + "     , m.mld_ins_discipline_key"
                 + "     , m.mld_melding_behandelaar_key behandelaar"
                 + "     , m.mld_melding_behandelaar2_key behandelaar2"
                 + "     , " + lcl.xsqla('md.ins_discipline_omschrijving', 'md.ins_discipline_key')
                 + "     , " + lcl.xsqla('s.mld_stdmelding_omschrijving', 's.mld_stdmelding_key')
                 + "     , " + lcl.xsql('md2.ins_discipline_omschrijving', 'md2.ins_discipline_key') + " mld_ins_discipline_oms"
                 + "     , COALESCE(s.mld_stdmelding_directklaar, mdp.mld_disc_params_directklaar, 0) mld_directklaar"
                 + "     , mdp.mld_disc_params_frontendprio"
                 + "     , mdp.mld_disc_params_kanpubliek"
                 + "     , mdp.mld_disc_params_startdatum"
                 + "     , mdp.mld_disc_params_bestellimiet"
                 + "     , m.fac_activiteit_key"
                 + "     , s.mld_stdmelding_freetext"
                 + "     , s.mld_stdmelding_subject"
                 + "     , (SELECT k.prs_kostenplaats_module"
                 + "      FROM prs_kostenplaats k"
                 + "      WHERE k.prs_kostenplaats_key = m.prs_kostenplaats_key) module"
                 + "     , s.mld_stdmelding_planbaar"
                 + "     , s.mld_stdmelding_planbaarfe"
                 + "     , s.alg_onrgoed_niveau"
                 + "     , md.ins_discipline_kpnverplicht"
                 + "     , s.ins_srtinst_verplichtstatus"
                 + "     , mg.mld_stdmeldinggroep_naam"
                 + "     , mdp.mld_disc_params_eigen_kp"
                 + "     , mdp.mld_disc_params_fenotes"
                 + "     , mdp.mld_disc_params_keten"
                 + "     , mdp.mld_disc_params_bonotify"
                 + "     , mdp.mld_disc_params_nobnotify"
                 + "     , mdp.mld_disc_params_srtgroep"
                 + "     , mdp.mld_disc_params_primairbeh"
                 + "     , m.mld_melding_kto_type"
                 + "     , m.mld_melding_kto_key"
                 + "     , m.mld_melding_kto" // kto over mijzelf?
                 + "     , m.mld_melding_kto_verstuurd"
                 + "     , m.mld_melding_satisfaction"
                 + "     , m.mld_melding_satisfaction_op"
                 + "     , s.mld_stdmelding_kto" // misschien kto over mijzelf?
                 + "     , m.mld_melding_mldgroup_key"
                 + "     , m.mld_melding_indult"
                 + "     , m.mld_melding_afgerond"
                 + "     , (SELECT COUNT(mo.ins_deel_key)"
                   + "        FROM mld_melding_object mo"
                   + "       WHERE mo.mld_melding_key = " + mld_key + ") aantal_objects"
                 + "     , (SELECT COUNT(m1.mld_melding_key)"
                   + "        FROM mld_melding m1"
                   + "       WHERE m1.mld_melding_parentkey = " + mld_key + ") aantal_childs"
                 + "     , (SELECT COUNT(m2.mld_melding_key)"
                   + "        FROM mld_melding m2"
                   + "       WHERE m2.mld_melding_kto_key = " + mld_key
                   + "         AND m2.mld_melding_kto_type = 'M') aantal_references"
                 + "     , m.mld_melding_flag"
                 + "     , m.mld_melding_actiecode"
                 + "     , m.mld_melding_locked_user_key"
                 + "     , m.mld_melding_locked_date"
                 + "     , m.res_rsv_ruimte_key"
                 + "     , rr.res_rsv_ruimte_volgnr"
                 + "     , rr.res_reservering_key"
                 + "     , m.mld_melding_naam_ext"
                 + "     , m.mld_melding_email_ext"
                 + "     , m.mld_melding_tel_ext"
                 + "     , s.mld_stdmelding_thirdparty"
                 + "     , s.mld_stdmelding_notes"
                 + "     , m.mld_melding_dwgx"
                 + "     , m.mld_melding_dwgy"
                 + "     , m.mld_melding_dwgz"
                 + "     , m.mld_melding_x"
                 + "     , m.mld_melding_y"
                 + "     , m.mld_melding_z"
                 + "     , m.mld_melding_tag_key"
                 + "     , mmt.mld_melding_tag_naam"
                 + "     , mmt.mld_melding_tag_datum_tot"
                 + "  FROM mld_melding m"
                 + "     , mld_stdmelding s"
                 + "     , mld_stdmeldinggroep mg"
                 + "     , alg_v_allonrgoed_gegevens g"
                 + "     , prs_perslid p"
                 + "     , mld_discipline md"  // informatie van vakgroep
                 + "     , mld_discipline md2" // informatie van behandelteam (optioneel)
                 + "     , mld_disc_params mdp"
                 + "     , ins_srtdiscipline sd"  // informatie van vakgroeptype
                 + "     , ins_srtdiscipline sd2" // informatie van behandelteamtype (optioneel)
                 + "     , res_rsv_ruimte rr"
                 + "     , prs_afdeling d"
                 + "     , (SELECT mld.getactualuitvoer(" + mld_key + ") actualuitvoertijd FROM DUAL) au"
                 + "     , mld_melding_tag mmt"
                 + " WHERE mld_melding_key = " + mld_key
                 + "   AND m.mld_melding_tag_key = mmt.mld_melding_tag_key(+)"
                 + "   AND s.mld_stdmelding_key = m.mld_stdmelding_key"
                 + "   AND s.mld_stdmeldinggroep_key = mg.mld_stdmeldinggroep_key(+)"
                 + "   AND m.mld_alg_onroerendgoed_keys = g.alg_onroerendgoed_keys(+)"
                 + "   AND m.prs_perslid_key = p.prs_perslid_key"
                 + "   AND d.prs_afdeling_key = COALESCE(m.prs_afdeling_key, p.prs_afdeling_key)"
                 + "   AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
                 + "   AND md.ins_discipline_key = s.mld_ins_discipline_key"
                 + "   AND m.mld_ins_discipline_key = md2.ins_discipline_key(+)"
                 + "   AND md2.ins_srtdiscipline_key = sd2.ins_srtdiscipline_key(+)"
                 + "   AND mdp.mld_ins_discipline_key = s.mld_ins_discipline_key"
                 + "   AND m.res_rsv_ruimte_key = rr.res_rsv_ruimte_key(+)";
             var oRs = Oracle.Execute(sql);
             if (oRs.Eof)
             {
                 shared.record_not_found(L("lcl_complain") + " " + mld_key);
             }

             var alg_level = 0;
             switch (oRs("ins_srtdiscipline_alg").Value)
             {
                 case 1: alg_level = 5; break; // Ruimte
                 case 3: alg_level = 4; break; // Verdieping
                 case 5: alg_level = 3; break; // Gebouw
                 case 7: alg_level = 2; break; // Locatie
                 default: alg_level = 0;       // niet tonen
             }

             var result = { mld_key: mld_key,
                            mld_omschr: oRs("mld_melding_omschrijving").Value,
                            mld_onderwerp: oRs("mld_melding_onderwerp").Value,
                            mld_onderwerp_ai: oRs("mld_melding_onderwerp_ai").Value,
                            melddatum: new Date( oRs("mld_melding_datum").Value),
                            actiedatum: oRs("mld_melding_actiedatum").Value != null? new Date(oRs("mld_melding_actiedatum").Value) : null,
                            afmelddatum: oRs("afmelddatum").Value != null? new Date(oRs("afmelddatum").Value) : null,
                            disc_key: oRs("stdm_ins_discipline_key").Value,
                            dienst_key: oRs("prs_dienst_key").Value,
                            stdm_key: oRs("mld_stdmelding_key").Value,
                            place_key: oRs("mld_alg_onroerendgoed_keys").Value,
                            uitvoertijd: oRs("uitvoertijd_tijdsduur").Value,
                            uitvoertijd_eenheid: oRs("uitvoertijd_eenheid").Value || 'D',
                            actualuitvoertijd: oRs("actualuitvoertijd_tijdsduur").Value,
                            actualuitvoertijd_eenheid: oRs("actualuitvoertijd_eenheid").Value,
                            einddatum: new Date(oRs("mld_melding_einddatum").Value),          // Gepland
                            einddatum_std: new Date(oRs("mld_melding_einddatum_std").Value),  // Zou moeten volgens SLA
                            mld_kk: oRs("mld_kosten_klant").Value || 0,
                            kostenpl_key: oRs("prs_kostenplaats_key").Value || -1,
                            stdm_ksrt_key: oRs("prs_kostensoort_key").Value,
                            mld_ordernr: oRs("mld_melding_ordernr").Value,
                            parent_key: oRs("mld_melding_parentkey").Value,
                            melder_key: oRs("prs_perslid_key").Value,
                            afdeling_key: oRs("prs_afdeling_key").Value,
                            melder_telefoonnr: oRs("prs_perslid_telefoonnr").Value,
                            perslid_key_voor:  oRs("prs_perslid_key_voor").Value,
                            remark: oRs("mld_melding_opmerking").Value,
                            alg_ruimte: oRs("mld_alg_onroerendgoed_keys").Value || -1,
                            mld_status: oRs("mld_melding_status").Value,
                            mld_alg_onroerendgoed_keys: oRs("mld_alg_onroerendgoed_keys").Value,
                            mld_conceptstatus: oRs("mld_melding_conceptstatus").Value,
                            mld_status_str: mld.getmldstatustext(oRs("mld_melding_parentkey").Value ? oRs("mld_melding_status").Value : mld.getextendedmldstatus(oRs("mld_melding_status").Value, mld_key)),
                            respijt: oRs("respijt_tijdsduur").Value || 0,
                            respijt_eenheid: oRs("respijt_eenheid").Value || (oRs("uitvoertijd_eenheid").Value || 'D'),
                            meldbron_key: oRs("mld_meldbron_key").Value,
                            meldbron_nr: oRs("mld_meldbron_nr").Value,
                            externnr: oRs("mld_melding_externnr").Value,
                            prefix: S("mld_num_prefix_mode") == 1?oRs("prs_afdeling_naam").Value+"#":oRs("ins_srtdiscipline_prefix").Value,  // null for no prefix
                            mld_srtins_prefix: oRs("mld_srtins_prefix").Value,  // null for no prefix
                            srtdisc_key: oRs("ins_srtdiscipline_key").Value,
                            deladdress_key: oRs("mld_adres_key").Value,
                            publiek: oRs("mld_melding_publiek").Value,
                            mprio: oRs("mld_melding_spoed").Value,
                            mimpact: oRs("mld_melding_impact").Value,
                            murgentie: oRs("mld_melding_urgentie").Value,
                            alg_level: alg_level,
                            show_alg: alg_level > 0,
                            show_ins: oRs("ins_srtdiscipline_ins").Value == 1,
                            show_bes: oRs("ins_srtdiscipline_bes").Value > 0,
                            show_res: oRs("ins_srtdiscipline_res").Value == 1,
                            afleveradres_verplicht: oRs("ins_srtdiscipline_bes").Value == 1,
                            srtdisc_oms: oRs("ins_srtdiscipline_omschrijving").Value,
                            mld_srtdisc_oms: oRs("mld_ins_srtdiscipline_oms").Value,
                            loc_key: oRs("alg_locatie_key").Value,
                            bld_key: oRs("alg_gebouw_key").Value,
                            flr_key: oRs("alg_verdieping_key").Value,
                            room_key: oRs("alg_ruimte_key").Value,
                            bttype: oRs("bttype").Value? oRs("bttype").Value : "",
                            noWorkflow: (oRs("workflow").Value == null),
                            wfstep: oRs("workflow").Value,
                            startkey: oRs("mld_melding_start_key").Value,
                            mld_ins_discipline_key: oRs("mld_ins_discipline_key").Value,
                            behandel_key: oRs("behandelaar").Value,
                            behandel2_key: oRs("behandelaar2").Value,
                            ins_discipline_omschrijving: oRs("ins_discipline_omschrijving").Value,
                            mld_stdmelding_omschrijving: oRs("mld_stdmelding_omschrijving").Value,
                            mld_ins_discipline_omschrijving: oRs("mld_ins_discipline_oms").Value,
                            is_fo_melding: oRs("mld_directklaar").Value > 0, // Welke knoppen mag ik zien?
                            directklaar: oRs("mld_directklaar").Value,
                            show_start_date: oRs("mld_disc_params_startdatum").Value == 1,
                            bestellimiet: oRs("mld_disc_params_bestellimiet").Value,
                            frontendprio: (oRs("mld_disc_params_frontendprio").Value == 1),
                            canbepublished: (oRs("mld_disc_params_kanpubliek").Value == 1),
                            act_key: oRs("fac_activiteit_key").Value || -1,
                            freetext: oRs("mld_stdmelding_freetext").Value,
                            subject: oRs("mld_stdmelding_subject").Value,
                            module: oRs("module").Value,
                            srtinst_verplichtstatus: oRs("ins_srtinst_verplichtstatus").Value,
                            planbaar: ((oRs("mld_stdmelding_planbaar").Value & 4) == 4? oRs("mld_stdmelding_planbaar").Value - 4 : oRs("mld_stdmelding_planbaar").Value),
                            planbaarfe: oRs("mld_stdmelding_planbaarfe").Value,
                            show_actiedatum: ((oRs("mld_stdmelding_planbaar").Value & 4) == 4),
                            meldinggroep: oRs("mld_stdmeldinggroep_naam").Value,
                            alg_onrgoed_niveau: oRs("alg_onrgoed_niveau").Value,
                            kpnverplicht: (oRs("ins_discipline_kpnverplicht").Value == 1),
                            show_eigen_kp: (oRs("mld_disc_params_eigen_kp").Value == 1),
                            fenotes: oRs("mld_disc_params_fenotes").Value,
                            keten: oRs("mld_disc_params_keten").Value,
                            bonotify: oRs("mld_disc_params_bonotify").Value,
                            nobnotify: oRs("mld_disc_params_nobnotify").Value,
                            srtgroep: oRs("mld_disc_params_srtgroep").Value,
                            primaire_behandelaar: oRs("mld_disc_params_primairbeh").Value,
                            kto_type: oRs("mld_melding_kto_type").Value == "T"? null : oRs("mld_melding_kto_type").Value,     // TODO: Als (kto_type = "T") dan met script leeg maken.
                            kto_key: oRs("mld_melding_kto_type").Value == "T"? null : oRs("mld_melding_kto_key").Value || -1, // TODO: Als (kto_type = "T") dan met script leeg maken.
                            kto: oRs("mld_melding_kto").Value == 1,
                            kto_verstuurd: oRs("mld_melding_kto_verstuurd").Value,
                            satisfaction: oRs("mld_melding_satisfaction").Value,
                            satisfaction_op: oRs("mld_melding_satisfaction_op").Value,
                            kto_opt: oRs("mld_stdmelding_kto").Value || 0,
                            mldgroup_key: oRs("mld_melding_mldgroup_key").Value,
                            indult: oRs("mld_melding_indult").Value == 1, // 0=normaal, 1=indult=vrijgewaard=telt niet mee
                            mld_afgerond: oRs("mld_melding_afgerond").Value == 1, // 0=niet afgerond, 1=afgerond
                            aantal_objects: oRs("aantal_objects").Value,
                            haschild: oRs("aantal_childs").Value > 0,
                            hasreference: oRs("aantal_references").Value > 0,
                            flag: oRs("mld_melding_flag").Value,
                            actiecode: oRs("mld_melding_actiecode").Value,
                            locked_user_key: oRs("mld_melding_locked_user_key").Value,
                            locked_date: new Date(oRs("mld_melding_locked_date").Value),
                            rsv_ruimte_key: oRs("res_rsv_ruimte_key").Value,
                            rsv_ruimte_volgnr: oRs("res_rsv_ruimte_volgnr").Value,
                            res_key: oRs("res_reservering_key").Value,
                            naam_ext: oRs("mld_melding_naam_ext").Value,
                            email_ext: oRs("mld_melding_email_ext").Value,
                            tel_ext: oRs("mld_melding_tel_ext").Value,
                            canholdthirdparty: oRs("mld_stdmelding_thirdparty").Value,
                            stdm_notes: oRs("mld_stdmelding_notes").Value,
                            dwgx: oRs("mld_melding_dwgx").Value,
                            dwgy: oRs("mld_melding_dwgy").Value,
                            dwgz: oRs("mld_melding_dwgz").Value,
                            x: oRs("mld_melding_x").Value,
                            y: oRs("mld_melding_y").Value,
                            z: oRs("mld_melding_z").Value,
                            tag_key: oRs("mld_melding_tag_key").Value,
                            tag_naam: oRs("mld_melding_tag_naam").Value,
                            tag_datum: oRs("mld_melding_tag_datum_tot").Value != null? new Date(oRs("mld_melding_tag_datum_tot").Value) : null
                          };
             // voor eventuele nieuwe opdrachten
            if (S("mld_opdr_discipline_mode") == 1)
                result.opdr_disc_key = result.disc_key;
            else
                result.opdr_disc_key = result.mld_ins_discipline_key || result.disc_key;

            oRs.Close();

            result.workflowRoot = (!result.noWorkflow && result.startkey == mld_key);

            // Create discipline Array for Authorisation, combining Vakgroep & Behandelteam
            result.aut_disc_arr = [];
            result.aut_disc_arr.push(result.disc_key);
            if (result.mld_ins_discipline_key > 0)
                result.aut_disc_arr.push(result.mld_ins_discipline_key);

            if (result.locked_user_key)
            {
              var expire = new Date;
              expire.setMinutes(expire.getMinutes() - S("mld_locked_expire"));
              if (result.locked_date < expire)
              { // In de database laten we het lock gewoon staan ter analyse achteraf welke locks niet worden vrijgegeven.
                result.locked_user_key = null;
                result.locked_date = null;
              }
            }

            if (result.uitvoertijd_eenheid == "D")
              result.uitvoertijdtxt = result.uitvoertijd + " " + L("lcl_mld_days");
            else
              result.uitvoertijdtxt = Math.round(result.uitvoertijd * 100) / 100 + " " + L("lcl_mld_hours");

            if (result.actualuitvoertijd_eenheid == "D")
              result.actualuitvoertijdtxt = Math.round(result.actualuitvoertijd * 100) / 100 + " " + L("lcl_mld_days");
            else
              result.actualuitvoertijdtxt = Math.round(result.actualuitvoertijd * 100) / 100 + " " + L("lcl_mld_hours");

            if (result.respijt_eenheid == "D")
              result.respijttxt = result.respijt + " " + L("lcl_mld_days");
            else
              result.respijttxt = Math.round(result.respijt * 100) / 100 + " " + L("lcl_mld_hours");

             // Als de melding kinderen heeft, haal ze dan op
             if (result.haschild)
             {
               sql = "SELECT m.mld_melding_key"
                   + "     , sd.ins_srtdiscipline_prefix"
                   + "  FROM mld_melding m"
                   + "     , mld_stdmelding s"
                   + "     , mld_discipline md"
                   + "     , ins_srtdiscipline sd"
                   + " WHERE m.mld_stdmelding_key = s.mld_stdmelding_key"
                   + "   AND s.mld_ins_discipline_key = md.ins_discipline_key"
                   + "   AND md.ins_srtdiscipline_key = sd.ins_srtdiscipline_key"
                   + "   AND m.mld_melding_parentkey = " + mld_key
                   + " ORDER BY m.mld_melding_key";
                var oRsC = Oracle.Execute(sql);
                result.childs = new Array();
                while (!oRsC.eof)
                {
                  result.childs.push({key: oRsC("mld_melding_key").Value,
                                      nr:  oRsC("ins_srtdiscipline_prefix").Value || "" + oRsC("mld_melding_key").Value
                                    });
                  oRsC.MoveNext();
                }
                oRsC.Close();
             }

             // Als naar deze melding wordt verwezen in andere meldingen, haal ze dan op
             if (result.hasreference)
             {
               sql = "SELECT m.mld_melding_key"
                   + "     , sd.ins_srtdiscipline_prefix"
                   + "  FROM mld_melding m"
                   + "     , mld_stdmelding s"
                   + "     , mld_discipline md"
                   + "     , ins_srtdiscipline sd"
                   + " WHERE m.mld_stdmelding_key = s.mld_stdmelding_key"
                   + "   AND s.mld_ins_discipline_key = md.ins_discipline_key"
                   + "   AND md.ins_srtdiscipline_key = sd.ins_srtdiscipline_key"
                   + "   AND m.mld_melding_kto_key = " + mld_key
                   + " ORDER BY m.mld_melding_key";
               oRsR = Oracle.Execute(sql);
               result.references = new Array();
               while (!oRsR.eof)
               {
                 result.references.push({key: oRsR("mld_melding_key").Value,
                                         nr:  oRsR("ins_srtdiscipline_prefix").Value || "" + oRsR("mld_melding_key").Value
                                       });
                 oRsR.MoveNext();
               }
               oRsR.Close();
             }

             sql = "SELECT ins_deel_key"
                 + "     , ins_deelsrtcontrole_key"
                 + "  FROM mld_v_aanwezigmelding_object"
                 + " WHERE mld_melding_key = " + mld_key;
             oRs = Oracle.Execute(sql);

             result.room_obj_arr = new Array;
             while (!oRs.eof)
             {
               result.room_obj_arr.push({ins_key: oRs("ins_deel_key").Value, deelsrtcont_key: oRs("ins_deelsrtcontrole_key").Value});
               oRs.MoveNext();
             }
             oRs.close();
             return result;
           },

        mld_opdr_kosten_velden:
           function _mld_opdr_kosten_velden(result)
           { // Bepaling welke kosten velden getoond moeten worden.

             // De typeopdr setting "mld_typeopdr_matchtype" opgesplitst in de volgende vier typeopdr settingen (FCLT#57833):
             // 1) mld_typeopdr_uren.
             // 2) mld_typeopdr_materiaal.
             // 3) mld_typeopdr_totaal.
             // 4) mld_typeopdr_factuur.
             //
             // Opdrachttype-Uren (mld_typeopdr_uren) is dan een keuze uit:
             // 0)	Geen.
             // 1)	Externe uren (en tarief) optioneel.
             // 2)	Externe uren (en tarief) verplicht.
             // 3)	Interne uren (geraamd) verplicht (is een ondergrens, maak je deze optioneel dan heb je niks).
             // 4)	Interne uren (maximaal) verplicht.
             // 5)	Interne uren (per week) verplicht.
             // (Tarief veld indien totaal "Invulbaar(1)" is)
             //
             // Opdrachttype-Materiaal (mld_typeopdr_materiaal) is dan een keuze uit:
             // 0)	Geen.
             // 1)	Bedrag.
             // 2)	Materiaallijst.
             // 3)  Verplichte materiaallijst.
             //
             // Opdachttype-Totaal (mld_typeopdr_totaal) is dan een keuze uit:
             // 0)	Berekend.
             // 1)	Invulbaar (Correctie en Tarief velden worden getoond. Met deze twee velden kan het totaal dan beïnvloed worden).
             // 2)  Invulbaar met ORDAFR rechten.
             //
             // Opdrachttype-Factuurmatching (mld_typeopdr_factuur) is dan een keuze uit:
             // 0)	Geen kosten (is geen extern te factureren verplichting).
             // 1)	Eén factuur (vaste prijs; 2e factuur is nooit automatisch goed).
             // 2)	Eén factuur (nacalculatie; de aangegeven toleranties worden toegepast).
             // 3)	Mogelijk meerdere facturen (vaste prijs, automatisch goed zolang onder het totaal).
             // 4)	Contracttermijnen.

             //----------

             // Het uurtarief veld tonen indien het uren veld aanwezig is.
             result.tonen_uren = result.typeopdr_uren == 1 ||
                                 result.typeopdr_uren == 2 ||
                                 result.typeopdr_uren == 3 ||
                                 result.typeopdr_uren == 4 ||
                                 result.typeopdr_uren == 5;

             // Het materiaal bedrag veld tonen als materiaal is "Bedrag(1)":
             result.tonen_materiaal_bedrag = result.typeopdr_materiaal >= 1;

             // Heb ik rechten om af te ronden (WEB_ORDAFR)?
             var authparamsORDAFR = user.checkAutorisation("WEB_ORDAFR", true);
             var canWriteORDAFR = authparamsORDAFR && authparamsORDAFR.PRSwritelevel < 9 && authparamsORDAFR.ALGwritelevel < 9

             // Het correctie veld tonen indien:
             // 1) Totaal is invulbaar of
             // 2) Totaal is invulbaar met ORDAFR rechten (canWriteORDAFR).
             result.tonen_correctie = result.typeopdr_totaal >= 1;
             result.correctie_readonly = result.tonen_correctie && result.typeopdr_totaal == 2 && !canWriteORDAFR;

             // Het totaal veld tonen indien er kosten gemaakt kunnen worden.
             // Dit is alleen het geval als er geen uren(0), geen materialen(0) zijn en uren staat op berekend(0).
             result.tonen_totaal = result.tonen_uren || result.tonen_materiaal_bedrag || result.tonen_correctie;
             // Dit is gelijk aan: !(result.typeopdr_uren == 0 && result.typeopdr_materiaal == 0 && result.typeopdr_totaal == 0);

             // Het kostenplaats veld tonen indien:
             // 1) De setting "mld_ord_show_kostenplaats" (show kostenplaats field for orders) op 1=editable of 2=show staat
             // 2) Indien het totaal veld getoond wordt en er dus kosten gemaakt kunnen worden.
             // 3) De setting "mld_use_order_approval" (Approval mechanism is used for mld orders) op 1=enabled staat.
             result.tonen_kostenplaats = (S("mld_ord_show_kostenplaats") >= 1 &&
                                          (result.tonen_totaal ||
                                           S("mld_use_order_approval") == 1));

             return result;
           },


        mld_opdr_info:
           function _mld_opdr_info(opdr_key)
           {
             _DetectMultipleCalls("mld.mld_opdr_info", opdr_key);

             // TODO: mld_opdr_info bevat ook heel veel melding/contract info
             //       Dat kan beter opgehaald worden met:
             //       var mld_opdr = mld.mld_opdr_info(opdr_key);
             //       var mld_info = mld.mld_melding_info(mld_opdr.mld_key);
             //       Dan kan deze functie veel compacter
             var sql = "SELECT mld_opdr_datumbegin"
                     + "     , o.mld_melding_key"
                     + "     , o.mld_opdr_contactpersoon"
                     + "     , o.mld_opdr_omschrijving"
                     + "     , o.mld_opdr_parent_key"
                     + "     , (SELECT mld_typeopdr_isofferte"
                     + "          FROM mld_opdr o1"
                     + "             , mld_typeopdr mto"
                     + "         WHERE o1.mld_typeopdr_key = mto.mld_typeopdr_key"
                     + "           AND o1.mld_opdr_key = o.mld_opdr_parent_key) parent_isofferte"
                     + "     , fac.count_Work_Days(mld_opdr_datumbegin, mld_opdr_einddatum) aantal_dagen"
                     + "     , o.mld_opdr_discipline_key"
                     + "     , o.mld_opdr_uren"
                     + "     , o.mld_opdr_uren_refiat"
                     + "     , o.mld_opdr_materiaal"
                     + "     , o.mld_opdr_materiaal_refiat"
                     + "     , o.mld_opdr_kosten"
                     + "     , o.mld_opdr_fiatbedrag"
                     + "     , o.mld_opdr_kosten_refiat"
                     + "     , o.mld_uitvoerende_keys"
                     + "     , c.cnt_contract_nummer_intern"
                                   + " || CASE WHEN c.cnt_contract_versie IS NOT NULL THEN '.'||c.cnt_contract_versie  END"
                                   + " || '-' || c.cnt_contract_omschrijving cnt_name"
                     + "     , o.cnt_contract_key"
                     + "     , COALESCE(o.mld_opdr_uurloon, 0) mld_opdr_uurloon"
                     + "     , COALESCE(o.mld_opdr_uurloon_refiat, 0) mld_opdr_uurloon_refiat"
                     + "     , o.mld_typeopdr_key"
                     + "     , o.mld_opdr_halted"
                     + "     , o.mld_opdr_teverzenden"
                     + "     , o.mld_opdr_verzonden"
                     + "     , " + lcl.xsqla('mto.mld_typeopdr_omschrijving', 'mto.mld_typeopdr_key')
                     + "     , mto.mld_typeopdr_uren"
                     + "     , mto.mld_typeopdr_materiaal"
                     + "     , mto.mld_typeopdr_totaal"
                     + "     , mto.mld_typeopdr_factuur"
                     + "     , mto.mld_typeopdr_slamode"
                     + "     , mto.mld_typeopdr_kosten"
                     + "     , mto.mld_typeopdr_sluitmelding"
                     + "     , mto.mld_typeopdr_annuleermelding"
                     + "     , mto.mld_typeopdr_afmeldmarge"
                     + "     , mto.mld_typeopdr_offertelimiet"
                     + "     , mto.mld_typeopdr_isofferte"
                     + "     , mto.mld_typeopdr_typeopdr_key"
                     + "     , mto.mld_typeopdr_contract"
                     + "     , mto.mld_typeopdr_afhandeling"
                     + "     , mto.mld_typeopdr_confirm_for_send"
                     + "     , mto.mld_typeopdr_kosten_verplicht"
                     + "     , mto.mld_typeopdr_sequential"
                     + "     , mto.mld_typeopdr_decentraal"
                     + "     , mto.mld_typeopdr_afmelden_extern"
                     + "     , mto.mld_typeopdr_zichtbaarfe"
                     + "     , mto.mld_typeopdr_gvs"
                     + "     , mto.mld_typeopdr_fvs"
                     + "     , mto.mld_typeopdr_accept"
                     + "     , mto.mld_typeopdr_image"
                     + "     , o.prs_perslid_key mld_opdr_contact_key"            // key van de interne contactpersoon
                     + "     , (SELECT p.prs_perslid_naam_full FROM prs_v_perslid_fullnames_all p WHERE p.prs_perslid_key = o.prs_perslid_key) mld_opdr_contact_naam"
                     + "     , o.prs_contactpersoon_key"
                     + "     , (SELECT cp.prs_perslid_key FROM prs_contactpersoon cp WHERE cp.prs_contactpersoon_key = o.prs_contactpersoon_key) prs_contactpersoon_perslid_key"  // key van externe cp indien user
                     + "     , o.mld_statusopdr_key"
                     + "     , o.mld_statusopdr_key_refiat"
                     + "     , m.mld_stdmelding_key"
                     + "     , m.mld_alg_locatie_key"
                     + "     , m.mld_alg_onroerendgoed_keys"
                     + "     , m.prs_perslid_key melding_user_key"
                     + "     , CASE WHEN sd.ins_srtdiscipline_prefix IS NULL"
                       + "          THEN ''"
                       + "          ELSE sd.ins_srtdiscipline_prefix || '-'"
                       + "          END"
                       + "          || " + lcl.xsqla('d.ins_discipline_omschrijving', 'd.ins_discipline_key')
                     + "     , m.mld_kosten_klant"
                     + "     , mld_melding_afgerond"
                     + "     , o.prs_kostenplaats_key"
                     + "     , k.prs_kostenplaats_fiat kp_fiat"
                     + "     , o.mld_opdr_opmerking_fiat"
                     + "     , o.mld_opdr_bedrijfopdr_volgnr"
                     + "     , o.mld_opdr_ordernr"
                     + "     , mdp.mld_disc_params_opdr_kosten"
                     + "     , o.mld_opdr_opmerking"
                     + "     , mld_opdr_einddatum"
                     + "     , o.mld_opdr_flag"
                     + "     , sd.ins_srtdiscipline_key"
                     + "     , sd.ins_srtdiscipline_bes"
                     + "     , sd.ins_srtdiscipline_prefix"
                     + "     , o.fac_activiteit_key"
                     + "     , mu.type"
                     + "     , mu.intern"
                     + "     , mu.naam"
                     + "     , prs.getfiatteur (o.prs_kostenplaats_key"
                     + "                      , -1"
                     + "                      , mld_opdr_kosten"
                     + "                      , o.mld_opdr_discipline_key"
                     + "                      , o.mld_opdr_fiatbedrag" // Bij een kpg fiatteur moeten we de volgende hebben en niet de laatste, daarom (fiatbedrag >= 0) meegeven.
                     + "                       ) fiatteur_kp_key"
                     + "     , kg.prs_perslid_key fiatteur_kpg_key"
                     + "     , kg.prs_kostenplaatsgrp_fiat2_key"
                     + "     , kg.prs_kostenplaatsgrp_fiat3_key"
                     + "     , kg.prs_kostenplaatsgrp_fin_limit1"
                     + "     , kg.prs_kostenplaatsgrp_fin_limit2"
                     + "     , d.ins_discipline_key"
                     + "     , COALESCE(sm.prs_kostensoort_key, d.prs_kostensoort_key) prs_kostensoort_def_key"
                     + "     , (SELECT ks.prs_kostensoort_oms || '-' || " + lcl.xsqla('ks.prs_kostensoort_opmerking', 'ks.prs_kostensoort_key')
                     + "          FROM prs_kostensoort ks"
                     + "         WHERE ks.prs_kostensoort_key = COALESCE(sm.prs_kostensoort_key, d.prs_kostensoort_key)) kostensoort_def_oms"
                     + "     , o.prs_kostensoort_key"
                     + "     , (SELECT COALESCE(ks.prs_kostensoort_btw, 0)"
                     + "          FROM prs_kostensoort ks"
                     + "         WHERE ks.prs_kostensoort_key = COALESCE(o.prs_kostensoort_key, sm.prs_kostensoort_key, d.prs_kostensoort_key)) inclBTW"
                     + "     , (SELECT ks.prs_kostensoort_oms || '-' || " + lcl.xsqla('ks.prs_kostensoort_opmerking', 'ks.prs_kostensoort_key')
                     + "          FROM prs_kostensoort ks"
                     + "         WHERE ks.prs_kostensoort_key = COALESCE(o.prs_kostensoort_key, sm.prs_kostensoort_key, d.prs_kostensoort_key)) kostensoort_oms"
                     + "     , CASE"
                       + "     WHEN mld_opdr_fiatbedrag IS NULL"
                       // Het veld mld_opdr.mld_opdr_fiatbedrag wordt leeg gemaakt als de setting "mld_opdr_refiat_preference" op 1 staat
                       // en de goedkeurder heeft aangegeven dat de opdracht opnieuw als een nieuwe opdracht moet worden gefiatteerd.
                       // Er is dan wel "ORDFOK" tracking aanwezig terwijl de opdracht als nieuw behandeld moet worden (GEEN mld_opdr_fiat_user).
                       + "     THEN null"
                       + "     ELSE fac.gettrackinguserkey('ORDFOK', o.mld_opdr_key)"
                       + "     END mld_opdr_fiat_user"
                     + "     , o.mld_opdr_approved"
                     + "     , o.mld_opdr_approved_refiat"
                     + "     , fac.gettrackingdate('ORDFIA', o.mld_opdr_key) trackdateFIA"
                     + "     , fac.gettrackingdate('ORDFOK', o.mld_opdr_key) trackdateFOK"
                     + "     , (SELECT GREATEST( (SELECT COALESCE(MAX(t.fac_tracking_datum), TO_DATE('01-01-1970','dd-mm-yyyy'))"
                                            + "     FROM fac_tracking t"
                                            + "        , fac_srtnotificatie st"
                                            + "    WHERE t.fac_srtnotificatie_key = st.fac_srtnotificatie_key"
                                            + "      AND st.fac_srtnotificatie_code IN ('ORDUPD','ORDDAT','ORDPL2')"
                                            + "      AND st.fac_srtnotificatie_xmlnode = 'opdracht'"
                                            + "      AND t.fac_tracking_refkey = ro.mld_opdr_key"
                                            + "  )"
                                            + ", (SELECT COALESCE(MAX(n.mld_opdr_note_aanmaak), TO_DATE('01-01-1970','dd-mm-yyyy'))"
                                            + "     FROM mld_opdr_note n"
                                            + "    WHERE n.mld_opdr_key = ro.mld_opdr_key"
                                            + "   )"
                                            + ") lasttracknote"
                       + "        FROM mld_opdr ro"
                       + "       WHERE ro.mld_opdr_key = o.mld_opdr_key) mld_opdr_laatstgewijzigd"
                     + "     , o.mld_opdr_laatstgezien"
                     + "     , CASE"
                     + "           WHEN (SELECT COALESCE(MAX(t.fac_tracking_datum), TO_DATE('01-01-1970', 'dd-mm-yyyy'))"
                     + "                   FROM fac_tracking t"
                     + "                      , fac_srtnotificatie st"
                     + "                  WHERE t.fac_srtnotificatie_key = st.fac_srtnotificatie_key"
                     + "                    AND st.fac_srtnotificatie_code IN ('ORDUPD', 'ORDDAT', 'ORDPL2')"
                     + "                    AND st.fac_srtnotificatie_xmlnode = 'opdracht'"
                     + "                    AND t.fac_tracking_refkey = o.mld_opdr_key)"
                     + "                >"
                     + "                (SELECT COALESCE(MAX(n.mld_opdr_note_aanmaak), TO_DATE('01-01-1970', 'dd-mm-yyyy'))"
                     + "                   FROM mld_opdr_note n"
                     + "                  WHERE n.mld_opdr_key = o.mld_opdr_key)"
                     + "           THEN"
                     + "               (SELECT t.prs_perslid_key"
                     + "                  FROM fac_tracking t"
                     + "                 WHERE t.fac_tracking_key = (SELECT MAX(t1.fac_tracking_key)"
                     + "                                               FROM fac_tracking t1"
                     + "                                                  , fac_srtnotificatie st"
                     + "                                              WHERE t1.fac_srtnotificatie_key = st.fac_srtnotificatie_key"
                     + "                                                AND st.fac_srtnotificatie_code IN ('ORDUPD', 'ORDDAT', 'ORDPL2')"
                     + "                                                AND st.fac_srtnotificatie_xmlnode = 'opdracht'     "
                     + "                                                AND t1.fac_tracking_refkey = o.mld_opdr_key))    "
                     + "           ELSE"
                     + "               (SELECT n.prs_perslid_key"
                     + "                  FROM mld_opdr_note n"
                     + "                 WHERE n.mld_opdr_note_key = (SELECT MAX(n1.mld_opdr_note_key)"
                     + "                                                FROM mld_opdr_note n1"
                     + "                                               WHERE n1.mld_opdr_key = o.mld_opdr_key))"
                     + "       END"
                     + "           laatstgewijzigddoor"
                     + "     , mdp.mld_disc_params_offerteauto"
                     + "     , mdp.mld_disc_params_bestellimiet"
                     + "     , mdp.mld_disc_params_bestellimiet2"
                     + "     , mdp.mld_disc_params_bestellimiet3"
                     + "     , mdp.mld_disc_params_bestellimiet4"
                     + "     , mdp.mld_disc_params_bestellimiet5"
                     + "     , mdp.mld_disc_params_pgb"
                     + "     , (SELECT COALESCE(SUM(mld_opdr_uren_besteed),0)"
                       + "        FROM mld_opdr_uren"
                       + "       WHERE mld_opdr_key = o.mld_opdr_key) mld_opdr_uren_besteed"
                     + "     , o.mld_opdr_plandatum"
                     + "     , o.mld_opdr_plandatum2"
                     + "     , o.mld_opdr_id"
                     + "     , o.mld_opdr_handfiat"
                     + "     , o.mld_opdr_actiecode"
                     + "     , sm.mld_stdmelding_opdrtypevast"
                     + "     , sm.mld_ins_discipline_key"
                     + "  FROM mld_opdr o"
                     + "     , mld_melding m"
                     + "     , mld_stdmelding sm"        // Let op! In BGT is mld_opdr.mld_melding_key altijd NULL.
                     + "     , ins_tab_discipline d"     //         Deze vier tabellen hebben dan geen betekenis
                     + "     , mld_disc_params mdp"      //         en krijgen daarom een outer-join.
                     + "     , ins_srtdiscipline sd"     //
                     + "     , mld_typeopdr mto"
                     + "     , prs_kostenplaats k"
                     + "     , prs_kostenplaatsgrp kg"
                     + "     , cnt_v_aanwezigcontract c"
                     + "     , mld_v_uitvoerende mu"
                     + " WHERE o.mld_melding_key = m.mld_melding_key(+)"
                     + "   AND m.mld_stdmelding_key = sm.mld_stdmelding_key(+)"
                     + "   AND sm.mld_ins_discipline_key = d.ins_discipline_key(+)"
                     + "   AND d.ins_srtdiscipline_key = sd.ins_srtdiscipline_key(+)"
                     + "   AND d.ins_discipline_key = mdp.mld_ins_discipline_key(+)"
                     + "   AND o.mld_typeopdr_key = mto.mld_typeopdr_key"
                     + "   AND o.prs_kostenplaats_key = k.prs_kostenplaats_key(+)" // kostenplaats van de opdracht kan leeg zijn
                     + "   AND k.prs_kostenplaatsgrp_key = kg.prs_kostenplaatsgrp_key(+)"
                     + "   AND o.cnt_contract_key = c.cnt_contract_key(+)"
                     + "   AND o.mld_uitvoerende_keys = mu.mld_uitvoerende_key"
                     + "   AND o.mld_opdr_key = " + opdr_key;
             var oRs = Oracle.Execute(sql);


             // Numeric values are used (only) here to calculate corr_cost.
             var hours = oRs("mld_opdr_uren").Value;
             var hours_refiat = oRs("mld_opdr_uren_refiat").Value;
             var m_cost_refiat = oRs("mld_opdr_materiaal_refiat").Value;
             var t_cost = oRs("mld_opdr_kosten").Value;
             var t_cost_refiat = oRs("mld_opdr_kosten_refiat").Value;
             var h_rate = oRs("mld_opdr_uurloon").Value;
             var h_rate_refiat = oRs("mld_opdr_uurloon_refiat").Value;
             var corr_cost = null;
             var typeopdr_uren = oRs("mld_typeopdr_uren").Value;
             var typeopdr_materiaal = oRs("mld_typeopdr_materiaal").Value;

             if (typeopdr_materiaal > 0)
             {
                 var m_cost = oRs("mld_opdr_materiaal").Value;
             }

             if (t_cost != null ||
                (typeopdr_materiaal > 0 && m_cost != null) ||                // Alleen als het materiaal veld aanwezig is moet er naar m_cost gekeken worden.
                (typeopdr_uren > 0 && (h_rate != null) && (hours != null)))  // Alleen als het uren veld aanwezig is moet er naar h_rate en hours gekeken worden.
             {
                 corr_cost = (t_cost || 0);
                 if (typeopdr_materiaal > 0)
                   corr_cost = corr_cost - (m_cost || 0);
                 if (typeopdr_uren > 0)
                   corr_cost = corr_cost - Math.round(100 * (h_rate || 0) * (hours || 0)) / 100; // Waarom hier afronden?;
                 // Correctie is het -berekende- veld dat uitgerekend is obv afgeronde bedragen, dat moet omgekeerd dus ook zo zijn
                 // Als corr_cost 0 is dan deze gewoon tonen.
                 // Als er daarnaast alleen nog een totaal is, dan wordt deze ook 0 en hoeft bij wijzigen niet opnieuw 0 te worden ingevuld.
             }
             var corr_cost_refiat = null;
             if (t_cost_refiat != null || m_cost_refiat != null || ( (h_rate_refiat != null) && (hours_refiat != null) ))
             {
                 corr_cost_refiat = ((t_cost_refiat || 0) - (m_cost_refiat || 0) - ((h_rate_refiat || 0) * (hours_refiat || 0)));
                 corr_cost_refiat = (corr_cost_refiat == 0 ? null : corr_cost_refiat);
             }

             var result = { opdr_key: opdr_key,
                            mld_opdr_datumbegin: new Date(oRs("mld_opdr_datumbegin").Value),
                            mld_key: oRs("mld_melding_key").Value,
                            contactpers: oRs("mld_opdr_contactpersoon").Value,
                            opdr_omschr: oRs("mld_opdr_omschrijving").Value,
                            parent_key: oRs("mld_opdr_parent_key").Value,
                            parent_isofferte: oRs("parent_isofferte").Value,
                            period: oRs("aantal_dagen").Value || 0,
                            hours: hours,
                            hours_refiat: hours_refiat,
                            m_cost: m_cost,
                            m_cost_refiat: m_cost_refiat,
                            t_cost: t_cost,
                            t_cost_refiat: t_cost_refiat,
                            fiatbedrag: oRs("mld_opdr_fiatbedrag").Value || 0,
                            uitvoerende_key: oRs("mld_uitvoerende_keys").Value,
                            contract_naam: oRs("cnt_contract_key").Value
                                           ? oRs("cnt_name").Value
                                           : "",
                            contract_key: oRs("cnt_contract_key").Value || -1,
                            h_rate: h_rate,
                            h_rate_refiat: h_rate_refiat,
                            opdr_type: oRs("mld_typeopdr_key").Value,
                            opdr_type_omschr: oRs("mld_typeopdr_omschrijving").Value,
                            typeopdr_uren: oRs("mld_typeopdr_uren").Value,
                            typeopdr_materiaal: oRs("mld_typeopdr_materiaal").Value,
                            typeopdr_totaal: oRs("mld_typeopdr_totaal").Value,
                            typeopdr_factuur: oRs("mld_typeopdr_factuur").Value,
                            typeopdr_slamode: oRs("mld_typeopdr_slamode").Value,
                            typeopdr_kosten: oRs("mld_typeopdr_kosten").Value,
                            typeopdr_sluitmelding: oRs("mld_typeopdr_sluitmelding").Value,
                            typeopdr_annuleermelding: oRs("mld_typeopdr_annuleermelding").Value,
                            typeopdr_afmeldmarge: oRs("mld_typeopdr_afmeldmarge").Value || 0,
                            typeopdr_offertelimiet: oRs("mld_typeopdr_offertelimiet").Value || -1, // Boven dit bedrag is een offerte vereist (met name voor niet-offerteopdrachten)
                            typeopdr_isofferte: oRs("mld_typeopdr_isofferte").Value, // Of deze opdracht een offerte is
                            typeopdr_typeopdr_key: oRs("mld_typeopdr_typeopdr_key").Value, // De mld_typeopdr_key voor vervolgopdracht (indien dit een offerte was)
                            typeopdr_contract: oRs("mld_typeopdr_contract").Value, // Of bij deze opdracht een contract moet (3), kan (2) of niet kan (0) worden opgegeven
                            typeopdr_afhandeling: oRs("mld_typeopdr_afhandeling").Value, // Afhandeling verplicht bij afmelden opdracht van dit opdrachttype (0=Nee/1=Ja)
                            typeopdr_confirm_for_send: oRs("mld_typeopdr_confirm_for_send").Value, // Hoe moet de opdrachten verstuurd worden (0=Direct versturen (Default), 1=Eerst Vragen, 2=Niet vragen, alleen handmatig en achteraf te versturen)
                            typeopdr_kosten_verplicht: oRs("mld_typeopdr_kosten_verplicht").Value || 0, // Opdracht kosten verplicht (bitwise) bij (0 = niet verplicht, 1 = save + 2 = afmelden, 4 = afronden).
                            typeopdr_sequential: oRs("mld_typeopdr_sequential").Value, // 0 t/m 7 (2^0 + 2^1 + 2^2).
                            typeopdr_decentraal: oRs("mld_typeopdr_decentraal").Value, // 0=centraal (Opdrachtgever (ORDBOF)), 1=beide, 2=decentraal (Opdrachtnemer (EXTORD)).
                            typeopdr_afmelden_extern: oRs("mld_typeopdr_afmelden_extern").Value,
                            typeopdr_zichtbaarfe: oRs("mld_typeopdr_zichtbaarfe").Value,
                            typeopdr_fvs: oRs("mld_typeopdr_fvs").Value,
                            typeopdr_gvs: oRs("mld_typeopdr_gvs").Value,
                            typeopdr_accept: oRs("mld_typeopdr_accept").Value,
                            typeopdr_image: oRs("mld_typeopdr_image").Value,
                            contactpers_key: oRs("mld_opdr_contact_key").Value || -1,
                            contactpers_naam: oRs("mld_opdr_contact_naam").Value,
                            contactpersuitv_key: oRs("prs_contactpersoon_key").Value,
                            contactpersuitv_perslid_key: oRs("prs_contactpersoon_perslid_key").Value,  // als cp een user is, is dit de corresponderende perslid_key
                            opdr_status: oRs("mld_statusopdr_key").Value,
                            extended_opdr_status: mld.getextendedopdrstatus(oRs("mld_statusopdr_key").Value, opdr_key),
                            opdr_status_refiat: oRs("mld_statusopdr_key_refiat").Value || 0,
                            mld_opdr_fiat_user: oRs("mld_opdr_fiat_user").Value,  // Laatste fiatteur die gefiatteerd heeft
                            halted: oRs("mld_opdr_halted").Value,
                            verzonden: oRs("mld_opdr_verzonden").Value,
                            teverzenden: oRs("mld_opdr_teverzenden").Value,
                            stdm_key: oRs("mld_stdmelding_key").Value,
                            mld_alg_locatie_key: oRs("mld_alg_locatie_key").Value,
                            mld_alg_onroerendgoed_keys: oRs("mld_alg_onroerendgoed_keys").Value,
                            melding_user_key: oRs("melding_user_key").Value,
                            vakgroep: oRs("ins_discipline_omschrijving").Value,
                            kosten_klant: oRs("mld_kosten_klant").Value || 0,
                            mld_afgerond: oRs("mld_melding_afgerond").Value == 1,
                            kp_key: oRs("prs_kostenplaats_key").Value,
                            kp_fiat: oRs("kp_fiat").Value == 1,
                            mld_opdr_opmerking_fiat: oRs("mld_opdr_opmerking_fiat").Value,
                            mld_opdr_bedrijfopdr_volgnr: oRs("mld_opdr_bedrijfopdr_volgnr").Value,
                            volgnr: oRs("mld_opdr_bedrijfopdr_volgnr").Value,
                            mld_opdr_ordernr: oRs("mld_opdr_ordernr").Value,
                            opdrkosten_verplicht: oRs("mld_disc_params_opdr_kosten").Value || 0,
                            opdr_opmerking: oRs("mld_opdr_opmerking").Value,
                            mld_opdr_einddatum: oRs("mld_opdr_einddatum").Value != null? new Date(oRs("mld_opdr_einddatum").Value) : null,
                            flag: oRs("mld_opdr_flag").Value,
                            srtdisc_key: oRs("ins_srtdiscipline_key").Value || -1,
                            srtdiscbes: (oRs("ins_srtdiscipline_bes").Value == 1),
                            srtdiscprefix: oRs("ins_srtdiscipline_prefix").Value,
                            act_key: oRs("fac_activiteit_key").Value || -1,
                            uitv_type: oRs("type").Value,
                            uitv_intern: oRs("intern").Value == 1,
                            uitv_naam: oRs("naam").Value,
                            corr_cost: corr_cost,
                            corr_cost_refiat: corr_cost_refiat,
                            fiatteur_kp_key: oRs("fiatteur_kp_key").Value || -1,
                            fiatteur_kpg_key: oRs("fiatteur_kpg_key").Value || -1,
                            fiatteur2_kpg_key: oRs("prs_kostenplaatsgrp_fiat2_key").Value || -1,
                            fiatteur3_kpg_key: oRs("prs_kostenplaatsgrp_fiat3_key").Value || -1,
                            kpg_fin_limit1: oRs("prs_kostenplaatsgrp_fin_limit1").Value || S("mld_opdr_kpg_fin_limit1"),
                            kpg_fin_limit2: oRs("prs_kostenplaatsgrp_fin_limit2").Value || S("mld_opdr_kpg_fin_limit2"),
                            dis_key: oRs("ins_discipline_key").Value,
                            opdr_disc_key: oRs("mld_opdr_discipline_key").Value,
                            kostensoort_def_key: oRs("prs_kostensoort_def_key").Value,
                            kostensoort_def_oms: oRs("kostensoort_def_oms").Value,
                            kostensoort_key: oRs("prs_kostensoort_key").Value,
                            inclBTW: oRs("inclBTW").Value,
                            kostensoort_oms: oRs("kostensoort_oms").Value,
                            offerteauto: oRs("mld_disc_params_offerteauto").Value == 1,
                            booked: oRs("mld_opdr_uren_besteed").Value,
                            approved: oRs("mld_opdr_approved").Value || -1,
                            approved_refiat: oRs("mld_opdr_approved_refiat").Value || -1,
                            refiat_is_approvedby_kp: (oRs("mld_statusopdr_key_refiat").Value || 0) > 0 &&                       // Refiat van de opdracht
                                                     oRs("mld_statusopdr_key").Value == 3 &&                                    // Opdracht staat "Ter fiattering"
                                                     oRs("trackdateFIA").Value != null && oRs("trackdateFOK").Value != null &&  // Er is al eens gefiatteerd
                                                     oRs("trackdateFIA").Value < oRs("trackdateFOK").Value,                     // De eerste fiatteur heeft opnieuw gefiatteerd.
                            bestellimiet: oRs("mld_disc_params_bestellimiet").Value || 0,
                            bestellimiet2: oRs("mld_disc_params_bestellimiet2").Value || 0,
                            bestellimiet3: oRs("mld_disc_params_bestellimiet3").Value || 0,
                            bestellimiet4: oRs("mld_disc_params_bestellimiet4").Value || 0,
                            bestellimiet5: oRs("mld_disc_params_bestellimiet5").Value || 0,
                            disc_params_pgb: oRs("mld_disc_params_pgb").Value || 0,
                            mld_opdr_plandatum: oRs("mld_opdr_plandatum").Value != null ? new Date(oRs("mld_opdr_plandatum").Value) : null,
                            mld_opdr_plandatum2: oRs("mld_opdr_plandatum2").Value != null ? new Date(oRs("mld_opdr_plandatum2").Value) : null,
                            mld_opdr_id: oRs("mld_opdr_id").Value,
                            opdr_handfiat: oRs("mld_opdr_handfiat").Value == 1, // Vrijwillig fiatteren.
                            actiecode: oRs("mld_opdr_actiecode").Value,
                            opdrtypevast: oRs("mld_stdmelding_opdrtypevast").Value == 1,
                            mld_ins_discipline_key: oRs("mld_ins_discipline_key").Value,
                            laatstgewijzigd: new Date(oRs("mld_opdr_laatstgewijzigd").Value),
                            laatstgezien: new Date(oRs("mld_opdr_laatstgezien").Value),
                            laatstgewijzigddoor: oRs("laatstgewijzigddoor").Value
                          };
             oRs.close();
             result.recentgewijzigd = result.laatstgewijzigd > result.laatstgezien && result.laatstgewijzigddoor != user_key;
             result.nextfiatteur_kpg_key = result.fiatteur_kpg_key; // welke van de drie is aan de beurt
             if (result.fiatbedrag > 0) // dan is de kp-verantwoordelijke al wel geweest en staat zijn budget er in
             {
                 if (result.fiatbedrag >= result.kpg_fin_limit1) // dan is de 1e kpg-verantwoordelijke al geweest
                     result.nextfiatteur_kpg_key = result.fiatteur2_kpg_key;
                 if (result.fiatbedrag >= result.kpg_fin_limit2) // dan is de 2e kpg-verantwoordelijke al geweest
                     result.nextfiatteur_kpg_key = result.fiatteur3_kpg_key;
             }
             // Uitvoertijd.
             if (result.uitvoerende_key > 0)
               result.uitvoertijd = mld.getbedrijfuitvoertijd(result.uitvoerende_key, result.mld_key);

             // Bepaling welke kosten velden getoond moeten worden.
             result = mld.mld_opdr_kosten_velden(result);

             return result;
           },

        mld_opdr_info_new:
           function _mld_opdr_info_new(mld_key, opdr_type, params)
           {
             params = params || {};
             var result = {};
             // Even apart in een eigen interne functie
             // Deze functie verrijkt (of overschrijft) het (_mld_opdr_info_new-gescopede-)result-object met gegevens over het relevante opdrachttype
             function _addOpdrTypeInfo() {
              var sql = "SELECT " + lcl.xsqla("t.mld_typeopdr_omschrijving", "t.mld_typeopdr_key")
                  + "     , t.mld_typeopdr_image"
                  + "     , t.mld_typeopdr_uren"
                  + "     , t.mld_typeopdr_materiaal"
                  + "     , t.mld_typeopdr_totaal"
                  + "     , t.mld_typeopdr_factuur"
                  + "     , t.mld_typeopdr_slamode"
                  + "     , t.mld_typeopdr_kosten"
                  + "     , t.mld_typeopdr_offertelimiet"
                  + "     , t.mld_typeopdr_isofferte"
                  + "     , t.mld_typeopdr_typeopdr_key"
                  + "     , t.mld_typeopdr_contract"
                  + "     , t.mld_typeopdr_kosten_verplicht"
                  + "     , t.mld_typeopdr_fvs"
                  + " FROM mld_typeopdr t"
                  + " WHERE t.mld_typeopdr_key = " + opdr_type;
              var oRs = Oracle.Execute(sql);
              //
              result.opdr_type = opdr_type;
              result.opdr_type_omschr = oRs("mld_typeopdr_omschrijving").Value;
              result.typeopdr_uren = oRs("mld_typeopdr_uren").Value;
              result.typeopdr_image = oRs("mld_typeopdr_image").Value;
              result.typeopdr_materiaal = oRs("mld_typeopdr_materiaal").Value;
              result.typeopdr_totaal = oRs("mld_typeopdr_totaal").Value;
              result.typeopdr_factuur = oRs("mld_typeopdr_factuur").Value;
              result.typeopdr_slamode = oRs("mld_typeopdr_slamode").Value;
              result.typeopdr_kosten = oRs("mld_typeopdr_kosten").Value;
              result.typeopdr_offertelimiet = oRs("mld_typeopdr_offertelimiet").Value || -1; // Boven dit bedrag is een offerte vereist (met name voor niet-offerteopdrachten)
              result.typeopdr_isofferte = oRs("mld_typeopdr_isofferte").Value; // Of deze opdracht een offerte is
              result.typeopdr_typeopdr_key = oRs("mld_typeopdr_typeopdr_key").Value; // De mld_typeopdr_key voor vervolgopdracht (indien dit een offerte was)
              result.typeopdr_contract = oRs("mld_typeopdr_contract").Value;
              result.typeopdr_kosten_verplicht = oRs("mld_typeopdr_kosten_verplicht").Value || 0; // Opdracht kosten verplicht (bitwise) bij (0 = niet verplicht, 1 = save + 2 = afmelden, 4 = afronden).
              result.typeopdr_fvs = oRs("mld_typeopdr_fvs").Value;
              oRs.Close();
             }
             var uitvoerende_key = params.uitvoerende_key || -1;
             var cnt_key         = params.cnt_key || -1;
             var opdr_copy_key   = params.opdr_copy_key || -1;
             var act_key         = params.act_key || -1;
             //
             var copy = (opdr_copy_key > -1);
             if (copy)
             {
               // Haal de opdrachtgegevens op van de opdracht
               result = mld.mld_opdr_info(opdr_copy_key);
               // Overschrijf de waarden die anders zijn dan de waarden van de orginele opdracht..
               result.opdr_key = -1;
               result.opdr_status = -1;
               result.extended_opdr_status = -1;
               result.opdr_status_refiat = 0;
               result.halted = 0;
               result.approved = -1;
               result.approved_refiat = -1;
               // Origineel materiaal is niet meegekopieerd dus de kosten ook niet.
               if (result.typeopdr_materiaal >= 2)
               {
                 result.t_cost = 0;
                 result.m_cost = 0;
                 result.corr_cost = 0;
                 result.h_rate = 0;
               }
               result.opdr_type_org = result.opdr_type; // As in/from database. Flexkenmerken overnemen van gekopieerde opdracht
               mld_key = result.mld_key;
               //
               if (result.contactpersuitv_key == null)
                 result.contactpersuitv_key = -1;

               // Overschrijft de opdrachttype gegeven van get result-object met opdrachttype-gegevens van het opgegeven(/gekozen, nieuwe) opdrachttype (ipv die van de gekopieerde opdracht)
               _addOpdrTypeInfo();
             }
             else // echt nieuw
             {
               result = { mld_key: mld_key,
                          t_cost: 0,
                          m_cost: 0,
                          corr_cost: 0,
                          h_rate: 0,
                          contactpersuitv_key: -1,
                          opdr_status: -1,
                          contract_key: cnt_key,
                          opdr_opmerking: "",
                          period: 0, // Te laat is altijd 0
                          hours: 0,
                          uitvoerende_key: uitvoerende_key,
                          contactpers_key: -1,
                          opdr_type_org: -1, // As in/from database
                          kp_key: -1,
                          kp_fiat: true,
                          fiatbedrag: 0,
                          mld_opdr_ordernr: ""
                        };
               // Voeg opdrachttype-gegevens toe aan het result-object
               _addOpdrTypeInfo();
               // Onderscheid uitvoerders m.b.t. initiële waarde beheerder:
               // 1) Extern bedrijf: Beheerder is default de user (invoerder).
               // 2) Interne persoon: Beheerder is default de user (invoerder).
               // 3) Intern bedrijf: Beheerder is default leeg.
               if (result.uitvoerende_key > 0)
               {
                 var sql = "SELECT b.prs_bedrijf_naam"
                         + "     , COALESCE (prs_bedrijf_uurloon, 0) uurloon"
                         + "     , COALESCE (prs_bedrijf_mld_limiet, 0) limiet"
                         + "     , COALESCE (prs_bedrijf_intern, 0) intern"
                         + "  FROM prs_bedrijf b"
                         + " WHERE b.prs_bedrijf_key = " + result.uitvoerende_key;
                 var oRs = Oracle.Execute(sql);
                 if (!oRs.eof) // Had in theorie ook een persoon kunnen zijn?
                 {
                   result.uitv_type = 'B';
                   result.h_rate = oRs("uurloon").Value;
                   if (result.typeopdr_isofferte == 0) {
                    result.corr_cost = oRs("limiet").Value;
                   }
                   result.uitvoerende = oRs("prs_bedrijf_naam").Value;
                   result.uitv_intern = oRs("intern").Value == 1;
                 }
                 else
                 {
                   result.uitv_type = 'B';
                   result.uitv_intern = 1;
                 }
                 oRs.Close();
               }
               //
               sql = "SELECT m.mld_stdmelding_key"
                     + "   , CASE"
                     + "     WHEN sd.ins_srtdiscipline_prefix IS NULL"
                     + "     THEN ''"
                     + "     ELSE sd.ins_srtdiscipline_prefix || '-'"
                     + "     END"
                     + "     || " + lcl.xsqla('d.ins_discipline_omschrijving', 'd.ins_discipline_key')
                   + "     , mdp.mld_disc_params_opdr_kosten"
                   + "     , sd.ins_srtdiscipline_prefix"
                   + "     , sd.ins_srtdiscipline_bes"
                   + "     , sd.ins_srtdiscipline_res"
                   + "     , m.mld_melding_datum"
                   + "     , m.mld_melding_einddatum"
                   + "     , m.mld_melding_omschrijving"
                   + "     , COALESCE(sm.prs_kostensoort_key, d.prs_kostensoort_key) prs_kostensoort_def_key"
                   + "     , (SELECT ks.prs_kostensoort_oms || '-' || " + lcl.xsqla('ks.prs_kostensoort_opmerking', 'ks.prs_kostensoort_key')
                   + "          FROM prs_kostensoort ks"
                   + "         WHERE ks.prs_kostensoort_key = COALESCE(sm.prs_kostensoort_key, d.prs_kostensoort_key)) kostensoort_def_oms"
                   + "     , (SELECT COALESCE(ks.prs_kostensoort_btw, 0)"
                   + "           FROM prs_kostensoort ks"
                   + "          WHERE ks.prs_kostensoort_key = d.prs_kostensoort_key) inclBTW"
                   + "     , mdp.mld_disc_params_pgb"
                   + "     , d.ins_discipline_key"
                   + "  FROM mld_melding m"
                   + "     , mld_stdmelding sm"
                   + "     , ins_tab_discipline d"
                   + "     , mld_disc_params mdp"
                   + "     , ins_srtdiscipline sd"
                   + " WHERE d.ins_discipline_key = mdp.mld_ins_discipline_key"
                   + "   AND m.mld_stdmelding_key = sm.mld_stdmelding_key"
                   + "   AND d.ins_srtdiscipline_key = sd.ins_srtdiscipline_key(+)"
                   + "   AND d.ins_discipline_key = " + (S("mld_opdr_discipline_mode") == 1?"sm.mld_ins_discipline_key":"COALESCE(m.mld_ins_discipline_key, sm.mld_ins_discipline_key)")
                   + "   AND m.mld_melding_key = " + mld_key;
               oRs = Oracle.Execute(sql);
               //
               result.stdm_key = oRs("mld_stdmelding_key").Value;
               result.vakgroep = oRs("ins_discipline_omschrijving").Value;
               result.opdr_omschr = oRs("mld_melding_omschrijving").Value;
               result.kostensoort_def_key = oRs("prs_kostensoort_def_key").Value;
               result.kostensoort_def_oms = oRs("kostensoort_def_oms").Value;
               result.opdrkosten_verplicht = oRs("mld_disc_params_opdr_kosten").Value;
               result.srtdiscprefix = oRs("ins_srtdiscipline_prefix").Value;
               result.srtdiscbes = (oRs("ins_srtdiscipline_bes").Value == 1);
               result.inclBTW = oRs("inclBTW").Value;
               result.disc_params_pgb = oRs("mld_disc_params_pgb").Value || 0;
               result.opdr_disc_key = oRs("ins_discipline_key").Value; // vakgroep of behandelteam
               result.act_key = (act_key > 0 ? act_key : -1); // fac_activiteit_key vanuit BES?
               oRs.Close();
             }

             // Bepaling welke kosten velden getoond moeten worden.
             result = mld.mld_opdr_kosten_velden(result);

             //----------
               if (!result.tonen_totaal)
               { // Als geen van de velden uren, materiaal en correctie aanwezig zijn is er ook geen totaal, dus hoeft totaal ook niet getoond te worden.
                 result.m_cost = 0;
                 result.corr_cost = 0;
                 result.h_rate = 0;
               }
               if (!result.tonen_uren && !result.tonen_materiaal_bedrag && !result.tonen_correctie && !result.tonen_totaal)
               {
                 result.t_cost = 0;
               }
               else
               {
                 result.t_cost = (result.tonen_uren ? ((result.hours ? result.hours : 0) * (result.h_rate ? result.h_rate : 0)) : 0)
                               + (result.tonen_materiaal_bedrag ? result.m_cost : 0)
                               + (result.tonen_correctie ? result.corr_cost : 0);
               }
             //
             sql = "SELECT mld.bepaalopdrmeldingvolgnr(" + mld_key + ") volg"
                 + " FROM DUAL";
             oRs = Oracle.Execute(sql);
             result.mld_opdr_bedrijfopdr_volgnr = oRs("volg").Value;
             oRs.Close();
             //

             if (result.typeopdr_slamode == 2) // Melding-SLA
             {
               result.uitvoertijd = mld.getmeldinguitvoertijd(mld_key);
             }

             return result;
           },

        dialectIsSet: false,

        mld_set_dialect:
            function (mld_key)
            {
                var sql = "SELECT md.ins_srtdiscipline_key"
                        + "  FROM mld_melding mm, mld_stdmelding ms, mld_discipline md"
                        + " WHERE mm.mld_melding_key = " + mld_key
                        + "   AND ms.mld_stdmelding_key = mm.mld_stdmelding_key"
                        + "   AND ms.mld_ins_discipline_key = md.ins_discipline_key";
                var oRs = Oracle.Execute(sql);
                lcl.set_dialect(oRs("ins_srtdiscipline_key").Value, "MLD_SRTDISCIPLINE_KEY");
                oRs.Close();
                mld.dialectIsSet = true;
            },

        mld_stdmeldinginfo:
           function _mld_stdmelding(mld_stdmelding_key) {
               var sql = "SELECT " + lcl.xsqla('ms.mld_stdmelding_omschrijving','ms.mld_stdmelding_key')
                       + "     , ms.mld_stdmelding_omschrijving mld_stdm_omschrijving_dblang"
                       + "     , ms.mld_stdmelding_volgnr"
                       + "     , md.ins_discipline_key"
                       + "     , ms.mld_stdmeldinggroep_key"
                       + "     , DECODE(COALESCE(sd.ins_srtdiscipline_prefix, ''), '', '', sd.ins_srtdiscipline_prefix) prefix"
                       + ", "+ lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
                       + "     , " + lcl.xsqla('md.ins_discipline_omschrijving', 'md.ins_discipline_key')
                       + "     , dp.mld_disc_params_srtgroep srtgroep" // Soort vakgroep
                       + "     , ms.mld_stdmelding_default_disc" // Default behandelteam
                       + "     , ms.mld_stdmelding_t_uitvoertijd.tijdsduur uitvoertijd" // Uitvoertijd Normaal
                       + "     , ms.mld_stdmelding_t_uitvtijd_pr1.tijdsduur uitvoertijd1" // Uitvoertijd Kritisch
                       + "     , ms.mld_stdmelding_t_uitvtijd_pr2.tijdsduur uitvoertijd2" // Uitvoertijd Hoog
                       + "     , ms.mld_stdmelding_t_uitvtijd_pr4.tijdsduur uitvoertijd4" // Uitvoertijd Laag
                       + "     , ms.mld_stdmelding_t_uitvoertijd.eenheid eenheid" // Eenheid uitvoertijd Normaal
                       + "     , ms.mld_stdmelding_t_uitvtijd_pr1.eenheid eenheid1" // Eenheid uitvoertijd Kritisch
                       + "     , ms.mld_stdmelding_t_uitvtijd_pr2.eenheid eenheid2" // Eenheid uitvoertijd Hoog
                       + "     , ms.mld_stdmelding_t_uitvtijd_pr4.eenheid eenheid4" // Eenheid uitvoertijd Laag
                       + "     , ms.mld_stdmelding_t_accepttijd.tijdsduur accepttijd_t"
                       + "     , ms.mld_stdmelding_t_accepttijd.eenheid accepttijd_e"
                       + "     , ms.mld_stdmelding_priomatrix"
                       + "     , ms.mld_stdmelding_taggable"
                       + "     , ms.mld_stdmelding_planbaar"
                       + "     , ms.mld_stdmelding_planbaarfe"
                       + "     , ms.mld_stdmelding_thirdparty"
                       + "     , md.ins_srtdiscipline_key"
                       + "     , md.ins_discipline_kpnverplicht"
                       + "     , sd.ins_srtdiscipline_kostenklant"
                       + "     , sd.ins_srtdiscipline_alg"
                       + "     , sd.ins_srtdiscipline_ins"
                       + "     , sd.ins_srtdiscipline_bes"
                       + "     , sd.ins_srtdiscipline_res"
                       + "     , sd.ins_srtdiscipline_mldgroup"
                       + "     , dp.mld_disc_params_mldgroup"
                       + "     , COALESCE(ms.mld_stdmelding_directklaar, dp.mld_disc_params_directklaar, 0) mld_directklaar"  // is wel/geen FO-vakgroep
                       + "     , dp.mld_disc_params_frontendprio"
                       + "     , dp.mld_disc_params_eigen_kp"
                       + "     , ms.mld_stdmelding_notfrontend"
                       + "     , ms.mld_stdmelding_notify"
                       + "     , ms.prs_kostensoort_key"
                       + "     , ms.prs_kostenplaats_key"
                       + "     , " + S("prs_kpn_string") + " kpstring"
                       + "     , k.prs_kostenplaats_module"
                       + "     , dp.mld_disc_params_startdatum"
                       + "     , ms.mld_stdmelding_freetext"
                       + "     , ms.mld_stdmelding_subject"
                       + "     , ms.mld_stdmelding_afmeldtext"
                       + "     , ms.ins_srtinst_verplichtstatus"
                       + "     , ms.alg_onrgoed_niveau"
                       + "     , ms.alg_onrgoed_obj_niveau"
                       + "     , ms.alg_org_obj_niveau"
                       + "     , ms.mld_stdmelding_prsafdobj"
                       + "     , ms.mld_stdmelding_prseigen"
                       + "     , " + lcl.xsqla('ms.mld_stdmelding_hint', 'ms.mld_stdmelding_key')
                       + "     , ms.mld_stdmelding_hint mld_stdmelding_hint_dblang"
                       + "     , sd.ins_srtdiscipline_image"
                       + "     , md.ins_discipline_image"
                       + "     , ms.mld_stdmelding_image"
                       + "     , ms.prs_dienst_key"
                       + "     , ms.mld_stdmelding_vereisdienst"
                       + "     , ms.mld_stdmelding_opdrtypevast"
                       + "     , ms.mld_typeopdr_key"
                       + "     , ms.mld_stdmelding_autoorder"
                       + "     , ms.mld_stdmelding_autoorderamount"
                       + "     , ms.bes_ins_discipline_key"
                       + "     , ms.mld_stdmelding_kopieerbaar"
                       + "     , ms.mld_stdmelding_doublecheck"
                       + "     , ms.mld_stdmelding_regime"
                       + "     , ms.mld_stdmelding_malusbasis"
                       + "     , ms.mld_stdmelding_malus"
                       + "     , ms.mld_stdmelding_malusmax"
                       + "     , ms.mld_stdmelding_afhankelijk"
                       + "     , ms.mld_stdmelding_kto"
                       + "     , ms.mld_stdmelding_vervaldatum"
                       + "     , ms.mld_stdmelding_kanverwijzen"
                       + "     , ms.mld_stdmelding_slabewaken"
                       + "     , ms.mld_stdmelding_externurl"
                       + "     , ms.cad_thema_key"
                       + "     , ms.mld_stdmelding_enddate_empty"
                       + "     , (SELECT COUNT(*)"    // ietwat grof qua autorisatie controle maar aantal_faq (iets) te hoog is geen risco
                       + "          FROM fac_faq ff"  // Hoogstens een keer de hele aantal_faq er uit schrijven
                       + "             , mld_stdmeldingfaq sf"
                       + "         WHERE ff.fac_faq_key = sf.fac_faq_key"
                       + "           AND (sf.mld_stdmelding_key = ms.mld_stdmelding_key"
                       + "                OR (sf.mld_stdmelding_key IS NULL"
                       + "                AND sf.ins_discipline_key = ms.mld_ins_discipline_key))"
                       + "           AND (ff.fac_functie_key IS NULL"
                       + "                 OR ff.fac_functie_key IN "
                       + "                   (SELECT fac_functie_key FROM fac_v_webgebruiker"
                       + "                     WHERE prs_perslid_key = " + user_key + "))"
                       + "           AND ff.fac_faq_datum < SYSDATE"
                       + "           AND (ff.fac_faq_lang = " + safe.quoted_sql(user_lang) + " OR ff.fac_faq_lang IS NULL)) aantal_faq"
                       + "     , ms.mld_stdmelding_conceptstatus"
                       + "     , ms.mld_stdmelding_objects_allowed"
                       + "  FROM mld_stdmelding ms"
                       + "     , mld_discipline md"
                       + "     , mld_disc_params dp"
                       + "     , ins_srtdiscipline sd"
                       + "     , prs_kostenplaats k"
                       + " WHERE ms.mld_stdmelding_key = " + mld_stdmelding_key
                       + "   AND ms.mld_ins_discipline_key = md.ins_discipline_key"
                       + "   AND md.ins_discipline_key = dp.mld_ins_discipline_key"
                       + "   AND md.ins_srtdiscipline_key = sd.ins_srtdiscipline_key(+)" // TODO JGL: Waarom outer join?
                       + "   AND ms.prs_kostenplaats_key = k.prs_kostenplaats_key(+)";
               var oRs = Oracle.Execute(sql);
               if (!mld.dialectIsSet) // Belangrijk voor prio-teksten
                    lcl.set_dialect(oRs("ins_srtdiscipline_key").Value, "MLD_SRTDISCIPLINE_KEY");

               var prios = {}; // let op: geen array dus maar object!
               // Normaal (3) is er altijd, desnoods met de default-default waarden.
               prios[3] = { text: L("lcl_mld_urg_normaal"),
                            key: 3,
                            uitvoertijd: oRs("uitvoertijd").Value? oRs("uitvoertijd").Value : "",
                            eenheid: oRs("eenheid").Value || 'D'
                          };
               if (oRs("uitvoertijd1").Value)
                 prios[1] = { text: L("lcl_mld_urg_kritiek"),
                              key: 1,
                              uitvoertijd: oRs("uitvoertijd1").Value? oRs("uitvoertijd1").Value : "",
                              eenheid: oRs("eenheid1").Value || 'D'
                              };
               if (oRs("uitvoertijd2").Value)
                 prios[2] = { text: L("lcl_mld_urg_hoog"),
                              key: 2,
                              uitvoertijd: oRs("uitvoertijd2").Value? oRs("uitvoertijd2").Value : "",
                              eenheid: oRs("eenheid2").Value || 'D'
                             };
               if (oRs("uitvoertijd4").Value)
                 prios[4] = { text: L("lcl_mld_urg_laag"),
                              key: 4,
                              uitvoertijd: oRs("uitvoertijd4").Value? oRs("uitvoertijd4").Value : "",
                              eenheid: oRs("eenheid4").Value || 'D'
                            };

               var alg_level = 0;
               switch (oRs("ins_srtdiscipline_alg").Value)
               {
                   case 1: alg_level = 5; break; // Ruimte
                   case 3: alg_level = 4; break; // Verdieping
                   case 5: alg_level = 3; break; // Gebouw
                   case 7: alg_level = 2; break; // Locatie
                   default: alg_level = 0;       // niet tonen
               }

               var result = { mld_stdmelding_key: mld_stdmelding_key,
                              stdmelding_omschrijving: oRs("mld_stdmelding_omschrijving").Value,
                              stdmelding_omschrijving_dblang: oRs("mld_stdm_omschrijving_dblang").Value,
                              stdmelding_volgnr: oRs("mld_stdmelding_volgnr").Value,
                              ins_discipline_key: oRs("ins_discipline_key").Value,
                              stdmeldinggroep_key: oRs("mld_stdmeldinggroep_key").Value,
                              srtdisc_oms: oRs("ins_srtdiscipline_omschrijving").Value,
                              ins_srtdiscipline_key: oRs("ins_srtdiscipline_key").Value,
                              ins_srtdiscipline_alglevel: alg_level,
                              ins_srtdiscipline_alg: alg_level > 0,
                              ins_srtdiscipline_ins: oRs("ins_srtdiscipline_ins").Value == 1,
                              ins_srtdiscipline_bes: oRs("ins_srtdiscipline_bes").Value > 0,
                              ins_srtdiscipline_res: oRs("ins_srtdiscipline_res").Value == 1,
                              ins_srtdiscipline_mldgroup: oRs("ins_srtdiscipline_mldgroup").Value,
                              afleveradres_verplicht: oRs("ins_srtdiscipline_bes").Value == 1,
                              mld_disc_params_mldgroup:   oRs("mld_disc_params_mldgroup").Value,
                              srt_disc_mldgroup: (oRs("mld_disc_params_mldgroup").Value==0 ? oRs("ins_srtdiscipline_mldgroup").Value : oRs("mld_disc_params_mldgroup").Value),
                              directklaar: oRs("mld_directklaar").Value,
                              ins_srtdiscipline_prefix: oRs("prefix").Value,
                              ins_srtdiscipline_kostenklant: oRs("ins_srtdiscipline_kostenklant").Value,
                              discipline_omschrijving: oRs("ins_discipline_omschrijving").Value,
                              prioriteiten: prios,
                              frontendprio: oRs("mld_disc_params_frontendprio").Value,
                              notfrontend: oRs("mld_stdmelding_notfrontend").Value,
                              notify: oRs("mld_stdmelding_notify").Value,
                              kostensoort: oRs("prs_kostensoort_key").Value,
                              kp_key: oRs("prs_kostenplaats_key").Value,
                              kpstring: oRs("kpstring").Value || "",
                              kpmodule: oRs("prs_kostenplaats_module").Value,
                              startdatum: oRs("mld_disc_params_startdatum").Value == 1,
                              srtgroep: oRs("srtgroep").Value,
                              default_ins_disc_key: oRs("mld_stdmelding_default_disc").Value,
                              accepttijd: oRs("accepttijd_t").Value,
                              eenheid_accepttijd: oRs("accepttijd_e").Value || 'D',
                              priomatrix: oRs("mld_stdmelding_priomatrix").Value,
                              taggable: oRs("mld_stdmelding_taggable").Value,
                              planbaar: ((oRs("mld_stdmelding_planbaar").Value & 4) == 4? oRs("mld_stdmelding_planbaar").Value - 4 : oRs("mld_stdmelding_planbaar").Value),
                              planbaarfe: oRs("mld_stdmelding_planbaarfe").Value,
                              show_actiedatum: (oRs("mld_stdmelding_planbaar").Value & 4) == 4,
                              canholdthirdparty: oRs("mld_stdmelding_thirdparty").Value,
                              kpnverplicht: oRs("ins_discipline_kpnverplicht").Value,
                              show_eigen_kp: (oRs("mld_disc_params_eigen_kp").Value == 1),
                              freetext: oRs("mld_stdmelding_freetext").Value,
                              subject: oRs("mld_stdmelding_subject").Value,
                              afmeldtext: oRs("mld_stdmelding_afmeldtext").Value,
                              srtinst_verplichtstatus: oRs("ins_srtinst_verplichtstatus").Value,
                              alg_onrgoed_niveau: oRs("alg_onrgoed_niveau").Value,
                              alg_onrgoed_obj_niveau: oRs("alg_onrgoed_obj_niveau").Value || "",
                              alg_org_obj_niveau: oRs("alg_org_obj_niveau").Value,
                              prsafdobj: oRs("mld_stdmelding_prsafdobj").Value,
                              prseigen: oRs("mld_stdmelding_prseigen").Value == 1,
                              hint: oRs("mld_stdmelding_hint").Value,
                              hint_dblang: oRs("mld_stdmelding_hint_dblang").Value,
                              image: (oRs("mld_stdmelding_image").Value ? oRs("mld_stdmelding_image").Value
                                                                        : (oRs("ins_discipline_image").Value ? oRs("ins_discipline_image").Value
                                                                                                             : (oRs("ins_srtdiscipline_image").Value ? oRs("ins_srtdiscipline_image").Value : null)
                                                                           )
                                       ),
                              prs_dienst_key: oRs("prs_dienst_key").Value,
                              vereisdienst: oRs("mld_stdmelding_vereisdienst").Value == 1,
                              opdrtypevast: oRs("mld_stdmelding_opdrtypevast").Value == 1,
                              typeopdr_key: oRs("mld_typeopdr_key").Value,
                              autoorder: oRs("mld_stdmelding_autoorder").Value,
                              autoorderamount: oRs("mld_stdmelding_autoorderamount").Value,
                              bes_ins_discipline_key: oRs("bes_ins_discipline_key").Value,
                              kopieerbaar: oRs("mld_stdmelding_kopieerbaar").Value,
                              doublecheck: oRs("mld_stdmelding_doublecheck").Value || 0,
                              regime: oRs("mld_stdmelding_regime").Value || 1, // 1 is kantoortijden
                              malusbasis: oRs("mld_stdmelding_malusbasis").Value,
                              malus: oRs("mld_stdmelding_malus").Value,
                              malusmax: oRs("mld_stdmelding_malusmax").Value,
                              afhankelijk: oRs("mld_stdmelding_afhankelijk").Value,
                              stdmelding_kto: oRs("mld_stdmelding_kto").Value || 0,
                              vervaldatum: oRs("mld_stdmelding_vervaldatum").Value != null? new Date(oRs("mld_stdmelding_vervaldatum").Value) : oRs("mld_stdmelding_vervaldatum").Value,
                              kanverwijzen: oRs("mld_stdmelding_kanverwijzen").Value,
                              slabewaken: oRs("mld_stdmelding_slabewaken").Value == 1,
                              externurl: oRs("mld_stdmelding_externurl").Value,
                              cad_thema_key: oRs("cad_thema_key").Value,
                              enddateempty: oRs("mld_stdmelding_enddate_empty").Value == 1,
                              conceptstatus: oRs("mld_stdmelding_conceptstatus").Value,
                              objects_allowed: oRs("mld_stdmelding_objects_allowed").Value,
                              aantal_faq: oRs("aantal_faq").Value, // Totaal aantal
                              fixed_faq: [], // deze worden altijd getoond
                              popup_faq: false, // Popupje tonen?
                              is_kto_antwoord: oRs("ins_srtdiscipline_key").Value == S("kto_srtdiscipline_key") // dan bevriest een en ander
                            };
               oRs.Close();

               // De delen waarop een stdmelding betrekking heeft toevoegen.
               var std_srtinst = [];
               var sql = "SELECT mld_stdmelding_srtinst_key"
                       + "     , ins_srtinstallatie_key"
                       + "     , ins_srtinstallatie_niveau"
                       + "  FROM mld_stdmelding_srtinst"
                       + " WHERE mld_stdmelding_key = " + mld_stdmelding_key;
               var oRs = Oracle.Execute(sql);
               while (!oRs.eof)
               {
                 var v_srtinst = { mld_stdmelding_srtinst_key: oRs("mld_stdmelding_srtinst_key").Value,
                                   ins_srtinstallatie_niveau: oRs("ins_srtinstallatie_niveau").Value,
                                   ins_srtinstallatie_key: oRs("ins_srtinstallatie_key").Value
                                 };
                 std_srtinst.push(v_srtinst);
                 oRs.MoveNext();
               }
               oRs.Close();
               result.ins_srtinst = std_srtinst;

               if (result.aantal_faq > 0)
               {
                 var canFAQUSEread = user.checkAutorisation("WEB_FAQUSE", true);
                 var canFAQFOFread = user.checkAutorisation("WEB_FAQFOF", true);

                  var sql = "SELECT ff.fac_faq_key, "
                           + "       fac_faq_question, "
                           + "       fac_faq_answer,"
                           + "       fac_faq_answer2,"
                           + "       fac_faq_url, "
                           + "       fac_faq_level, "
                           + "       fac_faq_displaymode"
                           + "  FROM fac_faq ff"
                           + "     , mld_stdmeldingfaq sf"
                           + " WHERE ff.fac_faq_key = sf.fac_faq_key"
                           + "   AND (sf.mld_stdmelding_key = " + mld_stdmelding_key
                           + "        OR (sf.mld_stdmelding_key IS NULL"
                           + "            AND sf.ins_discipline_key = " + result.ins_discipline_key + "))"
                           + "   AND (fac_functie_key IS NULL"
                           + "        OR fac_functie_key IN "
                           + "            (SELECT fac_functie_key FROM fac_v_webgebruiker"
                           + "              WHERE prs_perslid_key = " + user_key + "))"
                           + "   AND fac_faq_datum < SYSDATE"
                           + "   AND (fac_faq_lang = " + safe.quoted_sql(user_lang) + " OR fac_faq_lang IS NULL)"

                  sql += " AND (    ff.faq_ins_discipline_key IN "
                        + "             (SELECT ins_discipline_key FROM fac_v_webgebruiker"
                        + "                WHERE prs_perslid_key = " + user_key
                        + "                  AND fac_functie_key = " + F("WEB_FAQBOF") + ")"
                        + "       OR BITAND (fac_faq_level, 2) = 2" // Zichtbaar frontoffice
                        + "          AND ff.faq_ins_discipline_key IN "
                        + "             (SELECT ins_discipline_key FROM fac_v_webgebruiker"
                        + "                WHERE prs_perslid_key = " + user_key
                        + "                  AND fac_functie_key = " + F("WEB_FAQFOF") + ")"
                        + "       OR BITAND (fac_faq_level, 1) = 1" // Zichtbaar frontend
                        + "          AND ff.faq_ins_discipline_key IN "
                        + "             (SELECT ins_discipline_key FROM fac_v_webgebruiker"
                        + "                WHERE prs_perslid_key = " + user_key
                        + "                  AND fac_functie_key = " + F("WEB_FAQUSE") + ")"
                        + "     )"

                   sql +=    " ORDER BY fac_faq_rank DESC NULLS LAST"
                           + "        , fac_faq_datum DESC"
                           + "        , fac_faq_question";

                   var oRs = Oracle.Execute(sql);
                   result.popup_faq = false;
                   while (!oRs.EOF)
                   {
                     var displaymode = oRs("fac_faq_displaymode").Value;

                     // Displaymode +1=Altijd tonen melding, +2=Pop-up melding, +4=Altijd tonen opdracht, +8=Pop-up opdracht.
                     if ((displaymode & 2) == 2) // Pop-up
                     {
                         if (((S("faq_kennisbank_popup") & 1) && canFAQUSEread) || // Voor FE
                             ((S("faq_kennisbank_popup") & 2) && canFAQFOFread))   // Voor FO
                           result.popup_faq = true
                     }
                     if ((displaymode & 1) == 1) // Vast in beeld
                     {
                         var data = { question: oRs("fac_faq_question").Value,
                                      answer: oRs("fac_faq_answer").Value,
                                      answer2: oRs("fac_faq_answer2").Value,
                                      displaymode: oRs("fac_faq_displaymode").Value
                                    };
                         var fac_url = oRs("fac_faq_url").value;
                         if (fac_url)
                         {
                           var arr = fac_url.split("|");
                           var hurl = arr[0];
                           data.hlnk = arr.length>1?arr[1]:hurl;

                           if (hurl.slice(0,4) == "http") // extern
                             data.hurl = hurl;
                           else // in cust subdir
                             data.hurl = custpath + "/" + hurl;
                         }
                         result.fixed_faq.push(data);
                     }
                     oRs.MoveNext();
                   }
                   oRs.Close();
               }

               return result;
        },
        alg_algfaq_info:
           function _alg_faq_info(loc_key, alg_key) {
               if (!loc_key || loc_key == -1) return; // Minimal requirement
               var sql = "SELECT NVL(o.alg_type, 'L') scope"
                       + "     , l.alg_locatie_code ||"
                       + "       DECODE(o.alg_plaatsaanduiding, NULL, NULL, '-' || o.alg_plaatsaanduiding) plaats"
                       + "  FROM alg_locatie l"
                       + "     , alg_v_onroerendgoed_gegevens o"
                       + " WHERE l.alg_locatie_key = o.alg_locatie_key(+)"
                       + "   AND l.alg_locatie_key = " + loc_key
                       + "   AND " + ((alg_key && alg_key != -1) ? alg_key : "-1") + " = o.alg_onroerendgoed_keys(+)";
                var oRs = Oracle.Execute(sql);
                var ret = { scope: oRs("scope").Value, plaats: oRs("plaats").Value };
                oRs.Close();
                return ret;
        },
        faq_info:
           function _faq_info(loc_key, alg_key_arr, ins_disc_key, stdm_key, opdr_type, afdeling_key, changed, is_popup, for_order, showall) {
               var has = {   ins:  ins_disc_key && ins_disc_key != -1,
                             stdm: stdm_key && stdm_key != -1,
                             opdrtype: opdr_type && opdr_type != -1,
                             afdeling: afdeling_key && afdeling_key != -1,
                             loc:  loc_key && loc_key != -1,
                             alg:  alg_key_arr.length && alg_key_arr.length > 0 };

               if (!has.ins && !has.stdm && !has.opdrtype && !has.afdeling && !has.loc)
                    return {};

               if (!has.ins && has.stdm && changed == 1) // Then find ins_disc_key
               {
                   var insSql = "SELECT mld_ins_discipline_key FROM mld_stdmelding WHERE mld_stdmelding_key = " + stdm_key;
                   var insoRs = Oracle.Execute(insSql);
                   ins_disc_key = insoRs(0).Value;
                   insoRs.Close();
                   has.ins = ins_disc_key && ins_disc_key != -1;
               }

               var canFAQUSEread = user.checkAutorisation("WEB_FAQUSE", true);
               var canFAQFOFread = user.checkAutorisation("WEB_FAQFOF", true);

               function getSelect(afdeling, discstdm, opdrtype, plaats)
               {
                 var rank = (discstdm? 4 : 0) + (opdrtype? 2 : 0) + (plaats? 1 : 0);
                 var sql_select = ", " + rank + " rank";

                 if (afdeling)
                   sql_select += "     , DECODE (pf.prs_afdeling_key,"
                               + "               NULL, DECODE (pf.prs_bedrijf_key,"
                               + "                             NULL, 'X', 'C')," // [C]ompany
                               + "               'D') prs_type"; // [D]epartment
                 else
                   sql_select += "     , 'X' prs_type";

                 if (discstdm)
                   sql_select += "     , DECODE (sf.mld_stdmelding_key,"
                               + "               NULL, DECODE (sf.ins_discipline_key,"
                               + "                             NULL, 'X', 'I'),"
                               + "               'S') stdm_type";
                 else
                   sql_select += "     , 'X' stdm_type";

                 // Bij kennisitems voor meldingen is het opdrachttype niet interessant en zal deze -1 zijn (has.opdrtype is false).
                 // In dat geval moet er niet naar het opdrachttype gekeken worden.
                 if (opdrtype && has.opdrtype)
                   sql_select += "     , DECODE(tof.mld_typeopdr_key, NULL, 'X', 'O') opdr_type";
                 else
                   sql_select += "     , 'X' opdr_type";

                 if (plaats)
                   sql_select +="      , DECODE (og.alg_onroerendgoed_keys,"
                               + "               NULL, DECODE (af.alg_locatie_key,"
                               + "                             NULL, 'X', 'L'),"
                               + "               og.alg_type) alg_type ";
                 else
                   sql_select += "     , 'X' alg_type";

                 sql_select += "       , fac_faq_displaymode displaymode";
                 return sql_select;
               }

               function getFrom(afdeling, discstdm, opdrtype, plaats)
               {
                 var sql_from = "";
                 if (afdeling)
                   sql_from += "       , prs_v_aanwezigafdeling pa"
                             + "       , prs_prsfaq pf";

                 if (discstdm)
                   sql_from += "       , mld_stdmeldingfaq sf";

                 // Bij kennisitems voor meldingen is het opdrachttype niet interessant en zal deze -1 zijn (has.opdrtype is false).
                 // In dat geval moet er niet naar het opdrachttype gekeken worden.
                 if (opdrtype && has.opdrtype)
                   sql_from += "       , mld_typeopdrfaq tof";

                 if (plaats)
                   sql_from +="        , alg_algfaq af"
                               + "     , alg_v_onroerendgoed og";

                 return sql_from;
               }

               function getWhere(afdeling, discstdm, opdrtype, plaats)
               {
                 var sql_where = (is_popup
                                 ? " AND BITAND(ff.fac_faq_displaymode, 10) <> 0" // Minstens 2 (pop-up MLD) of 8 (pop-up ORD)
                                 : " AND ff.fac_faq_displaymode <> 0") // Minstens iets;

                 if (afdeling)
                 { // Stdmfilter
                   sql_where += "    AND ff.fac_faq_key = pf.fac_faq_key"
                              + "    AND pa.prs_afdeling_key = " + afdeling_key
                              + "    AND pa.prs_bedrijf_key = pf.prs_bedrijf_key"
                              + "    AND (   pf.prs_afdeling_key = pa.prs_afdeling_key"
                              + "         OR pf.prs_afdeling_key IS NULL)";
                 }
                 else
                   sql_where += "    AND NOT EXISTS (SELECT ''"
                              + "                      FROM prs_prsfaq pf"
                              + "                     WHERE pf.fac_faq_key = ff.fac_faq_key)";

                 if (discstdm)
                 { // Stdmfilter
                   sql_where += "    AND ff.fac_faq_key = sf.fac_faq_key"
                              + "    AND ";

                   if (has.ins)  // Vakgroep
                     sql_where += "      ((sf.ins_discipline_key = " + ins_disc_key
                                + "  AND sf.mld_stdmelding_key IS NULL)";
                   if (has.stdm) // Stdmelding
                     sql_where += (has.ins ? " OR " : "")
                                + "      sf.mld_stdmelding_key = " + stdm_key;
                   if (has.ins)
                     sql_where += "      )";
                 }
                 else
                   sql_where += "    AND NOT EXISTS (SELECT ''"
                              + "                      FROM mld_stdmeldingfaq sf"
                              + "                     WHERE sf.fac_faq_key = ff.fac_faq_key)";

                 // Bij kennisitems voor meldingen is het opdrachttype niet interessant en zal deze -1 zijn (has.opdrtype is false).
                 // In dat geval moet er niet naar het opdrachttype gekeken worden.
                 if (has.opdrtype)
                 {
                   if (opdrtype)
                     sql_where += "    AND ff.fac_faq_key = tof.fac_faq_key"
                                + "    AND tof.mld_typeopdr_key = " + opdr_type;
                   else
                     sql_where += "    AND NOT EXISTS (SELECT ''"
                                + "                      FROM mld_typeopdrfaq tof"
                                + "                     WHERE tof.fac_faq_key = ff.fac_faq_key)";
                 }

                 if (plaats)
                 {
                   sql_where +="     AND ff.fac_faq_key = af.fac_faq_key"
                              + "    AND af.alg_onroerendgoed_keys = og.alg_onroerendgoed_keys(+)"
                              + "    AND ";

                   // Plaatsfilter
                   if (has.loc)
                     sql_where += "      ((af.alg_locatie_key = " + loc_key
                                + "  AND af.alg_onroerendgoed_keys IS NULL)";
                   if (has.alg)
                     sql_where += (has.loc ? " OR " : "")
                                + "      af.alg_onroerendgoed_keys IN (" + alg_key_arr + ")";
                   if (has.loc)
                     sql_where += "      )";
                 }
                 else
                 {
                   sql_where += "    AND NOT EXISTS (SELECT ''"
                              + "                      FROM alg_algfaq af"
                              + "                     WHERE af.fac_faq_key = ff.fac_faq_key)";
                 }

                 return sql_where;
               }

               // Deze functie wordt alleen aangeroepen als de plaats, stdmelding of opdrachttype is aangepast.
               var sql = [];

               // Opbouw query voor het bepalen welke kennisbankitems getoond moeten worden.
               // Kennisbankitems kunnen gekoppeld zijn aan en specifiek zijn voor vakgroep/melding, opdrachttype en/of plaats.
               // Er zijn dan 8 mogelijkeheden te onderscheiden waarbij kennisbankitems gekoppeld kunnen zijn.
               // Kennisbankitems gekoppeld aan: (vakgroep/melding, opdrachttype, plaats)
               //                                1) plaats (0001)
               //                                2) opdrachttype (0010)
               //                                3) opdrachtype en plaats (0011)
               //                                4) vakgroep/melding (0100)
               //                                5) vakgroep/melding en plaats (0101)
               //                                6) vakgroep/melding en opdrachttype (0110)
               //                                7) vakgroep/melding, opdrachttype en plaats (0111)
               //                                8) bedrijf en/of afdeling (1000)
               // Voor elke mogelijkheid wordt een union aan de query toegevoegd.

               // 1) discstdm, opdrtype, plaats => false, false, true: kennisbank items gekoppeld aan plaats en niet aan vakgroep/stdm en opdrtype.
               if ((has.loc || has.alg) && (!is_popup || showall || changed >= 2))
                 sql.push(mld.getkennisbank_sql(getSelect(false, false, false, true),
                                                  getFrom(false, false, false, true),
                                                 getWhere(false, false, false, true)));

               // 2) discstdm, opdrtype, plaats => false, true, false: kennisbank items gekoppeld aan opdrtype en niet aan vakgroep/stdm en plaats.
               if (has.opdrtype && (!is_popup || showall || changed <= 1))
                 sql.push(mld.getkennisbank_sql(getSelect(false, false, true, false),
                                                  getFrom(false, false, true, false),
                                                 getWhere(false, false, true, false)));

               // 3) discstdm, opdrtype, plaats => false, true, true: kennisbank items gekoppeld aan opdrtype en plaats en niet vakgroep/stdm.
               if ((has.loc || has.alg) && has.opdrtype && (!is_popup || showall || changed <= 1))
                 sql.push(mld.getkennisbank_sql(getSelect(false, false, true, true),
                                                  getFrom(false, false, true, true),
                                                 getWhere(false, false, true, true)));

               // 4) discstdm, opdrtype, plaats => true, false, false: kennisbank items gekoppeld aan vakgroep/stdm en niet aan opdrtype en plaats.
               if ((has.ins || has.stdm) && (!is_popup || showall || changed <= 1))
                 sql.push(mld.getkennisbank_sql(getSelect(false, true, false, false),
                                                  getFrom(false, true, false, false),
                                                 getWhere(false, true, false, false)));

               // 5) discstdm, opdrtype, plaats => true, false, true: kennisbank items gekoppeld aan vakgroep/stdm en plaats en niet opdrtype.
               if ((has.ins || has.stdm) && (has.loc || has.alg) && (!is_popup || showall || changed >= 2))
                 sql.push(mld.getkennisbank_sql(getSelect(false, true, false, true),
                                                  getFrom(false, true, false, true),
                                                 getWhere(false, true, false, true)));

               // 6) discstdm, opdrtype, plaats => true, true, false: kennisbank items gekoppeld aan vakgroep/stdm en opdrtype en niet aan plaats.
               if ((has.ins || has.stdm) && has.opdrtype && (!is_popup || showall || changed <= 1))
                 sql.push(mld.getkennisbank_sql(getSelect(false, true, true, false),
                                                  getFrom(false, true, true, false),
                                                 getWhere(false, true, true, false)));

               // 7) discstdm, opdrtype, plaats => true, true, true: kennisbank items gekoppeld aan vakgroep/stdm, opdrtype en plaats.
               if ((has.ins || has.stdm) && has.opdrtype && (has.loc || has.alg) && (!is_popup || showall || changed <= 1))
                 sql.push(mld.getkennisbank_sql(getSelect(false, true, true, true),
                                                  getFrom(false, true, true, true),
                                                 getWhere(false, true, true, true)));

               // 7) discstdm, opdrtype, plaats => true, true, true: kennisbank items gekoppeld aan vakgroep/stdm, opdrtype en plaats.
               if (has.afdeling && (!is_popup || showall || changed == 9)) // Zonder 'changed', deze query-en we er altijd bij want ze zijn uniek (en alleen) voor afdelingen.
                 sql.push(mld.getkennisbank_sql(getSelect(true, false, false, false),
                                                  getFrom(true, false, false, false),
                                                 getWhere(true, false, false, false)));

               sql = sql.join(" UNION ALL ")
                   + " ORDER BY fac_faq_rank DESC NULLS LAST"
                   + "        , fac_faq_datum DESC"
                   + "        , fac_faq_question";

               var oRs = Oracle.Execute(sql);
               var result = { fixed_faq: [],
                              popup_faq: false };

               while (!oRs.EOF)
               {
                   var displaymode = oRs("displaymode").Value;

                   // Displaymode +1=Altijd tonen melding, +2=Pop-up melding, +4=Altijd tonen opdracht, +8=Pop-up opdracht.
                   if ((!for_order && (displaymode & 2) == 2) || (for_order && (displaymode & 8) == 8)) // Pop-up
                   {
                       if (((S("faq_kennisbank_popup") & 1) && canFAQUSEread) || // Voor FE
                           ((S("faq_kennisbank_popup") & 2) && canFAQFOFread))   // Voor FO
                           result.popup_faq = true;
                   }

                   if ((!for_order && (displaymode & (is_popup? 2 : 1)) == (is_popup? 2 : 1)) ||
                        (for_order && (displaymode & (is_popup? 8 : 4)) == (is_popup? 8 : 4)))
                   {
                       var data = { faq_key: oRs("fac_faq_key").Value,
                                    has_kenm: oRs("aantal_kenm").Value > 0,
                                    question: oRs("fac_faq_question").Value,
                                    answer: oRs("fac_faq_answer").Value,
                                    answer2: oRs("fac_faq_answer2").Value,
                                    displaymode: oRs("displaymode").Value,
                                    faq_type: "faq_" + oRs("stdm_type").Value + oRs("alg_type").Value
                                  };
                       var fac_url = oRs("fac_faq_url").value;
                       if (fac_url)
                       {
                         var arr = fac_url.split("|");
                         var hurl = arr[0];
                         data.hlnk = arr.length>1?arr[1]:hurl;

                         if (hurl.slice(0,4) == "http") // extern
                           data.hurl = hurl;
                         else // in cust subdir
                           data.hurl = custpath + "/" + hurl;
                       }
                       result.fixed_faq.push(data);
                   }

                   oRs.MoveNext();
               }
               oRs.Close();
               return result;
        },
        func_enabled_mld: // Heb ik als FO, BO, of FE, enige write rechten voor een discipline binnen de meegekregen discipline string
            function _func_enabled_mld(pkey, ptype) {
                // is pkey een srtdiscipline of discipline
                if (ptype == "S")
                {
                  var sql = "SELECT md.ins_discipline_key"
                          + " FROM mld_discipline md"
                          + " WHERE md.ins_discipline_verwijder IS NULL"
                          + " AND md.ins_srtdiscipline_key = " + pkey;
                  var oRs = Oracle.Execute(sql);
                  var lins_discipline_string = "";
                  while (!oRs.eof)
                  {
                    lins_discipline_string += (lins_discipline_string == ""? "" : ", ") + oRs("ins_discipline_key").Value;
                    oRs.MoveNext();
                  }
                  oRs.Close();
                }
                else // ptype == "D"
                {
                  if (pkey == "object" && pkey instanceof Array)
                     var lins_discipline_string = pkey.join(", ");
                  else
                     var lins_discipline_string = "" + pkey;
                }
                var mresult = user.func_enabled("MLD",
                                                lins_discipline_string,
                                                -1, //moRs("mld_alg_onroerendgoed_keys").Value, // TODO: Wat als geen INS_SRTDISCIPLINE_ALG?
                                                user_key,
                                                true); // Check optimistisch: je moet de rechten van minstens één discipline hebben!
                // melding
                // Algemeen niveau
                mresult.canFOwrite = mresult.canWrite("WEB_MLDFOF");
                mresult.canBOwrite = mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3");
                mresult.canFEwrite = mresult.canWrite("WEB_MLDUSE"); // nieuwe melding dus nog geen && user.isCollega(moRs("prs_perslid_key").Value);

                mresult.canFOread = mresult.canRead("WEB_MLDFOF");
                mresult.canBOread = mresult.canRead("WEB_MLDBOF");
                mresult.canFEread = mresult.canRead("WEB_MLDUSE");
                mresult.canMIread = mresult.canRead("WEB_MLDBAC");
                mresult.canReadAny  = mresult.canFORead || mresult.canBORead || mresult.canFERead || mresult.canMIread;
                mresult.canReadFEOnly = ((mresult.canReadAny && !mresult.canFOread && !mresult.canBOread && !mresult.canMIread) ? true : false);

                // opdracht
                // Algemeen niveau
                mresult.canORDBOFwrite = mresult.canWrite("WEB_ORDBOF");
                mresult.canORDBOFread = mresult.canRead("WEB_ORDBOF");
                mresult.haveORDSUPrights = user.checkAutorisation("WEB_ORDSUP", true) != null;
                mresult.haveORDFINrights = user.checkAutorisation("WEB_ORDFIN", true) != null;
                return mresult;
            },

        // Functie die bepaald of de meegegeven workflowstep afgewezen mag worden
        // De functie bepaald de start workflowstep en van daaruit wordt gekeken of in elke tak de flowstep gevonden kan worden,
        // ofwel of de workflowstep in een sequentiele of parallelle tak aanwezig is.
        // Wordt de wfstep in elke tak van de tree gevonden (sequentieel) dan wordt true teruggegeven anders fals (parallel)
        // De te vinden workflowstep moet meegegeven worden aan de functie.
        wfIsRejectable:
            function _wfIsRejectable(wfstep) {
                // Recursieve functie die kijkt of de volgende stap de te vinden flowstep is, anders kijkt die verder in de tree met een recursieve aanroep.
                // Wordt de wfstep gevonden dan wordt true teruggegeven.
                // Wordt de wfstep niet gevonden als de functie eindigt aan de eind van de tak zonder de wfstep te vinden. In dat geval wordt false teruggegeven.
                function findFlowstepInEveryTree(wfstartkey, wfstep)
                {
                  var wfsql = "SELECT wr.mld_workflowstep_next_key"
                            + " FROM mld_workflowrule wr"
                            + " WHERE wr.mld_workflowstep_key = " + wfstartkey;
                  var wfoRs = Oracle.Execute(wfsql);

                  if (wfoRs.eof)
                  {
                    wfoRs.Close();
                    return false;
                  }

                  var wfstepInTree = true;
                  while (!wfoRs.eof)
                  {
                    var wfnextkey = wfoRs("mld_workflowstep_next_key").Value;
                    wfstepInTree = wfstepInTree && ((wfnextkey == wfstep) || findFlowstepInEveryTree(wfnextkey, wfstep));
                    if (!wfstepInTree)
                      break;
                    wfoRs.MoveNext();
                  }
                  wfoRs.Close();
                  return wfstepInTree;
                }

                // vindt de start workflowstep
                var fsql = "SELECT ws.mld_workflowstep_start_key"
                         + " FROM mld_workflowstep ws"
                         + " WHERE ws.mld_workflowstep_key = " + wfstep;
                var foRs = Oracle.Execute(fsql);
                var wfstartkey = foRs("mld_workflowstep_start_key").Value;

                var wf_is_rejectable = findFlowstepInEveryTree(wfstartkey, wfstep)
                foRs.Close();

                return wf_is_rejectable;
            },

        isCollegaGoedkeur:
            function(pmld_opdr_key)
            {
              var prsKeys = user.collegakeylist();
              var sql = "SELECT f.fac_functie_code"
                      + "     , g.prs_perslid_key"
                      + "  FROM fac_v_webgebruiker g"
                      + "     , fac_functie f"
                      + "     , prs_perslid p"
                      + "     , prs_v_afdeling d"
                      + "     , mld_melding m"
                      + "     , alg_v_allonroerendgoed onrg"
                      + "     , (SELECT m1.mld_alg_locatie_key"
                      + "             , p1.prs_afdeling_key"
                      + "             , m1.mld_melding_key"
                      + "             , o1.mld_opdr_discipline_key"
                      + "          FROM mld_melding m1"
                      + "             , prs_perslid p1"
                      + "             , mld_opdr o1"
                      + "             , mld_typeopdr mto"
                      + "             , mld_disc_params mdp"
                      + "         WHERE m1.prs_perslid_key = p1.prs_perslid_key"
                      + "           AND o1.mld_opdr_discipline_key = mdp.mld_ins_discipline_key"
                      + "           AND o1.mld_typeopdr_key = mto.mld_typeopdr_key"
                      + "           AND o1.mld_statusopdr_key = 10"
                      + "           AND m1.mld_melding_key = o1.mld_melding_key"
                      + "           AND o1.mld_opdr_key = " + pmld_opdr_key + ") inf"
                      + " WHERE g.fac_functie_key = f.fac_functie_key"
                      + "   AND g.prs_perslid_key = p.prs_perslid_key"
                      + "   AND d.prs_afdeling_key = p.prs_afdeling_key"
                      + "   AND p.prs_perslid_key IN (" + prsKeys + ")"
                      + "   AND g.ins_discipline_key = inf.mld_opdr_discipline_key"
                      + "   AND m.mld_alg_onroerendgoed_keys = onrg.alg_onroerendgoed_keys(+)"
                      + "   AND m.mld_melding_key = inf.mld_melding_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 = inf.prs_afdeling_key))"
                      + "     OR (g.fac_gebruiker_prs_level_write > 0"
                      + "     AND p.prs_afdeling_key IN"
                      + "             (SELECT prs_afdeling_key"
                      + "                FROM prs_v_afdeling_familie a"
                      + "               WHERE a.prs_afdeling_elder_key IN (SELECT aa.prs_afdeling_elder_key"
                      + "                                                    FROM prs_v_afdeling_familie aa"
                      + "                                                   WHERE aa.prs_afdeling_key = inf.prs_afdeling_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 inf.mld_alg_locatie_key"
                      + "           IN (SELECT alg_locatie_key"
                      + "                 FROM fac_v_my_locations"
                      + "                WHERE prs_perslid_key = p.prs_perslid_key"
                      + "                  AND niveau = fac_gebruiker_alg_level_write)))"
                      + "   AND (g.fac_gebruiker_alg_level_write = -1"
                      + "     OR (g.fac_gebruiker_alg_level_write < 9"
                      + "     AND (CASE"
                      + "              WHEN m.mld_alg_onroerendgoed_keys IS NULL"
                      + "               AND m.mld_alg_locatie_key IN (SELECT alg_locatie_key"
                      + "                                               FROM fac_v_my_locations"
                      + "                                              WHERE prs_perslid_key = p.prs_perslid_key"
                      + "                                                AND niveau = g.fac_gebruiker_alg_level_write)"
                      + "              THEN"
                      + "                  1"
                      + "              WHEN onrg.alg_type = 'T'"
                      + "               AND m.mld_alg_onroerendgoed_keys IN (SELECT t.alg_terreinsector_key"
                      + "                                                      FROM fac_v_my_locations l, alg_terreinsector t"
                      + "                                                     WHERE t.alg_locatie_key = l.alg_locatie_key"
                      + "                                                       AND l.prs_perslid_key = p.prs_perslid_key"
                      + "                                                       AND l.niveau = g.fac_gebruiker_alg_level_write)"
                      + "              THEN"
                      + "                  1"
                      + "              WHEN onrg.alg_type = 'G'"
                      + "               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_gebouw_key"
                      + "                                                      FROM fac_v_my_buildings"
                      + "                                                     WHERE prs_perslid_key = p.prs_perslid_key"
                      + "                                                       AND niveau = g.fac_gebruiker_alg_level_write)"
                      + "              THEN"
                      + "                  1"
                      + "              WHEN onrg.alg_type = 'V'"
                      + "               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_verdieping_key"
                      + "                                                      FROM fac_v_my_floors"
                      + "                                                     WHERE prs_perslid_key = p.prs_perslid_key"
                      + "                                                       AND niveau = g.fac_gebruiker_alg_level_write)"
                      + "              THEN"
                      + "                  1"
                      + "              WHEN onrg.alg_type = 'R'"
                      + "               AND m.mld_alg_onroerendgoed_keys IN (SELECT alg_ruimte_key"
                      + "                                                      FROM fac_v_my_rooms"
                      + "                                                     WHERE prs_perslid_key = p.prs_perslid_key"
                      + "                                                       AND niveau = g.fac_gebruiker_alg_level_write)"
                      + "              THEN"
                      + "                  1"
                      + "              ELSE"
                      + "                  0"
                      + "          END) = 1))"
                      + "   AND f.fac_functie_code IN ('WEB_ORDGOE',"
                      + "                              'WEB_ORDGO2',"
                      + "                              'WEB_ORDGO3',"
                      + "                              'WEB_ORDGO4',"
                      + "                              'WEB_ORDGO5')"
                var oRs = Oracle.Execute(sql);
                var isCollegaGoedkeur = { ordgoe: false,
                                          ordgo2: false,
                                          ordgo3: false,
                                          ordgo4: false,
                                          ordgo5: false
                                        };
                while (!oRs.Eof)
                {
                  switch (oRs("fac_functie_code").Value)
                  {
                    case "WEB_ORDGOE": isCollegaGoedkeur.ordgoe = isCollegaGoedkeur.ordgoe ||
                                                                  user_key == oRs("prs_perslid_key").Value ||
                                                                  (S("mld_opdr_validate_by_substitute") == 1 && user.isCollega(oRs("prs_perslid_key").Value));
                                       break;
                    case "WEB_ORDGO2": isCollegaGoedkeur.ordgo2 = isCollegaGoedkeur.ordgo2 ||
                                                                  user_key == oRs("prs_perslid_key").Value ||
                                                                  (S("mld_opdr_validate_by_substitute") == 1 && user.isCollega(oRs("prs_perslid_key").Value));
                                       break;
                    case "WEB_ORDGO3": isCollegaGoedkeur.ordgo3 = isCollegaGoedkeur.ordgo3 ||
                                                                  user_key == oRs("prs_perslid_key").Value ||
                                                                  (S("mld_opdr_validate_by_substitute") == 1 && user.isCollega(oRs("prs_perslid_key").Value));
                                       break;
                    case "WEB_ORDGO4": isCollegaGoedkeur.ordgo4 = isCollegaGoedkeur.ordgo4 ||
                                                                  user_key == oRs("prs_perslid_key").Value ||
                                                                  (S("mld_opdr_validate_by_substitute") == 1 && user.isCollega(oRs("prs_perslid_key").Value));
                                       break;
                    case "WEB_ORDGO5": isCollegaGoedkeur.ordgo5 = isCollegaGoedkeur.ordgo5 ||
                                                                  user_key == oRs("prs_perslid_key").Value ||
                                                                  (S("mld_opdr_validate_by_substitute") == 1 && user.isCollega(oRs("prs_perslid_key").Value));
                                       break;
                  }
                  oRs.MoveNext();
                }
                oRs.Close();
                return isCollegaGoedkeur;
            },

        userIsBlokbehandelaar: // Checken of de user rechten heeft om een kenmerkblok aan te passen.
            function _userIsBlokbehandelaar(pmld_key, params)
            { // Kenmerkblokken ophalen.
              var foundUser = false;
              var filtcode = params.mld_status == 0? "BH2F" : "BH2B";
              sql = "SELECT ins_discipline_key" // Tertiar Behandelteam.
                  + "     , prs_perslid_key"    // Tertiar Behandelaar.
                  + "  FROM mld_kenmerkblokmelding"
                  + " WHERE mld_melding_key = " + pmld_key
                  + "   AND (ins_discipline_key IS NOT NULL OR prs_perslid_key IS NOT NULL)";
              oRs = Oracle.Execute(sql);
              while (!oRs.eof && !foundUser)
              {
                if (oRs("prs_perslid_key").Value > 0) { // Tertiar Behandelaar.
                  foundUser = (oRs("prs_perslid_key").Value == user_key);
                  if (foundUser) {
                    break;
                  }
                }

                // Zit de user in het behandelteam.
                // Vergelijkbare code in de functie getFiltClausePersoon(filtcode, params) in bestand persoonFilter.inc. Maar dit bestand willen we hier niet includen.
                var disc_key = oRs("ins_discipline_key").Value || -1;     // Tertiar Behandelteam.
                var afd_key = new Perslid(params.melder_key).prs_afdeling_key(); // Afdeling van de melder!
                // Let op: *mijn* rechten (params.autlevel) doen niet ter zake. Het gaat om de rechten van de collega
                var autfunction = params.mld_status == 0? "WEB_MLDFOF" : "WEB_MLDBOF";
                var filtClause = " AND p.prs_perslid_key IN"
                                + "              (SELECT prs_perslid_key"
                                + "                 FROM fac_v_webgebruiker g"
                                + "                WHERE g.fac_functie_key = " + F(autfunction)
                                + "                  AND g.ins_discipline_key = " + disc_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 = " + afd_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 = " + afd_key
                                + "                                   AND aa.niveau = g.fac_gebruiker_prs_level_write))"
                                + "                      )"
                                + "              )";
                if (params.loc_key > 0)
                  filtClause += " AND (g.fac_gebruiker_alg_level_write = -1"
                              + "   OR (g.fac_gebruiker_alg_level_write < 9"
                              + "       AND " + params.loc_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)"
                              + "      ))";
                filtClause +=") ";

                sql = "SELECT p.prs_perslid_key"
                    + " FROM prs_perslid p" // Geen prs_v_aanwezigperslid: afhankelijk van filtcode wordt " AND prs_perslid_verwijder IS NULL" toegevoegd
                    + "    , prs_v_afdeling d "
                    + " WHERE p.prs_afdeling_key = d.prs_afdeling_key"
                    + " " + filtClause
                    // faalt bij NULL values: " AND p.prs_perslid_oslogin NOT LIKE '\\_%' ESCAPE '\\' "
                    + " AND (prs_perslid_oslogin IS NULL OR prs_perslid_oslogin NOT LIKE '\\_%' ESCAPE '\\')"
                    + " AND BITAND(prs_perslid_flags, 2) = 0"
                    + " AND p.prs_perslid_key = " + user_key;
                oRs2 = Oracle.Execute(sql);
                foundUser = foundUser || !oRs2.eof;
                oRs2.close();

                oRs.MoveNext();
              }
              oRs.close();
              return foundUser;
            },

        func_enabled_melding: // Wat mag ik zoal op deze specifieke melding?
            function _func_enabled_melding(pmld_melding_key, params) {
                _DetectMultipleCalls("mld.func_enabled_melding", pmld_melding_key);

                params = params || {};
                var msql = "SELECT sm.mld_ins_discipline_key stdm_ins_discipline_key"
                         + "     , sm.mld_stdmelding_vervaldatum vervaldatum"
                         + "     , m.mld_ins_discipline_key mld_ins_discipline_key"
                         + "     , m.mld_alg_onroerendgoed_keys"
                         + "     , m.mld_alg_locatie_key"
                         + "     , m.mld_melding_status"
                         + "     , m.mld_melding_conceptstatus"
                         + "     , m.prs_perslid_key"
                         + "     , m.prs_perslid_key_voor"
                         + "     , m.prs_afdeling_key"
                         + "     , m.mld_workflowstep_key"
                         + "     , m.mld_melding_start_key"
                         + "     , m.mld_melding_parentkey"
                         + "     , m.mld_melding_publiek"
                         + "     , COALESCE(sm.mld_stdmelding_directklaar, mdp.mld_disc_params_directklaar) mld_directklaar"
                         + "     , mdp.mld_disc_params_frontendprio"
                         + "     , mld_stdmelding_kopieerbaar"
                         + "     , mld_stdmelding_doublecheck"
                         + "     , mdp.mld_disc_params_fenotes"
                         + "     , mdp.mld_disc_params_keten"
                         + "     , mdp.mld_disc_params_srtgroep"
                         + "     , sm.mld_stdmelding_planbaar"
                         + "     , sm.mld_stdmelding_planbaarfe"
                         + "     , (SELECT COUNT(o.mld_opdr_key)"
                         + "          FROM mld_opdr o"
                         + "         WHERE o.mld_melding_key = " + pmld_melding_key
                         + "           AND o.mld_statusopdr_key NOT IN (1, 2, 6, 7, 9)) openopdrachten" // 1=afgewezen, 2=Niet akkoord, 6=Technisch Voltooid/Afgemeld, 7=Verwerkt en 9= Kosten Voltooid
                         + "     , (SELECT COUNT(o.mld_opdr_key)"
                         + "          FROM mld_opdr o"
                         + "         WHERE o.mld_melding_key = " + pmld_melding_key
                         + "           AND o.mld_statusopdr_key IN (1, 2, 6, 7, 9)) closedopdrachten" // 1=afgewezen, 2=Niet akkoord, 6=Technisch Voltooid/Afgemeld, 7=Verwerkt en 9= Kosten Voltooid
                         + "     , m.fac_activiteit_key mld_action"
                         + "     , (SELECT COUNT (o.mld_opdr_key)"
                         + "          FROM mld_opdr o  "
                         + "         WHERE o.mld_melding_key = " + pmld_melding_key
                         + "           AND o.fac_activiteit_key IS NOT NULL) opdr_action"
                         + "     , (SELECT CASE"
                         + "               WHEN ((MAX(fa.fac_activiteit_aantal) IS NOT NULL AND MAX(fa.fac_activiteit_aantal) > 0)"              // Soort actie: "Eenmalig" en "Aantal keer"
                         + "                  OR (MAX(fa.fac_activiteit_einddatum) IS NOT NULL AND MAX(fa.fac_activiteit_einddatum) > SYSDATE))" // Soort actie: "Tot einddatum"
                         + "               THEN 1"
                         + "               ELSE 0"
                         + "               END"
                         + "          FROM mld_opdr o"
                         + "             , fac_activiteit fa"
                         + "         WHERE o.fac_activiteit_key = fa.fac_activiteit_key"
                         + "           AND o.mld_melding_key = " + pmld_melding_key
                         + "           AND o.fac_activiteit_key IS NOT NULL) has_actions"
                         + "     , m.mld_melding_afgerond"
                         + "     , mdp.mld_disc_params_bonotify"
                         + "     , sm.mld_stdmelding_conceptstatus"
                         + "  FROM mld_melding m"
                         + ",      mld_stdmelding sm"
                         + ",      mld_disc_params mdp"
                         + " WHERE mld_melding_key = " + pmld_melding_key
                         + "   AND m.mld_stdmelding_key = sm.mld_stdmelding_key"
                         + "   AND mdp.mld_ins_discipline_key = sm.mld_ins_discipline_key";
                var moRs = Oracle.Execute(msql);
                if (moRs.Eof)
                {
                    shared.record_not_found(L("lcl_complain") + " " + pmld_melding_key);
                }
                var vervalDatum = moRs("vervaldatum").Value;
                var mld_status = moRs("mld_melding_status").Value;
                var is_fo_melding = moRs("mld_directklaar").Value > 0;
                var frontendprio = moRs("mld_disc_params_frontendprio").Value == 1;
                var is_wf_step = !(moRs("mld_workflowstep_key").Value == null);
                var is_wf_root = is_wf_step && (moRs("mld_melding_start_key").Value == pmld_melding_key);
                var is_wf = is_wf_step || is_wf_root;
                var is_kopieerbaar = moRs("mld_stdmelding_kopieerbaar").Value == 1;
                var wfstep = moRs("mld_workflowstep_key").Value;
                var melder_key = moRs("prs_perslid_key").Value;
                var perslid_key_voor = moRs("prs_perslid_key_voor").Value;
                var afdeling_key = moRs("prs_afdeling_key").Value;
                var parent_key = moRs("mld_melding_parentkey").Value;
                var doublecheck = moRs("mld_stdmelding_doublecheck").Value;
                var fenotes = moRs("mld_disc_params_fenotes").Value;
                var keten = moRs("mld_disc_params_keten").Value == 1;
                var hasTeams = (moRs("mld_disc_params_srtgroep").Value & 4) == 4;
                var public = moRs("mld_melding_publiek").Value;
                var planbaar = ((moRs("mld_stdmelding_planbaar").Value & 4) == 4? moRs("mld_stdmelding_planbaar").Value - 4 : moRs("mld_stdmelding_planbaar").Value);
                var planbaarfe = moRs("mld_stdmelding_planbaarfe").Value;
                var show_actiedatum = ((moRs("mld_stdmelding_planbaar").Value & 4) == 4);
                var hasopenopdrachten = moRs("openopdrachten").Value > 0;
                var hasclosedopdrachten = moRs("closedopdrachten").Value > 0;
                var hasopdrachten = hasopenopdrachten || hasclosedopdrachten;
                var is_planned_action = moRs("mld_action").Value != null || moRs("opdr_action").Value > 0;
                var is_conceptmelding = moRs("mld_melding_conceptstatus").Value > 0;
                var has_actions = moRs("has_actions").Value == 1;
                var mld_afgerond = moRs("mld_melding_afgerond").Value == 1;
                var bonotify = moRs("mld_disc_params_bonotify").Value;
                var melding_conceptstatus = moRs("mld_melding_conceptstatus").Value;
                var stdmelding_conceptstatus = moRs("mld_stdmelding_conceptstatus").Value;
                // MLDBO3 accept notificatie, sturing puur op basis van mld_disc_params_bonotify.
                // Alleen voor mld_disc_params_bonotify is 2 (bo3) of 3 (bo3+bof) is er MLDBO3 accept notificatie (activeMLDBO3).
                var activeMLDBO3 = bonotify > 1;
                // fenotes is afhankelijk van de discipline (vakgroep) en geeft aan of FE notities mag zien.
                // 00 (0) Notitie is default niet zichtbaar voor FE (&1 == 0)
                // 01 (1) Notitie is default wel zichtbaar voor FE (&1 == 1)
                // 10 (2) Door FOBO te kiezen (per notitie) of FE notitie mag zien. Default waarde volgens &1 is niet zien (&2 == 1 en &1 == 0)
                // 11 (3) Door FOBO te kiezen (per notitie) of FE notitie mag zien. Default waarde volgens &1 is wel zien (&2 == 1 en &1 == 1)

                // Ben ik ook verantwoordelijk voor meldingen als vervanger van de melder
                var isVerantwoordelijke = (user.isCollega(melder_key));

                var stdm_ins_discipline_key = moRs("stdm_ins_discipline_key").Value;
                var mld_ins_discipline_key  = moRs("mld_ins_discipline_key").Value;

                var disc_arr = [];
                disc_arr.push(stdm_ins_discipline_key);
                if (mld_ins_discipline_key > 0)
                    disc_arr.push(mld_ins_discipline_key);

                var iamFinFiatteur = false; // Is verschillend t.o.v. isVerantwoordelijke omdat niet tegen een profiel van een persoon wordt getest.
                                            // isVerantwoordelijke kan false zijn als iamFinFiatteur true is.
                var iamFinGoedkeurder = false;
                if (hasopdrachten)
                {
                  // Moet ik 1 van deze facturen fiatteren of goedkeuren? Dan mag ik deze opdracht bekijken.
                  var fsql = "SELECT f.fin_factuur_statuses_key"
                          + "     , fin.getfiatteur(f.fin_factuur_key) kpverantwoordelijke"
                          + "     , prs_perslid_key_goedkeur"
                          + "  FROM fin_factuur f"
                          + "     , mld_opdr o"
                          + " WHERE f.mld_opdr_key = o.mld_opdr_key"
                          + "   AND o.mld_melding_key = " + pmld_melding_key
                          + "   AND f.fin_factuur_verwijder IS NULL";
                  var foRs = Oracle.Execute(fsql);
                  var authparamsFINBOF = user.checkAutorisation("WEB_FINBOF", true);
                  var hasFINBOFwrite = authparamsFINBOF && authparamsFINBOF.PRSwritelevel < 9 && authparamsFINBOF.ALGwritelevel < 9;
                  while (!foRs.eof)
                  {
                    iamFinFiatteur = iamFinFiatteur || hasFINBOFwrite || ((foRs("fin_factuur_statuses_key").Value == 2) && (user.isCollega(foRs("kpverantwoordelijke").Value)));
                    iamFinGoedkeurder = iamFinGoedkeurder || (foRs("fin_factuur_statuses_key").Value == 5) && (user.isCollega(foRs("prs_perslid_key_goedkeur").Value));
                    foRs.MoveNext();
                  }
                  foRs.Close();
                }

                var canFEread = public && user.has("WEB_MLDUSE"); // Je moet wel uberhaupt meldingen kunnen zien
                var userIsBlokbehandelaar = false;
                if (!params.dontcareblokheader)
                {
                  // Checken of de user rechten heeft om een kenmerkblok aan te passen.
                  userIsBlokbehandelaar = mld.userIsBlokbehandelaar(pmld_melding_key, { mld_status: mld_status,
                                                                                        melder_key: melder_key,
                                                                                        loc_key: moRs("mld_alg_locatie_key").Value});
                }

                var user_func_params = { ins_discipline_key: disc_arr,
                                         alg_key: moRs("mld_alg_onroerendgoed_keys").Value, // TODO: Wat als geen INS_SRTDISCIRPLINE_ALG?
                                         loc_key: moRs("mld_alg_onroerendgoed_keys").Value == null? moRs("mld_alg_locatie_key").Value : null,
                                         knownread: params.knownread,
                                         checkOptimistic: true,
                                         isOptional: params.knownread || canFEread || iamFinFiatteur || iamFinGoedkeurder || userIsBlokbehandelaar
                                       }
                if (S("mld_use_department") == 1)
                    user_func_params.afd_key = afdeling_key;
                else
                    user_func_params.prs_key = moRs("prs_perslid_key").Value;

                var mresult = user.func_enabled2("MLD", user_func_params);

                mresult.canFEread  = (mresult.canRead("WEB_MLDUSE") && user.isCollega(moRs("prs_perslid_key").Value)) || canFEread;
                mresult.canFEwrite = mresult.canWrite("WEB_MLDUSE") && user.isCollega(moRs("prs_perslid_key").Value);

                if (mld_ins_discipline_key > 0)
                {
                    user_func_params.ins_discipline_key = stdm_ins_discipline_key;
                    user_func_params.isOptional = true;
                    delete user_func_params.checkOptimistic;
                    var mresult_vakg = user.func_enabled2("MLD", user_func_params);

                    mresult_vakg.canFEread  = mresult_vakg.canRead("WEB_MLDUSE")  && user.isCollega(moRs("prs_perslid_key").Value);
                    mresult_vakg.canFEwrite = mresult_vakg.canWrite("WEB_MLDUSE") && user.isCollega(moRs("prs_perslid_key").Value);
                }
                else
                    var mresult_vakg = mresult;

                // Geeft alleen canWrite = true terug als er gekeken wordt naar de actuele urole (indien aanwezig)
                mresult_vakg.canWriteUrole = function() {
                  var currentUrole = (typeof urole == "undefined" ? "xx" : urole);
                  var canWriteUrole = false;
                  for (var i = 0; i < arguments.length; i++) {
                    var func = arguments[i];
                    switch (currentUrole.toLowerCase()) {
                      case "fe": canWriteUrole |= (func == "WEB_MLDUSE" ? mresult_vakg.canWrite(func) : false); break;
                      case "fo": canWriteUrole |= (func == "WEB_MLDFOF" ? mresult_vakg.canWrite(func) : false); break;
                      case "bo": canWriteUrole |= (func == "WEB_MLDBOF" ||
                                                   func == "WEB_MLDBO3" ? mresult_vakg.canWrite(func) : false); break;
                      default: canWriteUrole |= mresult_vakg.canWrite(func); break; // Zonder urole kijken we gewoon naar de fac_functie
                    }
                  }
                  return canWriteUrole;
                }
                mresult.canChangeUrole = (typeof urole == "undefined" ? "" : urole);  // (mld_close kent deze niet, en change-t ook niet interactief)

                delete user_func_params.ins_discipline_key;
                user_func_params.isOptional = mresult.canFEread || iamFinFiatteur || iamFinGoedkeurder;
                var mresult_no_disc = user.func_enabled2("MLD", user_func_params);

                moRs.Close();

                // Kunnen instemmen is alleen relevant voor een conceptmelding. Normaliter zul je best wel
                // leesrechten hebben op dit soort meldingen, maar als dat niet zo is kun je met dit criterium iig
                // je instemming geven (of juist afwijzen). Dan verdwijnt de melding wel na het instemmen/afwijzen
                // uit je autorisatie, dus krijg je na de reload een unauthorized.
                //
                // Binnenkort gaat iemand waarschijnlijk vinden dat vervangers ook moeten kunnen instemmen
                // Dan moet je inderdaad hier zijn.
                var instemmer = is_conceptmelding && mld.getinstemmer_key(pmld_melding_key);
                // Als de instemmer niet zelf mag instemmen (conceptstatus van de melding wijkt af van die van de stdmelding), dan mag hij dat ook niet met WEB_MLDMSU rechten.
                var isInstemmer = (is_conceptmelding &&
                                   (user.isCollega(instemmer) ||
                                    (user.checkAutorisation("WEB_MLDMSU", true) && !(melding_conceptstatus != stdmelding_conceptstatus && user_key == melder_key))));

                // -- CONTROLE LEESRECHTEN --
                mresult.canReadAny = mresult.canRead("WEB_MLDFOF") ||
                                     mresult.canRead("WEB_MLDBOF") ||
                                     mresult.canRead("WEB_MLDBO2") ||
                                     mresult.canRead("WEB_MLDBO3") ||
                                     mresult.canRead("WEB_MLDBAC") ||
                                     mresult.canFEread ||
                                     isVerantwoordelijke ||
                                     isInstemmer;

                if (!mresult.canReadAny) // laatste kans: heb ik een child die verwijst naar mij als parent?
                {
                    var sql = "SELECT mld_melding_key"
                            + "  FROM mld_melding"
                            + " WHERE mld_melding_parentkey = " + pmld_melding_key
                            + "   AND prs_perslid_key = " + user_key;
                    var oRs = Oracle.Execute(sql);
                    if (!oRs.Eof)
                    {
                      mresult.canReadAny = mresult.canFEread = true;
                      mresult.parentOfOwnRead = true; // Ik heb FEread rechten gekregen vanwege het feit dat de melding een parent van een eigen melding is.
                    }
                    oRs.Close();
                }

                // JGL: Kan hier al user.auth_required_or_abort(this_mld.canReadAny)?
                //      Mogelijk nog niet ivm. fiatteerders?
                //      Doen we wel in mld_show_melding

                // Speciaal voor Continue button FO: die is onafhankelijk van de rechten op de *huidige* melding
                //var authparamsMLDFOF = user.checkAutorisation("WEB_MLDFOF", true);
                //var mldfof_write = authparamsMLDFOF && (authparamsMLDFOF.PRSwritelevel < 9 && authparamsMLDFOF.ALGwritelevel < 9);
                // Algemeen niveau
                mresult.canFOread = mresult.canRead("WEB_MLDFOF");
                mresult.canBOread = mresult.canRead("WEB_MLDBOF") || mresult.canRead("WEB_MLDBO3");
                mresult.canMIread = mresult.canRead("WEB_MLDBAC");
                mresult.canFOwrite = mresult.canWrite("WEB_MLDFOF");
                mresult.canBOwrite = mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3");
                mresult.canVakgBOFwrite = mresult_vakg.canWrite("WEB_MLDBOF");
                mresult.canViewConfidential = mresult.canBOwrite || user_key == perslid_key_voor;
                mresult.hasTeams = hasTeams;

                // Voor notities geldt ja/nee autorisatie voor de WEB_MLDXXX autorisatie functies.
                mresult.canWriteNotes = (mresult.canRead("WEB_MLDFOF") ||
                                         mresult.canRead("WEB_MLDBOF") ||
                                         mresult.canRead("WEB_MLDBO3") ||
                                        (mresult.canFEread && fenotes > 0) ||
                                         mresult.canRead("WEB_MLDBAC")) ||
                                         userIsBlokbehandelaar;
                // In de newstyle mode moet ik in ieder geval ook rechten hebben om de melding te kunnen zien.
                mresult.canReadNotes = mresult.canWriteNotes || mresult.canReadAny;
                mresult.haveOnlyFErights = (!mresult.canRead("WEB_MLDFOF") && !mresult.canRead("WEB_MLDBOF") && mresult.canFEread);
                mresult.haveFOBOrights = mresult.canRead("WEB_MLDFOF") || mresult.canRead("WEB_MLDBOF");
                mresult.canWriteFlags = mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDFOF"); // Kan ik flags aanpassen

                // Op button niveau
                mresult.canChange = false;            // Wijzig knop tonen
                mresult.canChangeKenmerkBlok = false; // Moet een kenmerkblok behanden.
                mresult.canChangeUrole = (typeof urole == "undefined" ? "" : urole);  // (mld_close kent deze niet, en change-t ook niet interactief)
                mresult.canAccept = false;            // Accepteren melding
                mresult.canVakgAccept = false;        // Accepteren primaire vakgroep
                mresult.canReject = false;            // Afwijzen
                mresult.canForward = false;           // Doorsturen
                mresult.canForwardTeam = false;       // Behandelteam doorsturen
                mresult.canClose = false;             // Afmelden
                mresult.canReopen =  false;           // Heropenen van afgemelde melding
                mresult.canCloseWithOrder = false;    // Afmelden melding + opdracht(en)
                mresult.canContinue = false;          // Vervolg ('kopie')
                mresult.canDoorzet = false;           // Doorzetten naar backoffice
                mresult.canTerugzet = false;          // Terugzetten naar frontoffice
                mresult.canCopy = is_kopieerbaar && ((vervalDatum > new Date()) || vervalDatum == null) && (mresult.canFEwrite || mresult.canFOwrite || mresult.canBOwrite) && !is_planned_action;
                mresult.canAdd2Faq = false;           // Voordragen voor kennisbank
                mresult.canAfrond = false;            // SLA-technisch goedkeuren
                mresult.canVerwerk = false;           // Verwerkt verklaren
                mresult.canAddOpdr = false;           // Opdracht aanmaken
                mresult.canInstem = false;            // Instemmen met een conceptmelding
                mresult.canHerplan = false;           // Herplannen melding

                // Op invoerveld niveau
                mresult.canVakgChange = false;        // Vakgroep (discipline): ((mld_status == 1) && fronto) || (mld_status == 2 && !backo)
                mresult.canStdmChange = false;        // Melding (stdmelding): mld_status == 1 || mld_status == 2 || ((mld_status != 5 && mld_status != 6 && mld_status != 7) && backo)
                mresult.canDeptChange = false;        // Afdeling: (mld_status == 1 || mld_status == 2 || ((mld_status != 5 && mld_status != 6 && mld_status != 7) && backo) && !fronto)
                mresult.canKostChange = false;        // Kosten (kostenplaats, kosten klant en ordernummer): (mld_status == 1 || mld_status == 2 || ((mld_status != 5 && mld_status != 6 && mld_status != 7) && backo) && !fronto)
                mresult.canFlexChange = true;         // Standaard geen spciale restricties, maar kan wel afhankelijk zijn van de status
                mresult.canPlaatsChange = false;      // Plaats (locatie, gebouw, verdieping, ruimte): (mld_status == 1 || mld_status == 2 || ((mld_status != 5 && mld_status != 6 && mld_status != 7) && backo))
                mresult.canAflChange = false;         // Afleveradres: (mld_status == 1 || mld_status == 2 || ((mld_status != 5 && mld_status != 6 && mld_status != 7) && backo))
                mresult.canPersChange = false;        // Persooon (naam melder): fronto && (mld_status != 1 && mld_status < 4)
                mresult.canPrioChange = false;        // Prioriteit
                mresult.canOmsChange = false;         // Omschrijving: Aan te passen als mld_status <= 3 en voor frontoffice als status nog actief is (Pending(0), Ingevoerd(2), Ingezien(3), Geaccepteerd(4), Uitgegeven(7))
                mresult.canAfhandChange = false;      // Afhandeling gegevens
                mresult.canSLAChange = false;         // SLA (respijt)
                mresult.canWriteDatums = false;       // Datums (start/eind datum)
                mresult.canUnlink = false;
                mresult.canLink = false;

                // TODO: Voor sommige acties hoef je niet noodzakelijk fronto rechten te hebben op de *huidige* melding?
                if (parent_key)
                {   // dan mag je praktisch niets meer
                    switch (mld_status)
                    {
                        case 0: // Pending, welbeschouwd zag de backo deze al nooit
                                mresult.canUnlink       = mresult.canWrite("WEB_MLDFOF");
                                break;
                        case 1: // Afgewezen
                                mresult.canUnlink       = (S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF"));
                                break;
                        case 2: // Ingevoerd ('nieuw'), bo heeft er nog niet naar omgezien
                                mresult.canUnlink       = mresult.canWrite("WEB_MLDFOF");
                                break;
                        case 4: // Geaccepteerd ('In behandeling') (expliciet mld_accept_save_save.asp of als backoffice bewerkt en opslaat)
                                mresult.canUnlink       = mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3");
                                break;
                        case 7: // Uitgegeven
                                mresult.canUnlink       = mresult.canWrite("WEB_MLDBOF");
                                break;
                        case 5: // Afgemeld
                                mresult.canUnlink       = mresult.canWrite("WEB_MLDFOF"); //mldfof_write;
                                break;
                        case 6: // Admin voltooid
                                mresult.canUnlink       = false;
                                break;
                    }
                }
                else
                {
                    // Let op: WEB_MLDMSU is niet discipline gebonden en zit dus niet in mresult
                    mresult.canFixSLA = user.checkAutorisation("WEB_MLDMSU", true) && !is_planned_action && !is_conceptmelding; // Bijna status onafhankelijk
                    if (params.checkPublishRights) {
                      if (is_planned_action) {
                        mresult.canPublish = false;
                      } else {
                        var sql_msg = "SELECT 1 FROM fac_nieuws WHERE mld_melding_key = " + pmld_melding_key; // Een melding mag maar 1x gepubliceerd worden
                        var oRs_msg = Oracle.Execute(sql_msg);
                        mresult.canPublish = oRs_msg.EOF && mresult.canWrite("WEB_MLDFOF") && user.checkAutorisation("WEB_MSGBOF", true); // Publiceren melding (naar nieuwsbericht), status onafhankelijk
                        oRs_msg.Close();
                      }
                    }
                    // Vanaf 2025.2 is canFlexChange minder afhankelijk van de autorisaties bij een bepaalde status
                    // omdat de autorisatie primair met de kenmerk_rolcode wordt geregeld. Daarmee lijkt-ie me overbodig te gaan worden.
                    // de default is nu daarom true, en pakken we alleen nog de beperkingen
                    switch (mld_status)
                    {
                        case 0: // Pending, welbeschouwd zag de backo deze al nooit
                                mresult.canChange       = mresult.canWrite("WEB_MLDFOF");
                                mresult.canChangeUrole  = 'fo';
                                mresult.canReject       = mresult.canWrite("WEB_MLDFOF") &&
                                                          (!is_wf_step || (is_wf_step && mld.wfIsRejectable(wfstep))) &&
                                                          !is_planned_action;
                                mresult.canDoorzet      = mresult.canWrite("WEB_MLDFOF") && !is_planned_action;
                                mresult.canClose        = mresult.canWrite("WEB_MLDFOF") && !is_wf_root && !is_planned_action &&
                                                          (!hasopenopdrachten || S("mld_first_close_orders") == 0);
                                mresult.canCloseWithOrder = mresult.canWrite("WEB_MLDFOF") && !is_wf_root && !is_planned_action &&
                                                            hasopenopdrachten && S("mld_first_close_orders") == 1;
                                mresult.canVakgChange   = mresult_vakg.canWrite("WEB_MLDFOF");
                                mresult.canStdmChange   = mresult_vakg.canWrite("WEB_MLDFOF") && !is_wf_root;
                                mresult.canDeptChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canKostChange   = mresult.canWrite("WEB_MLDFOF");
                                //mresult.canFlexChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canPlaatsChange = mresult.canWrite("WEB_MLDFOF");
                                mresult.canAflChange    = mresult.canWrite("WEB_MLDFOF");
                                mresult.canPersChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canOmsChange    = mresult.canWrite("WEB_MLDFOF");
                                mresult.canAfhandChange = mresult.canWrite("WEB_MLDFOF");
                                mresult.canWriteDatums  = mresult.canWrite("WEB_MLDFOF");
                                mresult.canAddOpdr      = mresult.canWrite("WEB_ORDBOF");
                                break;
                        case 1: // Afgewezen
                                mresult.canChange       = (S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF"));
                                mresult.canChangeUrole  = 'fo';
                                mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !S("mld_disable_continuation"); //mldfof_write;
                                mresult.canVakgChange   = mresult_vakg.canWrite("WEB_MLDFOF");
                                mresult.canStdmChange   = mresult_vakg.canWrite("WEB_MLDFOF") && !is_wf_root;
                                mresult.canDeptChange   = ((S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF")) || mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                                mresult.canKostChange   = ((S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF")) || mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                                //mresult.canFlexChange   = true;
                                mresult.canPlaatsChange = (S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF"));
                                mresult.canAflChange    = (S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF"));
                                mresult.canPersChange   = (S("mld_rejected_is_open") == 1 && mresult.canWrite("WEB_MLDFOF"));
                                // Alleen FO kan melding aanpassen. FE toevoegen voor canPrioChange heeft geen zin.
                                mresult.canPrioChange   = (planbaar == 0 && planbaarfe == 0 && mresult.canWrite("WEB_MLDFOF"));
                                mresult.canOmsChange    = mresult.canWrite("WEB_MLDFOF");
                                mresult.canAfhandChange = mresult.canWrite("WEB_MLDFOF");
                                mresult.canWriteDatums  = mresult.canWrite("WEB_MLDFOF");
                                mresult.canSLAChange    = S("mld_rejected_is_open") == 1 &&
                                                          ((S("mld_sla_indult_for_mldafr_only") == 0 && mresult.canWrite("WEB_MLDBOF")) ||
                                                           (S("mld_sla_indult_for_mldafr_only") == 1 && mresult.canWrite("WEB_MLDAFR")));
                                break;
                        case 2: // Ingevoerd ('nieuw'), bo heeft er nog niet naar omgezien
                                // note: !is_conceptmelding is in principe niet noodzakelijk omdat alleen de FE en de instemmer deze melding kunnen zien,
                                //       maar als deze ook FO zijn moet dat toch wel.
                                mresult.canChange       = mresult.canWrite("WEB_MLDFOF") || mresult.canFEwrite;
                                mresult.canChangeUrole  = mresult.canWrite("WEB_MLDFOF") ? 'fo' : 'fe'; // Bij deze status (2) impliceert wijzigen altijd de FO-rol, ook als mijn rol nu BO is.
                                mresult.canAccept       = ((mresult.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult.canWrite("WEB_MLDBO3")) && !is_planned_action && !is_conceptmelding;
                                mresult.canVakgAccept   = ((mresult_vakg.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult_vakg.canWrite("WEB_MLDBO3")) && !is_planned_action && !is_conceptmelding;

                                mresult.canInstem       = isInstemmer;

                                mresult.canReject       = ((mresult.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult.canWrite("WEB_MLDBO3")) &&
                                                          (!is_wf_step || (is_wf_step && mld.wfIsRejectable(wfstep))) &&
                                                          !is_planned_action  && !is_conceptmelding || mresult.canInstem;  //als je kan instemmen kun je ook negatief instemmen=afwijzen
                                mresult.canForward      = (mresult_vakg.canWrite("WEB_MLDBOF") && !is_planned_action && !is_wf && !is_conceptmelding);
                                mresult.canClose        = (mresult.canWrite("WEB_MLDBOF") || (mresult.canWrite("WEB_MLDFOF") && (params && params.verynew))) &&
                                                          !is_wf_root && !is_planned_action  && !is_conceptmelding &&
                                                          (!hasopenopdrachten || S("mld_first_close_orders") == 0);
                                mresult.canCloseWithOrder = (mresult.canWrite("WEB_MLDBOF") || (mresult.canWrite("WEB_MLDFOF") && (params && params.verynew))) &&
                                                            !is_wf_root && !is_planned_action  && !is_conceptmelding &&
                                                            hasopenopdrachten && S("mld_first_close_orders") == 1;
                                mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !is_conceptmelding && !S("mld_disable_continuation"); //mldfof_write;
                                mresult.canVakgChange   = mresult_vakg.canWriteUrole("WEB_MLDUSE", "WEB_MLDFOF", "WEB_MLDBOF");
                                mresult.canStdmChange   = mresult_vakg.canWriteUrole("WEB_MLDUSE", "WEB_MLDFOF", "WEB_MLDBOF") && !is_wf_root;
                                mresult.canDeptChange   = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                                mresult.canKostChange   = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                                //mresult.canFlexChange   = mresult.canWrite("WEB_MLDFOF") || mresult.canFEwrite;
                                mresult.canPlaatsChange = mresult.canWrite("WEB_MLDFOF") || mresult.canFEwrite;
                                mresult.canAflChange    = mresult.canWrite("WEB_MLDFOF") || mresult.canFEwrite;
                                mresult.canPersChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canPrioChange   = (planbaar == 0 && planbaarfe == 0 && mresult.canWrite("WEB_MLDFOF") || (mresult.canFEwrite && frontendprio));
                                mresult.canTerugzet     = (is_fo_melding && mresult.canWrite("WEB_MLDBOF") && !is_planned_action && !is_conceptmelding);
                                mresult.canForwardTeam  = ((S("mld_fo_can_assign_team") == 1 && mresult.canWrite("WEB_MLDFOF")) || mresult.canWrite("WEB_MLDBOF")) && hasTeams && !is_planned_action;
                                // Alleen FO en FE kan melding aanpassen. BOF/BO3 toevoegen heeft voor volgende twee geen zin
                                mresult.canOmsChange    = mresult.canWrite("WEB_MLDFOF") || mresult.canFEwrite;
                                mresult.canAfhandChange = mresult.canWrite("WEB_MLDFOF");
                                mresult.canWriteDatums  = (mresult.canWrite("WEB_MLDFOF") || (mresult.canFEwrite && planbaar == 0 && planbaarfe == 1));
                                mresult.canAddOpdr      = !is_conceptmelding && mresult.canWrite("WEB_ORDBOF");
                                mresult.canSLAChange    = (S("mld_sla_indult_for_mldafr_only") == 0 && mresult.canWrite("WEB_MLDBOF")) ||
                                                          (S("mld_sla_indult_for_mldafr_only") == 1 && mresult.canWrite("WEB_MLDAFR"));
                                mresult.canHerplan      = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")) && show_actiedatum;
                                break;
                        //status 3 bestaat al een tijdje niet meer
                        case 4: // Geaccepteerd ('In behandeling') (expliciet mld_accept_save.asp of als backoffice bewerkt en opslaat)
                                mresult.canStdmChange   = mresult_vakg.canWriteUrole("WEB_MLDBOF", "WEB_MLDBO3") && !is_wf_root;
                                mresult.canDeptChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                                mresult.canKostChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                                mresult.canPlaatsChange = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                                mresult.canAflChange    = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                                // Alleen BO/FO kan melding aanpassen. FE toevoegen voor canPrioChange heeft geen zin.
                                mresult.canPrioChange   = (planbaar == 0 && planbaarfe == 0 && mresult.canStdmChange);
                                mresult.canTerugzet     = (!hasclosedopdrachten && !is_wf_root && is_fo_melding && mresult.canWrite("WEB_MLDBOF") && !is_planned_action);
                                /* GEEN BREAK !! */
                        case 7: // Uitgegeven
                                /* canPlaatsChange and canPrioChange will be overruled only when mld_status == 7 */
                                if (mld_status == 7) {
                                  mresult.canPlaatsChange = (S("mld_can_change_prio_and_place_while_issued") && (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")));
                                  mresult.canPrioChange   = (S("mld_can_change_prio_and_place_while_issued") && (planbaar == 0 && planbaarfe == 0 && (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"))));
                                }
                                /* Waarden hierna gelden dus voor zowel 4 als 7 */
                                mresult.canPersChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canChange       = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDFOF"));
                                mresult.canChangeKenmerkBlok = userIsBlokbehandelaar;
                                mresult.canChangeUrole  = mresult.canWrite("WEB_MLDBOF") ? 'bo' : 'fo';
                                mresult.canForward      = (!is_wf &&
                                                           (S("mld_forward_if_active") == 1 || (keten && !hasopdrachten)) && // Een melding met opdrachten mag niet meer doorgestuurd worden (MAYF#36363).
                                                           mresult_vakg.canWrite("WEB_MLDBOF") &&
                                                           !is_planned_action);
                                mresult.canForwardKeten = (!is_wf_root && S("mld_forward_if_active") == 0 && mresult.canForward); // is het echt vanwege keten?
                                mresult.canClose        = (((mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO2")) && S("mld_behandelteam_canclose") == 1) ||
                                                           ((mresult_vakg.canWrite("WEB_MLDBOF") || mresult_vakg.canWrite("WEB_MLDBO2")) && S("mld_behandelteam_canclose") == 0)) &&
                                                          !is_wf_root && (!is_planned_action || (is_planned_action && !has_actions)) && // Als de laatste geplande actie is geweest mag de melding afgemeld worden.
                                                          (!hasopenopdrachten || S("mld_first_close_orders") == 0);
                                mresult.canReject       = mresult.canClose && !hasopenopdrachten; // als ik kan sluiten kan ik ook annuleren, in status 7 heb ik toch altijd open opdrachten?
                                mresult.canCloseWithOrder = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO2")) &&
                                                            !is_wf_root && (!is_planned_action || (is_planned_action && !has_actions)) && // Als de laatste geplande actie is geweest mag de melding afgemeld worden.
                                                            hasopenopdrachten && S("mld_first_close_orders") == 1;
                                mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !S("mld_disable_continuation"); //mldfof_write;
                                //mresult.canFlexChange   = (mresult.canWrite("WEB_MLDBOF") || (mresult.canWrite("WEB_MLDFOF") && S("mld_fof_canFlexChange")));
                                // FOF kan alleen omschrijving aanpassen
                                mresult.canOmsChange    = mresult.canWrite("WEB_MLDFOF");
                                mresult.canAfhandChange = mresult.canWrite("WEB_MLDBOF");
                                mresult.canForwardTeam  = mresult.canWrite("WEB_MLDBOF") && hasTeams && !is_planned_action;
                                mresult.canWriteDatums  = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                                mresult.canAddOpdr      = mresult.canWrite("WEB_ORDBOF");
                                mresult.canSLAChange    = (S("mld_sla_indult_for_mldafr_only") == 0 && mresult.canWrite("WEB_MLDBOF")) ||
                                                          (S("mld_sla_indult_for_mldafr_only") == 1 && mresult.canWrite("WEB_MLDAFR"));
                                mresult.canHerplan      = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")) && show_actiedatum;
                                break;
                        case 5: // Afgemeld
                                mresult.canAfrond       = mresult.canWrite("WEB_MLDAFR") && !hasopenopdrachten;
                                mresult.canVerwerk      = mresult.canWrite("WEB_MLDAFR") && !hasopenopdrachten && S("mld_archive_by_gui");
                                //mresult.canFlexChange   = mresult.canWrite("WEB_MLDAFR") && S("mld_afrond_canflex");
                                mresult.canSLAChange    = mresult.canWrite("WEB_MLDAFR");
                                mresult.canFixMelding   = mresult.canFixSLA;
                                mresult.canChange       = mresult.canWrite("WEB_MLDAFR");
                                mresult.canPersChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !S("mld_disable_continuation");
                                var authFaq             = (S("faq_enabled")==1) && user.checkAutorisation("WEB_FAQFOF", true);
                                mresult.canAdd2Faq      = (authFaq && authFaq.PRSwritelevel < 9 && !is_planned_action);  // Voordragen voor kennisbank
                                mresult.canAddOpdr      = mresult.canWrite("WEB_ORDBOF") && !mld_afgerond;
                                mresult.canReopen       = (((S("mld_can_reopen_call") & 2) && (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF"))) ||
                                                           ((S("mld_can_reopen_call") & 4) && mresult.canWrite("WEB_MLDREO")) ||
                                                           ((S("mld_can_reopen_call") & 1) && isVerantwoordelijke))  &&
                                                          !is_wf &&
                                                          S("mld_clear_on_close") == 0; // Er moet tijdens het afmelden niets gewist zijn.
                                break;
                        case 6: // Admin voltooid
                                mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !S("mld_disable_continuation");
                                mresult.canPersChange   = mresult.canWrite("WEB_MLDFOF");
                                mresult.canFixSLA       = false;
                                break;
                    }
                }
                if (!mresult.canChange && userIsBlokbehandelaar) { // Als ik alleen binnen mag komen omdat ik blokbehandelaar ben, dan doe ik dat als BO
                    mresult.canChangeUrole = 'bo';
                }

                // (dure) controle uitschakelbaar door { dontcarelink: true } mee te geven
                // Je mag dus niet linken, tenzij (i) deze check wordt uitgevoerd en (ii) geen resultaat oplevert.
                // Een workflow meldingen mag niet gekoppeld worden. Ook meldingen die al klaar zijn niet.
                if (!params.dontcarelink && (mld_status !=5 && mld_status !=6 && mld_status !=1) && !is_wf_step && (mresult.canFOwrite || mresult.canBOwrite) &&
                    mresult.canChange && !is_planned_action && S("mld_allow_parentmelding")) // misschien canLink als nog geen opdrachten of bestellingen
                {
                    var sql = "SELECT 1 FROM mld_opdr WHERE mld_melding_key = " + pmld_melding_key
                            + (S("mld_allow_parentmelding") & 2 ? " AND mld_statusopdr_key NOT IN (1, 2, 6, 7, 9)" : "")
                            + " UNION ALL SELECT 1 FROM bes_bestelling WHERE mld_melding_key = " + pmld_melding_key
                            + (S("mld_allow_parentmelding") & 2 ? " AND bes_bestelling_status NOT IN (1, 6, 7, 8)" : "")
                            + " UNION ALL SELECT 1 FROM mld_melding m WHERE m.mld_melding_parentkey = " + pmld_melding_key;
                    var oRs = Oracle.Execute(sql);
                    mresult.canLink = (oRs.Eof);
                    oRs.Close();
                }
                return mresult;
            },

        func_enabled_opdracht: // Wat mag ik zoal op deze specifieke opdracht?
            function _func_enabled_opdracht(pmld_opdr_key, params) {
                _DetectMultipleCalls("mld.func_enabled_opdracht", pmld_opdr_key);

                params = params || {};
                var mld_opdr = mld.mld_opdr_info(pmld_opdr_key);
                var tracking_present = mld_opdr.mld_opdr_fiat_user? true : false;
                var refiat = mld_opdr.opdr_status_refiat > 0;
                // Is er tijdens de refiat al door de budgethouder (kostenplaatverantwoordelijke) gefiatteerd.
                var typehas_cost = mld_opdr.typeopdr_kosten == 1;
                var is_planned_action = mld_opdr.act_key > 0;
                // (nog) niet alle velden zitten in mld_opdr
                // Opdracht mag niet meer gecanceld worden indien de opdracht een actuele factuur heeft met de status Ingevoerd(2), Akkoord(6) of Verwerkt(7).
                var msql = "SELECT (SELECT MIN(f.fin_factuur_statuses_key)"
                           + "        FROM fin_factuur f"
                           + "       WHERE o.mld_opdr_key = f.mld_opdr_key"
                           + "         AND f.fin_factuur_verwijder IS NULL"
                           + "         AND f.fin_factuur_statuses_key IN (2,6,7)) noCancel"
                         + "     , (SELECT COUNT(f.fin_factuur_key)"
                           + "        FROM fin_factuur f"
                           + "       WHERE f.mld_opdr_key = o.mld_opdr_key"
                           + "         AND f.fin_factuur_verwijder IS NULL) aantal_facturen"
                         + "  FROM mld_opdr o"
                         + " WHERE o.mld_opdr_key = " + pmld_opdr_key
                var moRs = Oracle.Execute(msql);
                var noCancel = moRs("noCancel").Value > 0; // Er zijn actuele facturen met de status Ingevoerd(2), Akkoord(6) of Verwerkt(7).
                var has_facturen = moRs("aantal_facturen").Value > 0; // De opdracht heeft facturen.
                moRs.Close();

                // tracking_present   KP     KPG    Verantwoordelijke
                // Nee                -      -      Niemand
                // Nee                A      -      A
                // Ja                 A      -      Niemand (de status is dan al gefiateerd of verder)
                // Nee                -      B      B
                // Ja                 -      B      Niemand (de status is dan al gefiateerd of verder)
                // Nee                A      B      A
                // Ja                 A      B      B of Niemand (de status is dan al gefiateerd of verder)
                // Nee                A      A      A
                // Ja                 A      A      Niemand (de status is dan al gefiateerd of verder)
                // isVerantwoordelijke wordt alleen gebruikt als status "Ter fiattering"
                var isVerantwoordelijke = false;
                var isApprovedRead = false;

                if (!tracking_present || (S("mld_opdr_refiat_preference") == 1 && refiat && !mld_opdr.refiat_is_approvedby_kp))
                { // Geen tracking of als nieuw fiatteren bij refiat als setting is gezet.
                  // Als nieuw fiatteren. Ik kan nu de functie getFirstApprover gebruiken.
                  var mld_info = mld.mld_melding_info(mld_opdr.mld_key);
                  var approver = mld.getFirstApprover(mld_info, mld_opdr); // vier-ogenprincipe wordt nu ook meegenomen.
                  fiat_key = approver.approver_key;
                  isVerantwoordelijke = (user.isCollega(fiat_key));
                }
                else
                { // tracking aanwezig
                  var fiat_key = prs.getFiatteur(mld_opdr.kp_key, (S("mld_opdr_reapproval_rate") >= 0? -1 : mld_opdr.mld_opdr_fiat_user), mld_opdr.t_cost, mld_opdr.opdr_disc_key, mld_opdr.fiatbedrag);
                  isVerantwoordelijke = (user.isCollega(fiat_key));

                  // Kostenplaats(groep)verantwoordelijken mogen na het approven de bestelopdracht inzien.
                  // Als een collega of de user al gefiatteerd heeft mag hij/zij ook de bestelopdracht inzien.
                  var isApprovedRead = false;
                  var sql = "SELECT fac_tracking_key"
                          + "  FROM fac_tracking tr"
                          + "     , fac_srtnotificatie str"
                          + " WHERE tr.fac_srtnotificatie_key = str.fac_srtnotificatie_key"
                          + "   AND str.fac_srtnotificatie_code = 'ORDFOK'"
                          + "   AND (tr.fac_tracking_refkey = " + pmld_opdr_key
                          + "   AND str.fac_srtnotificatie_xmlnode IN ('opdracht'))"
                          + "   AND tr.prs_perslid_key IN (" + user.collegakeylist() + ")";
                  var oRs = Oracle.Execute(sql);
                  if (!oRs.eof) isApprovedRead = true;
                  oRs.Close();
                }

                var iamFinFiatteur = false; // Is verschillend t.o.v. isVerantwoordelijke omdat niet tegen een profiel van een persson wordt getest.
                                            // isVerantwoordelijke kan false zijn als iamFinFiatteur true is.
                var iamFinGoedkeurder = false;
                if (has_facturen)
                { // Moet ik 1 van deze facturen fiatteren of goedkeuren? Dan mag ik deze opdracht bekijken.
                  var fsql = "SELECT f.fin_factuur_statuses_key"
                           + "     , fin.getfiatteur(f.fin_factuur_key) kpverantwoordelijke"
                           + "     , prs_perslid_key_goedkeur"
                           + "  FROM fin_factuur f"
                           + " WHERE f.mld_opdr_key = " + pmld_opdr_key
                           + "   AND f.fin_factuur_verwijder IS NULL";
                  var foRs = Oracle.Execute(fsql);
                  var authparamsFINBOF = user.checkAutorisation("WEB_FINBOF", true);
                  var hasFINBOFwrite = authparamsFINBOF && authparamsFINBOF.PRSwritelevel < 9 && authparamsFINBOF.ALGwritelevel < 9;
                  while (!foRs.eof)
                  {
                    iamFinFiatteur = iamFinFiatteur || hasFINBOFwrite || ((foRs("fin_factuur_statuses_key").Value == 2) && (user.isCollega(foRs("kpverantwoordelijke").Value)));
                    iamFinGoedkeurder = iamFinGoedkeurder || (foRs("fin_factuur_statuses_key").Value == 5) && (user.isCollega(foRs("prs_perslid_key_goedkeur").Value));
                    foRs.MoveNext();
                  }
                  foRs.Close();
                }

                var user_func_params = { ins_discipline_key: mld_opdr.opdr_disc_key,
                                         alg_key: mld_opdr.mld_alg_onroerendgoed_keys,
                                         loc_key: mld_opdr.mld_alg_locatie_key,
                                         checkOptimistic: false, // pessimist
                                         isOptional: isVerantwoordelijke ||
                                                     iamFinFiatteur ||
                                                     iamFinGoedkeurder ||
                                                     isApprovedRead ||
                                                     params.checkOptimistic ||
                                                     ("forNotes" in params && params.forNotes)
                                       }

                var mresult = user.func_enabled2("MLD", user_func_params);

                mresult.mld_opdr = mld_opdr; // mag de aanroeper optioneel hergebruiken maar is niet gegarandeerd gevuld
                mresult.mld_info = mld_info;
                // Algemeen niveau
                mresult.haveORDSUPrights = user.checkAutorisation("WEB_ORDSUP", true) != null;
                mresult.haveORDFINrights = user.checkAutorisation("WEB_ORDFIN", true) != null;
                mresult.haveORDOAPrights = mresult.canRead("WEB_ORDOAP");

                // Op button niveau
                // ORDUSE zijn meldrachten: heb ik de (melding en) opdracht aangemaakt?
                mresult.canFEread = mresult.canRead("WEB_ORDUSE") && user.isCollega(mld_opdr.contactpers_key);
                mresult.canFEwrite = mresult.canWrite("WEB_ORDUSE") && user.isCollega(mld_opdr.contactpers_key);
                // can register time with opdrachttype-Uren in (3, 6, 7) web_uuruse or web_uurfof rights
                mresult.canTimeReg = (mld_opdr.typeopdr_uren == 3 ||
                                      mld_opdr.typeopdr_uren == 4 ||
                                      mld_opdr.typeopdr_uren == 5) &&
                                     (user.has("WEB_UURUSE") || // scopeloos dus niet in mresult
                                      user.has("WEB_UURFOF"));

                // Als ik de melder ben of de vervanger van de melder en het type opdracht is zichtbaar voor de fe (mld_typeopdr_zichtbaarfe == 1),
                // dan mag ik de opdracht ook zien/wijzigen met WEB_MLDUSE lees/schrijf rechten.
                if (mld_opdr.typeopdr_zichtbaarfe == 1 && user.isCollega(mld_opdr.melding_user_key))
                {
                    mresult.canFEread  |= mresult.canRead("WEB_MLDUSE");
                    mresult.canFEwrite |= mresult.canWrite("WEB_MLDUSE");
                }

                var lopende_offertes = false;
                var uitvOpdrNaOfferte = false;
                if (mld_opdr.typeopdr_isofferte)
                { // Alleen voor offerte opdrachten uitvoeren
                  // Zijn er nog lopende offertes die nog niet Technisch Voltooid/Afgemeld (6) zijn.
                  // Als er nog lopende offertes zijn dan kan ik nog geen offerte accepteren.
                  var osql = "SELECT COUNT(o.mld_opdr_key) aantal"
                           + "  FROM mld_opdr o"
                           + "     , mld_typeopdr mto"
                           + " WHERE o.mld_typeopdr_key = mto.mld_typeopdr_key"
                           + "   AND mto.mld_typeopdr_isofferte = 1"
                           + "   AND o.mld_melding_key = (SELECT mld_melding_key FROM mld_opdr WHERE mld_opdr_key = " + pmld_opdr_key + ")"
                           + "   AND o.mld_typeopdr_key = (SELECT mld_typeopdr_key FROM mld_opdr WHERE mld_opdr_key = " + pmld_opdr_key + ")"
                           + "   AND o.mld_opdr_key != " + pmld_opdr_key
                           + "   AND o.mld_statusopdr_key IN (3, 4, 5, 8, 10)"
                  var ooRs = Oracle.Execute(osql);
                  lopende_offertes = ooRs("aantal").Value > 0;

                  // Laatste opdracht volgnummer van een melding ophalen. Om te checken of er na de offerteaanvraag nog een uitvoeringsopdracht is gekomen.
                  var osql = "SELECT MAX (mld_opdr_bedrijfopdr_volgnr) lastopdrachtvolgnr"
                           + "  FROM mld_opdr o"
                           + "     , mld_typeopdr mto"
                           + " WHERE o.mld_typeopdr_key = mto.mld_typeopdr_key"
                           + "   AND mto.mld_typeopdr_isofferte = 0"
                           + "   AND o.mld_melding_key = " + mld_opdr.mld_key
                           + " GROUP BY o.mld_melding_key"
                  var ooRs = Oracle.Execute(osql);
                  if (!ooRs.eof)
                  { // Er kan een uitvoeringsopdracht zijn na de offerteaanvraag. Dit m.b.v. de volgnummers checken.
                    var lastopdrachtvolgnr = ooRs("lastopdrachtvolgnr").Value;
                    uitvOpdrNaOfferte = lastopdrachtvolgnr > mld_opdr.mld_opdr_bedrijfopdr_volgnr;
                  }
                  ooRs.Close();
                }

                // -- CONTROLE LEESRECHTEN --
                // Een afmelder (EXTORD of ORDBO2) mag externe opdrachten zien/afmelden onder bepaalde voorwaarden:
                // EXTORD: Hij mag opdrachten zien/afmelden van externe bedrijven waar hij contactpersoon van is,
                //         als hij ALG read/write rechten (WEB_EXTORD) heeft op de plaats van de bijbehorende melding van de opdracht.
                // ORDBO2: Setting mld_typeopdr_afmelden_extern: Afmelder (ORDBO2) mag externe opdrachten (0=Niet zien, 1=Zien, 2=Afmelden)
                //         Als hij een interne (decentraal/intern) uitvoerder is mag hij de externe opdrachten niet zien/afmelden als mld_typeopdr_afmelden_extern==0/(0 of 1).
                //         De voorwaarde en setting geldt niet als de opdracht toegekend is aan een (intern) persoon (P) of (intern) bedrijf (BI). Dan mag hij ALLE interne opdrachten zien.
                mresult.iamContact = user.iamContact();                                                         // Ben ik een contactpersoon?
                mresult.iamBedrijfContact = !mld_opdr.uitv_intern && user.iamContact(mld_opdr.uitvoerende_key); // Ben ik contactpersoon van het externe uitvoerende bedrijf?
                var EXTCanRead = mresult.iamBedrijfContact && mresult.canRead("WEB_EXTORD");                                           // Contactpersoon extern bedrijf (BE) + canRead.
                var BO2CanRead = (mresult.canRead("WEB_ORDBO2") &&
                                  (mld_opdr.typeopdr_afmelden_extern > 0 ||                                                            // Setting mld_typeopdr_afmelden_extern 1=Zien of 2=Afmelden.
                                   mld_opdr.uitv_intern                                                                                // Intern
                                  ));

                mresult.canReadAny = mresult.canRead("WEB_ORDBOF") ||
                                     BO2CanRead || EXTCanRead ||
                                     mresult.canRead("WEB_ORDAFR") ||
                                     mresult.canRead("WEB_ORDFIN") ||
                                     mresult.canRead("WEB_ORDSUP") ||
                                     (mresult.canRead("WEB_MLDORD") && user.isCollega(mld_opdr.uitvoerende_key)) ||
                                     mresult.canFEread ||
                                     isVerantwoordelijke || iamFinFiatteur || iamFinGoedkeurder ||
                                     isApprovedRead;

                if (user_key === mld_opdr.uitvoerende_key
                    || (mld_opdr.uitv_intern ? user.isCollega(mld_opdr.uitvoerende_key)
                                             : user.iamContact(mld_opdr.uitvoerende_key)))
                    mresult.myRole = 4; // Ik ben uitvoerder
                else if (user.isCollega(mld_opdr.contactpers_key))
                    mresult.myRole = 2; // Ik ben FOBO (interne contactpersoon aka behandelaar zelfs)
                else if (user.isCollega(mld_opdr.melding_user_key))
                    mresult.myRole = 1; // Ik ben aanvrager
                else if (mresult.canReadAny)
                    mresult.myRole = 2; // Ik ben FOBO

                mresult.canReadBOF = mresult.canRead("WEB_ORDBOF");
                mresult.canReadORD = mresult.canRead("WEB_MLDORD");
                mresult.canReadBO2 = mresult.canRead("WEB_ORDBO2");

                // Als ik enige leesrechten of schrijfrechten heb (bij schrijfrechten heb ik ook leesrechten) dan mag ik opdracht notities wijzigen/toevoegen.
                mresult.canShowOpdrNote = mresult.canReadAny; // Als ik enige leesrechten heb (ook als fiatteur).
                mresult.canEditOpdrNote = mresult.canShowOpdrNote;

                // Factuur rechten
                var authparamsEXTFIN = user.checkAutorisation("WEB_EXTFIN", true);
                var authparamsFINFOF = user.checkAutorisation("WEB_FINFOF", true);
                var authparamsFINBOF = user.checkAutorisation("WEB_FINBOF", true);
                var authparamsMLDFIN = user.checkAutorisation("WEB_MLDFIN", true);
                // Alleen PRSreadlevel en PRSwritelevel van belang want fac_functie_min_level = 7 (lezen en schrijven organisatie)
                // Alleen FE (als contactpersoon) of FO kan aanmaken.
                mresult.canAddFactuur = typehas_cost && !has_facturen &&
                                        mld_opdr.opdr_status != 1 && mld_opdr.opdr_status != 2 && mld_opdr.opdr_status != 3 && mld_opdr.opdr_status != 10 &&
                                        ((mresult.iamBedrijfContact && authparamsEXTFIN && authparamsEXTFIN.PRSwritelevel < 9) ||
                                         (authparamsFINFOF && authparamsFINFOF.PRSwritelevel < 9)); // Kan rechtstreeks vanuit opdrachten een factuur aanmaken.
                mresult.canListFactuur = typehas_cost && has_facturen &&
                                         ((mresult.iamBedrijfContact && authparamsEXTFIN) ||
                                          authparamsFINFOF ||
                                          authparamsFINBOF ||
                                          user.isBudgethouder() ||
                                          // Heb ik MLDFIN rechten (authparamsMLDFIN) om de financiële (factuur) gegevens te zien die bij een eigen melding of opdracht horen?
                                          // Ik mag de factuur zien als:
                                          // 1) Ik WEB_MLDFIN rechten heb en
                                          // 2) Ik de melder ben van de melding.
                                          (authparamsMLDFIN &&                         // WEB_MLDFIN rechten(1)
                                           (user.isCollega(mld_opdr.melding_user_key)) // Melder ben van de melding(2)
                                          ));
                mresult.canChange = false;       // Wijzig knop tonen
                mresult.canChangeUrole = (typeof urole == "undefined" ? "" : urole);  // (mld_close kent deze niet, en change-t ook niet interactief)
                mresult.canGoedkeur = false;     // Goedkeuren niveau 1
                mresult.canGoedkeur2 = false;    // Goedkeuren niveau 2
                mresult.canGoedkeur3 = false;    // Goedkeuren niveau 3
                mresult.canGoedkeur4 = false;    // Goedkeuren niveau 4
                mresult.canGoedkeur5 = false;    // Goedkeuren niveau 5
                mresult.finalapproval = false;   // Is dit de laatste goedkeur actie.
                mresult.canApprove = false;      // Fiatteren
                mresult.canSetSent = false;      // Registreer de opdracht als zijnde verzonden
                mresult.canSend = false;         // Verstuur de opdracht
                mresult.canAccept = false;       // Accepteren (door uitvoerder)
                mresult.canReject = false;       // Afwijzen
                mresult.canCancel = false;       // Annuleren
                mresult.canClose = false;        // Afmelden
                mresult.canVerwerk = false;      // Verwerken
                mresult.canOnderbreken = false;  // Onderbreken
                mresult.canHervatten = false;    // Hervatten
                mresult.canFinish = false;       // Afronden
                mresult.couldClose = false;      // Kon de opdracht afmelden of heb hem afgemeld (Kan in show mode close kenmerken zien)
                mresult.canCopy = false;         // Kopiëren
                mresult.canAcceptOffer = false;  // Accepteren offerte
                mresult.canRejectOffer = false;  // Afwijzen offerte
                mresult.canSeeARFlex = false;    // Kan accepteren/afwijzen kenmerken zien voor offertes
                mresult.canChangeARFlex = false; // Kan accepteren/afwijzen kenmerken wijzigen voor offertes
                mresult.canViewConfidential = false; // Kan vertrouwelijke gegevens inzien

                // Ter leering ende vermaeck: ..Onderstaande code regel gelijk aan:
                // (mresult.canWrite("WEB_ORDBO2") && afmelden_extern == 2 && mld_opdr.uitv_type == "B") ||
                // (mresult.canWrite("WEB_ORDBO2") && mld_opdr.uitv_type == "P")

                // Op invoerveld niveau
                mresult.canVeldChange = false;      // Invoervelden uitgezonderd opdrachttype, uitvoerende, dienst, kostenplaats, contract, opdrachtdatum, einddatum, uren, materiaal en flexkenmerken: (opdr_status!=6 || authparamsORDFIN)
                mresult.canContractChange = false;  // Contract: canVeldChange maar ook nog wijzigbaar in de opdrachtstatussen Afgemeld(6) en Afgerond(9)
                mresult.canFlexChange = false;      // Flexkenmerken: zie canVeldChange met de toevoeging dat je ook in de status uitgegeven mag aanpassen als je "WEB_MLDBO2" rechten hebt.
                mresult.canUitvChange = false;      // Uitvoerende en dienst: ((opdr_status!=6 || mresult.canWrite("WEB_ORDFIN")) && (mresult.canWrite("WEB_ORDBOF")) && (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")))
                mresult.canDatesChange = false;     // Opdrachtdatum en einddatum: opdr_status!=6
                mresult.canPlanDatesChange = false; // Opdrachtdatum en einddatum: opdr_status!=6
                mresult.canKostChange = false;      // Kostenplaats: !this_opdr.canVeldChange && S("mld_ord_show_kostenplaats") == 1
                mresult.canOpmChange = false;       // Opmerking: (opdr_status!=6 || authparamsORDFIN). Met ORDBO2 rechten mag je dit veld ook aanpassen
                mresult.canUrenMatChange = false;   // Uren en materialen: (opdr_status!=6 || authparamsORDFIN). Met ORDBO2 en MLDORD rechten mag je dit veld ook aanpassen
                mresult.canOpdrTypeChange = false;  // Opdrachttype: canVeldChange maar van offertopdrachten mag je het opdrachttype niet aanpassen (!mld_opdr.typeopdr_isofferte).

                var canWriteORDBOF = mresult.canWrite("WEB_ORDBOF");
                var canReadORDBOF = mresult.canRead("WEB_ORDBOF");
                var canWriteMLDORD = mresult.canWrite("WEB_MLDORD") && user.isCollega(mld_opdr.uitvoerende_key);
                var canWriteORDAFR = mresult.canWrite("WEB_ORDAFR");
                // Een afmelder (EXTORD of ORDBO2) mag externe opdrachten zien/afmelden onder bepaalde voorwaarden:
                // EXTORD: Hij mag opdrachten zien/afmelden van externe bedrijven waar hij contactpersoon van is,
                //         als hij ALG read/write rechten (WEB_EXTORD) heeft op de plaats van de bijbehorende melding van de opdracht.
                // ORDBO2: Setting mld_typeopdr_afmelden_extern: Afmelder (ORDBO2) mag externe opdrachten (0=Niet zien, 1=Zien, 2=Afmelden)
                //         Als hij een interne (decentraal/intern) uitvoerder is mag hij de externe opdrachten niet zien/afmelden als mld_typeopdr_afmelden_extern==0/(0 of 1).
                //         De voorwaarde en setting geldt niet als de opdracht toegekend is aan een (intern) persoon (P) of (intern) bedrijf (BI). Dan mag hij ALLE interne opdrachten zien.
                var canWriteEXTORD = mresult.iamBedrijfContact && mresult.canWrite("WEB_EXTORD");                                       // Contactpersoon extern bedrijf (BE) + canWrite.
                var canWriteORDBO2 = (mresult.canWrite("WEB_ORDBO2") &&
                                   (mld_opdr.typeopdr_afmelden_extern == 2 ||                                                           // Setting mld_typeopdr_afmelden_extern 0=Niet Zien, 1=Zien of 2=Afmelden.
                                    (mld_opdr.uitv_intern)                                                                              // Intern.
                                   ));

                // Typeopdracht setting mld_typeopdr_decentraal:
                // 0=Centraal: Opdrachtgever (ORDBOF)),
                // 1=Beide: Opdrachtgever of Opdrachtnemer (ORDBOF, EXTORD)
                // 2=Decentraal: Opdrachtnemer (EXTORD)).
                var BOFCanClose = mld_opdr.typeopdr_decentraal == 0 || mld_opdr.typeopdr_decentraal == 1; // Centraal(0) of beide(1).
                var EXTCanClose = mld_opdr.typeopdr_decentraal == 1 || mld_opdr.typeopdr_decentraal == 2; // Decentraal(2) of beide(1).

                // Als je een contactpersoon bent van dat bedrijf dan mag je de velden "Uitvoerend", "Contactpersoon" en "Omschrijving" niet wijzigen als de status "Geaccepteerd(8)" is.
                // Alleen de velden "Plandatum" en "Afhandeling" kunnen/mogen door aannemer gewijzigd/ingevuld worden in de status "Geaccepteer(8)" (FCLT#38789).
                var canWriteORDBO2VeldAcc = canWriteORDBO2 && !mresult.iamBedrijfContact;

                mresult.canWriteFlags = S("mld_opdracht_flags") > 0 && (mresult.canWrite("WEB_EXTORD") || mresult.canWrite("WEB_ORDBO2") || mresult.canWrite("WEB_ORDBOF") || mresult.canWrite("WEB_MLDORD"));
                mresult.canWriteORDBOF = canWriteORDBOF;

                // zoiets. ws kunnen die userafhankelijke condities eruit omdat ze al in die andere zijn opgenomen? Of juist niet?
                mresult.canViewConfidential = (user_key == mld_opdr.melding_user_key ||
                                               user_key == mld_opdr.contactpers_key ||
                                               user_key == mld_opdr.contactpersuitv_perslid_key) ||
                                               (mresult.canWrite("WEB_ORDBOF") && BOFCanClose) ||
                                               (canWriteEXTORD && EXTCanClose) ||
                                               canWriteORDBO2 ||
                                               (mresult.canWrite("WEB_MLDORD")); // Confidentioal: canWriteMLDORD zonder "&& user.isCollega(mld_opdr.uitvoerende_key)".

                switch (mld_opdr.opdr_status)
                {
                    case 1: // Afgewezen
                            mresult.canChange          = canWriteORDBOF;
                            mresult.canChangeUrole     = "bo";
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canVeldChange      = canWriteORDBOF;
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canFlexChange      = canWriteORDBOF;
                            mresult.canUitvChange      = canWriteORDBOF;
                            mresult.canDatesChange     = canWriteORDBOF; // Leveranciers kunnen pas de datum aanpassen indien de opdracht is uitgegeven.
                            mresult.canKostChange      = (canWriteORDBOF && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canOpmChange       = canWriteORDBOF;
                            mresult.canUrenMatChange   = canWriteORDBOF;
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            break;
                    case 2: // Niet akkoord
                            mresult.canChange          = canWriteORDBOF;
                            mresult.canChangeUrole     = "bo";
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canVeldChange      = canWriteORDBOF;
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canFlexChange      = canWriteORDBOF;
                            mresult.canUitvChange      = canWriteORDBOF;
                            mresult.canDatesChange     = canWriteORDBOF; // Leveranciers kunnen pas de datum aanpassen indien de opdracht is uitgegeven.
                            mresult.canPlanDatesChange = true;
                            mresult.canKostChange      = (canWriteORDBOF && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canOpmChange       = canWriteORDBOF;
                            mresult.canUrenMatChange   = canWriteORDBOF;
                            mresult.canSeeARFlex       = (mld_opdr.typeopdr_isofferte && mresult.haveORDSUPrights);
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            break;
                    case 3: // Ter fiattering
                            mresult.canChange          = canWriteORDBOF;
                            mresult.canSend            = canWriteORDBOF && !mld_opdr.teverzenden && mld_opdr.verzonden == null && !is_planned_action;
                            mresult.canChangeUrole     = "bo";
                            mresult.canApprove         = (isVerantwoordelijke && !is_planned_action);
                            mresult.canReject          = (isVerantwoordelijke && !is_planned_action);
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canVeldChange      = canWriteORDBOF;
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canFlexChange      = canWriteORDBOF;
                            mresult.canUitvChange      = canWriteORDBOF;
                            mresult.canDatesChange     = canWriteORDBOF; // Leveranciers kunnen pas de datum aanpassen indien de opdracht is uitgegeven.
                            mresult.canPlanDatesChange = true;
                            mresult.canKostChange      = (canWriteORDBOF && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canOpmChange       = canWriteORDBOF;
                            mresult.canUrenMatChange   = canWriteORDBOF;
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            break;
                    case 4: // Gefiatteerd
                            mresult.canChange          = canWriteORDBOF;
                            mresult.canSetSent         = canWriteORDBOF && mld_opdr.uitv_type == "B" && !mld_opdr.teverzenden && !is_planned_action;  // Handmatig versturen (als Putorders dat niet doet)
                            mresult.canSend            = canWriteORDBOF && !mld_opdr.teverzenden && mld_opdr.verzonden == null && !is_planned_action;
                            mresult.canChangeUrole     = "bo";
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canVeldChange      = canWriteORDBOF;
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canFlexChange      = canWriteORDBOF;
                            mresult.canUitvChange      = canWriteORDBOF;
                            mresult.canDatesChange     = canWriteORDBOF; // Leveranciers kunnen pas de datum aanpassen indien de opdracht is uitgegeven.
                            mresult.canPlanDatesChange = true;
                            mresult.canKostChange      = (canWriteORDBOF && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canOpmChange       = canWriteORDBOF;
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            // mresult.canUrenMatChange: Kosten (uren en materiaal) niet wijzigbaar.
                            //                           Status gaat in de meeste gevallen door het script putorders direct door naar Uitgegeven(5).
                            //                           Het is daarnaast ook ongewoon om in deze status net na het fiatteren de kosten aan te passen.
                            //                           Het is daarnaast geen probleem om de kosten velden readonly te maken.
                            break;
                    case 5: // Uitgegeven
                            // Leveranciers kunnen de opdrachten accepteren zodat ze kunnen zien of de opdrachten al in behandeling zijn genomen
                            mresult.canAccept          = (canWriteORDBOF ||
                                                          canWriteEXTORD ||
                                                          canWriteORDBO2 ||
                                                          canWriteMLDORD) &&
                                                         !is_planned_action && mld_opdr.typeopdr_accept == 1;
                            mresult.canSetSent         = (canWriteORDBOF &&  // Handmatig versturen (als Putorders dat niet doet)
                                                          mld_opdr.uitv_type == "B" &&
                                                          mld_opdr.verzonden == null &&
                                                          !mld_opdr.teverzenden &&
                                                          !is_planned_action)
                            mresult.canSend            = canWriteORDBOF && !mld_opdr.teverzenden && mld_opdr.verzonden == null && !is_planned_action;
                            // GEEN break!
                    case 8: // en geaccepteerd
                            mresult.canChange          = (canWriteORDBOF ||
                                                          canWriteEXTORD ||
                                                          canWriteORDBO2 ||
                                                          canWriteMLDORD);
                            if (canWriteORDBOF) mresult.canChangeUrole   = "bo";
                            mresult.canCancel          = (canWriteORDBOF || canWriteEXTORD || canWriteORDBO2 || (mld_opdr.opdr_status == 5 && canWriteMLDORD)) &&
                                                         !is_planned_action &&  /* AAFM#23455 */
                                                         !noCancel;  /* AAZC#28894 */
                            mresult.canCloseRights     = ((canWriteORDBOF && BOFCanClose) ||
                                                          (canWriteEXTORD && EXTCanClose) ||
                                                          canWriteORDBO2 ||
                                                          (canWriteMLDORD && EXTCanClose)) &&
                                                         !is_planned_action;
                            mresult.canOnderbreken     = (mld_opdr.typeopdr_sequential&1) == 1 && mresult.canCloseRights && mld_opdr.opdr_status == 8 && mld_opdr.halted!=1;
                            mresult.canHervatten       = mresult.canCloseRights && mld_opdr.opdr_status == 8 && mld_opdr.halted==1;  /* && (mld_opdr.typeopdr_sequential & 1) == 1 would be logical but halted will do */
                            mresult.canClose           = mresult.canCloseRights &&
                                                         (!mresult.canHervatten || (mresult.canHervatten && (mld_opdr.typeopdr_sequential & 4) == 4));
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canVeldChange      = (canWriteORDBOF || canWriteORDBO2VeldAcc);
                            mresult.canContactChange   = (canWriteORDBOF || canWriteORDBO2VeldAcc || canWriteEXTORD);
                            mresult.canContractChange  = (canWriteORDBOF || canWriteORDBO2VeldAcc);
                            mresult.canFlexChange      = (canWriteORDBOF || (canWriteEXTORD || canWriteORDBO2));
                            mresult.canUitvChange      = canWriteORDBOF;
                            mresult.canDatesChange     = (canWriteORDBOF || (S("mld_endate_ordbo2") == 1 && ((canWriteEXTORD || canWriteORDBO2) || mresult.canWrite("WEB_MLDORD"))));
                            mresult.canPlanDatesChange = true;
                            mresult.canKostChange      = (canWriteORDBOF && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canOpmChange       = (canWriteORDBOF || canWriteEXTORD || canWriteORDBO2 || canWriteMLDORD);
                            mresult.canUrenMatChange   = (canWriteORDBOF ||
                                                          (canWriteEXTORD && (S("mld_opdr_costs_readonly_after_rfc") == 0 ||
                                                           !(mld_opdr.parent_key && mld_opdr.parent_isofferte == 1))) ||
                                                          canWriteORDBO2 ||
                                                          canWriteMLDORD);
                            mresult.canSeeARFlex       = (mld_opdr.typeopdr_isofferte && mresult.haveORDSUPrights);
                            mresult.canChangeARFlex    = (mld_opdr.typeopdr_isofferte && mresult.haveORDSUPrights);
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            break;
                    case 6: // Technisch Voltooid/Afgemeld
                            mresult.canChange          = (mresult.haveORDFINrights || mresult.haveORDSUPrights ||
                                                         ((canWriteEXTORD || canWriteORDBO2) && canWriteORDAFR) ||  /* AANS#22655 */
                                                          (typehas_cost && canWriteORDAFR) ||
                                                          (mld_opdr.typeopdr_isofferte && canReadORDBOF && mresult.haveORDOAPrights));
                            mresult.couldClose         = ((canWriteORDBOF && BOFCanClose) ||
                                                          (canWriteEXTORD && EXTCanClose) ||
                                                          canWriteORDBO2 ||
                                                          canWriteMLDORD);
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canFlexChange      = (mresult.haveORDFINrights || mresult.haveORDSUPrights) ||
                                                         ((canWriteEXTORD || canWriteORDBO2) && canWriteORDAFR && !mld_opdr.typeopdr_isofferte);  /* AANS#22655 */
                            mresult.canKostChange      = (mresult.haveORDFINrights && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canFinish          = (!mld_opdr.typeopdr_isofferte && typehas_cost && canWriteORDAFR && !is_planned_action);
                            mresult.canVerwerk         = S("mld_opdr_archive_by_gui") && canWriteORDAFR && canReadORDBOF;
                            mresult.canAcceptOffer     = (mld_opdr.typeopdr_isofferte && (!lopende_offertes || !mld_opdr.offerteauto) &&
                                                          mresult.haveORDOAPrights && canReadORDBOF &&
                                                          !(uitvOpdrNaOfferte && mld_opdr.offerteauto) && !is_planned_action);
                            mresult.canRejectOffer     = (mld_opdr.typeopdr_isofferte && mresult.haveORDOAPrights &&
                                                          canReadORDBOF && !(uitvOpdrNaOfferte && mld_opdr.offerteauto) &&
                                                          !is_planned_action);
                            mresult.canOpmChange       = (mresult.haveORDSUPrights || mresult.canAcceptOffer || mresult.canRejectOffer) ||
                                                         ((canWriteEXTORD || canWriteORDBO2) && canWriteORDAFR);  /* AANS#22655 */
                            mresult.canUrenMatChange   = (mresult.canFinish || mresult.haveORDFINrights) ||
                                                         ((canWriteEXTORD || canWriteORDBO2) && canWriteORDAFR);  /* AANS#22655 */
                            mresult.canSeeARFlex       = (mld_opdr.typeopdr_isofferte && (mresult.haveORDSUPrights || (canReadORDBOF && mresult.haveORDOAPrights)));
                            mresult.canChangeARFlex    = (mld_opdr.typeopdr_isofferte && (mresult.haveORDSUPrights || (canReadORDBOF && mresult.haveORDOAPrights)));
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            break;
                    case 9: // Kostentechnisch voltooid gemeld (doorgaans door uitvoerende)
                            mresult.canChange          = (mresult.haveORDFINrights || mresult.haveORDSUPrights ||
                                                          (mld_opdr.typeopdr_isofferte && canReadORDBOF && mresult.haveORDOAPrights));
                            mresult.canVerwerk         = S("mld_opdr_archive_by_gui") && canWriteORDAFR && canReadORDBOF;
                            mresult.couldClose         = ((canWriteORDBOF && BOFCanClose) ||
                                                          (canWriteEXTORD && EXTCanClose) ||
                                                          canWriteORDBO2 ||
                                                          canWriteMLDORD);
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canFlexChange      = (mresult.haveORDFINrights || mresult.haveORDSUPrights);
                            mresult.canKostChange      = (mresult.haveORDFINrights && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canUrenMatChange   = (mresult.haveORDFINrights);
                            mresult.canSeeARFlex       = (mld_opdr.typeopdr_isofferte && (mresult.haveORDSUPrights || (canReadORDBOF && mresult.haveORDOAPrights)));
                            mresult.canChangeARFlex    = (mld_opdr.typeopdr_isofferte && (mresult.haveORDSUPrights || (canReadORDBOF && mresult.haveORDOAPrights)));
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            break;
                    case 10: // Nog goedkeur
                            mresult.canChange          = canWriteORDBOF;
                            mresult.canSend            = canWriteORDBOF && !mld_opdr.teverzenden && mld_opdr.verzonden == null && !is_planned_action;
                            mresult.canChangeUrole     = "bo";
                            var isCollegaGoedkeur      = mld.isCollegaGoedkeur(pmld_opdr_key); // Heeft de user WEB_ORDGOX rechten of is hij vervanger van iemand die WEB_ORDGOX rechten heeft.
                            mresult.canGoedkeur        = isCollegaGoedkeur.ordgoe && !is_planned_action &&   // Heb ik de rechten om goed te keuren op dit niveau 1?
                                                         (((S("mld_opdr_approval_all") == 0 && ((mld_opdr.t_cost >= mld_opdr.bestellimiet) ||
                                                                                                (mld_opdr.t_cost >= mld_opdr.typeopdr_gvs && mld_opdr.approved < 0))) ||
                                                           (S("mld_opdr_approval_all") == 1 && mld_opdr.t_cost <= mld_opdr.bestellimiet2)) &&
                                                          ((!refiat && mld_opdr.approved <= mld_opdr.bestellimiet) || (refiat && mld_opdr.t_cost >= mld_opdr.typeopdr_gvs && mld_opdr.approved < 0)));
                            mresult.canGoedkeur2       = isCollegaGoedkeur.ordgo2 && !is_planned_action &&
                                                         // Setting mld_opdr_approval_all is
                                                         // 0: Het approved bedrag is eigen bestellimiet of vorige goedkeur niveau rechten heb ik al (dan direct niveau hoger)
                                                         // 1: Het approved bedrag is kleiner of gelijk aan eigen bestellimiet
                                                         ((S("mld_opdr_approval_all") == 0 && mld_opdr.t_cost >= mld_opdr.bestellimiet2 && (mld_opdr.approved == mld_opdr.bestellimiet2 || mresult.canGoedkeur)) ||
                                                          (S("mld_opdr_approval_all") == 1 && mld_opdr.t_cost <= mld_opdr.bestellimiet3 && ((!refiat && mld_opdr.approved <= mld_opdr.bestellimiet2) || (refiat && mld_opdr.t_cost >= mld_opdr.typeopdr_gvs && mld_opdr.approved < 0))));
                            mresult.canGoedkeur3       = isCollegaGoedkeur.ordgo3 && !is_planned_action &&
                                                         ((S("mld_opdr_approval_all") == 0 && mld_opdr.t_cost >= mld_opdr.bestellimiet3 && (mld_opdr.approved == mld_opdr.bestellimiet3 || mresult.canGoedkeur2)) ||
                                                          (S("mld_opdr_approval_all") == 1 && mld_opdr.t_cost <= mld_opdr.bestellimiet4 && (!refiat && mld_opdr.approved <= mld_opdr.bestellimiet3 || (refiat && mld_opdr.t_cost >= mld_opdr.typeopdr_gvs && mld_opdr.approved < 0))));
                            mresult.canGoedkeur4       = isCollegaGoedkeur.ordgo4 && !is_planned_action &&
                                                         ((S("mld_opdr_approval_all") == 0 && mld_opdr.t_cost >= mld_opdr.bestellimiet4 && (mld_opdr.approved == mld_opdr.bestellimiet4 || mresult.canGoedkeur3)) ||
                                                          (S("mld_opdr_approval_all") == 1 && mld_opdr.t_cost <= mld_opdr.bestellimiet5 && (!refiat && mld_opdr.approved <= mld_opdr.bestellimiet4 || (refiat && mld_opdr.t_cost >= mld_opdr.typeopdr_gvs && mld_opdr.approved < 0))));
                            mresult.canGoedkeur5       = isCollegaGoedkeur.ordgo5 && !is_planned_action &&
                                                         ((S("mld_opdr_approval_all") == 0 && mld_opdr.t_cost >= mld_opdr.bestellimiet5 && (mld_opdr.approved >= mld_opdr.bestellimiet5 || mresult.canGoedkeur4)) ||
                                                          (S("mld_opdr_approval_all") == 1 && mld_opdr.t_cost > mld_opdr.bestellimiet5 && (!refiat && mld_opdr.approved <= mld_opdr.bestellimiet5 || (refiat && mld_opdr.t_cost >= mld_opdr.typeopdr_gvs && mld_opdr.approved < 0)))) &&
                                                         mld_opdr.t_cost > mld_opdr.approved;
                            mresult.canReject          = (mresult.canGoedkeur ||
                                                          mresult.canGoedkeur2 ||
                                                          mresult.canGoedkeur3 ||
                                                          mresult.canGoedkeur4 ||
                                                          mresult.canGoedkeur5);
                            mresult.canCopy            = (canWriteORDBOF && !is_planned_action && !mld_opdr.mld_afgerond);
                            mresult.canContractChange  = canWriteORDBOF;
                            mresult.canVeldChange      = canWriteORDBOF;
                            mresult.canFlexChange      = canWriteORDBOF;
                            mresult.canUitvChange      = canWriteORDBOF;
                            mresult.canDatesChange     = canWriteORDBOF; // Leveranciers kunnen pas de datum aanpassen indien de opdracht is uitgegeven.
                            mresult.canPlanDatesChange = true;
                            mresult.canKostChange      = (canWriteORDBOF && S("mld_ord_show_kostenplaats") == 1);
                            mresult.canOpmChange       = canWriteORDBOF;
                            mresult.canUrenMatChange   = canWriteORDBOF;
                            mresult.canOpdrTypeChange  = (canWriteORDBOF && !mld_opdr.typeopdr_isofferte && !mld_opdr.opdrtypevast);
                            if (mresult.canGoedkeur && (S("mld_opdr_approval_all") == 1 || !mresult.canGoedkeur2)) // Kan ik deze opdracht goedkeuren tot de eerste limiet? Als ik ook al tot de tweede limiet goed kan keuren dan direct maar tot de tweede limiet (volgende if).
                              mresult.finalapproval = (S("mld_opdr_approval_all") == 1 || mld_opdr.t_cost <= mld_opdr.bestellimiet2 || mld_opdr.approved > mld_opdr.bestellimiet2);
                            else if (mresult.canGoedkeur2 && (S("mld_opdr_approval_all") == 1 || mresult.canGoedkeur3)) // Kan ik deze opdracht goedkeuren tot de tweede limiet? Als ik ook boven de derde limiet goed kan keuren dan direct maar tot de derde limiet (volgende if).
                              mresult.finalapproval = (S("mld_opdr_approval_all") == 1 || mld_opdr.t_cost <= mld_opdr.bestellimiet3 || mld_opdr.approved > mld_opdr.bestellimiet3);
                            else if (mresult.canGoedkeur3 && (S("mld_opdr_approval_all") == 1 || !mresult.canGoedkeur4)) // Kan ik deze opdracht goedkeuren tot de derde limiet? Als ik ook boven de vierde limiet goed kan keuren dan direct maar tot de vierde limiet (volgende if).
                              mresult.finalapproval = (S("mld_opdr_approval_all") == 1 || mld_opdr.t_cost <= mld_opdr.bestellimiet4 || mld_opdr.approved > mld_opdr.bestellimiet4);
                            else if (mresult.canGoedkeur4 && (S("mld_opdr_approval_all") == 1 || !mresult.canGoedkeur5)) // Kan ik deze opdracht goedkeuren tot de vierde limiet? Als ik ook boven de vijfde limiet goed kan keuren dan direct maar tot de vijfde limiet (volgende if).
                              mresult.finalapproval = (S("mld_opdr_approval_all") == 1 || mld_opdr.t_cost <= mld_opdr.bestellimiet5 || mld_opdr.approved > mld_opdr.bestellimiet5);
                            else if (mresult.canGoedkeur5) // Kan ik dit contract volledig fiatteren en acfief maken?
                              mresult.finalapproval = true;
                            break;
                    case 7: // Verwerkt
                            mresult.couldClose         = (canWriteORDBOF || canWriteEXTORD || canWriteORDBO2);
                            mresult.canSeeARFlex       = (mld_opdr.typeopdr_isofferte && (mresult.haveORDSUPrights || (canReadORDBOF && mresult.haveORDOAPrights)));
                            break;
               }

               if (mresult.iamBedrijfContact && mresult.canUrenMatChange)
               {
                 if (mld_opdr.t_cost > S("mld_max_kosten_extern"))
                     mresult.canUrenMatChange = false;
               }

               return mresult;
           },

        // Geeft het PGB overschrijdingsbedrag van de PGB-limiet terug
        get_pgb_exceed_amount: function(opdrachtbedrag, prs_key, opdr_disc_key, opdr_key)
        {
         var amount = opdrachtbedrag; // Indien geen pgblimiet dan gehele opdracht bedrag

         // Opvragen PGB limiet
         var pgblimiet = budget.get_pgblimiet(prs_key, opdr_disc_key);

         if (pgblimiet != null)
         { // Verschil PGB limiet met het besteed budget van persoon en desbetreffende discipline voor dit jaar inclusief opdrachtbedrag
           amount = (budget.besteed_budget_pgb(prs_key, opdr_disc_key, {opdr_key: opdr_key}) + opdrachtbedrag - pgblimiet);
         }
         return amount;
        },

        // Geeft het AGB overschrijdingsbedrag van de AGB-limiet terug
        get_agb_exceed_amount: function(opdrachtbedrag, kp_key, opdr_disc_key, opdr_key)
        {
         var amount = opdrachtbedrag; // Indien geen agblimiet dan gehele bestel bedrag

         // Opvragen AGB limiet
         var agblimiet = budget.get_agblimiet(kp_key, opdr_disc_key);

         if (agblimiet != null)
         { // Verschil AGB limiet met het besteed budget van persoon en desbetreffende discipline voor dit jaar inclusief opdrachtbedrag
           amount = (budget.besteed_budget_agb(kp_key, {opdr_key: opdr_key}) + opdrachtbedrag - agblimiet);
         }
         return amount;
        },

        // Persoonlijk Gebonden Budget (PGB) en/of Afdeling Gebonden Budget (AGB) controle
        // mld_opdr.disc_params_pgb: 0 = Geen van beiden
        //                           1 = Alleen pgb
        //                           2 = Alleen agb
        //                           3 = Beiden, pgb en agb

        // Geeft true als het opdracht bedrag boven de PGB-limiet van prs_key uit komt
        // en dus (eventueel) goedkeuring vereist zal zijn.
        exceeds_pgb: function(opdrachtbedrag, prs_key, opdr_disc_key)
        {
          if (mld_opdr.disc_params_pgb == 1 || mld_opdr.disc_params_pgb == 3)
            return budget.exceeds_profiel(opdrachtbedrag + budget.besteed_budget_pgb(prs_key, opdr_disc_key), prs_key, opdr_disc_key);
          else // Geen pgb. Dan kan je ook niet boven de pgb zitten
            return false;
        },

        // Geeft true als het opdracht bedrag boven de AGB-limiet van prs_key uit komt
        // en dus (eventueel) goedkeuring vereist zal zijn.
        // Negeer evt bestaand opdrachtbedrag van opdr_key (indien > -1)
        exceeds_agb: function(opdrachtbedrag, kp_key, opdr_disc_key, opdr_key)
        {
          if (mld_opdr.disc_params_pgb == 2 || mld_opdr.disc_params_pgb == 3)
            return budget.exceeds_limietagb(opdrachtbedrag + budget.besteed_budget_agb(kp_key, {opdr_key: opdr_key}), kp_key, opdr_disc_key);
          else // Geen agb. Dan kan je ook niet boven de agb zitten
            return false;
        },

        // maak een nieuwe melding aan. Resultaat mld_key
        // params = { fields: (array als voor save2db)
        //            alg_onroerendgoed_keys  optioneel
        //            locatie_key             optioneel
        //            kostenplaats_key        optioneel
        //            mld_adres_key           optioneel
        //            perslid_key             optioneel (anders user_key)
        //            prio                    optioneel, default 3
        //          }
        // Context: - meldracht
        //          - Logboek mode
        //          - (API/api_mldsoap.asp zou dit ook moeten gebruiken?)
        insertmelding:
             function(stdm_key, params)
             {
                 // Dit is nog ongeacht de melding
                 // Eerst controleren of ik MLDFOF rechten heb. Is dat niet het geval
                 // dan heb ik in ieder geval MLDUSE rechten nodig voor het aanmaken van een melding.
                 // Dit is nog ongeacht de melding
                 if (!user.checkAutorisation("WEB_MLDFOF", true) && !user.checkAutorisation("WEB_ORDUSE", true))
                   user.checkAutorisation("WEB_MLDUSE");

                 var voor_key = params.perslid_key || user_key;
                 var voor_user = user;
                 if (params.perslid_key != user_key)
                     voor_user = new Perslid(voor_key);

                 var fields = params.fields || [];
                 var stdm_info = mld.mld_stdmeldinginfo(stdm_key);

                 var locatiekey = params.locatiekey||-1;
                 var prio = stdm_info.prioriteiten[params.prio||3]; // normaal

                 if (stdm_info.ins_srtdiscipline_alg)
                 {
                     var alg_onroerendgoed_keys = params.alg_onroerendgoed_keys||-1;
                     if (alg_onroerendgoed_keys==-1)
                     {
                         if (stdm_info.alg_level == 2)
                             alg_onroerendgoed_keys = voor_user.alg_locatie_key();
                         else
                             alg_onroerendgoed_keys = voor_user.alg_ruimte_key();
                     }
                     fields.push({ dbs: "mld_alg_onroerendgoed_keys", typ: "key", val: alg_onroerendgoed_keys });
                 }

                 if (stdm_info.ins_srtdiscipline_bes)
                 {
                     var mld_adres_key = params.mld_adres_key||-1;
                     if (mld_adres_key==-1)
                     {
                         var prs_info = new prs.prs_perslid(voor_key, { withAflever: true });
                         mld_adres_key = prs_info.mld_adres_key;
                     }
                     fields.push( { dbs: "mld_adres_key",          typ: "key",   val: mld_adres_key } );
                     if (locatiekey==-1 && mld_adres_key>0)
                     {
                         var oRs = Oracle.Execute('SELECT alg_locatie_key FROM mld_adres WHERE mld_adres_key = ' + mld_adres_key);
                         if (!oRs.eof && oRs(0).Value)
                         {
                             locatiekey = oRs(0).Value;
                         }
                         oRs.Close();
                     }
                 }
                 // Dit is de datum volgens de SLA:
                 var enddate_std = mld.geteinddatum(new Date(), stdm_key, prio.key, -1);

                 fields = fields.concat(
                               [ { dbs: "mld_melding_key",                     typ: "key",      seq: "mld_s_mld_melding_key" },
                                 { dbs: "mld_meldbron_key",                    typ: "key",      val: S("mld_meldbron_key") },
                                 { dbs: "mld_melding_module",                  typ: "varchar",  val: "MLD" },
                                 { dbs: "mld_melding_spoed",                   typ: "key",      val: params.prio||3 }, // default normaal
                                 { dbs: "mld_melding_impact",                  typ: "key",      val: params.impact,   savewhen: ("impact" in params)},
                                 { dbs: "mld_melding_urgentie",                typ: "key",      val: params.urgentie, savewhen: ("urgentie" in params)},
                                 { dbs: "prs_perslid_key",                     typ: "key",      val: voor_key },
                                 { dbs: "mld_stdmelding_key",                  typ: "key",      val: stdm_key},
                                 { dbs: "mld_melding_datum",                   typ: "datetime", val: new Date() },
                                 { dbs: "mld_melding_einddatum",               typ: "datetime", val: enddate_std },
                                 { dbs: "mld_melding_t_uitvoertijd.tijdsduur",
                                   obj: "MLD_T_UITVOERTIJD",                   typ: "float",    val: prio.uitvoertijd },
                                 { dbs: "mld_melding_t_uitvoertijd.eenheid",
                                   obj: "MLD_T_UITVOERTIJD",                   typ: "varchar",  val: prio.eenheid },
                                 { dbs: "mld_alg_locatie_key",                 typ: "key",      val: locatiekey }
                               ]);

                 if (stdm_info.kpnverplicht || params.kostenplaats_key)
                 {
                     var kostenplaats_key = params.kostenplaats_key || user.prs_kostenplaats_key() || -1;
                     if (!user.checkAutorisation("WEB_MLDFOF", true))
                       // Ik maak zelf als FE met WEB_MLDUSE of ORDUSE rechten een nieuwe melding aan.
                       var ins_srtdiscipline_kk = (stdm_info.ins_srtdiscipline_kostenklant & 1) == 1;
                     else
                       // Ik maak als FO met MLDFOF rechten een nieuwe melding aan.
                       var ins_srtdiscipline_kk = (stdm_info.ins_srtdiscipline_kostenklant & 4) == 4;
                     fields.push({ dbs: "prs_kostenplaats_key",    typ: "key",      val: kostenplaats_key },
                                 { dbs: "mld_kosten_klant",        typ: "check",    val: ins_srtdiscipline_kk? 1 : 0 }
                                 );
                 }

                 var mldIns = buildInsert("mld_melding", fields, { noValidateToken: true });
                 var mld_key = mldIns.sequences["mld_melding_key"];

                 Oracle.Execute(mldIns.sql);

                 mld.setmeldingstatus(mld_key, 2); // Zorgt ook voor tracking & daarmee notificatie

                 return mld_key;
             },

        // levert een te tonen berichtstring op
        sendNeedApprovalNotification: function (opdr_key, approver_key)
        {
            var lsender;
            if (approver_key == null || approver_key == -1)
              return false;

            // These notifications are now sent on behalf of the system, what might be the local FM organisation
            var sql = "SELECT COALESCE (l1.alg_locatie_email, l2.alg_locatie_email)"
                    + "  FROM mld_opdr o, mld_melding m, mld_adres ma, alg_locatie l1, alg_locatie l2"
                    + " WHERE m.mld_adres_key = ma.mld_adres_key(+)"
                    + "   AND ma.alg_locatie_key = l1.alg_locatie_key(+)"
                    + "   AND m.mld_alg_locatie_key = l2.alg_locatie_key(+)"
                    + "   AND m.mld_melding_key = o.mld_melding_key"
                    + "   AND o.mld_opdr_key = " + opdr_key;
            var oRs = Oracle.Execute(sql);
            if (!oRs.eof) {
                lsender = oRs(0).Value;
            } else {
                lsender = null;
            }
            oRs.Close();

            // notify approver by message & mail as configured in fac_srtnotificatie with MLDAP1
            // putnotificationsrtprio doet geen vertaling van ##OPDR_KEY## (notify_tracking zou dat wel doen)
            // dus doen we het hier zelf maar.
            var omssql = "SELECT fac_srtnotificatie_oms"
                       + "  FROM fac_srtnotificatie"
                       + " WHERE fac_srtnotificatie_code = 'MLDAP1'";
            var oRs = Oracle.Execute(omssql);
            var oms = L(oRs("fac_srtnotificatie_oms").Value, { autolcl: true });
            oRs.Close();

            Oracle.Execute("BEGIN fac.putnotificationsrtprio(NULL"
                           + ", " + approver_key
                           + ", 'MLDAP1'"
                           + ", " + opdr_key
                           + ", mld.opdrsprintf(" + safe.quoted_sql(oms) + ", " + opdr_key + ")"
                           + ",  NULL, NULL, NULL, NULL, 2"
                           + ", " + (lsender ?  safe.quoted_sql(lsender) : "NULL") + "); END;");

            var sql = "SELECT prs_perslid_naam_full FROM prs_v_perslid_fullnames_all WHERE prs_perslid_key = " + approver_key;
            var oRs = Oracle.Execute(sql);
            var prsname = oRs("prs_perslid_naam_full").Value;
            oRs.Close();
            return L("lcl_mld_opdr_regApprov") + prsname;
        },

        lock: function (mld_key)
        {
          var sql = "UPDATE mld_melding"
                  + "   SET mld_melding_locked_user_key = " + user_key
                  + "     , mld_melding_locked_date = SYSDATE"
                  + " WHERE mld_melding_key = " + mld_key;
          Oracle.Execute(sql);
        },

        unlock: function (mld_key)
        {
          var sql = "UPDATE mld_melding"
                  + "   SET mld_melding_locked_user_key = NULL"
                  + "     , mld_melding_locked_date = SYSDATE"
                  + " WHERE mld_melding_key = " + mld_key
                  + "   AND mld_melding_locked_user_key = " + user_key; // Alleen als we zelf het lock hadden
          Oracle.Execute(sql);
        },

        _getLayout: function() {
          if ("LAYOUT" in mld) {
            return mld.LAYOUT;
          }
          mld.BLOCKS = [  // De id's van alle MLD-BLOCK's in de default volgorde
            "mldCaller",
            "mldMelding",
            "mldAlg",
            "mldBes",
            "mldInfo",
            "mldProcessing",
            "mldFaq",
            "mldIns",
            "mldFlex",
            "mldOmschrijving",
            "mldAfhandel"
          ];
          mld.BLOCKLETTER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".substring(0, mld.BLOCKS.length); // 1 Letter voor elk block
          var layout = S("mld_layout").slice(0, mld.BLOCKS.length); // Een Array met letters die de (volgorde van de) blokken representeren

          for (var iter = 0; iter < layout.length; iter++) {
            layout[iter] = sharedTrim(layout[iter]).toUpperCase();  // Trim & uppercase
          }

          for (var iter = 0; iter < mld.BLOCKS.length; iter++) {    // Als bij de setting niet alle blokken (letters) ingevuld zijn, vullen we de layout-array hier aan in de default volgorde
            if (!inArray(mld.BLOCKLETTER.charAt(iter), layout)) {
              layout.push(mld.BLOCKLETTER.charAt(iter));
            }
          }
          return layout;
        },

        _initBlockUtils: function() {
          blockPrinted = {};  // Houdt bij welke blokken geweest zijn
          mld.LAYOUT = mld._getLayout();

          mld.nextBlock = function () {
            var _objectSize = function (obj) {
              var size = 0
              for (var key in obj) {
                if (obj.hasOwnProperty(key)) size++;
              }
              return size;
            };
            var nextBlock = mld.BLOCKS[mld.BLOCKLETTER.indexOf(mld.LAYOUT[_objectSize(blockPrinted) + 1])];
            if (nextBlock && !blockPrinted[nextBlock]) { // Het kan alleen het volgende block zijn als het nog niet geprint is
              return nextBlock;
            }
            return null;
          }
        },

        _destroyBlockUtils: function () {
          blockPrinted = null;
          delete mld._nextBlock;
          delete mld.LAYOUT;
          delete mld.BLOCKS;
          delete mld.BLOCKLETTER;
        },

        writeBlocks: function() // Veronderstelt de aanwezigheid van een writeBlock-functie met BLOCK-definities
        {
          mld._initBlockUtils();

          /* Print nu de blokken in de DOM in de ingesteld volgorde */
          for (var iter = 0; iter < mld.LAYOUT.length; iter++) {
            var blockName = mld.BLOCKS[mld.BLOCKLETTER.indexOf(mld.LAYOUT[iter])];  // Vind het id van het block op index [iter] in S(mld_layout)
            blockPrinted[blockName] = writeBlock(blockName);                        // Print dat block, en sla op in blockPrinted of dat gelukt is
          }

          mld._destroyBlockUtils();
        },

        useAlgScope: function (id) {
          var block;
          var result = null;
          var plaatsBlock = "C";  // Letter die correspondeert met het 'Plaatsgegevens'-block
          switch (id) {
            case "A": // [A]anvrager
              block = "A";  // Letter die correspondeert met het 'Aanvrager'-block
              break;
            case "D": // [D]iscipline
            case "S": // [S]tandaarmelding
              block = "B";  // Letter die correspondeert met het 'Categorie'-block
              break;
            default:
              result = true; // Default wel (waar gevraagd)
          }
          if (result == null && typeof blockPrinted !== "undefined" && blockPrinted !== null) { // Ik ben de blokken nu aan het printen
            result = blockPrinted["mldAlg"]; // De plaats-gegevens worden alleen als extra scoping gebruikt als het block al bestaat
          } else if (typeof blockPrinted !== "undefined" && blockPrinted !== null) {

          }
          if (result == null) {
            mld.LAYOUT = mld._getLayout();
            for (var iterator = 0; iterator < mld.LAYOUT.length; iterator++) {
              if (mld.LAYOUT[iterator] == block || mld.LAYOUT[iterator] == plaatsBlock) {
                result = mld.LAYOUT[iterator] == plaatsBlock; // 'Plaatsgegevens'-block is als eerste gevonden
                break;
              }
            }
          }
          return result;
        },

        taggable_select_html: function _taggable_select_html(urole, params) {
            if (!(params.stdm_taggable & 1) || urole == "fe" && !(params.stdm_taggable & 2)) {
              return '<tr class="tr_tag"></tr>';
            }
            // had eigenlijk de presentatie met lcl_melding_tag_string configureerbaar willen hebben
            var sql_tag = "SELECT mld_melding_tag_key"
                        + "     , mld_melding_tag_naam || DECODE(mld_melding_tag_datum_tot,NULL,'',' ('||TO_CHAR(mld_melding_tag_datum_tot, 'DD-MM-YYYY')||')') omschrijving"
                        + "     , mld_melding_tag_naam"
                        + "     , " + lcl.xsqla('mld_melding_tag_oms', 'mld_melding_tag_key')
                        + "     , mld_melding_tag_datum_tot"
                        + "  FROM mld_melding_tag"
                        + " WHERE (mld_melding_tag_datum_van IS NULL OR mld_melding_tag_datum_van <= TRUNC(SYSDATE))"  // denk ik
                        + "   AND mld_melding_tag_verwijder IS NULL"
                        + "   AND mld_melding_tag_actief = 1"
                        + "   AND ins_srtdiscipline_key = " + params.srtdisc_key
                        +  (params.stdmeldinggroep_key
                          ? "   AND (    mld_stdmeldinggroep_key = " + params.stdmeldinggroep_key
                          + "         OR mld_stdmeldinggroep_key IS NULL)" // Deze mag natuurlijk ook
                          : "") // Dan geldt alleen de vakgroeptype-scope
                        + " ORDER BY mld_melding_tag_datum_tot DESC, mld_melding_tag_naam";
            var result =
              FCLTselector_HTML("tag_key",
                                sql_tag,
                                { initKey: params.tag_key || -1
                                , initEmpty: true
                                , label: L("mld_melding_tag_naam")
                                , titleCol: "mld_melding_tag_oms"
                                , trclass: "tr_tag"
                                //, onChange: "onChangeTag()"  // ik denk de einddatum aanpassen aan mld_melding_tag_datum_tot
                                });
            return result;
        },

        generate_relobject_editblock: function (mld_key, params, mld_melding, stdm_info)
        {
          // Noot: mld_key zit ook in mld_melding.mld_key
          // Als een object verplicht is bij afmelden en niet is ingevuld, dan moet ik een object kunnen invullen als ik ook afmeld rechten heb.
          var showSelect = params.hasMultiObj;
          var canChangeObj = (params.ins_key < 0 && ((mld_key <= 0 || params.canPlaatsChange) || (params.module == "O" && params.canChange))) || params.thereAreObjects || (params.canClose && stdm_info.srtinst_verplichtstatus == 5);
          if (canChangeObj)
          {
            var rwparams = { datatype: "button",
                             html: "title='" + L("lcl_mld_objects_select")
                                 + "' onclick='" + params.onclickobj + "'"
                                 + (params.disableobjects || !(params.aantalobj > 0) ? " disabled" : "")
                                 + " isObject=1",
                             endicon: "fa-hand-point-left",
                             trclass: "tr_r_objs"
                           }
            RWFIELDTR("r_objs_button", "button", L("lcl_mld_objects"), L("lcl_mld_objects") + " (" + params.aantalobj + ")", rwparams);
          }
          else // !canChangeObj
          {
            showSelect = true;
          }
%>
          <tr class="tr_r_objs">
            <td>
            </td>
            <td>
<%
              var element_description;
              if (S("ins_element_description") == "")
              {
                var plaatsaanduiding = (S("prs_wpprefix_objectid") == 1
                                       ? " CASE"
                                         + " WHEN o.prs_werkplek_omschrijving IS NOT NULL"
                                         + " THEN ' ' || o.prs_werkplek_omschrijving"
                                         + " ELSE ''"
                                         + " END"
                                       : "''");
                element_description = "d.ins_deel_omschrijving || " + plaatsaanduiding
                                    + " || ' (' || " + lcl.xsql("s.ins_srtdeel_omschrijving", "s.ins_srtdeel_key")
                                    + " || ') ' || d.ins_deel_opmerking ";
              }
              else
              {
                element_description = S("ins_element_description");
              }

              if (mld_key > 0)
              {
                var sql = "SELECT DISTINCT d.ins_deel_key"
                        + "     , " + element_description + " deel"
                        + "     , 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 uitvoertijd" // Uitvoertijd is in dagn.
                        + "  FROM ins_deel d"
                        + "     , ins_srtdeel s"
                        + "     , mld_melding_object m"
                        + "     , ins_v_alg_overzicht o"
                        + "     , ins_srtgroep g"
                        + "     , ins_tab_discipline dis"
                        + " WHERE m.mld_melding_key = " + mld_key
                        + "   AND d.ins_deel_key = m.ins_deel_key"
                        + "   AND d.ins_deel_verwijder IS NULL"
                        + "   AND d.ins_srtdeel_key = s.ins_srtdeel_key"
                        + "   AND s.ins_srtgroep_key = g.ins_srtgroep_key"
                        + "   AND g.ins_discipline_key = dis.ins_discipline_key"
                        + "   AND d.ins_alg_ruimte_key = o.alg_onroerendgoed_keys(+)"
                        + "   AND d.ins_alg_ruimte_type = o.alg_onroerendgoed_type(+)"
                        + "   AND d.ins_alg_locatie_key = o.alg_locatie_key(+)"
                        + " ORDER BY deel";
              }
              else // mogelijk voorgeselecteerd object
              {
                var sql = "SELECT d.ins_deel_key"
                        + "     , " + element_description + " deel"
                        + "     , 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 uitvoertijd" // Uitvoertijd is in dagn.
                        + "  FROM ins_deel d"
                        + "     , ins_srtdeel s"
                        + "     , ins_v_alg_overzicht o"
                        + "     , ins_srtgroep g"
                        + "     , ins_tab_discipline dis"
                        + " WHERE d.ins_deel_key = " + params.ins_key
                        + "   AND d.ins_deel_verwijder IS NULL"
                        + "   AND d.ins_srtdeel_key = s.ins_srtdeel_key"
                        + "   AND s.ins_srtgroep_key = g.ins_srtgroep_key"
                        + "   AND g.ins_discipline_key = dis.ins_discipline_key"
                        + "   AND (d.ins_deel_vervaldatum IS NULL OR d.ins_deel_vervaldatum > TRUNC(SYSDATE))"
                        + "   AND d.ins_alg_ruimte_key = o.alg_onroerendgoed_keys(+)"
                        + "   AND d.ins_alg_ruimte_type = o.alg_onroerendgoed_type(+)"
                        + "   AND d.ins_alg_locatie_key = o.alg_locatie_key(+)"
                        + " ORDER BY deel";
              }
              // showObjDetail alleen in show-mode
              FCLTselector("r_objs",
                           sql,
                           { label: "", //L("lcl_mld_objects"),
                             multi: true,
                             size: 1,
                             required: params.srtinst_verplichtstatus == 2,
                             extraclass: (showSelect ? "" : "hidden"),
                             extraParamValue: "uitvoertijd" // uitvoertijd is hier in uren
                           });
 %>           <input type='hidden' name='has_r_objs' value='1'>
 <%
              var urlAdd;
              var fieldArray = {"L": "locatiekey",        "G": "gebouwkey",         "V": "verdiepingkey",     "R": "ruimtekey"};
              var initArray  = {"L": mld_melding.loc_key, "G": mld_melding.bld_key, "V": mld_melding.flr_key, "R": mld_melding.room_key};
              if (params.module == "M") // Melding
              {
                urlAdd = [{ urlParam: "stdm_key",   field: "stdm",                                   init: mld_melding.stdm_key}
                         ,{ urlParam: "alg_niveau", field: "suggest_alg_niveau",                     init: stdm_info.alg_onrgoed_niveau }
                         ,{ urlParam: "prs_key",    field: (typeof personForExist == "boolean" && personForExist ? "personFor" : "person")
                                                  , init:  (typeof personForExist == "boolean" && personForExist ? mld_melding.perslid_key_voor : mld_melding.melder_key)}
                         ,{ urlParam: "alg_key",    field: fieldArray[stdm_info.alg_onrgoed_niveau], init: initArray[stdm_info.alg_onrgoed_niveau]}
                         ];
              }
              else if (params.module == "O") // Opdracht
              {
                urlAdd = [{ urlParam: "stdm_key",   val: mld_melding.stdm_key,                       init: mld_melding.stdm_key}
                         ,{ urlParam: "alg_niveau", val: stdm_info.alg_onrgoed_niveau,               init: stdm_info.alg_onrgoed_niveau }
                         ,{ urlParam: "prs_key",    field: "sgCaller",                               init: mld_melding.melder_key}
                         ,{ urlParam: "alg_key",    field: fieldArray[stdm_info.alg_onrgoed_niveau], init: initArray[stdm_info.alg_onrgoed_niveau]}
                         ];
              }

              FCLTobjectselector("r_objs",
                                 "sgObject",
                                 { label: "",
                                   module: "MLD",
                                   objectKey: params.ins_key > 0 ? params.ins_key : params.init_obj_key,
                                   urlAdd: urlAdd,
                                   prerequisite: (params.module == "M" ? "checkPrerequisite" : ""),
                                   onChange: (params.module == "M" ? "onChangeObject" : ""),
                                   required: params.srtinst_verplichtstatus == 2,
                                   disabled: params.disableobjects,
                                   hidden: showSelect,
                                   extracode: "UITV",
                                   extraParamValue: "uitvoertijd",
                                   autfunction: "WEB_INSUSE"
                                 });
 %>
            </td>
          </tr>
          <script>
            $(function ()
            {
              var objCount = $("#r_objs").get(0).options.length;
              if ($("#r_objs").attr("size") != Math.max(objCount, 1))
              {
                  $("#r_objs").attr("size", Math.max(objCount, 1));
                  FcltMgr.resized();
              }
            });
          </script>
 <%
 },

        generate_relobject_block: function (mld_key)
        {
          var element_description;
          if (S("ins_element_description") == "")
          {
            var parentdeel = "CASE WHEN d.ins_deel_parent_key IS NOT NULL"
                           + "     THEN (SELECT p.ins_deel_omschrijving"
                           + "             FROM ins_deel p"
                           + "            WHERE p.ins_deel_key = d.ins_deel_parent_key"
                           + "          ) ||' / '"
                           + "     ELSE ''"
                           + "END ";
            var plaatsaanduiding = (S("prs_wpprefix_objectid") == 1
                                   ? " CASE"
                                     + " WHEN o.prs_werkplek_omschrijving IS NOT NULL"
                                     + " THEN ' ' || o.prs_werkplek_omschrijving"
                                     + " ELSE ''"
                                     + " END"
                                   : "''");
            element_description = parentdeel + " || d.ins_deel_omschrijving || " + plaatsaanduiding
                                + " || ' (' || " + lcl.xsql('s.ins_srtdeel_omschrijving', 's.ins_srtdeel_key') + " || ')' ";
          }
          else
          {
            element_description = S("ins_element_description");
          }
          var sql = "SELECT DISTINCT d.ins_deel_key"
                  + "     , " + element_description + " deel"
                  + "     , d.ins_deel_flag"
                  + "  FROM ins_deel d"
                  + "     , ins_srtdeel s"
                  + "     , mld_melding_object m"
                  + "     , ins_v_alg_overzicht o"
                  + "     , ins_srtgroep g"
                  + "     , ins_tab_discipline dis"
                  + " WHERE m.mld_melding_key = " + mld_key
                  + "   AND d.ins_deel_key = m.ins_deel_key"
                  + "   AND d.ins_srtdeel_key = s.ins_srtdeel_key"
                  + "   AND s.ins_srtgroep_key = g.ins_srtgroep_key"
                  + "   AND g.ins_discipline_key = dis.ins_discipline_key"
                  + " AND d.ins_alg_ruimte_key = o.alg_onroerendgoed_keys(+)"
                  + " AND d.ins_alg_ruimte_type = o.alg_onroerendgoed_type(+)"
                  + " AND d.ins_alg_locatie_key = o.alg_locatie_key(+)"
                  + " ORDER BY 2";
          var oRs = Oracle.Execute(sql);
          if (!oRs.Eof)
          {
            var clikker = "";
            if (user.checkAutorisation("WEB_INSMAN", true))
              clikker = "onclick='showObjListTab({0})'".format(mld_key);
%>
            <tr><td class="label"><span class="<%=clikker?"details":""%>" <%=clikker%>><%=L("lcl_mld_objects")%></span></td><td>
<%
            while( !oRs.eof )
            {
              var flagkey = oRs("ins_deel_flag").Value || 0;
              var flagtxt = "";
              if (S("ins_deel_flags") > 1)
              {
                flagtxt = "<span class='insflag" + flagkey + " inss' title='" + safe.htmlattr(L("lcl_ins_flag" + flagkey)) + "'>"
                        + I("fa-fclt-flag" + (flagkey == 0 ? "0" : ""))
                        + "</span>";
              }
%>
              <%=flagtxt%>
              <span id="r_objs" class="fld details" onclick='showObjDetail(<%=oRs("ins_deel_key").Value%>, "bo")'><%=safe.htmlattr(oRs("deel").Value)%></span>
<%
              oRs.MoveNext();
              if (!oRs.eof)
                Response.Write("<br>");
            }
            Response.Write("</td>");
            Response.Write("</tr>");
          }
          oRs.close();
        },

        dienst_controle: function (stdm_key, locatiekey, gebouwkey, ruimtekey, obj_key_arr, prs_key_voor, check_autoorder)
        {
            var sql;
            sql = "SELECT ms.mld_stdmelding_vereisdienst"
                + "     , ms.prs_dienst_key"
                + "     , ms.mld_stdmelding_prseigen"
                + "     , " + lcl.xsqla("pd.prs_dienst_omschrijving", "pd.prs_dienst_key")
                + "     , isd.ins_srtdiscipline_bes"
                + "     , ms.mld_stdmelding_autoorder"
                + "  FROM mld_stdmelding ms"
                + "     , mld_discipline md"
                + "     , ins_srtdiscipline isd"
                + "     , prs_dienst pd"
                + " WHERE pd.prs_dienst_key(+) = ms.prs_dienst_key"
                + "   AND ms.mld_ins_discipline_key = md.ins_discipline_key"
                + "   AND md.ins_srtdiscipline_key = isd.ins_srtdiscipline_key"
                + "   AND mld_stdmelding_key = " + stdm_key;
            var oRs = Oracle.Execute(sql);
            var vereisdienst = oRs("mld_stdmelding_vereisdienst").Value == 1;
            var eigenprs = oRs("mld_stdmelding_prseigen").Value == 1;
            var prs_dienst_key = oRs("prs_dienst_key").Value;
            var prs_dienst_desc = oRs("prs_dienst_omschrijving").Value; // 'Schoonmaken'
            var srtdiscbes = oRs("ins_srtdiscipline_bes").Value;   // Leverancier of uitvoerende
            var check_autoorder = oRs("mld_stdmelding_autoorder").Value == 1;
            var prs_bedrijf_key = -1;
            oRs.Close();

            if (prs_dienst_key)
            {   // Controleer of er een/één bedrijf is dat deze dienst levert op deze locatie/dit gebouw
                sql = "SELECT MIN(bdl.prs_bedrijf_key) prs_bedrijf_key"
                    + "     , COUNT(DISTINCT bdl.prs_bedrijf_key) aantal"
                    + "     , MAX(bdl.mld_autoorder) autoorder"
                    + "  FROM prs_bedrijfdienstlocatie bdl"
                    + "     , prs_v_aanwezigbedrijf b"
                    + " WHERE bdl.prs_bedrijf_key = b.prs_bedrijf_key"
                    + "   AND bdl.prs_dienst_key = " + prs_dienst_key
                    // Als ins_srtdiscipline_bes is gezet dan is het bedrijf een leverancier anders een uitvoerende.
                    + (srtdiscbes == 1 // Leverancier of uitvoerende
                      ? " AND b.prs_bedrijf_leverancier = 1"
                      : " AND b.prs_bedrijf_uitvoerende = 1")
                // Als in de tabel de alg_gebouw_key en/of alg_locatie_key NULL is dan levert het bedrijf de dienst op ALLE gebouwen en/of locaties.
                if (gebouwkey > 0)
                    sql += " AND ((bdl.alg_gebouw_key = " + gebouwkey + " OR bdl.alg_gebouw_key IS NULL) AND"
                         + "      (bdl.alg_locatie_key = " + locatiekey + " OR bdl.alg_locatie_key IS NULL)" + ")";
                else if (locatiekey > 0) // überhaupt plaatsgegevens?
                    sql += " AND (bdl.alg_locatie_key = " + locatiekey + " OR bdl.alg_locatie_key IS NULL)";
                oRs = Oracle.Execute(sql);
                var bedrijf_aantal = oRs("aantal").Value;
                var min_bedrijf_key = oRs("prs_bedrijf_key").Value;
                var has_autoorder = oRs("autoorder").Value;
                oRs.Close();

                if (vereisdienst && bedrijf_aantal == 0)
                { // Er is geen enkele dienst gevonden.
                  err_msg = (check_autoorder ? L("lcl_mld_dienst_noautoorder") : "")
                          + L("lcl_mld_dienstunavailablehere") + prs_dienst_desc;
                  abort_with_warning(err_msg);
                }
                else if (check_autoorder)
                {
                  if (has_autoorder == 1)
                  { // Er is tenminste één autoorder waarde gevonden die niet is uitgesloten van automatische opdracht.
                    // De niet uitgesloten ophalen.
                    sql += " AND bdl.mld_autoorder = 1" // 0=Uitsluiten van automatische opdracht (vinkje AAN), 1=Autoorder van stdmelding gebruiken (vinkje UIT).
                    oRs2 = Oracle.Execute(sql);
                    var bedrijf_aantal2 = oRs2("aantal").Value;
                    var min_bedrijf_key2 = oRs2("prs_bedrijf_key").Value;
                    oRs2.Close();
                    if (bedrijf_aantal2 == 1)
                    { // Bedrijf ophalen uit relatiebeheer.
                      prs_bedrijf_key = min_bedrijf_key2; // straks mogelijk vanzelf opdracht.
                    }
                    else
                    { // Bedrijf ophalen uit contractbeheer.
                      // Zoekt naar de best passende plaats: Als er een ruimtekey wordt meegegeven maar daarvoor bestaat geen cnt_contract_plaats
                      // dan wordt er gekeken of er wel een contract_plaats voor gebouw of locatie voor deze ruimte bestaat.
                      var sql_p = "  SELECT c.cnt_prs_bedrijf_key"
                                + "       , c.cnt_contract_key"
                                + "       , CASE cp.cnt_alg_plaats_code"
                                + "              WHEN 'R' THEN 5"
                                + "              WHEN 'V' THEN 4"
                                + "              WHEN 'G' THEN 3"
                                + "              WHEN 'T' THEN 2"
                                + "              ELSE 1"
                                + "          END prio"
                                + "    FROM cnt_contract c"
                                + "       , cnt_disc_params cd"
                                + "       , cnt_contract_plaats cp"
                                + "   WHERE c.ins_discipline_key = cd.cnt_ins_discipline_key"
                                + "     AND c.cnt_contract_verwijder IS NULL"
                                + "     AND c.cnt_contract_status != 1"  // niet inactief
                                + "     AND SYSDATE BETWEEN c.cnt_contract_looptijd_van"
                                + "                     AND c.cnt_contract_looptijd_tot"
                                + "     AND c.prs_dienst_key = " + prs_dienst_key
                                + "     AND cd.cnt_srtcontract_type IN (3,5)"
                                + "     AND c.cnt_contract_key = cp.cnt_contract_key"
                                + "     AND (" + (locatiekey > 0 ? "   (cp.cnt_alg_plaats_code = 'L' AND cp.cnt_alg_plaats_key = " + locatiekey + ")" : "(1=1)")
                                + "          " + (gebouwkey  > 0 ? "OR (cp.cnt_alg_plaats_code = 'G' AND cp.cnt_alg_plaats_key = " + gebouwkey  + ")" : "")
                                + "          " + (ruimtekey  > 0 ? "OR (cp.cnt_alg_plaats_code = 'R' AND cp.cnt_alg_plaats_key = " + ruimtekey  + ")" : "")
                                + "         )";

                      var sql_o = "";
                      if (obj_key_arr && obj_key_arr.length > 0)
                      {
                          sql_o = "  SELECT c.cnt_prs_bedrijf_key"
                                + "       , c.cnt_contract_key"
                                + "       , CASE WHEN co.cnt_ins_deel_key IS NULL"
                                + "              THEN 6"
                                + "              ELSE 7"
                                + "          END prio"
                                + "    FROM cnt_contract c"
                                + "       , cnt_disc_params cd"
                                + "       , cnt_contract_object co"
                                + "   WHERE c.ins_discipline_key = cd.cnt_ins_discipline_key"
                                + "     AND c.cnt_contract_verwijder IS NULL"
                                + "     AND c.cnt_contract_status != 1" // niet inactief
                                + "     AND SYSDATE BETWEEN c.cnt_contract_looptijd_van"
                                + "                     AND c.cnt_contract_looptijd_tot"
                                + "     AND c.prs_dienst_key = " + prs_dienst_key
                                + "     AND cd.cnt_srtcontract_type IN (1,3)"
                                + "     AND c.cnt_contract_key = co.cnt_contract_key"
                                + "     AND (  (    co.cnt_ins_deel_key IS NOT NULL"
                                + "            AND  co.cnt_ins_deel_key IN (" + obj_key_arr.join(",") + ")"
                                + "            )"
                                + "         OR (   co.cnt_ins_deel_key IS NULL"
                                + "            AND co.cnt_ins_srtdeel_key IN"
                                + "                (SELECT i.ins_srtdeel_key"
                                + "                   FROM ins_deel i"
                                + "                  WHERE i.ins_deel_key IN (" + obj_key_arr.join(",") + ")"
                                + "                )"
                                + "            )"
                                + "         )";
                      }

                      var sql_c = "SELECT MIN(cnt_prs_bedrijf_key) cnt_prs_bedrijf_key"
                                + "     , COUNT(*) aantal"
                                + "  FROM (SELECT cnt_prs_bedrijf_key"
                                        + "     , cnt_contract_key"
                                        + "     , prio"
                                        + "     , COUNT(DISTINCT cnt_prs_bedrijf_key) aantal"
                                        + "  FROM (" + sql_p
                                                     + (obj_key_arr && obj_key_arr.length > 0 ? " UNION " + sql_o : "")
                                        + "       )"
                                        + " GROUP BY cnt_prs_bedrijf_key, cnt_contract_key, prio"
                                        + " ORDER BY prio DESC"
                                + "       )";
                      var oRs_c = Oracle.Execute(sql_c);
                      if (oRs_c("aantal").Value == 1)
                      {
                        prs_bedrijf_key = oRs_c("cnt_prs_bedrijf_key").Value;
                      }
                      oRs_c.Close();
                    }
                  }
                  else
                  {
                    // Uitgesloten van automatische opdracht. Dan hoeft er geen opdracht aangemaakt te worden.
                    prs_bedrijf_key = -2;
                  }
                }
                else if (bedrijf_aantal == 1)
                {
                  prs_bedrijf_key = min_bedrijf_key;
                }
            }

            if (locatiekey > 0 || gebouwkey > 0 || ruimtekey > 0)
            {
                // Als de melding onderdeel is van *een* dienstniveau dan moet bij de
                // ruimte een niveau ingevuld zijn waar deze melding onderdeel van is
                sql = "SELECT COUNT(*) aantal"
                    + "  FROM mld_dienstpakket"
                    + " WHERE mld_stdmelding_key = " + stdm_key;
                oRs = Oracle.Execute(sql);
                var aantal = oRs("aantal").Value;
                oRs.Close();
                if (aantal > 0) // er zit een beperking op deze melding
                {
                  // Zoek de scherptst gedefinieerde dienstniveau
                  if (ruimtekey > 0)
                      sql = "SELECT COALESCE(ar.mld_dienstniveau_key,"
                          + "                av.mld_dienstniveau_key,"
                          + "                ag.mld_dienstniveau_key,"
                          + "                al.mld_dienstniveau_key) mld_dienstniveau_key"
                          + "  FROM alg_ruimte ar,"
                          + "       alg_verdieping av,"
                          + "       alg_gebouw ag,"
                          + "       alg_locatie al"
                          + " WHERE ar.alg_ruimte_key = " + ruimtekey
                          + "   AND ar.alg_verdieping_key = av.alg_verdieping_key"
                          + "   AND av.alg_gebouw_key = ag.alg_gebouw_key"
                          + "   AND ag.alg_locatie_key = al.alg_locatie_key";
                  else if (gebouwkey > 0)
                      sql = "SELECT COALESCE(ag.mld_dienstniveau_key, "
                          + "                al.mld_dienstniveau_key) mld_dienstniveau_key"
                          + "  FROM alg_gebouw ag,"
                          + "       alg_locatie al"
                          + " WHERE ag.alg_gebouw_key = " + gebouwkey
                          + "   AND ag.alg_locatie_key = al.alg_locatie_key";
                  else if (locatiekey > 0)
                      sql = "SELECT al.mld_dienstniveau_key"
                          + "  FROM alg_locatie al"
                          + " WHERE al.alg_locatie_key = " + locatiekey;
                  var oRs = Oracle.Execute(sql);
                  var dienstniveau_key = oRs("mld_dienstniveau_key").Value || -1;
                  oRs.Close();
                  // Zit onze melding in dienstniveau_key pakket?
                  sql = "SELECT 1"
                      + "  FROM mld_dienstpakket mdp"
                      + " WHERE mld_stdmelding_key = " + stdm_key
                      + "   AND mdp.mld_dienstniveau_key = " + dienstniveau_key
                  oRs = Oracle.Execute(sql);
                  if (oRs.Eof) // er zit een beperking op deze melding
                      abort_with_warning(L("lcl_mld_dienst_not_for_room"));
                  oRs.Close();
                }

                if (prs_key_voor > 0)
                {
                    // Als bij de melding is aangegeven dat hij alleen voor de eigen organisatie mag dan
                    // moet die ruimte (via PRS_RUIMTEAFDELING) gehuurd worden door 'eigen' afdeling
                    // 'eigen' is gedefinieerd als een afdeling die ons als parent heeft
                    //         of een afdeling die een parent van ons is
                    if (eigenprs) // er zit een beperking op deze melding
                    {
                        var uservoor = new Perslid(prs_key_voor);
                        // TODO: kan dit met een nog goedkopere view?
                        sql = "SELECT 1"
                            + "  FROM prs_ruimteafdeling"
                            + " WHERE alg_ruimte_key = " + ruimtekey
                            + " AND prs_afdeling_key IN "
                            + "    (SELECT prs_afdeling_key FROM prs_v_afdeling_familie a"
                            + "      WHERE a.prs_afdeling_elder_key ="+uservoor.prs_afdeling_key()
                            + "      UNION ALL"
                            + "     SELECT prs_afdeling_elder_key FROM prs_v_afdeling_familie a"
                            + "      WHERE a.prs_afdeling_key ="+uservoor.prs_afdeling_key() + ")";
                        oRs = Oracle.Execute(sql);
                        if (oRs.Eof) // er zit een beperking op deze melding
                          abort_with_warning(L("lcl_mld_dienst_not_for_org"));
                        oRs.Close();
                    }
                }
            }
            return prs_bedrijf_key;
        },

        link_child_to_parent: function(child_key, parent_key)
        {
          var sql = "UPDATE mld_melding"
                  + "   SET mld_melding_parentkey = " + parent_key
                  + " WHERE mld_melding_key = " + child_key;
          Oracle.Execute(sql);

          var sql = "SELECT mld_melding_status"
                  + "     , mld_ins_discipline_key"
                  + "     , mld_melding_behandelaar2_key"
                  + "  FROM mld_melding m"
                  + " WHERE mld_melding_key = " + parent_key;
          var oRs = Oracle.Execute(sql);
          var parent_status = oRs("mld_melding_status").Value;
          var parent_behandelteam = oRs("mld_ins_discipline_key").Value;
          var parent_behandelaar2 = oRs("mld_melding_behandelaar2_key").Value;
          oRs.Close();

          var sql = "SELECT mld_melding_status"
                  + "     , mld_ins_discipline_key"
                  + "     , mld_melding_behandelaar2_key"
                  + "  FROM mld_melding m"
                  + " WHERE mld_melding_key = " + child_key;
          var oRs = Oracle.Execute(sql);
          var child_status = oRs("mld_melding_status").Value;
          var child_behandelteam = oRs("mld_ins_discipline_key").Value;
          var child_behandelaar2 = oRs("mld_melding_behandelaar2_key").Value;
          oRs.Close();

          if (child_status === null)
              mld.setmeldingstatus(child_key, 2); // Alvast op ingevoerd

          if (parent_status == 6)
              parent_status = 5; // Niet rechtstreeks naar verwerkt
          else if (parent_status == 7)
              parent_status = 4; // Trigger maakt er toch 7 van indien nodig en zo kan de package hem ook oppakken.

          // Via package voor tracking
          mld.setmeldingstatus(child_key, parent_status);

          // Tracking na het zetten van de status pas aanroepen.
          // Als het een nieuwe melding is, dan is er nu ook een MLDNEW tracking/notificatie gedaan.
          // Als er een XML document (bon) wordt aangemaakt moet de status van de melding gezet zijn,
          // anders levert de functie xml.make_xml2() NULL op (FSN#46388).
          var track_oms = L("lcl_linked_to").format(shared.mld_prefix(child_key) + child_key, shared.mld_prefix(parent_key) + parent_key);
          mld.trackmeldingupdate(child_key, track_oms);

          // Behandelteam van de child melding moet die van de parent volgen.
          // Een child kan geen geplande actie zijn.
          if (parent_behandelteam != child_behandelteam)
          {
            var sql_u = "UPDATE mld_melding"
                      + "   SET mld_ins_discipline_key = " + parent_behandelteam
                      + " WHERE mld_melding_key = " + child_key;
            Oracle.Execute(sql_u);
            mld.trackAndNotifyBehandelteam(child_key, parent_behandelteam, true); // Tracking en notificatie child. Wijziging gedaan door _SYSTEM
          }

          // Behandelaar2 van de child melding moet die van de parent volgen.
          // Een child kan geen geplande actie zijn.
          if (parent_behandelaar2 != child_behandelaar2)
          {
            var sql_u = "UPDATE mld_melding"
                      + "   SET mld_melding_behandelaar2_key = " + parent_behandelaar2
                      + " WHERE mld_melding_key = " + child_key;
            Oracle.Execute(sql_u);
            mld.trackbehandelaar2(child_key, parent_behandelaar2, false); // Tracking en notificatie child
          }

          return ""; // mld_link.asp -> warning
        },
        evaluations:
        {
            // evaluate an expression, returns evaluation outcome
            // [table] can be "melding" or "opdr"
            evaluateExpression: function (key, value, table)
            {
              var index;
              var arr_match;
              var evaluation;
              var arr_flexfields;
              var arr_words;
              var arr_expression = [];
              if (value.indexOf("##SHOW## ") != -1)
              {
                arr_expression = value.split("##SHOW## ");
              }
              else if(value.indexOf("##EXPR## ") != -1)
              {
                arr_expression = value.split("##EXPR## ");
              }
              // a length other then 2 is false
              if (arr_expression.length != 2)
              {
                return false;
              }
              // split the expression by :flex
              arr_flexfields = arr_expression[1].split(":flex");
              for (index=1; index < arr_flexfields.length; index++)
              {
                // replace the :flex pointer with a select statement
                arr_match = arr_flexfields[index].match(/[^0-9]/);
                if (arr_match)
                {
                  arr_words = arr_flexfields[index].split(arr_match[0]);
                }
                // flex key value only
                else
                {
                  arr_words = [arr_flexfields[index]];
                }
                arr_words[0] = "(SELECT mld_kenmerk" + table + "_waarde"
                             + " FROM mld_kenmerk" + table
                             + " WHERE mld_" + table + "_key = " + key
                             + " AND mld_kenmerk_key = " + arr_words[0] + ")";
                // recombine the condition where each flex pointer is replaced with a SELECT statement(s)
                if (arr_match)
                {
                  arr_flexfields[index] = arr_words.join(arr_match[0]);
                }
                else
                {
                  arr_flexfields[index] = arr_words[0];
                }
              }
              var oRs_flex = Oracle.Execute("SELECT (" + arr_flexfields.join("") + ") value FROM dual");
              if (oRs_flex.Eof)
              {
                oRs_flex.Close();
                return false;
              }
              evaluation = oRs_flex("value").Value;
              oRs_flex.Close();
              return evaluation;
            },
            // evaluate an OPDR expression, returns evaluation outcome
            evaluateOpdrExpression: function (key, value)
            {
                return mld.evaluations.evaluateExpression(key, value, "opdr");
            },
            // evaluate a show expression, returns evaluation outcome which can be interpreted as a truthy/falsy value
            showIsVisible: function (key, value, table)
            {
                return mld.evaluations.evaluateExpression(key, value, (table || "melding"));
            }
        },

        hasRequiredStatusEmptyMelding: function(mld_key, status)
        {
            var sql = "SELECT *"
                    + "  FROM (SELECT mk.*"
                          + "       , (SELECT km.mld_kenmerkmelding_waarde"
                          + "            FROM mld_kenmerkmelding km"
                          + "           WHERE km.mld_kenmerk_key = mk.mld_kenmerk_key"
                          + "             AND km.mld_melding_key = mk.mld_melding_key) waarde"
                          + "    FROM (SELECT m.mld_melding_key"
                          + "               , k.mld_kenmerk_key"
                          + "               , COALESCE (" + lcl.xsql("k.mld_kenmerk_omschrijving", "k.mld_kenmerk_key")
                          + "                        ,  " + lcl.xsql("v.mld_srtkenmerk_omschrijving", "v.mld_srtkenmerk_key") + ") mld_kenmerk_omschrijving"
                          + "               , v.mld_srtkenmerk_kenmerktype"
                          + "               , k.mld_kenmerk_verplicht"
                          + "               , k.mld_kenmerk_verplicht_status"
                          + "               , k.mld_kenmerk_show_expr"
                          + "            FROM mld_kenmerk k"
                          + "               , mld_melding m"
                          + "               , mld_stdmelding s"
                          + "               , mld_discipline d"
                          + "               , mld_srtkenmerk v"
                          + "           WHERE k.mld_srtkenmerk_key = v.mld_srtkenmerk_key"
                          + "             AND v.mld_srtkenmerk_kenmerktype NOT IN ('l', 'b', 'L')"
                          + "             AND s.mld_stdmelding_key = m.mld_stdmelding_key"
                          + "             AND s.mld_ins_discipline_key = d.ins_discipline_key"
                          + "             AND ((k.mld_stdmelding_key IS NULL AND k.mld_kenmerk_niveau = 'A')"
                          + "               OR (k.mld_stdmelding_key = s.mld_stdmelding_key AND k.mld_kenmerk_niveau = 'S')"
                          + "               OR (k.mld_stdmelding_key = s.mld_ins_discipline_key AND k.mld_kenmerk_niveau = 'D')"
                          + "               OR (k.mld_stdmelding_key = d.ins_srtdiscipline_key  AND k.mld_kenmerk_niveau = 'T'))"
                          + "             AND v.mld_srtkenmerk_verwijder IS NULL"
                          + "             AND k.mld_kenmerk_verwijder IS NULL"
                          + "         ) mk"
                          + " ) mkw"
                    + " WHERE mkw.mld_melding_key = " + mld_key
                    + "   AND (mkw.mld_kenmerk_verplicht_status IN (2, " + status + ")" // Als de status 2 is, dan is het altijd (vanaf de invoer) verplicht.
                    + "     OR mkw.mld_kenmerk_verplicht = 1)"                          // De kenmerken die altijd verplicht zijn.
                    + "   AND mkw.waarde IS NULL";
            var oRs = Oracle.Execute(sql);
            var kenm_ontbreekt = [];
            while (!oRs.eof)
            {
                // conditional characteristics are only evalued when visible
                if (oRs("mld_kenmerk_show_expr").Value == null || mld.evaluations.showIsVisible(mld_key, oRs("mld_kenmerk_show_expr").Value))
                {
                  if (oRs("mld_srtkenmerk_kenmerktype").Value == "M")
                  {
                      var lijst = BijlagenList("MLD", "M", mld_key, String(oRs("mld_kenmerk_key").Value));
                      if (!lijst.length) // Anders ontbreekt type "M" (Folder met bestanden) dus niet
                          kenm_ontbreekt.push(oRs("mld_kenmerk_omschrijving").Value);
                  }
                  else
                      kenm_ontbreekt.push(oRs("mld_kenmerk_omschrijving").Value);
                }

                oRs.MoveNext();
            }
            oRs.Close();
            // Levert array op met kenmerken die ingevuld hadden moeten zijn.

            var obj_ontbreekt = false;
            sql = "SELECT sm.ins_srtinst_verplichtstatus"
                + "  FROM mld_melding m"
                + "     , mld_stdmelding sm"
                + " WHERE m.mld_stdmelding_key = sm.mld_stdmelding_key"
                + "   AND m.mld_melding_key = " + mld_key;
            var oRs = Oracle.Execute(sql);
            var status_ojb_verplicht = oRs("ins_srtinst_verplichtstatus").Value;
            oRs.Close();

            if (status_ojb_verplicht == 2 || (status_ojb_verplicht == 21) || status_ojb_verplicht == status) // Als de status 2 is, dan is het altijd (vanaf de invoer) verplicht.
            {
              sql = "SELECT COUNT(mo.mld_melding_object_key) aantal_obj"
                + "    FROM mld_melding m"
                + "       , mld_melding_object mo"
                + "   WHERE m.mld_melding_key = mo.mld_melding_key"
                + "     AND m.mld_melding_key = " + mld_key;
              var oRs = Oracle.Execute(sql);
              obj_ontbreekt = (status_ojb_verplicht != 21 && oRs("aantal_obj").Value == 0);
              oRs.Close();
            }

            return {kenm_ontbreekt: kenm_ontbreekt, obj_ontbreekt: obj_ontbreekt};
        },

        hasActieKenmerkenOpdr: function(opdr_key, params)
        {
            var sql = "SELECT *"
                    + "  FROM (SELECT ok.*"
                          + "       , (SELECT ko.mld_kenmerkopdr_waarde"
                          + "            FROM mld_kenmerkopdr ko"
                          + "           WHERE ko.mld_kenmerk_key = ok.mld_kenmerk_key"
                          + "             AND ko.mld_opdr_key = ok.mld_opdr_key) waarde"
                          + "    FROM (SELECT o.mld_opdr_key"
                                  + "       , k.mld_kenmerk_key"
                                  + "       , k.mld_kenmerk_show_expr"
                                  + "       , COALESCE (" + lcl.xsql("k.mld_kenmerk_omschrijving", "k.mld_kenmerk_key")
                                  + "                ,  " + lcl.xsql("v.mld_srtkenmerk_omschrijving", "v.mld_srtkenmerk_key") + ") mld_kenmerk_omschrijving"
                                  + "       , v.mld_srtkenmerk_kenmerktype"
                                  + "       , k.mld_kenmerk_verplicht_status"
                                  + "       , k.mld_kenmerk_onderbreken"
                                  + "       , k.mld_kenmerk_niveau"
                                  + "    FROM mld_kenmerk k"
                                  + "       , mld_srtkenmerk v"
                                  + "       , mld_opdr o"
                                  + "       , mld_typeopdr t"
                                  + "   WHERE k.mld_srtkenmerk_key = v.mld_srtkenmerk_key"
                                  + "     AND o.mld_typeopdr_key = t.mld_typeopdr_key"
                                  + "     AND (k.mld_typeopdr_key = t.mld_typeopdr_key OR k.mld_typeopdr_key IS NULL)"
                                  + "     AND k.mld_kenmerk_niveau IN ('P', 'O')"
                                  + "     AND v.mld_srtkenmerk_kenmerktype <> 'O'"
                                  + "     AND v.mld_srtkenmerk_verwijder IS NULL"
                                  + "     AND k.mld_kenmerk_verwijder IS NULL"
                                  + " ) ok"
                          + " ) okw"
                    + " WHERE okw.mld_opdr_key = " + opdr_key
                    + (params.status
                      ? "   AND okw.mld_kenmerk_verplicht_status = " + params.status // De kenmerken die verplicht zijn bij de opgegeven status ophalen.
                      : "")
                    + (params.halt
                      ? "   AND okw.mld_kenmerk_onderbreken > 0" // De Onderbreken kenmerken ophalen.
                      : "   AND okw.waarde IS NULL");
            var oRs = Oracle.Execute(sql);
            var ontbreekt = [];
            while (!oRs.eof)
            {
                // conditional characteristics are only valued when visible
                if (oRs("mld_kenmerk_show_expr").Value == null || mld.evaluations.showIsVisible(opdr_key, oRs("mld_kenmerk_show_expr").Value, "opdr"))
                {
                  if (oRs("mld_srtkenmerk_kenmerktype").Value == "M")
                  {
                      var lijst = BijlagenList("MLD", "O", opdr_key, String(oRs("mld_kenmerk_key").Value));
                      if (!lijst.length) // Anders ontbreekt type "M" (Folder met bestanden) dus niet
                          ontbreekt.push(oRs("mld_kenmerk_omschrijving").Value);
                  }
                  else
                      ontbreekt.push(oRs("mld_kenmerk_omschrijving").Value);
                }
                oRs.MoveNext();
            }
            oRs.Close();
            // Levert array op met kenmerken die ingevuld hadden moeten zijn.
            return ontbreekt;
        },

        srtdisc_sql: function (params)
        {
            params = params || {};
            params.ins_key = (typeof params.ins_key == "number" ? [params.ins_key] : params.ins_key);

            var mySRTsql = // All ins_srtdiscipline with any ins_discipline beneath it we have write-rights for
                           "SELECT sd.ins_srtdiscipline_key"
                         + ", " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
                         + ",      sd.ins_srtdiscipline_image"
                         + "  FROM ins_v_aanwezigsrtdiscipline sd"
                         + "     , mld_discipline td"
                         + "     , mld_disc_params dp0" // Unieke alias omdat de filter_from hem ook kan toevoegen
                         + "     , mld_stdmelding msm"
                         + (params.filter_from ? params.filter_from : "")
                         + " WHERE td.ins_srtdiscipline_key = sd.ins_srtdiscipline_key"
                         + "   AND msm.mld_ins_discipline_key = td.ins_discipline_key"
                         + "   AND td.ins_discipline_key = dp0.mld_ins_discipline_key"
                         + (params.filter_where ? params.filter_where : "")
                         + "   AND sd.ins_srtdiscipline_module = 'MLD'"
                         + "   AND sd.ins_srtdiscipline_key <> " + S("kto_srtdiscipline_key")
                         + "   AND msm.mld_stdmelding_verwijder IS NULL"
                         + "   AND (msm.mld_stdmelding_vervaldatum IS NULL"
                         + "     OR msm.mld_stdmelding_vervaldatum > TRUNC(SYSDATE))"
                         + "   AND EXISTS (SELECT fw.ins_discipline_key"
                         + "                 FROM fac_v_webgebruiker fw"
                         + "                    , fac_functie ff"
                         + "                WHERE msm.mld_ins_discipline_key = fw.ins_discipline_key"
                         + "                  AND fw.fac_functie_key = ff.fac_functie_key"
                         + "                  AND ff.fac_functie_code IN ('WEB_MLDFOF', 'WEB_MLDUSE')"
                         + "                  AND ((ff.fac_functie_code = 'WEB_MLDUSE'"
                         + "                    AND msm.mld_stdmelding_notfrontend = 0)"
                         + "                    OR ff.fac_functie_code = 'WEB_MLDFOF')"
                         + "                  AND fw.fac_gebruiker_alg_level_write < 9"
                         + "                  AND fw.fac_gebruiker_prs_level_write < 9"
                         + "                  AND fw.prs_perslid_key = " + user_key + ")"
                         + (params.ref_type == "C" // issue initiated from contract
                            ? "  AND BITAND(msm.mld_stdmelding_kanverwijzen,32) = 32"
                            : "")
                         + (("mldgroup" in params)
                            ? "  AND DECODE(dp0.mld_disc_params_mldgroup,"
                            + "             0, BITAND(sd.ins_srtdiscipline_mldgroup, 1)," // 0 = Zoals vakgroeptype
                            + "                BITAND(dp0.mld_disc_params_mldgroup, 1))"  // Anders, volgens vakgroep-instelling
                            + "      = 1"                                                 // 1 = Kan groepering zijn
                            : "")
                         + (params.ins_key > 0  // dan moet die discipline ook nog meldingen hebben die betrekking *kunnen*
                                                // hebben op ons object. In theorie zouden we ook nog kunnen ALG-scopen...
                          ? "   AND EXISTS (SELECT msm.mld_ins_discipline_key"
                            + "               FROM mld_v_mld_stdmelding_srtinst mss"
                            + "                  , ins_deel d"
                            + "              WHERE msm.mld_stdmelding_key = mss.mld_stdmelding_key"
                            + "                AND mss.ins_deel_key = d.ins_deel_key"
                            + "                AND mss.ins_deel_key IN (" + params.ins_key.join(",") + ")"
                            + "                AND ((d.ins_alg_ruimte_type = 'A' AND msm.alg_org_obj_niveau < 9)"
                            + "                  OR d.ins_alg_ruimte_type != 'A'))"
                            + " AND msm.mld_ins_discipline_key = td.ins_discipline_key"
                            + " AND msm.mld_stdmelding_verwijder IS NULL"
                            + " AND sd.ins_srtdiscipline_ins = 1"
                          : "")
                        + (params.org_srtdisc_key > 0
                          ? "    AND (    EXISTS ("
                              + "           SELECT vb.ins_srtdiscipline_key_1 "
                              + "             FROM mld_vervolg_beperking vb "
                              + "            WHERE vb.ins_srtdiscipline_key_1 = " +  params.org_srtdisc_key
                              + "                  AND td.ins_srtdiscipline_key = vb.ins_srtdiscipline_key_2) "
                              + "     OR NOT EXISTS"
                              + "          (SELECT 'dummy' "
                              + "             FROM mld_vervolg_beperking"
                              + "            WHERE ins_srtdiscipline_key_1 = " +  params.org_srtdisc_key + "))"
                            : "")
                    + " GROUP BY sd.ins_srtdiscipline_key, sd.ins_srtdiscipline_omschrijving, sd.ins_srtdiscipline_image"
                    + " ORDER BY 2";

             return mySRTsql;
        },

        reference_sql: function ()
        {
            // Alle referenties die ooit bij een melding zijn gebruikt.
            var refsql = "SELECT 'M'"                                        // Alle meldingen [M].
                       + "     , " + safe.quoted_sql(L("lcl_mld_stdmelding_all"))
                       + "  FROM mld_melding"
                       + " WHERE mld_melding_kto_type = 'M'"
                       + " UNION"
                       + " SELECT 'O'"                                       // Opdracht [O].
                       + "      , " + safe.quoted_sql(L("lcl_opdr_info"))
                       + "  FROM mld_melding"
                       + " WHERE mld_melding_kto_type = 'O'"
                       + " UNION"
                       + " SELECT 'R'"                                       // Reservering (R).
                       + "      , " + safe.quoted_sql(L("lcl_res_reservation"))
                       + "  FROM mld_melding"
                       + " WHERE mld_melding_kto_type = 'R'"
                       + " UNION"
                       + " SELECT 'B'"                                       // Bestelling (B).
                       + "      , " + safe.quoted_sql(L("lcl_bes_bestelling"))
                       + "  FROM mld_melding"
                       + " WHERE mld_melding_kto_type = 'B'"
                       + " UNION"
                       //+ " SELECT 'X'"                                       // Bestelopdr [X]. /* reserved for future use */
                       //+ "      , " + safe.quoted_sql(L("lcl_bes_bestelopdracht"))
                       //+ "  FROM mld_melding"
                       //+ " WHERE mld_melding_kto_type = 'X'"
                       //+ " UNION"
                       + " SELECT 'C'"                                       // Contract [C].
                       + "      , " + safe.quoted_sql(L("lcl_contract"))
                       + "  FROM mld_melding"
                       + " WHERE mld_melding_kto_type = 'C'"
                       + " UNION"
                       //+ " SELECT 'F'"                                       // Factuur [F].    /* reserved for future use */
                       //+ "      , " + safe.quoted_sql(L("lcl_fin_invoice"))
                       //+ "  FROM mld_melding"
                       //+ " WHERE mld_melding_kto_type = 'F'"
                       //+ " UNION"
                       + " SELECT 'T'"                                       // Taken [T].
                       + ", " + safe.quoted_sql(L("lcl_mld_taak"))
                       + "  FROM mld_melding m"
                       + "     , mld_melding_object mo"
                       + " WHERE m.mld_melding_key = mo.mld_melding_key"
                       + "   AND mo.ins_deelsrtcontrole_key IS NOT NULL"
                       + " ORDER BY 2";
             return refsql;
        },

        suggest_uitvoerende_sql: // Maak de sql voor de lijst met uitvoerenden
            function _suggest_uitvoerende_sql(filtClause, params)
            { // Zie ook Shared/Suggest/SuggestUitvoerende.asp en Shared/Suggest/uitvoerendeFilter.inc.
              filtClause = filtClause || {};
              params = params || {};
              var chars       = params.chars;
              var dienst      = params.dienst;
              var loc_key     = params.loc_key;
              var bld_key     = params.bld_key;
              var lutype      = params.lutype;
              var externonly  = params.externonly;
              var exhandler   = params.exhandler;

              var chars = chars.replace(/\*/g,"%");
              var filtClause = getFiltClauseUitvoerende(params.filtcode, params);

              // De uitvoerende. CONN#15546 vindt dat voor BES-meldingen er ook beter
              // uit leveranciers kan worden gekozen dan uit uitvoerenden.
              // Kan dit nog zuiverder? Bijvoorbeeld tegelijk MLD en BES?
              if (lutype == "L")
                var uitvtabel = "prs_v_leverancierbedrijf"; // prs_bedrijf_leverancier = 1
              else if (lutype == "U")
                var uitvtabel = "prs_v_uitvoerendebedrijf"; // prs_bedrijf_uitvoerende = 1
              else // lutype == "B"
                var uitvtabel = "prs_v_aanwezigbedrijf"; // aanwezig prs_bedrijf

              // Let op de bijzonder manier om prs_bedrijfdienstlocatie mee te nemen: hier interesseren me
              // slechts de verschillende diensten, de plaats doet er niet toe.
              // Geen autorisatie bij externe bedrijven (prs_bedrijf met prs_bedrijf_uitvoerende = 1 of prs_bedrijf_leverancier = 1)
              // Niet persoon of plaats afhankelijk
              sqlD = " SELECT b.prs_bedrijf_key uitv_key"
                   + ",       " + safe.quoted_sql(L("lcl_mld_bedrijf_prefix")) + " || b.prs_bedrijf_naam naam"
                   + ",       '' dienst"
                   + ",       'B' extra"
                   + ",       10"
                   + ",       prs_bedrijf_naam_upper"
                   + "   FROM " + uitvtabel + " b"
                   + "  WHERE 1 = 1"
                   + filtClause.bedrijf
                   + "    AND UPPER(b.prs_bedrijf_naam) LIKE " + safe.quoted_sql_wild("%" + chars + "%")

              sqlP = " SELECT p.prs_perslid_key uitv_key"
                   + ",       " + safe.quoted_sql(L("lcl_mld_person_prefix")) + " || " + S("prs_pers_string") + " naam"
                   + ",       " + safe.quoted_sql(L("lcl_mld_intern")) + " dienst"
                   + ",       'P' extra"
                   + ",       99"
                   + ",       prs_perslid_upper"
                   + "   FROM prs_v_aanwezigperslid p"
                   + "  WHERE (UPPER(" + safe.quoted_sql(L("lcl_mld_person_prefix")) + " || " + S("prs_pers_string") + ") LIKE " + safe.quoted_sql_wild(chars + "%")
                   + "      OR UPPER(" + safe.quoted_sql(L("lcl_mld_intern")) + ") LIKE " + safe.quoted_sql_wild(chars + "%")+")"
                   + filtClause.perslid

              sqlL = filtClause.locatie;
              sqlG = filtClause.gebouw;

              sqlarr = [sqlD];
              if (loc_key > 0) sqlarr.push(sqlL);
              if (bld_key > 0) sqlarr.push(sqlG);
              var mld_opdr_sel_intern_uitv = S("mld_opdr_sel_intern_uitv") == 1; // Internal contractors can be selected for all services {0=no (default) | 1=Yes}.
              if ((dienst == -1 || mld_opdr_sel_intern_uitv) && !externonly && !exhandler) sqlarr.push(sqlP);  // Personen voldoen nooit aan een dienst

              sql = sqlarr.join(" UNION ALL ");
              sql = "SELECT * FROM(" + sql + ") ORDER BY 5, 6";

              return sql;
            },
        reject_offerte:
            function _reject_offerte(opdr_key, opmerk)
            {
              var mld_opdr = mld.mld_opdr_info(opdr_key);
              lcl.set_dialect(mld_opdr.opdr_type, "MLD_TYPEOPDR_KEY");

              // Nog de afmeld opmerking opslaan.
              var this_opdr = mld.func_enabled_opdracht(opdr_key); // wat mag ik zoal op deze opdracht
              if (this_opdr.canOpmChange && opmerk)
              {
                var fields = [ { dbs: "mld_opdr_opmerking", typ: "varchar", val: opmerk, track: L("lcl_mld_inf_Opmerking") } ];
                var mldUpd = buildTrackingUpdate("mld_opdr", "mld_opdr_key = " + opdr_key, fields);

                if (mldUpd && mldUpd.trackarray.length)
                {
                  Oracle.Execute(mldUpd.sql);
                  var ins_srtdiscipline_prefix = shared.mld_prefix(mld_opdr.mld_key);
                  var formattedID = ins_srtdiscipline_prefix + mld_opdr.mld_key + "/" + mld_opdr.volgnr;
                  mld.trackopdrachtupdate(opdr_key, L("lcl_ord_is_ordupdtrack").format(formattedID) + "\n" + mldUpd.trackarray.join("\n"));
                }
              }

              // Zetten van de status en afhandelen van de tracking van het afwijzen (reject).
              mld.setopdrachtstatus(opdr_key, 2); // Afgekeurd

              // De status van de melding zou gewijzigd kunnen/moeten worden hierdoor
              mld.updatemeldingstatus(mld_opdr.mld_key, 0);
            },

        getReqStatusEmptyMelding:
            function _getReqStatusEmptyMelding(objkenmerkEmpty, mld_key, status)
            { // Zijn er nog kenmerken die nu wel verplicht zijn en/of een object?
              var afwezig = mld.hasRequiredStatusEmptyMelding(mld_key, status);
              if (afwezig.kenm_ontbreekt.length || afwezig.obj_ontbreekt)
              {
                var mldnr = shared.mld_prefix(mld_key) + mld_key;
                if (afwezig.kenm_ontbreekt.length)
                  objkenmerkEmpty.push(L("lcl_mld_req_status_empty").format(afwezig.kenm_ontbreekt.join(", "), mldnr) );
                if (afwezig.obj_ontbreekt)
                  objkenmerkEmpty.push(L("lcl_mld_req_obj").format(mldnr) );
              }
              return objkenmerkEmpty;
            },

        getActieKenmerkenOpdr:
            function _getActieKenmerkenOpdr(kenmerkEmpty, opdr_key, params)
            { // Zijn er nog kenmerken die nu wel verplicht zijn?
              var kvsAfwezig = mld.hasActieKenmerkenOpdr(opdr_key, params);
              if (kvsAfwezig.length)
              {
                var mld_opdr = mld.mld_opdr_info(opdr_key);
                var mldnr = shared.mld_prefix(mld_opdr.mld_key) + mld_opdr.mld_key + "/" + mld_opdr.volgnr;
                kenmerkEmpty.push(L("lcl_mld_opdr_req_status_empty").format(kvsAfwezig.join(", "), mldnr) );
              }
              return kenmerkEmpty;
            },

         getEmptyRequiredFields:
            function _getEmptyRequiredFields(mld_melding)
            {
              var emptyRequiredFields = false;
              // Plaatsgegevens.
              if (mld_melding.show_alg)
              {
                switch (mld_melding.alg_onrgoed_niveau)
                {
                  case "R": emptyRequiredFields = (mld_melding.bttype != "T" && mld_melding.room_key == -1);
                            break;
                  case "V": emptyRequiredFields = (mld_melding.bttype != "T" && mld_melding.flr_key == -1);
                            break;
                  case "G": emptyRequiredFields = (mld_melding.bld_key == -1);
                            break;
                  case "L": emptyRequiredFields = (mld_melding.loc_key == -1);
                            break;
                }
              }
              // Dan de velden kostenplaats, afleveradres en objecten ook maar testen of ze, als ze verplicht zijn, zijn ingevuld.
              // Kostenplaats.
              emptyRequiredFields = emptyRequiredFields || (mld_melding.kpnverplicht && mld_melding.kostenpl_key == -1);
              // Afleveradres.
              emptyRequiredFields = emptyRequiredFields || (mld_melding.afleveradres_verplicht && !mld_melding.deladdress_key);
              // Objecten.
              if (mld_melding.show_ins && mld_melding.srtinst_verplichtstatus == 2)
              { // Verplicht een objecten te selecteren.
                var sql = "SELECT COUNT(*) aantal FROM mld_melding_object WHERE mld_melding_key = " + mld_melding.mld_key;
                var oRs = Oracle.Execute(sql);
                var noObjSelected = oRs("aantal").Value == 0;
                oRs.close();
                emptyRequiredFields = emptyRequiredFields || noObjSelected;
              }
              // Omschrijving melding.
              emptyRequiredFields = emptyRequiredFields || (mld_melding.freetext == 2 && !mld_melding.mld_omschr);

              return emptyRequiredFields;
            },

         getMldKenmerk_sql:
            function _getMldKenmerk_sql(pmld_key, pfiltClause)
            {
              var filtClause = pfiltClause || {};
              var where = "";

              if (filtClause.wheres && filtClause.wheres.length > 0)
                where = " AND " + filtClause.wheres.join(" AND ");

              var sql = "SELECT mkm.mld_kenmerk_key"
                      + "     , mkm.mld_kenmerk_niveau"
                      + "     , mkm.mld_kenmerk_volgnummer"
                      + "     , mkm.mld_kenmerk_rolcode"
                      + "     , COALESCE (" + lcl.xsql("mkm.mld_kenmerk_omschrijving", "mkm.mld_kenmerk_key")
                      + "              ,  " + lcl.xsql("msk.mld_srtkenmerk_omschrijving", "msk.mld_srtkenmerk_key") + ") mld_kenmerk_omschrijving"
                      + "     , msk.mld_srtkenmerk_kenmerktype"
                      + "     , mkm.mld_srtkenmerk_key"
                      + "  FROM mld_kenmerk mkm"
                      + "     , mld_srtkenmerk msk"
                      + "     , mld_melding mm"
                      + "     , mld_stdmelding sm"
                      + "     , mld_discipline md"
                      + "     , (SELECT 'S' mld_kenmerk_niveau"
                      + "             , mld_stdmelding_key ref_mld_stdmelding_key"
                      + "             , mld_stdmelding_key"
                      + "             , ins_discipline_key"
                      + "             , m2.ins_srtdiscipline_key"
                      + "          FROM mld_stdmelding md"
                      + "             , mld_discipline m2"
                      + "         WHERE md.mld_ins_discipline_key = m2.ins_discipline_key"
                      + "         UNION ALL"
                      + "        SELECT 'D' mld_kenmerk_niveau"
                      + "             , ins_discipline_key ref_mld_stdmelding_key"
                      + "             , NULL mld_stdmelding_key"
                      + "             , ins_discipline_key ins_discipline_key"
                      + "             , ins_srtdiscipline_key"
                      + "          FROM mld_discipline m2"
                      + "         UNION"
                      + "        SELECT 'T' mld_kenmerk_niveau"
                      + "             , ins_srtdiscipline_key ref_mld_stdmelding_key"
                      + "             , NULL mld_stdmelding_key"
                      + "             , NULL ins_discipline_key"
                      + "             , ins_srtdiscipline_key"
                      + "          FROM ins_srtdiscipline m2"
                      + "         UNION"
                      + "        SELECT 'A' mld_kenmerk_niveau"
                      + "             , NULL ref_mld_stdmelding_key"
                      + "             , NULL mld_stdmelding_key"
                      + "             , NULL ins_discipline_key"
                      + "             , NULL ins_srtdiscipline_key"
                      + "          FROM ins_srtdiscipline m2"
                      + "       ) s"
                      + " WHERE mkm.mld_kenmerk_verwijder IS NULL"
                      + "   AND (mkm.mld_stdmelding_key = s.ref_mld_stdmelding_key OR mkm.mld_stdmelding_key IS NULL)"
                      + "   AND mkm.mld_kenmerk_niveau = s.mld_kenmerk_niveau"
                      + "   AND mkm.mld_srtkenmerk_key = msk.mld_srtkenmerk_key"
                      + "   AND mm.mld_stdmelding_key = sm.mld_stdmelding_key"
                      + "   AND md.ins_discipline_key = sm.mld_ins_discipline_key"
                      + "   AND (('A' = mkm.mld_kenmerk_niveau AND mkm.mld_stdmelding_key IS NULL)"
                      + "     OR (((s.ins_discipline_key = sm.mld_ins_discipline_key)"
                      + "       OR ('T' = mkm.mld_kenmerk_niveau AND s.ins_srtdiscipline_key = md.ins_srtdiscipline_key))"
                      + "     AND ((s.mld_stdmelding_key = sm.mld_stdmelding_key)"
                      + "       OR ('D' = mkm.mld_kenmerk_niveau AND s.ins_discipline_key = sm.mld_ins_discipline_key)"
                      + "       OR ('T' = mkm.mld_kenmerk_niveau AND s.ins_srtdiscipline_key = md.ins_srtdiscipline_key))"
                      + "        ))"
                      + "   AND mm.mld_melding_key = " + pmld_key
                      + where
                      + " ORDER BY mkm.mld_kenmerk_volgnummer ASC";

              return sql;
            },

        getopdroverzicht_sql:
            function (pautfunction, params)
            { // Lever opdrachten overzicht sql op.
              var urole = params.urole;
              var fronto = (urole == "fo");
              var backo = (urole == "bo");
              var frontend  = (urole == "fe");
              var bgtmode  = (urole == "bgt");

              // Voor resulttable de globalen zetten; zou ng anders moeten.
              var outputmode = params.outputmode; // print to 0 = screen, 1 = printer, 2 = excel, etc.
              var print = (outputmode == 1 || outputmode == 5);
              var excel = (outputmode == 2 || outputmode == 6);
              var showall = params.showall;

              var mld_key = params.mld_key;
              var ks_key = params.ks_key;
              var opdr_key = params.opdr_key; // opdracht nummer is voor de gebruiker hetzelfde als mld_key
              var opdr_id = params.opdr_id; // Referentienr
              var intopdr_key = params.intopdr_key;  // de technische echte mld_opdr_key
              var opdr_parent_key = params.opdr_parent_key;

              // Melding Behandelaar
              var behandel_key      = params.behandel_key;
              var behandel_key_arr  = params.behandel_key_arr || [];  // Array met keys (e.g. [3, 4, 5])
              var behandel2_key_arr = params.behandel2_key_arr || []; // Array met keys (e.g. [3, 4, 5])

              // Opdracht Behandelaar
              var uitvopdr_key = params.uitvopdr_key;
              var opdr_behandel_key_arr = params.opdr_behandel_key_arr || [];  // Array met keys (e.g. [3, 4, 5])

              var searchtekst = params.searchtekst;
              var reg_key_arr = params.reg_key_arr || [];
              var dist_key_arr = params.dist_key_arr || [];
              var loc_key_arr = params.loc_key_arr || [];
              var bld_key_arr = params.bld_key_arr || [];
              var flr_key_arr = params.flr_key_arr || [];
              var room_key_arr = params.room_key_arr || [];
              var adr_key = params.adr_key;
              var verantw_key = params.verantw_key;
              var caller_key = params.caller_key;
              var org_key = params.org_key;
              var srtdisc_key_arr = params.srtdisc_key_arr || [];
              var disc_key_arr = params.disc_key_arr || []; // Array met keys (e.g. [3, 4, 5])
              var meldinggrp_key = params.meldinggrp_key;
              var behandelgrp_key = params.behandelgrp_key;
              var priority_arr = params.priority_arr || [];
              var bosort = params.bosort;
              var stdm_key_arr = params.stdm_key_arr || [];
              var kp_key_arr = params.kp_key_arr || [];
              var tag_key_arr = params.tag_key_arr || [];
              var handler_key = params.handler_key;
              var internuit = params.internuit;
              var externuit = params.externuit;
              var opdrplanned = (typeof params.opdrplanned == "undefined" ? true : params.opdrplanned);
              var opdrunplanned = (typeof params.opdrunplanned == "undefined" ? true : params.opdrunplanned);
              var opdr_actiecode_bitor = params.opdr_actiecode_bitor || 0; // 0 laat alle substatussen zien
              var opdr_actiecode_att = params.opdr_actiecode_att;
              var mldstatus_arr = params.mldstatus_arr || [];
              var opdrstatus_arr = params.opdrstatus_arr || [];
              var chkAcceptEx = params.chkAcceptEx;
              var chkRunEx = params.chkRunEx;
              var chkSpoed = params.chkSpoed;
              var chkAfgerond = params.chkAfgerond;
              var startdatefrom = params.startdatefrom;
              var startdateto = params.startdateto;
              var enddatefrom = params.enddatefrom;
              var enddateto = params.enddateto;
              var plandatefrom = params.plandatefrom;
              var plandateto = params.plandateto;
              var opdr_bedrag_boven = params.opdr_bedrag_boven;
              var opdr_bedrag_onder = params.opdr_bedrag_onder;
              var opdrtype_key = params.opdrtype_key;
              var includeHours = params.includeHours;
              var contract = params.contract
              var cnt_key = params.cnt_key;
              var offerte = params.offerte; // Opdrachttype is een offerteaanvraag. Kan -1:don't care, 0:niet, 1:wel zijn.
              if (params.offertes) // Helaas geeft mld_search_list.asp het meervoud door
                offerte = 1;
              // Er kunen twee contract keys meegegeven worden. Een extra contract key die bij contract hoort.
              // Als cnt_key en contract_key verschillen kun het nooit een resultaat opleveren
              if (contract > 0)
                cnt_key = cnt_key + (cnt_key != ""? ", " : "") + contract;
              var uitvoerder = params.uitvoerder;
              var planb = params.planb;

              var bes = params.bes;
              var tiny = params.tiny;
              var inline = params.inline;
              var from_mld = params.from_mld;
              var showstatus = params.showstatus;
              var showopdrstatus = params.showopdrstatus;
              var mldopdrstrej = params.mldopdrstrej;
              var mldopdrstafm = params.mldopdrstafm;
              var mldopdrstver = params.mldopdrstver;
              var contactpersoon_key = params.contactpersoon_key;

              var groepering_key = params.groepering_key; // Voor maninfo. 2 en 16 ondersteund

              // AUTORISATIES
              // Even een simplistische 'ben ik -externe- uitvoerder'-check
              var exhandler = urole == "b2" && !(user.checkAutorisation("WEB_ORDBO2", true)) && user.iamContact();

              // Autorisatie check is al gedaan in mld_search_list.asp
              // Dit lijkt me om te kunnen bepalen of ik uberhaupt naar de PRS-autorisatie hoef te kijken
              var add_prs_restrict_ord = prshasrestrict(pautfunction);
              var add_prs_restrict_mld = from_mld && prshasrestrict("WEB_MLDBOF");

              if (from_mld)
              {
                var functiecode = "'WEB_MLDBOF'";
                for (var i = 0; i < pautfunction.length; i++)
                {
                  functiecode += "," + safe.quoted_sql(pautfunction[i]);
                }
              }
              else
              {
                if (typeof pautfunction == "object" && pautfunction instanceof Array)
                  var functiecode = safe.quoted_sql_join(pautfunction);
                else
                  var functiecode = safe.quoted_sql(pautfunction);
              }
              // check if user has a building or lower scope. If so we have to include onroerendgoed view.
              sql2  = "SELECT fac_groeprechten_key "
                    + "  FROM fac_functie f"
                    + "     , fac_groeprechten gr"
                    + "     , fac_gebruikersgroep gg"
                    + " WHERE gg.prs_perslid_key = " + user_key
                    + "   AND gr.fac_groep_key = gg.fac_groep_key"
                    + "   AND gr.fac_functie_key = f.fac_functie_key"
                    + "   AND (f.fac_functie_code IN (" + functiecode + "))"
                    + "   AND (   (    gr.fac_gebruiker_alg_level_read < 9 "
                    + "            AND gr.fac_gebruiker_alg_level_read > 2 "
                    + "           ) "
                    + "       OR (    gr.fac_gebruiker_alg_level_write < 9 "
                    + "            AND gr.fac_gebruiker_alg_level_write > 2 "
                    + "           ) "
                    + "       ) ";

              bld_scope = false;
              oRs2 = Oracle.Execute(sql2);
              if (!oRs2.eof)
              {
                bld_scope = true;
              }
              oRs2.Close();

              var sqltrack = (groepering_key == 2 || groepering_key == 16 // Minfo groepering Opdracht(2) en Opdracht + Kosten(16).
                             ? ", TO_DATE('01-01-1970', 'DD-MM-YYYY')"
                             : ", (SELECT MAX(fac_tracking_datum)"
                               + "   FROM (SELECT t.fac_tracking_datum"
                               + "           FROM fac_tracking t"
                               + "              , fac_srtnotificatie sn"
                               + "          WHERE t.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                               + "            AND t.fac_tracking_refkey = o.mld_opdr_key"
                               + "            AND sn.fac_srtnotificatie_xmlnode = 'opdracht'"
                               + "         UNION" // Geen UNION ALL gebruikt (is ook niet nodig). Dit geeft anders problemen bij ***sqlA = sqlA.split("UNION ALL");*** later in de code.
                               + "         SELECT mld_opdr_note_aanmaak recentdatum"
                               + "           FROM mld_opdr_note"
                               + "          WHERE mld_opdr_key = o.mld_opdr_key))")
                           + " recentdatum";

              var uitv_type = " CASE"
                            + " WHEN COALESCE ( (SELECT 'B'"
                            + "                    FROM prs_bedrijf"
                            + "                   WHERE prs_bedrijf_key = o.mld_uitvoerende_keys)"
                            + "               , (SELECT 'P'"
                            + "                    FROM prs_perslid"
                            + "                   WHERE prs_perslid_key = o.mld_uitvoerende_keys)) = 'B'"
                            + " THEN"
                            + "   CASE"
                            + "   WHEN (SELECT u.intern"
                            + "           FROM mld_v_uitvoerende u"
                            + "          WHERE u.mld_uitvoerende_key = o.mld_uitvoerende_keys) = 1"
                            + "   THEN"
                            + "     'BI'"
                            + "   ELSE"
                            + "     'BE'"
                            + "   END"
                            + " ELSE"
                            + "   'PI'"
                            + " END"
              var whereUs = ""; // straks voor de statussen
              var sql = "SELECT o.mld_melding_key"
                      + "     , o.mld_opdr_bedrijfopdr_volgnr"
                      + "     , o.mld_opdr_id"
                      + "     , o.mld_opdr_einddatum"
                      + "     , (SELECT on1.mld_opdr_note_omschrijving"
                      + "          FROM mld_opdr_note on1"
                      + "         WHERE on1.mld_opdr_key = o.mld_opdr_key"
                      + "           AND on1.mld_opdr_note_key = (SELECT MAX (on2.mld_opdr_note_key)"
                      + "                                          FROM mld_opdr_note on2"
                      + "                                         WHERE on2.mld_opdr_key = o.mld_opdr_key"
                      + (exhandler
                        ? "                                         AND BITAND(on2.mld_opdr_note_flag, 4) = 4"
                        : "")
                      + "                                       )"
                      + "       ) notitie"
                      + "     , (SELECT MAX(on3.mld_opdr_note_aanmaak)"
                      + "          FROM mld_opdr_note on3"
                      + "         WHERE on3.mld_opdr_key = o.mld_opdr_key"
                      + (exhandler
                        ? "         AND BITAND(on3.mld_opdr_note_flag, 4) = 4"
                        : "")
                      + "       ) notitiedatum"
                      + "     , l.alg_locatie_code "
                        + "     || COALESCE((SELECT '-' || v.alg_plaatsaanduiding || DECODE(v.alg_plaatsomschrijving, '','' , ' (' || v.alg_plaatsomschrijving || ')')"
                        + "                    FROM alg_v_allonrgoed_gegevens v"
                        + "                   WHERE m.mld_alg_onroerendgoed_keys = v.alg_onroerendgoed_keys"
                        + "                ), COALESCE(l.alg_locatie_omschrijving, ' ', ' (' || l.alg_locatie_omschrijving || ')')) plaatsmelding"
                      + "     , l.alg_locatie_adres"
                      + "     , l.alg_locatie_plaats"
                      + "     , l.alg_locatie_postcode"
                      + (S("mld_print_loc_address") == 2   // onverwachts, wegwerken hier?
                        ? "   , (SELECT geg.alg_gebouw_naam"
                          + "      FROM alg_v_allonrgoed_gegevens geg"
                          + "     WHERE geg.alg_onroerendgoed_keys = m.mld_alg_onroerendgoed_keys) alg_gebouw_naam"
                        : "")
                      + "     , di.alg_district_omschrijving"
                      + "     , (SELECT u.naam FROM mld_v_uitvoerende u WHERE U.mld_uitvoerende_key = O.mld_uitvoerende_keys) uitv_naam"
                      + "     , o.mld_uitvoerende_keys uitv_key"
                      + "     , o.prs_perslid_key"
                      + "     , (SELECT pf.prs_perslid_naam_friendly FROM prs_v_perslid_fullnames_all pf "
                        + "       WHERE pf.prs_perslid_key = o.prs_perslid_key) behandelaar"
                      + "     , (SELECT COALESCE(pf.prs_perslid_naam_friendly"
                        + "                     , DECODE (cp.prs_contactpersoon_voornaam, NULL, '', cp.prs_contactpersoon_voornaam || ' ')"
                        + "                    || DECODE (cp.prs_contactpersoon_tussenv,  NULL, '', cp.prs_contactpersoon_tussenv  || ' ')"
                        + "                    || cp.prs_contactpersoon_naam" //  contactpersoon_friendly
                        + "                     ) contactpersoon"
                        + "        FROM prs_v_perslid_fullnames_all pf"
                        + "           , prs_contactpersoon cp"
                        + "       WHERE cp.prs_perslid_key = pf.prs_perslid_key(+)"
                        + "         AND cp.prs_contactpersoon_key = o.prs_contactpersoon_key) contactpersoon"
                  + "     , (SELECT " + S("prs_kpn_string")
                        + "        FROM prs_kostenplaats k"
                        + "       WHERE k.prs_kostenplaats_key = o.prs_kostenplaats_key) kpstring"
                      + "     , o.mld_opdr_key"
                      + "     , o.mld_opdr_flag"
                      + "     , o.mld_opdr_actiecode"
                      + "     , c.cnt_contract_key"
                      + "     , c.cnt_contract_nummer"
                      + "     , c.cnt_contract_nummer_intern"
                      + "     , c.cnt_contract_versie"
                      + "     , o.mld_opdr_datumbegin"
                      + "     , o.mld_opdr_plandatum"
                      + "     , o.mld_opdr_plandatum2"
                      + "     , " + lcl.xsqla('t.mld_typeopdr_omschrijving', 't.mld_typeopdr_key')
                      + "     , t.mld_typeopdr_decentraal"
                      + "     , t.mld_typeopdr_afmelden_extern"
                      + "     , sd.ins_srtdiscipline_prefix"
                      + "     , sd.ins_srtdiscipline_omschrijving"
                      + "     , " + lcl.xsqla('std.mld_stdmelding_omschrijving','std.mld_stdmelding_key')
                      + "     , smg.mld_stdmeldinggroep_naam"
                      + "     , " + S("prs_pers_string") + " melder"
                      + "     , SYSDATE nu"
                      + "     , o.mld_opdr_kosten"
                      + (urole == 'mi' || true  // kan slimmer met ORDLST_INVOICED? relatief duur
                        ? "   , COALESCE((SELECT SUM(f.fin_factuur_totaal)"
                          + "               FROM fin_factuur f"
                          + "              WHERE f.mld_opdr_key = o.mld_opdr_key "
                          + "                AND f.fin_factuur_statuses_key <> 1"
                          + "                AND f.fin_factuur_verwijder IS NULL), 0) gefactureerd"
                        : "")
                      + "     , o.mld_opdr_uren"
                      + "     , o.mld_opdr_materiaal"
                      + "     , o.mld_opdr_uurloon"
                      + "     , COALESCE(o.mld_opdr_kosten, 0) - ((COALESCE(mld_opdr_uren, 0) * COALESCE(mld_opdr_uurloon, 0)) + COALESCE(mld_opdr_materiaal, 0)) correctie"
                      + (includeHours
                        ? "   , (SELECT COALESCE(SUM(mld_opdr_uren_besteed), 0)"
                        + "        FROM mld_opdr_uren"
                        + "       WHERE mld_opdr_key = o.mld_opdr_key) mld_opdr_uren_besteed"
                        : "")
                      + "     , o.mld_opdr_opmerking"
                      + "     , (SELECT " + S("prs_pers_string")
                        + "        FROM prs_perslid p"
                        + "       WHERE p.prs_perslid_key = m.prs_perslid_key_voor) aanvrager"
                      + "     , COALESCE((SELECT 'B'"
                      + "                  FROM prs_bedrijf"
                      + "                  WHERE prs_bedrijf_key = o.mld_uitvoerende_keys)"
                      + "              , (SELECT 'P'"
                      + "                  FROM prs_perslid"
                      + "                  WHERE prs_perslid_key = o.mld_uitvoerende_keys)) B_OF_P"
                      + "     , " + uitv_type + " uitv_type"
                      + "     , CASE"
                      + "       WHEN COALESCE ( (SELECT 'B'"
                      + "                          FROM prs_bedrijf"
                      + "                         WHERE prs_bedrijf_key = o.mld_uitvoerende_keys)"
                      + "                     , (SELECT 'P'"
                      + "                          FROM prs_perslid"
                      + "                         WHERE prs_perslid_key = o.mld_uitvoerende_keys)) = 'B'"
                      + "       THEN"
                      + "         CASE"
                      + "         WHEN (SELECT u.intern"
                      + "                 FROM mld_v_uitvoerende u"
                      + "                WHERE u.mld_uitvoerende_key = o.mld_uitvoerende_keys) = 1"
                      + "         THEN"
                      + "           1"
                      + "         ELSE"
                      + "           3"
                      + "         END"
                      + "       ELSE"
                      + "         2"
                      + "       END uitv_type_order"
                      + "     , m.mld_melding_spoed"
                      + "     , m.mld_melding_acceptdatum_std"
                      + "     , m.mld_melding_einddatum_std"
                      + "     , m.mld_melding_status"
                      + "     , m.mld_melding_einddatum"
                      + "     , std.mld_stdmelding_slabewaken"
                      + "     , m.mld_melding_indult"
                      + "     , m.mld_melding_parentkey"
                      + "     , (SELECT COUNT(o1.mld_opdr_key)"
                        + "        FROM mld_opdr o1"
                        + "       WHERE o1.mld_melding_key = m.mld_melding_key) nrOrders"
                      + "     , (SELECT COUNT(o2.mld_statusopdr_key)"
                        + "        FROM mld_opdr o2"
                        + "       WHERE o2.mld_melding_key = m.mld_melding_key"
                        + "         AND o2.mld_statusopdr_key NOT IN (1, 2, 6, 7, 9)) nrActief"
                      + "     , o.mld_opdr_omschrijving"
                      + "     , o.mld_statusopdr_key"
                      + "     , o.mld_opdr_verzonden"
                      + "     , t.mld_typeopdr_key" // Voor flexGroupId
                      + "     , " + lcl.xsqla('md.ins_discipline_omschrijving', 'md.ins_discipline_key')
                      + "     , (SELECT prs_perslid_naam_full"
                      + "          FROM prs_v_perslid_fullnames_all"
                      + "         WHERE prs_perslid_key = prs.getFiatteur(o.prs_kostenplaats_key"
                      + (S("mld_opdr_reapproval_rate") >= 0
                        ? "                                             , -1"
                        : "                                             , CASE"
                          + "                                             WHEN o.mld_opdr_fiatbedrag IS NULL"
                          + "                                             THEN NULL"
                          + "                                             ELSE fac.gettrackinguserkey('ORDFOK', o.mld_opdr_key)"
                          + "                                             END")
                      + "                                               , o.mld_opdr_kosten"
                      + "                                               , o.mld_opdr_discipline_key"
                      + "                                               , COALESCE(o.mld_opdr_fiatbedrag, 0))) fiatteur"
                      + "     , (SELECT COUNT (o.mld_opdr_key)"
                      + "          FROM mld_opdr o  "
                      + "         WHERE o.mld_melding_key = mld_melding_key"
                      + "           AND o.fac_activiteit_key IS NOT NULL) opdr_action"
                      + "     , m.fac_activiteit_key mld_action"
                      + "     , t.mld_typeopdr_kosten"
                      + "     , t.mld_typeopdr_isofferte"
                      + "     , t.mld_typeopdr_uren"
                      + "     , t.mld_typeopdr_materiaal"
                      + "     , t.mld_typeopdr_totaal"
                      + "     , t.mld_typeopdr_factuur"
                      + "     , t.mld_typeopdr_kosten_verplicht"
                      + "     , t.mld_typeopdr_accept"
                      + "     , mdp.mld_disc_params_opdr_kosten"
                      + "     , (SELECT GREATEST( (SELECT COALESCE(MAX(t.fac_tracking_datum), TO_DATE('01-01-1970','dd-mm-yyyy'))"
                        + "                          FROM fac_tracking t"
                        + "                             , fac_srtnotificatie st"
                        + "                         WHERE t.fac_srtnotificatie_key = st.fac_srtnotificatie_key"
                        + "                           AND st.fac_srtnotificatie_code = 'ORDUPD'"
                        + "                           AND st.fac_srtnotificatie_xmlnode = 'opdracht'"
                        + "                           AND t.fac_tracking_refkey = ro.mld_opdr_key"
                        + "                       )"
                        + "                     , (SELECT COALESCE(MAX(n.mld_opdr_note_aanmaak), TO_DATE('01-01-1970','dd-mm-yyyy'))"
                        + "                          FROM mld_opdr_note n"
                        + "                         WHERE n.mld_opdr_key = ro.mld_opdr_key"
                        + "                        )"
                        + "                     ) lasttracknote"
                        + "        FROM mld_opdr ro"
                        + "       WHERE ro.mld_opdr_key = o.mld_opdr_key) mld_opdr_laatstgewijzigd"
                      + "     , o.mld_opdr_laatstgezien"
                      + sqltrack
                      + "     , m.mld_melding_t_respijt.tijdsduur tijdsduur"
                      + "     , m.mld_melding_t_respijt.eenheid eenheid"
                      + "     , std.mld_stdmelding_key"
                      + "     , (SELECT COUNT(f.fin_factuur_key)"
                        + "        FROM fin_factuur f"
                        + "       WHERE f.mld_opdr_key = o.mld_opdr_key"
                        + "         AND f.fin_factuur_verwijder IS NULL) aantal_facturen"
                      + (!internuit || !externuit
                        ? "   , mu.intern"
                        : "")
                      + (params.anyflex
                         ? ", (SELECT LISTAGG("
                            + (params.multiflex ? "COALESCE (" + lcl.xsql("k.mld_kenmerk_omschrijving", "k.mld_kenmerk_key")
                                  + "                      , " + lcl.xsql("skm.mld_srtkenmerk_omschrijving", "skm.mld_srtkenmerk_key") + ")"
                                  + " || ':'|| CHR(160) ||"
                                : "")
                            + "            CASE"
                            + "            WHEN skm.mld_srtkenmerk_kenmerktype = 'R' OR skm.mld_srtkenmerk_kenmerktype = 'r' OR skm.mld_srtkenmerk_kenmerktype = 'S'"
                            + "            THEN flx.getdomeinwaarde (skm.fac_kenmerkdomein_key, km.mld_kenmerkopdr_waarde)"
                            + "            WHEN skm.mld_srtkenmerk_kenmerktype = 'N'"
                            + "             AND skm.mld_srtkenmerk_lengte = 1 "
                            + "             AND skm.mld_srtkenmerk_nmin = 0 "
                            + "             AND skm.mld_srtkenmerk_nmax = 1 "
                            + "             AND (skm.mld_srtkenmerk_dec = 0 OR skm.mld_srtkenmerk_dec IS NULL) "
                            + "            THEN DECODE (km.mld_kenmerkopdr_waarde, "
                            + "                         0, "+safe.qL("lcl_check_0")+", "
                            + "                         1, "+safe.qL("lcl_check_1")+", "
                            + "                         km.mld_kenmerkopdr_waarde)"
                            + "            ELSE km.mld_kenmerkopdr_waarde"
                            + "            END, CHR(13)) "
                            + "           WITHIN GROUP (ORDER BY mld_kenmerk_volgnummer) "
                            + "  FROM mld_srtkenmerk skm,  mld_kenmerk k, mld_kenmerkopdr km"
                            + " WHERE km.mld_opdr_key = o.mld_opdr_key"
                            + "   AND k.mld_kenmerk_key = km.mld_kenmerk_key"
                            + "   AND BITAND(k.mld_kenmerk_inlijst,1) = 1"
                            + "   AND BITAND(skm.mld_srtkenmerk_systeem,4) = 0"  // niet als vertrouwelijk
                            + "   AND skm.mld_srtkenmerk_key = k.mld_srtkenmerk_key"
                            + "   AND skm.mld_srtkenmerk_verwijder IS NULL"
                            + "   AND k.mld_kenmerk_verwijder IS NULL"
                            + "   AND km.mld_kenmerkopdr_verwijder IS NULL) flex"
                        : "")
                      + (params.anyins
                          ? ", (SELECT LISTAGG ( "
                            + "            s.ins_srtdeel_omschrijving "
                            + "            || ' ' "
                            + "            || ins_deel_omschrijving, "
                            + "            '{0}') "
                            + "            WITHIN GROUP (ORDER BY ins_deel_omschrijving) "
                            + "            deel "
                            + "   FROM ins_v_aanwezigdeel d, ins_srtdeel s, mld_melding_object mo "
                            + "  WHERE mo.mld_melding_key = m.mld_melding_key "
                            + "    AND d.ins_deel_key = mo.ins_deel_key "
                            + "    AND d.ins_srtdeel_key = s.ins_srtdeel_key "
                            + "    AND ROWNUM <= 20) object"
                            + ", (SELECT COUNT (1) "
                            + "     FROM ins_v_aanwezigdeel d, ins_srtdeel s, mld_melding_object mo "
                            + "    WHERE mo.mld_melding_key = m.mld_melding_key "
                            + "      AND d.ins_deel_key = mo.ins_deel_key "
                            + "      AND d.ins_srtdeel_key = s.ins_srtdeel_key) objCount"
                        : "")
                      + "  FROM mld_opdr o"
                      + "     , cnt_v_aanwezigcontract c"
                      + "     , mld_stdmelding std"
                      + "     , mld_stdmeldinggroep smg"
                      + "     , mld_melding m"
                      + "     , prs_kostenplaats kp"
                      + "     , prs_kostenplaatsgrp kpg"
                      + (bld_key_arr.length || flr_key_arr.length || room_key_arr.length || bld_scope || verantw_key
                        ? "   , alg_v_allonrgoed_gegevens g"
                        : "")
                      + "     , alg_locatie l"
                      + (verantw_key ? ", alg_gebouw gg, alg_terreinsector gt" : "")
                      + "     , alg_district di"
                      + "     , mld_discipline md"
                      + "     , mld_disc_params mdp"
                      + "     , ins_srtdiscipline sd"
                      + (add_prs_restrict_ord || add_prs_restrict_mld
                        ? "   ,    prs_v_afdeling_boom b"
                        : "")
                      // and more here
                      + "     , mld_typeopdr t"
                      + "     , prs_perslid p" // de melder
                      + (!internuit || !externuit
                        ? "   , mld_v_uitvoerende mu"
                        : "")
                      + " WHERE o.mld_melding_key = m.mld_melding_key" + (urole == 'bgt' ? '(+)' : '')
                      + "   AND m.mld_alg_locatie_key = l.alg_locatie_key(+)"
                      + "   AND l.alg_district_key = di.alg_district_key(+)"
                      + "   AND std.mld_ins_discipline_key = md.ins_discipline_key" + (urole == 'bgt' ? '(+)' : '')
                      + "   AND md.ins_discipline_key = mdp.mld_ins_discipline_key" + (urole == 'bgt' ? '(+)' : '')
                      + "   AND smg.mld_stdmeldinggroep_key(+) = std.mld_stdmeldinggroep_key"
                      + "   AND kp.prs_kostenplaats_key(+) = o.prs_kostenplaats_key"
                      + "   AND kpg.prs_kostenplaatsgrp_key(+) = kp.prs_kostenplaatsgrp_key"
                      + (params.act_key == -1 ? "   AND o.fac_activiteit_key IS NULL" : "")
                      + (contactpersoon_key > 0 ? "  AND o.prs_contactpersoon_key = " + contactpersoon_key : "")
                      + "   AND o.cnt_contract_key = c.cnt_contract_key(+)"
                      + "   AND m.mld_stdmelding_key = std.mld_stdmelding_key" + (urole == 'bgt' ? '(+)' : '')
                      + "   AND m.prs_perslid_key = p.prs_perslid_key"+ (urole == 'bgt' ? '(+)' : '')
                      + "   AND md.ins_srtdiscipline_key = sd.ins_srtdiscipline_key" + (urole == 'bgt' ? '(+)' : '')
                      + "   AND o.mld_typeopdr_key = t.mld_typeopdr_key";

              if (chkRunEx)
                 sql += " AND std.mld_stdmelding_planbaar NOT IN (2, 6)" // Einddatum NIET Onzichtbaar: 2 en 2+4(actiedatum)=6.

              if (add_prs_restrict_ord || add_prs_restrict_mld)
                sql += " AND b.prs_afdeling_key = COALESCE(m.prs_afdeling_key, p.prs_afdeling_key)";

              if (bld_key_arr.length || bld_scope || verantw_key)
                sql += " AND m.mld_alg_onroerendgoed_keys = g.alg_onroerendgoed_keys(+)";

              if (verantw_key)
                sql += " AND g.alg_gebouw_key = gg.alg_gebouw_key(+)"
                     + " AND g.alg_terreinsector_key = gt.alg_terreinsector_key(+)";

              if (urole == 'b2')
                sql += " AND (o.mld_statusopdr_key NOT IN (3, 10) OR o.mld_statusopdr_key_refiat IS NOT NULL)"

              if (frontend && mld_key)
                sql += " AND t.mld_typeopdr_zichtbaarfe = 1";

              if (opdr_actiecode_att === true) { // Attentie bitje is rol-specifiek
                sql += " AND BITAND(o.mld_opdr_actiecode, " + (exhandler ? "512) = 512" : "128) = 128");
              }

              if (opdr_actiecode_bitor > 0)
                sql += " AND BITAND(o.mld_opdr_actiecode, " + (opdr_actiecode_bitor & 127) + ") > 0";

              if (!params.isTemplate)
                sql += " AND NOT EXISTS"
                     + " (SELECT 1 FROM fac_activiteit f"
                     + "   WHERE f.fac_activiteit_key = o.fac_activiteit_key"
                     + "     AND f.fac_activiteit_eenheid = 5"
                     + " )";

              if (params.flags && params.flags.length > 0 && params.flags.length < S("mld_opdracht_flags"))
              {
                var filterNull = false;

                for (var i = 0; i < params.flags.length; i++)
                {
                 if (params.flags[i] === 0)
                   filterNull = true;
                }

                sql += " AND (o.mld_opdr_flag IN (" + params.flags.join(",") + ")";
                if (filterNull)
                  sql += " OR o.mld_opdr_flag IS NULL";
                sql += ")";
              }

              if (mld_key)
              {
                sql += " AND o.mld_melding_key = " + mld_key;
              }
              else if (opdr_key)
              {
                sql += " AND o.mld_melding_key = " + opdr_key; // opdracht nummer is voor de gebruiker hetzelfde als mld_key
              }
              else if (opdr_id)
              {
                sql += " AND UPPER(o.mld_opdr_id) = " + safe.quoted_sql_upper(opdr_id);
              }
              else if (intopdr_key)
              {
                sql += " AND o.mld_opdr_key = " + intopdr_key; // de echte opdrachtkey
              }
              else
              { //
                if (offerte >= 0)
                  sql += " AND t.mld_typeopdr_isofferte = " + offerte;

                // --------- De statussen ------
                // Meldingstatus
                if ((mldstatus_arr.length > 1) || ((mldstatus_arr.length == 1) && (mldstatus_arr[0] != -1)))
                {
                  mldstatus_arr = mldstatus_arr.join(",");
                }
                else
                {
                  mldstatus_arr = showstatus;
                }
                var sql_status = mld.getStatusSql(mldstatus_arr, "m");
                if (sql_status)
                  sql += " AND" + sql_status;
                // Opdrachtstatus
                if ((opdrstatus_arr.length > 1) || ((opdrstatus_arr.length == 1) && (opdrstatus_arr[0] != -1)))
                {
                  sql += " AND o.mld_statusopdr_key IN (" + opdrstatus_arr.join(",") + ")";
                } else {
                    if (showopdrstatus != "")
                        sql += " AND o.mld_statusopdr_key IN (" + showopdrstatus + ")";
                }
                // Spoed
                if (chkSpoed)
                  sql += " AND m.mld_melding_spoed < 3";
                // Afgerond
                if (chkAfgerond)
                  sql += " AND m.mld_melding_afgerond = 1";

                // Actie/door
                sql += mld.getwhereSrttracking(params);
                sql += mld.getwherePrstracking(params);
                //
                // Overschrijding acceptatietijd
                if (chkAcceptEx)
                {
                  whereUs += " WHERE " + mld.getwhere_to_late_accept_sql("us") + " = 1";
                }
                // Overschijding doorlooptijd
                if (chkRunEx)
                {
                  var whereT = mld.getwhere_to_late_run_sql("us", "us", "O") + " = 1";
                  if (whereUs.length > 0)
                    whereUs += " AND " + whereT;
                  else
                    whereUs = " WHERE " + whereT;
                }

                if (S("mld_max_history") > 0 && (mldopdrstafm || mldopdrstver)) // was alleen als je in de history keek
                  sql += " AND (o.mld_opdr_datumbegin >= SYSDATE - " + S("mld_max_history") + ")";

                // Hier wordt gezocht in de omschrijving, opmerking en de eventuele (tekst-)kenmerken
                // Dit is een potentieel en onvermijdelijk dure zoekactie.
                // Conform meldingen
                if (searchtekst)
                  sql += " AND (UPPER(mld_opdr_omschrijving) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%")
                       + " OR UPPER(mld_opdr_opmerking) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%")
                       + " OR UPPER(mld_opdr_id) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%")
                            +  " OR EXISTS (SELECT mld_opdr_key"
                            +  "              FROM mld_kenmerkopdr ko"
                            +  "             WHERE ko.mld_opdr_key = o.mld_opdr_key"
                            +  "               AND ko.mld_kenmerkopdr_verwijder IS NULL"
                            +  "               AND UPPER(ko.mld_kenmerkopdr_waarde) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%") + "))";

                if (room_key_arr.length)
                  sql += " AND g.alg_ruimte_key IN (" + room_key_arr.join(",") + ")";
                else if (flr_key_arr.length)
                  sql += " AND g.alg_verdieping_key IN (" + flr_key_arr.join(",") + ")";
                else if (bld_key_arr.length)
                  sql += " AND (g.alg_gebouw_key IN (" + bld_key_arr.join(",") + ") OR g.alg_terreinsector_key IN (" + bld_key_arr.join(",") + "))";
                else if (loc_key_arr.length)
                  sql += " AND m.mld_alg_locatie_key IN (" + loc_key_arr.join(",") + ")";
                else if (dist_key_arr.length)
                  sql +=  " AND di.alg_district_key IN (" + dist_key_arr.join(",") + ")";
                else if (reg_key_arr.length)
                  sql +=  " AND di.alg_regio_key IN (" + reg_key_arr.join(",") + ")";

                if (adr_key)
                { // opdrachten van een bepaald afleveradres
                  sql += " AND m.mld_adres_key = " + adr_key;
                }

                if (ks_key)
                  sql += " AND o.prs_kostensoort_key = " + ks_key;  // nog ff geen array dus

                if (kp_key_arr.length)
                  sql += " AND o.prs_kostenplaats_key IN (" + kp_key_arr.join(",") + ")";

                if (tag_key_arr.length)
                {
                  sqln += " AND (m.mld_melding_tag_key IN (" + tag_key_arr.join(",")+ ")"
                        + (inArray(-2, tag_key_arr) ? " OR m.mld_melding_tag_key IS NULL)" : ")");
                }
                if (org_key)
                  sql += " AND COALESCE(m.prs_afdeling_key, p.prs_afdeling_key) IN"
                       + " (SELECT a.prs_afdeling_key"
                       + " FROM prs_v_afdeling_familie a"
                       + " WHERE a.prs_afdeling_elder_key = " + org_key + ")";

                if (verantw_key)
                  sql += " AND (  gg.prs_perslid_key_verantw = "  + verantw_key
                       + "     OR gg.prs_perslid_key_verantw2 = " + verantw_key
                       + "     OR gt.prs_perslid_key_verantw = "  + verantw_key
                       + "     OR gt.prs_perslid_key_verantw2 = " + verantw_key
                       + "     )";

                if (caller_key)
                  sql += " AND m.prs_perslid_key = " + caller_key;

                // Opdracht Behandelaar/Uitvoerende (beide)
                if (uitvopdr_key)
                  sql += " AND (o.prs_perslid_key = " + uitvopdr_key + " OR (o.prs_perslid_key IS NULL AND (" + uitv_type + ") = 'BI'))";

                if (opdr_behandel_key_arr.length)
                  // Niet toegewezen (prs_perslid_key IS NULL) opdrachten van het opdrachttype Bedrijf Intern (BI) moeten ook getoond worden.
                  sql += " AND (o.prs_perslid_key IN (" + opdr_behandel_key_arr.join(",") + ") OR (o.prs_perslid_key IS NULL AND (" + uitv_type + ") = 'BI'))";

                // MLD Behandelaar
                if (behandel_key)
                  sql += " AND m.mld_melding_behandelaar_key = " + behandel_key;

                if (behandel_key_arr.length)
                  sql += " AND m.mld_melding_behandelaar_key IN (" + behandel_key_arr.join(",") + ")";

                if (behandel2_key_arr.length)
                  sql += " AND m.mld_melding_behandelaar2_key IN (" + behandel2_key_arr.join(",") + ")";

                if (opdrtype_key)
                  sql += " AND o.mld_typeopdr_key = " + opdrtype_key;

                // Soort melding, productgroep, melding (stdmelding), meldinggroep
                if (stdm_key_arr.length || meldinggrp_key)
                {
                  if (stdm_key_arr.length)
                    sql += " AND m.mld_stdmelding_key IN (" + stdm_key_arr.join(",") + ")";
                  if (meldinggrp_key)
                    sql += " AND std.mld_stdmeldinggroep_key IN (" + meldinggrp_key + ")";
                }
                else if (disc_key_arr.length)
                  sql += " AND std.mld_ins_discipline_key IN (" + disc_key_arr.join(",") + ")" ;
                else if (srtdisc_key_arr.length)
                  sql += " AND sd.ins_srtdiscipline_key IN (" + srtdisc_key_arr.join(",") + ") ";

                 // Behandelgroep
                if (behandelgrp_key)
                  sql += " AND mdp.mld_behandelgroep_key = " + behandelgrp_key;

                // Prioriteit
                if (priority_arr.length)
                {
                    sql += " AND m.mld_melding_spoed IN (" + priority_arr.join(",") + ")";
                }

                if (cnt_key)
                  sql += " AND o.cnt_contract_key IN (" +  cnt_key + ")";

                if (bes)
                  sql += " AND sd.ins_srtdiscipline_bes = 1";

                if (startdatefrom)
                { // Startdatum van.
                  if (planb)
                    sql += " AND (COALESCE(o.mld_opdr_plandatum, o.mld_opdr_datumbegin) IS NULL OR COALESCE(o.mld_opdr_plandatum, o.mld_opdr_datumbegin) >= " + startdatefrom.beginToSQL() + ")";
                  else
                    sql += " AND o.mld_opdr_datumbegin >= " + startdatefrom.beginToSQL();
                }

                if (startdateto)
                { // Startdatum t/m.
                  if (planb)
                    sql += " AND (COALESCE(o.mld_opdr_plandatum, o.mld_opdr_datumbegin) IS NULL OR COALESCE(o.mld_opdr_plandatum, o.mld_opdr_datumbegin) <= " + startdateto.endToSQL() + ")";
                  else
                    sql += " AND o.mld_opdr_datumbegin <= " + startdateto.endToSQL();
                }

                if (enddatefrom)
                { // Einddatum van.
                  if (planb)
                    sql += " AND (COALESCE(o.mld_opdr_plandatum2, o.mld_opdr_einddatum) IS NULL OR COALESCE(o.mld_opdr_plandatum2, o.mld_opdr_einddatum) >= " + enddatefrom.beginToSQL() + ")";
                  else
                    sql += " AND o.mld_opdr_einddatum >= " + enddatefrom.beginToSQL();
                }

                if (enddateto)
                { // Einddatum t/m.
                  if (planb)
                    sql += " AND (COALESCE(o.mld_opdr_plandatum2, o.mld_opdr_einddatum) IS NULL OR COALESCE(o.mld_opdr_plandatum2, o.mld_opdr_einddatum) <= " + enddateto.endToSQL() + ")";
                  else
                    sql += " AND o.mld_opdr_einddatum <= " + enddateto.endToSQL();
                }

                if (plandatefrom)
                { // geplande aanvangsdatum van.
                  if (!planb)
                    sql += " AND o.mld_opdr_plandatum >= " + plandatefrom.beginToSQL();
                }

                if (plandateto)
                { // geplande aanvangsdatum t/m.
                  if (!planb)
                    sql += " AND o.mld_opdr_plandatum <= " + plandateto.endToSQL();
                }

                if (offerte >= 0)
                  sql += " AND t.mld_typeopdr_isofferte = " + offerte;

                if (opdr_bedrag_boven != null)
                  sql += " AND o.mld_opdr_kosten >= " + opdr_bedrag_boven;
                if (opdr_bedrag_onder != null)
                  sql += " AND o.mld_opdr_kosten <= " + opdr_bedrag_onder;
              }

              if (opdr_parent_key)
              {
                sql += " AND o.mld_opdr_parent_key = " + opdr_parent_key;
              }
              // Als ik uitvoerder ben dan mag ik de aan mij toegekende opdrachten zien.
              if (uitvoerder)
              { // Ben ik misschien nog plaatsvervanger
                var prsKeys = user.collegakeylist();
                sql += " AND o.mld_uitvoerende_keys IN (" + prsKeys + ")";
              }

              // Een afmelder (EXTORD of ORDBO2) mag externe opdrachten zien/afmelden onder bepaalde voorwaarden:
              // EXTORD: Hij mag opdrachten zien/afmelden van externe bedrijven waar hij contactpersoon van is,
              //         als hij ALG read/write rechten (WEB_EXTORD) heeft op de plaats van de bijbehorende melding van de opdracht.
              // ORDBO2: Setting mld_typeopdr_afmelden_extern: Afmelder (ORDBO2) mag externe opdrachten (0=Niet zien, 1=Zien, 2=Afmelden)
              //         Als hij een interne (decentraal/intern) uitvoerder is mag hij de externe opdrachten niet zien/afmelden als mld_typeopdr_afmelden_extern==0/(0 of 1).
              //         De voorwaarde en setting geldt niet als:
              //         1) de opdracht toegekend is aan een (intern) persoon (P). Dan mag hij alleen eigen opdrachten zien.
              //         2) de opdracht toegekend is aan het eigen (intern) bedrijf (BI). Opdrachten van het eigen bedrijf mag hij alleen zien.
              var sql_EXTORD = " AND EXISTS (SELECT 'X' " // Ben ik contactpersoon van het uitvoerende externe bedrijf
                             + "               FROM prs_contactpersoon"
                             + "              WHERE prs_perslid_key = " + user_key
                             + "                AND prs_contactpersoon_verwijder IS NULL"
                             + "                AND prs_bedrijf_key = o.mld_uitvoerende_keys)";

              var sql_ORDBO2 = " AND (mld_typeopdr_afmelden_extern IN (1, 2)"
                             + "         OR EXISTS (SELECT 'X'" // Toegekend aan een intern persoon (P).
                             + "                      FROM prs_perslid"
                             + "                     WHERE prs_perslid_key = o.mld_uitvoerende_keys)"
                             + "         OR EXISTS (SELECT 'X'" // Toegekend aan het EIGEN interne bedrijf (B).
                             + "                      FROM prs_bedrijf b"
                             + "                         , prs_perslid p"
                             + "                         , prs_v_afdeling a"
                             + "                     WHERE b.prs_bedrijf_key = a.prs_bedrijf_key"
                             + "                       AND p.prs_afdeling_key = a.prs_afdeling_key"
                             + "                       AND b.prs_bedrijf_intern = 1"
                             + "                       AND b.prs_bedrijf_key = o.mld_uitvoerende_keys"
                             + "                       AND p.prs_perslid_key = " + user_key + ")"
                             + "     )";

              // Hier zijn nu alle meegegeven condities verwerkt, dat is:
              // Ofwel het nummer, ofwel de andere criteria.
              // We weten echter ook dat uitvoerende kan worden gehanteerd als een soort autorisatie
              // dus moeten we die ook checken, zelfs als er een nummer werd opgegeven.
              // De 3D autorisatie komt daar nog eens overheen.
              if (handler_key)
                sql = sql + " AND o.mld_uitvoerende_keys = " + handler_key;

              if (!internuit || !externuit)
              {
                sql += " AND o.mld_uitvoerende_keys = mu.mld_uitvoerende_key"
                     + " AND mu.intern = " + (internuit? "1" : "0");
              }

              if (!opdrplanned || !opdrunplanned)
              {
                // er moet wat uitgesloten worden
                sql += " AND mld_opdr_plandatum " + (opdrplanned ? "IS NOT NULL" :  "IS NULL");
              }

              var method = String(Request.ServerVariables("REQUEST_METHOD"));
              if (!mld_key)
                sql += getKenmerkSql("OPD", "o.mld_opdr_key", method == "POST");

              var sqlA = sql;
              if (from_mld)
              { // Dan moeten we het opdracht overzicht tonen voor het meldingen backoffice overzicht "Afhandelen Meldingen".
                // Dan wil ik alleen die opdrachten zien van de meldingen waar ik rechten voor heb. Dan moet ik WEB_MLDBOF rechten hebben voor de meldingen
                // apply 3D authorization to the locations and to the organisations (both ALG and PRS)
                sqlA = discx3d (sql,
                                "md.ins_discipline_key", // JGL: MLDBOF moet geen mld_opdr_discipline_gebruiken
                                "di.alg_regio_key",
                                "l.alg_district_key",
                                "l.alg_locatie_key",
                                "g.alg_gebouw_key",
                                "g.alg_verdieping_key",
                                "g.alg_ruimte_key",
                                "b.prs_bedrijf_key",
                                "b.prs_afdeling_key",
                                "WEB_MLDBOF",
                                (!mld_key && disc_key_arr.length? disc_key_arr : []),
                                (add_prs_restrict_mld ? 2 : 0));
              }
              // Indien sqlA uit meerdere delen (UNION ALL) bestaat dan al deze delen combineren met de pautfunction rechten.
              sqlA = sqlA.split("UNION ALL");

              if (typeof pautfunction != "object" || !(pautfunction instanceof Array))
                // Maak van de String een Array
                pautfunction = [pautfunction];

              var sqlAB = "";
              if (urole != 'bgt')
              {
                for (var jj = 0; jj < sqlA.length; jj++)
                {
                  // pautfunction is nu altijd een Array met webfuncties
                  for (var ii = 0; ii < pautfunction.length; ii++)
                  {
                    // Voorwaarden die meegenomen moeten worden voor de autorisaties WEB_EXTORD of WEB_ORDBO2:
                    // WEB_EXTORD: sql_EXTORD (Ik ben contactpersoon van externe bedrijf) + 3d autorisatie (ALG).
                    // WEB_ORDBO2: sql_ORDBO2 + 3d autorisatie.
                    var sql3d = sqlA[jj];
                    if (pautfunction[ii] == "WEB_EXTORD")
                      sql3d += sql_EXTORD;
                    else if (pautfunction[ii] == "WEB_ORDBO2")
                      sql3d += sql_ORDBO2;

                    // apply 3D authorization to the locations and to the organisations (both ALG and PRS)
                    // if "disc == 0" or disc is not defined then disc should be ""
                    // otherwise de 3d authorization adds a "AND (1=0)" line to the query and you will have never a result
                    sqlB = (ii > 0? sqlB + " UNION " : "") + discx3d (sql3d,
                                                                      "o.mld_opdr_discipline_key",
                                                                      "di.alg_regio_key",
                                                                      "l.alg_district_key",
                                                                      "l.alg_locatie_key",
                                                                      "g.alg_gebouw_key",
                                                                      "g.alg_verdieping_key",
                                                                      "g.alg_ruimte_key",
                                                                      "b.prs_bedrijf_key",
                                                                      "b.prs_afdeling_key",
                                                                      pautfunction[ii],
                                                                      (!(mld_key || opdr_key) && disc_key_arr.length? disc_key_arr : []),
                                                                      (add_prs_restrict_ord? 2 : 0)
                                                                     );
                  }
                  sqlAB = sqlAB + (jj > 0? " UNION " : "") + sqlB;
                }

                if (pautfunction.length > 1)
                { // We hebben dan rechten van meerdere autorisatie functies. Daardoor kan door discx3d() " UNION ALL " gebruikt worden om verschillende SELECT aan elkaar te plakken.
                  // In dat geval krijgen we dan dubbele resultataten.
                  // We moeten daarom deze UNION ALL's vervangen door UNION's.
                  sqlAB = sqlAB.replace(/UNION ALL/g, "UNION");
                }
                // Voeg laatste tracking datum toe
                sql = "SELECT /*+ CURSOR_SHARING_EXACT OPT_PARAM('optimizer_features_enable','11.2.0.4') */"
                    + "       * FROM (" + sqlAB + ") us"
                    + whereUs
                    + " ORDER BY" // ins_discipline_omschrijving is hier al vertaald
                    + (planb? " uitv_type_order, uitv_naam, behandelaar NULLS FIRST,mld_melding_spoed," : "") // het planbord sorteert clientside trouwens
                    + (excel? " UPPER(ins_discipline_omschrijving), mld_typeopdr_key," : ""); // Flexkenmerken verschillen per opdrachttype (mld_typeopdr_key)

                if (bosort == 1)
                  sql += " mld_melding_key DESC, mld_opdr_key DESC";
                else if (bosort == 2)
                  sql += " recentdatum DESC";
                else
                  sql += " mld_opdr_einddatum, mld_opdr_bedrijfopdr_volgnr";
              }

              return sql;
            },

        getkennisbank_sql:
            function (sqlSelect, sqlFrom, sqlWhere)
            { // Lever kennisbank items overzicht sql op.

               var fsql = "SELECT ff.fac_faq_key, "
                       + "       fac_faq_rank, "
                       + "       fac_faq_datum, "
                       + "       fac_faq_question, "
                       + "       fac_faq_answer,"
                       + "       fac_faq_answer2,"
                       + "       fac_faq_url, "
                       + "       fac_faq_level, "
                       + "       (SELECT COUNT (*)"
                       + "          FROM faq_kenmerk k"
                       + "         WHERE k.faq_kenmerk_verwijder IS NULL"
                       + "            OR k.faq_kenmerk_verwijder > SYSDATE) aantal_kenm"
                       + sqlSelect
                       + "  FROM fac_faq ff"
                       + sqlFrom
                       + " WHERE fac_faq_datum < SYSDATE"
                       + "   AND (ff.fac_faq_vervaldatum IS NULL OR ff.fac_faq_vervaldatum > SYSDATE)"
                       + "   AND (fac_faq_lang = " + safe.quoted_sql(user_lang) + " OR fac_faq_lang IS NULL)"
                           + " AND (fac_functie_key IS NULL"
                           + "     OR fac_functie_key IN "
                           + "             (SELECT fac_functie_key FROM fac_v_webgebruiker"
                           + "                WHERE prs_perslid_key = " + user_key + "))"
                       + sqlWhere;

                  fsql += " AND (    ff.faq_ins_discipline_key IN "
                        + "             (SELECT ins_discipline_key FROM fac_v_webgebruiker"
                        + "                WHERE prs_perslid_key = " + user_key
                        + "                  AND fac_functie_key = " + F("WEB_FAQBOF") + ")"
                        + "       OR BITAND (fac_faq_level, 2) = 2" // Zichtbaar frontoffice
                        + "          AND ff.faq_ins_discipline_key IN "
                        + "             (SELECT ins_discipline_key FROM fac_v_webgebruiker"
                        + "                WHERE prs_perslid_key = " + user_key
                        + "                  AND fac_functie_key = " + F("WEB_FAQFOF")
                        + "                  AND fac_gebruiker_prs_level_read < 9"
                        + "                  AND fac_gebruiker_alg_level_read < 9" + ")"
                        + "       OR BITAND (fac_faq_level, 1) = 1" // Zichtbaar frontend
                        + "          AND ff.faq_ins_discipline_key IN "
                        + "             (SELECT ins_discipline_key FROM fac_v_webgebruiker"
                        + "                WHERE prs_perslid_key = " + user_key
                        + "                  AND fac_functie_key = " + F("WEB_FAQUSE") + ")"
                        + "     )"

                   return fsql;
            },

        getBoardColumns_sql:
            function (params)
            { // Levert de verticale pilaren
              params = params || {};

              var mresult = user.func_enabled2("MLD", { checkOptimistic: true, isOptional: true });
              var myWriteRoleCode = (mresult.canWrite("WEB_MLDUSE") ? 1 : 0)
                                  + (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBAC") ? 2 : 0)
                                  + (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBAC") ? 4 : 0);

              var scopeWhere = "";
              if (params.stdm_key_arr.length) {
                scopeWhere = "                AND m.mld_stdmelding_key IN (" + params.stdm_key_arr.join(",") + ")";
              } else if (params.disc_key_arr.length) {
                scopeWhere = "                AND d.ins_discipline_key IN (" + params.disc_key_arr.join(",") + ")";
              } else if (params.srtdisc_key_arr.length) {
                scopeWhere = "                AND sd.ins_srtdiscipline_key IN (" + params.srtdisc_key_arr.join(",") + ")";
              }

              var sqls = [];

              var sql_any = "SELECT 1"
                          + "  FROM mld_discipline m, mld_disc_params mdp"
                          + " WHERE     m.ins_discipline_key = mdp.mld_ins_discipline_key"
                          + "       AND m.ins_discipline_verwijder IS NULL"
                          + "       AND BITAND (mdp.mld_disc_params_srtgroep, 1) = 1"
                          + "       AND mld_disc_params_primairbeh <> 0";
              var oRs_any = Oracle.Execute(sql_any);
              if (!oRs_any.EOF) {
                sqls.push("SELECT -2 AS key, lcl.l('lcl_mld_behandelaar') AS descr FROM DUAL"); // (Primaire) behandelaar
              }
              oRs_any.Close();

              sql_any = "SELECT 1"
                      + "  FROM DUAL"
                      + " WHERE EXISTS"
                      + "           (SELECT 1"
                      + "              FROM mld_disc_params dp1, mld_discipline d1"
                      + "             WHERE d1.ins_discipline_key = dp1.mld_ins_discipline_key"
                      + "               AND d1.ins_discipline_verwijder IS NULL"
                      + "               AND BITAND (dp1.mld_disc_params_srtgroep, 2) = 2)" // Is team
                      + "   AND EXISTS"
                      + "           (SELECT 1"
                      + "              FROM mld_disc_params dp2, mld_discipline d2"
                      + "             WHERE d2.ins_discipline_key = dp2.mld_ins_discipline_key"
                      + "               AND d2.ins_discipline_verwijder IS NULL"
                      + "               AND BITAND (dp2.mld_disc_params_srtgroep, 4) = 4)" // Has team
                      + "   AND ROWNUM <= 1";
              oRs_any = Oracle.Execute(sql_any);

              if (!oRs_any.EOF) { // canUseTeams?
                sqls.push("SELECT -3 AS key, lcl.l('mld_processing_group') AS descr FROM DUAL"); // Behandelteam
                sqls.push("SELECT -4 AS key, lcl.l('lcl_mld_processor') AS descr FROM DUAL"); // Actieve behandelaar
              }
              oRs_any.Close();

              var sqlWith = "WITH"
                          + "    meldingen_in_scope" // Alle relevante melding-categorien
                          + "    AS"
                          + "        (SELECT m.mld_stdmelding_key,"
                          + "                d.ins_discipline_key,"
                          + "                sd.ins_srtdiscipline_key"
                          + "           FROM mld_stdmelding  m"
                          + "                JOIN mld_discipline d"
                          + "                    ON m.mld_ins_discipline_key = d.ins_discipline_key"
                          + "                JOIN ins_srtdiscipline sd"
                          + "                    ON d.ins_srtdiscipline_key = sd.ins_srtdiscipline_key"
                          + "          WHERE     m.mld_stdmelding_verwijder IS NULL"
                          + "                AND d.ins_discipline_verwijder IS NULL"
                          + "                AND sd.ins_srtdiscipline_verwijder IS NULL"
                          + scopeWhere
                          + "        ),"
                          + "    auth" // Subselect voor de autorisatie
                          + "    AS"
                          + "        (  SELECT fac_functie_key,"
                          + "                  LEAST (MIN (fac_gebruiker_prs_level_write),"
                          + "                         MIN (fac_gebruiker_alg_level_write))    best_level"
                          + "             FROM fac_v_webgebruiker fw"
                          + "            WHERE fw.prs_perslid_key = " + user_key
                          + "         GROUP BY fac_functie_key),"
                          + "    kenmerk_melding"
                          + "    AS"
                          + "        (SELECT m.mld_stdmelding_key,"
                          + "                k.mld_kenmerk_key,"
                          + "                k.mld_srtkenmerk_key,"
                          + "                COALESCE (k.mld_kenmerk_omschrijving,"
                          + "                          sk.mld_srtkenmerk_omschrijving)    AS naam"
                          + "           FROM meldingen_in_scope  m"
                          + "                JOIN mld_kenmerk k"
                          + "                    ON (   k.mld_kenmerk_niveau = 'A'"
                          + "                        OR (    k.mld_kenmerk_niveau = 'S'"
                          + "                            AND k.mld_stdmelding_key = m.mld_stdmelding_key)"
                          + "                        OR (    k.mld_kenmerk_niveau = 'D'"
                          + "                            AND k.mld_stdmelding_key ="
                          + "                                m.ins_discipline_key)"
                          + "                        OR (    k.mld_kenmerk_niveau = 'T'"
                          + "                            AND k.mld_stdmelding_key ="
                          + "                                m.ins_srtdiscipline_key))"
                          + "                JOIN mld_srtkenmerk sk"
                          + "                    ON k.mld_srtkenmerk_key = sk.mld_srtkenmerk_key"
                          + "                JOIN fac_kenmerkdomein kd"
                          + "                    ON sk.fac_kenmerkdomein_key = kd.fac_kenmerkdomein_key"
                          + "                LEFT OUTER JOIN auth ON auth.fac_functie_key = k.fac_functie_key"
                          + "          WHERE     k.mld_kenmerk_verwijder IS NULL"
                          + "                AND (k.fac_functie_key IS NULL OR auth.best_level <= 5)" // Ik heb een evt. Extra autorisatie
                          + "                AND BITAND(k.mld_kenmerk_rolcode, " + myWriteRoleCode + ") <> 0"
                          + "                AND BITAND(k.mld_kenmerk_inlijst, 2) = 2"
                          + "                AND sk.mld_srtkenmerk_verwijder IS NULL"
                          + "                AND sk.mld_srtkenmerk_kenmerktype IN ('r', 'R', 'S')"
                          + "                AND NOT EXISTS" // Ik -ben- geen parent
                          + "                        (SELECT ''"
                          + "                           FROM fac_usrtab u1"
                          + "                          WHERE     u1.fac_usrtab_parentkey IS NOT NULL"
                          + "                                AND u1.fac_usrtab_key = kd.fac_usrtab_key)"
                          + "                AND NOT EXISTS" // Ik -heb- geen parent
                          + "                        (SELECT ''"
                          + "                           FROM fac_usrtab u1, fac_usrtab u2"
                          + "                          WHERE     u2.fac_usrtab_parentkey = u1.fac_usrtab_key"
                          + "                                AND u2.fac_usrtab_verwijder IS NULL"
                          + "                                AND u1.fac_usrtab_key = kd.fac_usrtab_key)"
                          + "                AND k.mld_kenmerk_show_expr IS NULL"
                          + "                AND kd.fac_kenmerkdomein_verwijder IS NULL),"
                          + "    universele_kenmerk_combi"
                          + "    AS"
                          + "        (  SELECT km.mld_srtkenmerk_key,"
                          + "                  km.naam"
                          + "             FROM kenmerk_melding km"
                          + "         GROUP BY km.mld_srtkenmerk_key, km.naam"
                          + "           HAVING COUNT (DISTINCT km.mld_stdmelding_key) =" // Dit stukje zorgt ervoor dat we alleen de soorten zien die voor alle meldingen in scope gelden
                          + "                  (SELECT COUNT (*) FROM meldingen_in_scope))";

              sqls.push(
                  "SELECT mld_srtkenmerk_key  AS key,"
                + "       naam                AS descr"
                + "  FROM universele_kenmerk_combi"
              );

              return sqlWith + " " + sqls.join(" UNION ALL ");
            }
}
%>
