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

<%
mld = {setmeldingstatus:
           function (mld_key, mld_status_key)
           {
               var sql = "BEGIN mld.setmeldingstatus(" + mld_key + ", " + mld_status_key + ", " + user_key + "); 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
           },

       setopdrachtstatus:
           function (opdr_key, opdr_status_key, uitvoerende)
           {
             // Deze zet de status en doet dan bijpassende tracking en notificatie
             var sql = "BEGIN mld.setopdrachtstatus(" + opdr_key + ", " + opdr_status_key + ", " + user_key + "); END;"
             Oracle.Execute(sql);
             // Nu nog "ORDMLI" (interne uitvoerder) of "ORDMLE" (externe uitvoerder) tracking indien status op uitgegeven (5) wordt gezet
             if (opdr_status_key == 5 && uitvoerende > 0) // Status wordt op 5 gezet indien opdracht niet ter fiattering wordt aangeboden
               mld.trackuitvoerende(opdr_key, uitvoerende);
           },

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

       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"
                 + " 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();
           },

       // 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);
           },


       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") + loRs(0).Value;
               else
                   var behandelaar_str = L("lcl_mld_is_mldbeh_none");
               loRs.close();

               shared.trackaction((nonoti?"#":"") + "MLDBEH", mld_key, behandelaar_str);
           },

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

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

       trackuitvoerende:
           function (opdr_key, uitvoerende)
           {
             // Is uitvoerende intern of extern?
             sql = "SELECT u.intern"
                 + " FROM mld_v_uitvoerende u"
                 + " WHERE u.mld_uitvoerende_key = " + uitvoerende
             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();

             shared.trackaction((intern? "ORDMLI" : "ORDMLE"), opdr_key);
           },

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

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

       saveobjects:
           function (mld_key, obj_arr)
           { // 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();
             }

             // Objecten verwijderen.
             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, ins_deel_key)"
                   + " SELECT " + mld_key
                   + "      , ins_deel_key"
                   + "   FROM ins_v_aanwezigdeel"
                   + "  WHERE 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;");
           },

       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)
           {
               if (S("mld_enable_workflow") == 1) {
                   var sql = "BEGIN mld.mld_nextworkflowstep (" + p_mld_key + ", " + p_success + "); END;";
                   Oracle.Execute(sql);
               }
           },

       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) + ")";
           },

       getFirstApprover:
           function (mld_info, mld_opdr)
           {
             //var mld_opdr = mld.mld_opdr_info(opdr_key);
             //var mld_info = mld.mld_melding_info(mld_opdr.mld_key);

             // Bepalen eerste persoon om te fiatteren.
             var approver_key = -1;
             var prsname = "";
             var pkey = -1;
             var for_approval = false;
             //var mld_info = mld.mld_melding_info(mld_opdr.mld_key);
             // 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)
               pkey = mld_info.melder_key;  // aanvrager van melding
             else
             { // Terugzoeken wie *oorspronkelijk* de opdrachtaanmaker was (De user op dat moment).
               var sql = "SELECT fac.gettrackinguserkey('ORDNEW', " + mld_opdr.opdr_key + ") opdrachtaanmaker FROM DUAL";
               var oRs = Oracle.Execute(sql);
               pkey = oRs("opdrachtaanmaker").Value || mld_info.behandel_key || user_key;
               oRs.Close();
             }

             if ((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_info.disc))) // Ik kan niet zelf fiatteren of kosten overschrijden het profiel
                )
             { // niet automatisch fiat(!)teren en profiel wordt overschreden.
               for_approval = true;
             }

             if (mld_opdr.opdr_handfiat || // Vrijwillig. Wel even checken of er een fiatteur gevonden kan worden.
                 for_approval ||
                 (S("mld_use_order_approval") &&
                  mld_opdr.t_cost > 0 &&
                  (mld_opdr.t_cost > S("can_selfapprove"))) // Ik kan niet zelf fiatteren of kosten overschrijden het profiel.
                )
             {
               for_approval = true;
               // Wie moet op verzoek goedkeuren voor deze kostenplaats, terwijl het bedrag wellicht onbekend is?
               // Eerste fiatteur (pkey) mag niet fiatteren want het zit boven zijn profiel limiet.
               // Alleen de melder/aanmaker van de melding mag niet zelf goedkeuren boven het bedrag can_selfapprove.
               approver_key = prs.getKpVerantwoordelijke(mld_opdr.kp_key, mld_opdr.t_cost, pkey);

               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; }
             }
             return ps;
           },

       getmldstatustext:
           function (p)
           {
             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: { statustekst = L("lcl_mld_ingevoerd"); 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 status 4 of dat nieuw(4) of oud(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));
                   }
                 }
               }
             }
             return result;
           },

       getextendedmldstatustext:
           function (pstatus, pmld_key)
           {
             var xstatus = mld.getextendedmldstatus(pstatus, pmld_key);
             return mld.getmldstatustext(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)
           {
             var sql = "SELECT mld_melding_einddatum"
                     + "  FROM mld_melding"
                     + " WHERE mld_melding_key = " + mld_key;
             var oRs = Oracle.Execute(sql);
             var mld_einddatum = new Date(oRs("mld_melding_einddatum").Value);
             oRs.Close();

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

       getbedrijfuitvoertijd:
           function (uitv_key)
           {
             var 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 = " + uitv_key;
             var oRs = Oracle.Execute(sql);
             if (oRs.Eof || oRs("tijdsduur").Value == null) // oRs.Eof: Waarschijnlijk persoon
               var uitvoertijd = null;
             else
               var 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;
           },

       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"
                        + "     , 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 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.mld_srtkenmerk_kenmerktype IN ('F', 'E', 'M')"
                        + "   AND (   (    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 = 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 k_old.mld_srtkenmerk_key = t.mld_srtkenmerk_key"
                        + "   AND k_new.mld_srtkenmerk_key = t.mld_srtkenmerk_key"
                        + "   AND t.mld_srtkenmerk_verwijder IS NULL"
                        + "   AND k_old.mld_kenmerk_groep = k_new.mld_kenmerk_groep";

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

       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
                 // Alleen voor status 4 komen twee statussen voor geaccepteerd en niet opgelost
                 if ((mldstatus_str.indexOf("4") == -1 && mldstatus_str.indexOf("99") == -1) ||
                     (mldstatus_str.indexOf("4") != -1 && mldstatus_str.indexOf("99") != -1))
                 { // Als geaccepteerd(4) en niet opgelost(99) beiden wel of niet zijn geselecteerd
                   var status_split = mldstatus_str.split(',');
                   if (mldstatus_str.indexOf("4") != -1 && mldstatus_str.indexOf("99") != -1)
                   { // verwijder 99 uit de mldstatus_str
                     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 + ")";
                 }
                 else if (mldstatus_str.indexOf("99") != -1)
                 { // 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
                     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 + ")"
                         // 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
                   { // 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)
                 { // 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
                     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
                   { // 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))";
                   }
                 }
                 //
                 // 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, 3, 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;
           },

       // 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 ssql = "SELECT fac_srtnotificatie_xmlnode, "
                        + "       fac_srtnotificatie_key"
                        + "  FROM fac_srtnotificatie"
                        + " WHERE fac_srtnotificatie_code = " + safe.quoted_sql(params.srt_tracking);
               var oRs = Oracle.Execute(ssql);
               var xmlnode = oRs("fac_srtnotificatie_xmlnode").Value;
               var fac_srtnotificatie_key = oRs("fac_srtnotificatie_key").Value;
               oRs.Close();
               if (xmlnode == "melding")
               {
                 sql += " AND EXISTS"
                     + "   (SELECT 1"
                     + "      FROM fac_tracking ft"
                     + "     WHERE ft.fac_srtnotificatie_key = " + fac_srtnotificatie_key
                     + "       AND ft.fac_tracking_refkey = m.mld_melding_key"
                     + sqln
                     + (params.prs_tracking > 0?"       AND ft.prs_perslid_key = " + params.prs_tracking:"")
                     + "  )";
               }
               else if (xmlnode == "opdracht")
               {
                 var groep_opdr = (params.groepering_key == 2 || params.groepering_key == 16);
                 sql += " AND EXISTS"
                     + "   (SELECT 1"
                     + "      FROM fac_tracking ft"
                     + (!groep_opdr?" , mld_opdr o":"")
                     + "     WHERE ft.fac_srtnotificatie_key = " + fac_srtnotificatie_key
                     + "       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":"")
                     + "   )";
               }
             }
             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 mld_key = params.mld_key;
             var opdr_key = params.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 = params.reg_key;
             var dist_key = params.dist_key;
             var loc_key = params.loc_key;
             var bld_key = params.bld_key;
             var flr_key = params.flr_key;
             var room_key = params.room_key;
             var behandel_key = params.behandel_key;
             var srtdisc_key = params.srtdisc_key;
             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 kp = params.kp;
             var handler_key = params.handler_key;
             var contact_key = params.contact_key;
             var opdrtype_key = params.opdrtype_key;
             var searchtekst = params.searchtekst;
             var omschr = params.omschr;
             var disc_key = params.disc_key;
             var insgroup_key = params.insgroup_key;
             var objsrt_key_str = params.objsrt_key_str;
             var objectoms = params.objectoms;
             var chkAcceptEx = params.chkAcceptEx;
             var chkRunEx = params.chkRunEx;
             var chkSpoed = params.chkSpoed;
             var chkAfgerond = params.chkAfgerond;
             var datefrom = params.datefrom;
             var dateto = params.dateto;
             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 dienst_key = params.dienst_key;
             var deel_key = params.deel_key;
             var rsv_ruimte_key = params.rsv_ruimte_key;
             //var stdm_key = params.stdm_key; // Ondersteunen we dit nog
             var mldstpen = params.mldstpen;
             var mldstnew = params.mldstnew;
             var mldsting = params.mldsting;
             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"
                   + ", mld_disc_params mdp"
                   + ", alg_v_allonrgoed_gegevens v"
                   + ", alg_locatie l"
                   + ", alg_district di"
                   + ", (SELECT m1.mld_melding_key"
                     + "      , mld.getactualuitvoer (m1.mld_melding_key) actualuitvoertijd"
                     + "   FROM mld_melding m1) gau"
                   + (verantw_key
                     ? ", alg_gebouw g"
                     : "")
                   + ", prs_perslid p"
                   + ", mld_stdmelding std"
                   + ((add_prs_restrict)? ", prs_v_afdeling_boom b" : "")
                   + (perform && srtdisc_key
                     ? ", ins_srtdiscipline sd"
                     : "")
                   + (!perform
                     ? ", ins_srtdiscipline sd"
                     : "")
                   + (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"
                     : "");

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

             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"
                   + ((add_prs_restrict)
                     ? " AND p.prs_afdeling_key = b.prs_afdeling_key"
                     : "")
                   + " AND std.mld_stdmelding_key = m.mld_stdmelding_key"
                   + " AND m.mld_melding_key = gau.mld_melding_key"
                   + (perform && srtdisc_key
                     ? " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
                     : "")
                   + (!perform
                     ? " AND m.fac_activiteit_key IS NULL"
                       + " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_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"
                     : "");

             if (handler_key || opdrtype_key || contact_key || opdr_key || opdrstatus_arr)
             { // meldingen filter je op 'die een opdracht hebben met xxxxxx'
               // opdrachten filter je rechtstreeks
               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
                       ? "   AND o.prs_perslid_key = " + contact_key
                       : "")
                     + (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
                       : "")
                     + (opdrstatus_arr
                       ? "   AND o.mld_statusopdr_key IN (" + opdrstatus_arr.join(",") + ")"
                       : "")
               if (!toon_opdr_overz)
                     sqln += ")"
             }

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

             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 (mldsting)  showstatus = (showstatus == ""? "" : showstatus + ",") + "3";
             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");
             if (sql_status)
               sqln += " AND" + sql_status;

             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 (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.
             if (searchtekst)
             {
               sqln += " AND (UPPER(mld_melding_omschrijving) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%")
                    +  " OR UPPER(mld_melding_onderwerp) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%")
                    +  " OR UPPER(mld_melding_opmerking) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%")
                    +  " 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("%" + searchtekst + "%") + ")"
                    +  " OR EXISTS (SELECT mld_melding_key"
                    +  "              FROM mld_melding_note n"
                    +  "             WHERE n.mld_melding_key = m.mld_melding_key "
                    +  "               AND UPPER(n.mld_melding_note_omschrijving) LIKE " + safe.quoted_sql_wild("%" + searchtekst + "%") + "))";
             }

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

             if (verantw_key)
                sqln += " AND v.alg_gebouw_key = g.alg_gebouw_key(+)"
                      + " AND (g.prs_perslid_key_verantw = " + verantw_key
                      + "  OR g.prs_perslid_key_verantw2 = " + verantw_key + ")";

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

             if (behandel_key)
               sqln += " AND m.mld_melding_behandelaar_key = " + behandel_key;

             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)
               sqln += " AND v.alg_ruimte_key = " + room_key;
             else if (flr_key)
               sqln += " AND v.alg_verdieping_key = " + flr_key;
             else if (bld_key)
               sqln += " AND (v.alg_gebouw_key IN (" + bld_key + ") OR v.alg_terreinsector_key IN (" + bld_key + ")) ";
             else if (loc_key)
               sqln += " AND m.mld_alg_locatie_key = " + loc_key;  // daarvoor hebben we v niet nodig, die is alleen voor de details
             else if (dist_key)
               sqln +=  " AND di.alg_district_key = " + dist_key;
             else if (reg_key)
               sqln +=  " AND di.alg_regio_key = " + reg_key;

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

             if (kp)
               sqln += (toon_opdr_overz
                       ? " AND o.prs_kostenplaats_key IN"
                       : " AND m.prs_kostenplaats_key IN")
                       + " (SELECT k.prs_kostenplaats_key"
                       + " FROM prs_kostenplaats k"
                       + " WHERE (UPPER(k.prs_kostenplaats_omschrijving) LIKE " + safe.quoted_sql_wild(kp)
                       + " OR UPPER(k.prs_kostenplaats_nr) LIKE " + safe.quoted_sql_wild(kp) + "))";

             if (org_key)
               sqln += " AND 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 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 || meldinggrp_key)
             {
               if (stdm_key_arr)
                 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)
               sqln += " AND std.mld_ins_discipline_key IN (" + disc_key_arr.join(",") + ")" ;
             else if (srtdisc_key)
               sqln += " AND sd.ins_srtdiscipline_key IN (" + srtdisc_key + ") ";

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

             // Discipline, group, objectsoort
             if (disc_key || insgroup_key || objsrt_key_str)
             {
               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_str)
                 sqln += " ins_srtdeel_key IN"
                       + " (SELECT ins_srtdeel_key"
                       + " FROM ins_srtdeel"
                       + " WHERE ins_srtdeel_key IN (" + objsrt_key_str.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.getwhere_to_late_run_sql("m", "std", "M") + " = 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.beginToSQL();
               var ora_date2 = dateto.endToSQL();
               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 (frontend)
             {
               var prsKeys = user.collegakeylist();
               sqln += " AND m.prs_perslid_key IN (" + prsKeys + ")"
             }

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

             if (!params.minfo || groepering_key == 1 || (groepering_key > 2 && groepering_key < 16) || groepering_key >= 18)
             { // Meldingen
                sqln += getKenmerkSql("MLD", "m.mld_melding_key");
             }
             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");
             }

             return sqln;
           },

       // 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)
           {
             var lbl = mld.referentielabel(ptype, pkey); // 'Reservering 1234'
             var params = null;
             switch(ptype)
             {
               case "R":
                 var params = { infoPointer: { Url: "appl/res/res_reservering.asp?urole="+urole+"&rsv_ruimte_key=" + pkey }};
                 break;
               case "M":
                 var params = { infoPointer: { Url: "appl/mld/mld_melding.asp?urole="+urole+"&mld_key=" + pkey}};
                 break;
               case "B":
                 var params = { infoPointer: { Url: "appl/bes/bes_bestelling.asp?urole="+urole+"&bes_key=" + pkey}};
                 break;
               case "X":
                 var params = { infoPointer: { Url: "appl/bes/bes_opdr.asp?urole="+urole+"&ordernr=" + pkey}};
                 break;
               case "O":
                 var params = { infoPointer: { Url: "appl/mld/mld_opdr.asp?urole="+urole+"&opdr_key=" + pkey}};
                 break;
               case "C":
                 var params = { infoPointer: { Url: "appl/cnt/cnt_contract.asp?urole="+urole+"&cnt_key=" + pkey}};
                 break;
               case "F":
                 var params = { infoPointer: { Url: "appl/fin/fin_factuur.asp?urole="+urole+"&fin_key=" + pkey}};
                 break;
               case "T":
                 var params = { infoPointer: { Url: "appl/ins/ins_inspect.asp?deelsrtcont_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);
                 return 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 : "");
                 break;
               case "M":
                 return L("lcl_complain") + " " + mld.mld_prefix(pkey) + pkey;
                 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);
                 return L("lcl_shared_order") + " " + oRs("mld_melding_key").Value + "/" + oRs("mld_opdr_bedrijfopdr_volgnr").Value;
                 break;
               case "C":
                 return L("lcl_contract") + " " + pkey;
                 break;
               case "F":
                 return L("lcl_fin_invoice") + " " + pkey;
                 break;
               case "T":
                 var sql = "SELECT lcl.x ('c.ins_discipline_omschrijving', c.ins_discipline_key, c.ins_discipline_omschrijving) ins_discipline_omschrijving"
                         + ", dsc.ins_deelsrtcontrole_opmerking"
                         + ", dsc.ins_deelsrtcontrole_datum"
                         + "  FROM ins_deelsrtcontrole dsc, ins_srtcontrole sc, ctr_discipline c"
                         + " WHERE     dsc.ins_srtcontrole_key = sc.ins_srtcontrole_key"
                         + "       AND sc.ctr_discipline_key = c.ins_discipline_key"
                         + "       AND ins_deelsrtcontrole_key = " + pkey;
                 var oRs = Oracle.Execute(sql);
                 return (oRs.eof
                        ? "x"
                        : oRs("ins_discipline_omschrijving").value + " " + (oRs("ins_deelsrtcontrole_datum").value != "" ? toDateString(oRs("ins_deelsrtcontrole_datum").value) : "x")
                        );
                 break;
             }
           },

       mld_prefix: // handig als je moet presenteren
           function (mld_key)
           {
             var sql = "SELECT sd.ins_srtdiscipline_prefix"
                             + "  FROM mld_melding m"
                             + ",      mld_stdmelding s"
                             + ",      mld_discipline md"
                             + ",      ins_srtdiscipline sd"
                             + " WHERE mld_melding_key = " + mld_key
                             + "   AND s.mld_stdmelding_key = m.mld_stdmelding_key"
                             + "   AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
                             + "   AND md.ins_discipline_key = s.mld_ins_discipline_key";
             var oRs = Oracle.Execute(sql);
             var result = oRs("ins_srtdiscipline_prefix").Value || "";
             oRs.Close();
             return result;
           },

       mld_melding_info:
          function (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);
            //       of desnoods mld_info.stdm_info = mld.mld_stdmeldinginfo(mld_info.stdm)
            //       Dan kan deze functie veel compacter


            // INITIALISATIE MET DE INITIEEL WEER TE GEVEN GEGEVENS
            sql = "SELECT mld_melding_omschrijving"
                + "     , mld_melding_onderwerp"
                + "     , mld_melding_datum"
                + "     , s.mld_ins_discipline_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"
                + "     , p.prs_afdeling_key"
                + "     , m.mld_melding_opmerking"
                + "     , m.prs_perslid_key"
                + "     , m.prs_perslid_key_voor"
                + "     , m.mld_melding_status"
                + "     , m.mld_melding_t_respijt.tijdsduur respijt_tijdsduur"
                + "     , m.mld_melding_t_respijt.eenheid respijt_eenheid"
                + "     , m.mld_meldbron_key"
                + "     , m.mld_meldbron_nr"
                + "     , sd.ins_srtdiscipline_prefix"
                + "     , md.ins_srtdiscipline_key"
                + "     , m.mld_adres_key"
                + "     , m.mld_melding_spoed"
                + "     , m.mld_melding_ordernr"
                + "     , m.mld_melding_parentkey"
                + "     , sd.ins_srtdiscipline_alg"
                + "     , sd.ins_srtdiscipline_ins"
                + "     , sd.ins_srtdiscipline_bes"
                + "     , " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
                + "     , 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"
                + "     , m.mld_workflowstep_key workflow"
                + "     , m.mld_melding_start_key"
                + "     , m.mld_melding_behandelaar_key behandelaar"
                + "     , " + lcl.xsqla('md.ins_discipline_omschrijving', 'md.ins_discipline_key')
                + "     , " + lcl.xsqla('s.mld_stdmelding_omschrijving','s.mld_stdmelding_key')
                + "     , COALESCE(s.mld_stdmelding_directklaar, mdp.mld_disc_params_directklaar, 0) mld_directklaar"
                + "     , mdp.mld_disc_params_frontendprio"
                + "     , 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.alg_onrgoed_niveau"
                + "     , md.ins_discipline_kpnverplicht"
                + "     , s.ins_srtinst_verplicht"
                + "     , mdp.mld_disc_params_eigen_kp"
                + "     , mdp.mld_disc_params_fenotes"
                + "     , mdp.mld_disc_params_keten"
                + "     , mdp.mld_disc_params_bonotify"
                + "     , 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_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 + ") aantal_references"
                + "     , m.mld_melding_flag"
                + "     , 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"
                + "  FROM mld_melding m"
                + "     , mld_stdmelding s"
                + "     , alg_v_allonrgoed_gegevens g"
                + "     , prs_perslid p"
                + "     , mld_discipline md"
                + "     , mld_disc_params mdp"
                + "     , ins_srtdiscipline sd"
                + "     , res_rsv_ruimte rr"
                + "     , (SELECT mld.getactualuitvoer(" + mld_key + ") actualuitvoertijd FROM DUAL) au"
                + " WHERE mld_melding_key = " + mld_key
                + "   AND s.mld_stdmelding_key = m.mld_stdmelding_key"
                + "   AND m.mld_alg_onroerendgoed_keys = g.alg_onroerendgoed_keys(+)"
                + "   AND m.prs_perslid_key = p.prs_perslid_key"
                + "   AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
                + "   AND md.ins_discipline_key = s.mld_ins_discipline_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,
                           melddatum: new Date( oRs("mld_melding_datum").Value),
                           disc: oRs("mld_ins_discipline_key").Value,
                           stdm: oRs("mld_stdmelding_key").Value,
                           place: 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,
                           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,
                           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_status_str: mld.getmldstatustext(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,
                           prefix: oRs("ins_srtdiscipline_prefix").Value,  // null for no prefix
                           srtdisc: oRs("ins_srtdiscipline_key").Value,
                           deladdress: oRs("mld_adres_key").Value,
                           mprio: oRs("mld_melding_spoed").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 == 1,
                           srtdisc_oms: oRs("ins_srtdiscipline_omschrijving").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,
                           noWorkflow: (oRs("workflow").Value == null),
                           Startkey: oRs("mld_melding_start_key").Value,
                           behandel_key: oRs("behandelaar").Value,
                           ins_discipline_omschrijving: oRs("ins_discipline_omschrijving").Value,
                           mld_stdmelding_omschrijving: oRs("mld_stdmelding_omschrijving").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),
                           act_key: oRs("fac_activiteit_key").Value,
                           freetext: oRs("mld_stdmelding_freetext").Value,
                           subject: oRs("mld_stdmelding_subject").Value,
                           module: oRs("module").Value,
                           srtinst_verplicht: (oRs("ins_srtinst_verplicht").Value == 1),
                           planbaar: (oRs("mld_stdmelding_planbaar").Value == 1),
                           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,
                           kto_type: oRs("mld_melding_kto_type").Value,
                           kto_key: oRs("mld_melding_kto_key").Value || -1,
                           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,
                           indult: oRs("mld_melding_indult").Value == 1, // 0=normaal, 1=indult=vrijgewaard=telt niet mee
                           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,
                           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
                         };

           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;
               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;
              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 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(oRs("ins_deel_key").Value);
              oRs.MoveNext();
            }
            oRs.close();
            return result;
          },

       mld_opdr_info:
          function _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"
                    + "     , fac.count_Work_Days(mld_opdr_datumbegin, mld_opdr_einddatum) aantal_dagen"
                    + "     , 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_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"
                    + "     , " + lcl.xsqla('mto.mld_typeopdr_omschrijving', 'mto.mld_typeopdr_key')
                    + "     , mto.mld_typeopdr_matchtype"
                    + "     , mto.mld_typeopdr_slamode"
                    + "     , mto.mld_typeopdr_kosten"
                    + "     , mto.mld_typeopdr_sluitmelding"
                    + "     , 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_kosten_verplicht"
                    + "     , 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"
                    + "     , o.mld_statusopdr_key"
                    + "     , o.mld_statusopdr_key_refiat"
                    + "     , m.mld_stdmelding_key"
                    + "     , m.prs_perslid_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"
                    + "     , o.prs_kostenplaats_key"
                    + "     , (SELECT k.prs_kostenplaats_fiat"
                      + "        FROM prs_kostenplaats k"
                      + "       WHERE k.prs_kostenplaats_key = o.prs_kostenplaats_key) 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"
                    + "     , sd.ins_srtdiscipline_bes"
                    + "     , sd.ins_srtdiscipline_prefix"
                    + "     , o.fac_activiteit_key"
                    + "     , mu.type"
                    + "     , mu.intern"
                    + "     , p2.prs_perslid_key fiatteur_kp_key"
                    + "     , (SELECT kg.prs_perslid_key"
                    + "          FROM prs_kostenplaats k"
                    + "     ,         prs_kostenplaatsgrp kg"
                    + "         WHERE k.prs_kostenplaatsgrp_key = kg.prs_kostenplaatsgrp_key"
                    + "           AND k.prs_kostenplaats_key = o.prs_kostenplaats_key) fiatteur_kpg_key"
                    + "     ,  d.ins_discipline_key"
                    + "     , (SELECT COALESCE(ks.prs_kostensoort_btw, 0)"
                    + "          FROM prs_kostensoort ks"
                    + "         WHERE ks.prs_kostensoort_key = d.prs_kostensoort_key) inclBTW"
                    + "     , fac.gettrackinguserkey('ORDFOK', o.mld_opdr_key) 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"
                    + "     , 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_id"
                    + "     , o.mld_opdr_handfiat"
                    + "  FROM mld_opdr o"
                    + "     , mld_melding m"
                    + "     , mld_stdmelding sm"
                    + "     , ins_tab_discipline d"
                    + "     , mld_disc_params mdp"
                    + "     , ins_srtdiscipline sd"
                    + "     , mld_typeopdr mto"
                    + "     , cnt_v_aanwezigcontract c"
                    + "     , mld_v_uitvoerende mu"
                    + "     , prs_v_perslid_fullnames_all p2"
                    + " 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.cnt_contract_key = c.cnt_contract_key(+)"
                    + "   AND o.mld_uitvoerende_keys = mu.mld_uitvoerende_key"
                    + "   AND p2.prs_perslid_key(+) = prs.getkpverantwoordelijke (o.prs_kostenplaats_key, " + S("prs_approvemethod") + ", -1)"
                    + "   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 = oRs("mld_opdr_materiaal").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;
            if (t_cost != null || m_cost != null || ( (h_rate != null) && (hours != null) ))
            {
                corr_cost = ((t_cost || 0) - (m_cost || 0) - ((h_rate || 0) * (hours || 0)));
                corr_cost = (corr_cost == 0 ? null : corr_cost);
            }
            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,
                           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,
                           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_matchtype: oRs("mld_typeopdr_matchtype").Value,
                           typeopdr_slamode: oRs("mld_typeopdr_slamode").Value,
                           typeopdr_kosten: oRs("mld_typeopdr_kosten").Value,
                           typeopdr_sluitmelding: oRs("mld_typeopdr_sluitmelding").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_kosten_verplicht: oRs("mld_typeopdr_kosten_verplicht").Value || 0, // Opdracht kosten verplicht (bitwise) bij (0 = niet verplicht, 1 = save + 2 = afmelden, 4 = afronden).
                           contactpers_key: oRs("mld_opdr_contact_key").Value || -1,
                           contactpers_naam: oRs("mld_opdr_contact_naam").Value,
                           contactpersuitv_key: oRs("prs_contactpersoon_key").Value,
                           opdr_status: oRs("mld_statusopdr_key").Value,
                           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
                           stdm_key: oRs("mld_stdmelding_key").Value,
                           perslidkey: oRs("prs_perslid_key").Value,
                           vakgroep: oRs("ins_discipline_omschrijving").Value,
                           kosten_klant: oRs("mld_kosten_klant").Value,
                           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: new Date(oRs("mld_opdr_einddatum").Value),
                           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,
                           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,
                           dis_key: oRs("ins_discipline_key").Value,
                           inclBTW: oRs("inclBTW").Value,
                           aanvrager: oRs("ins_discipline_key").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_id: oRs("mld_opdr_id").Value,
                           opdr_handfiat: oRs("mld_opdr_handfiat").Value == 1 // Vrijwillig fiatteren.
                         };
            oRs.close();
            // Uitvoertijd.
            if (result.uitvoerende_key > 0)
              result.uitvoertijd = mld.getbedrijfuitvoertijd(result.uitvoerende_key);
            return result;
          },

       mld_opdr_info_new:
          function _mld_opdr_info_new(mld_key, opdr_type, params)
          {
            params = params || {};
            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);
              if (result.typeopdr_matchtype == 5) // Origineel materiaal is niet meegekopieerd dus de kosten ook niet
              {
                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;
            }
            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,
                         opdr_type_org: -1, // As in/from database
                         kp_key: -1,
                         kp_fiat: true,
                         mld_opdr_ordernr: ""
                       };
              //
              if (result.uitvoerende_key > 0)
              {
                var sql = "SELECT b.prs_bedrijf_uurloon"
                        + ", b.prs_bedrijf_naam"
                        + "  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.h_rate = oRs("prs_bedrijf_uurloon").Value;
                  result.uitvoerende = oRs("prs_bedrijf_naam").Value;
                }
                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"
                  + "     , m.mld_melding_datum"
                  + "     , m.mld_melding_einddatum"
                  + "     , m.mld_melding_omschrijving"
                  + "     , (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 sm.mld_ins_discipline_key = d.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.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.dis_key = oRs("ins_discipline_key").Value;
              result.act_key = (act_key > 0 ? act_key : -1); // fac_activiteit_key vanuit BES?
              oRs.Close();
            }
            // ---
            // mld_opdr is nu al deels gevuld. Rest zowel voor nieuw als voor copy
            // ---
            // Er hoeft nu niet meer een mogelijk default opdrachttype bepaalt te worden. In het popupscherm is een opdrachttype gekozen.
            // Neem de opdrachttype key/omschrijving/matchtype/kosten van het opdrachttype dat in het popupscherm is gekozen.
            sql = "SELECT " + lcl.xsqla("t.mld_typeopdr_omschrijving", "t.mld_typeopdr_key")
                + "    , t.mld_typeopdr_matchtype"
                + "    , 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"
                + " FROM mld_typeopdr t"
                + " WHERE t.mld_typeopdr_key = " + opdr_type;
            oRs = Oracle.Execute(sql);
            //
            result.opdr_type = opdr_type;
            result.opdr_type_omschr = oRs("mld_typeopdr_omschrijving").Value;
            result.typeopdr_matchtype = oRs("mld_typeopdr_matchtype").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).

            if (copy)
            {
              if (result.typeopdr_matchtype == 3 ||
                  result.typeopdr_matchtype == 4 ||
                  result.typeopdr_matchtype == 5)
              { // Het nieuwe type kent geen kosten dus wissen
                result.m_cost = 0;
                result.corr_cost = 0;
                result.h_rate = 0;
              }
              if (result.typeopdr_matchtype == 4)
              {
                result.t_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')
                      + "     , mld_stdmelding_omschrijving mld_stdm_omschrijving_dblang"
                      + "     , mld_stdmelding_volgnr"
                      + "     , ins_discipline_key"
                      + "     , 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')
                      + "     , 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_planbaar"
                      + "     , ms.ins_srtinst_key"
                      + "     , ms.ins_srtinst_niveau"
                      + "     , md.ins_srtdiscipline_key"
                      + "     , md.ins_discipline_kpnverplicht"
                      + "     , sd.ins_srtdiscipline_kostenklant"
                      + "     , sd.ins_srtdiscipline_alg"
                      + "     , sd.ins_srtdiscipline_ins"
                      + "     , sd.ins_srtdiscipline_bes"
                      + "     , 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"
                      + "     , mld_stdmelding_notify"
                      + "     , ms.prs_kostensoort_key"
                      + "     , dp.mld_disc_params_startdatum"
                      + "     , ms.mld_stdmelding_freetext"
                      + "     , ms.mld_stdmelding_subject"
                      + "     , ms.mld_stdmelding_afmeldtext"
                      + "     , ms.ins_srtinst_verplicht"
                      + "     , ms.alg_onrgoed_niveau"
                      + "     , ms.alg_onrgoed_obj_niveau"
                      + "     , ms.alg_org_obj_niveau"
                      + "     , ms.mld_stdmelding_prseigen"
                      + "     , " + lcl.xsqla('ms.mld_stdmelding_hint', 'ms.mld_stdmelding_key')
                      + "     , ms.mld_stdmelding_hint mld_stdmelding_hint_dblang"
                      + "     , 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.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_afhankelijk"
                      + "     , ms.mld_stdmelding_kto"
                      + "     , ms.mld_stdmelding_vervaldatum"
                      + "     , ms.mld_stdmelding_kanverwijzen"
                      + "     , ms.mld_stdmelding_slabewaken"
                      + "     , (SELECT COUNT(*)"
                      + "          FROM fac_faq ff"
                      + "             , 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 fac_faq_datum < SYSDATE"
                      + "           AND (fac_faq_lang = " + safe.quoted_sql(user_lang) + " OR fac_faq_lang IS NULL)) aantal_faq"
                      + "  FROM mld_stdmelding ms, mld_discipline md"
                      + "     , mld_disc_params dp, ins_srtdiscipline sd"
                      + " 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?
              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 == 1,
                             directklaar: oRs("mld_directklaar").Value,
                             ins_srtdiscipline_prefix: oRs("prefix").Value,
                             ins_srtdiscipline_kostenklant: oRs("ins_srtdiscipline_kostenklant") == 1,
                             hide_kostenplaats_fe: oRs("ins_srtdiscipline_kostenklant") == 2,
                             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,
                             startdatum: oRs("mld_disc_params_startdatum").Value == 1,
                             accepttijd: oRs("accepttijd_t").Value,
                             eenheid_accepttijd: oRs("accepttijd_e").Value || 'D',
                             ins_srtinst_key: oRs("ins_srtinst_key").Value,
                             ins_srtinst_niveau: oRs("ins_srtinst_niveau").Value,
                             planbaar: oRs("mld_stdmelding_planbaar").Value == 1,
                             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_verplicht: oRs("ins_srtinst_verplicht").Value == 1,
                             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,
                             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,
                             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,
                             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,
                             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,
                             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();

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

                 var sql = "SELECT ff.fac_faq_key, "
                          + "       fac_faq_question, "
                          + "       fac_faq_answer, "
                          + "       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 BITAND(fac_faq_level," + faq_bits + ") <> 0"
                          + "   AND fac_faq_datum < SYSDATE"
                          + "   AND (fac_faq_lang = " + safe.quoted_sql(user_lang) + " OR fac_faq_lang IS NULL)"
                          + " ORDER BY fac_faq_rank DESC NULLS LAST"
                          + "        , fac_faq_datum DESC"
                          + "        , fac_faq_question";
                  var oRs = Oracle.Execute(sql);
                  while (!oRs.EOF)
                  {
                    result.faq_popup = false;
                    var displaymode = oRs("fac_faq_displaymode").Value;
                    if (displaymode == 0) // Auto
                    {
                        if (   ((S("faq_kennisbank_popup") & 1) && canFAQUSEread) // Voor FE
                            || ((S("faq_kennisbank_popup") & 2) && canFAQFOFread)) // Voor FO
                            result.popup_faq = true
                    }
                    else
                    {
                        var data = { question: oRs("fac_faq_question").Value,
                                     answer: oRs("fac_faq_answer").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;
       },

       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"
                 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;
           },

       func_enabled_melding: // Wat mag ik zoal op deze specifieke melding?
           function _func_enabled_melding(pmld_melding_key, params) {
               params = params || {};
               var msql = "SELECT sm.mld_ins_discipline_key"
                        + "     , m.mld_alg_onroerendgoed_keys"
                        + "     , m.mld_melding_status"
                        + "     , m.prs_perslid_key"
                        + "     , m.mld_workflowstep_key"
                        + "     , m.mld_melding_start_key"
                        + "     , m.mld_melding_parentkey"
                        + "     , 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"
                        + "     , sm.mld_stdmelding_planbaar"
                        + "     , (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, 6, 7, 9)) openopdrachten" // 1=afgewezen, 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, 6, 7, 9)) closedopdrachten" // 1=afgewezen, 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 MAX (fa.fac_activiteit_aantal)"
                        + "          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) opdr_action_aantal"
                        + "     , m.mld_melding_afgerond"
                        + "     , mdp.mld_disc_params_bonotify"
                        + "  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);
               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_kopieerbaar = moRs("mld_stdmelding_kopieerbaar").Value == 1;
               var wfstep = moRs("mld_workflowstep_key").Value;
               var melder_key = moRs("prs_perslid_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 planbaar = moRs("mld_stdmelding_planbaar").Value == 1;
               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 opdr_action_aantal = moRs("opdr_action_aantal").Value;
               var mld_afgerond = moRs("mld_melding_afgerond").Value == 1;
               var bonotify = moRs("mld_disc_params_bonotify").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 mresult = user.func_enabled2("MLD",
                                                 { ins_discipline_key: moRs("mld_ins_discipline_key").Value,
                                                   alg_key: moRs("mld_alg_onroerendgoed_keys").Value, // TODO: Wat als geen INS_SRTDISCIRPLINE_ALG?
                                                   prs_key: moRs("prs_perslid_key").Value,
                                                   knownread: params.knownread
                                                 }
                                               );
               var mresult_no_disc = user.func_enabled2("MLD",
                                                 { alg_key: moRs("mld_alg_onroerendgoed_keys").Value, // TODO: Wat als geen INS_SRTDISCIRPLINE_ALG?
                                                   prs_key: moRs("prs_perslid_key").Value,
                                                   knownread: params.knownread
                                                 }
                                               );


               mresult.canFEread = mresult.canRead("WEB_MLDUSE") && user.isCollega(moRs("prs_perslid_key").Value);
               mresult.canFEwrite = mresult.canWrite("WEB_MLDUSE") && user.isCollega(moRs("prs_perslid_key").Value);
               moRs.Close();
               // -- 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;

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

               // 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"));
               // In de newstyle mode moet ik in ieder geval ook rechten hebben om de melding te kunnen zien.
               mresult.canReadNotes = mresult.canWriteNotes || (S("mld_note_mode") == 2 && mresult.canReadAny);
               mresult.haveOnlyFErights = (!mresult.canRead("WEB_MLDFOF") && !mresult.canRead("WEB_MLDBOF") && mresult.canFEread);
               mresult.canWriteFlags = mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDFOF"); // Kan ik flags aanpassen

               // Op button niveau
               mresult.canChange = false;   // Wijzig knop tonen
               mresult.canChangeUrole = (typeof urole == "undefined" ? "" : urole);  // (mld_close kent deze niet, en change-t ook niet interactief)
               mresult.canAccept = false;   // Accepteren
               mresult.canReject = false;   // Afwijzen
               mresult.canForward = false;  // Doorsturen
               mresult.canClose = false;    // Afmelden
               mresult.canContinue = false; // Vervolg ('kopie')
               mresult.canDoorzet = false;  // Doorzetten naar backoffice
               mresult.canTerugzet = false; // Terugzetten naar frontoffice
               mresult.canCopy = is_kopieerbaar && (mresult.canFEwrite || mresult.canFOwrite || mresult.canBOwrite) && !is_planned_action;
               mresult.canAdd2Faq = false;  // Voordragen voor kennisbank
               mresult.canAfrond = false; // SLA-technisch goedkeuren
               mresult.canAddOpdr = false;

               // 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.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 = false;   // Flexkenmerken: (mld_status == 1 || mld_status == 2 || ((mld_status != 5 && mld_status != 6 && mld_status != 7) && backo))
               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       = mresult.canWrite("WEB_MLDFOF") && S("mld_rejected_is_open") == 1;
                               break;
                       case 2: // Ingevoerd ('nieuw'), bo heeft er nog niet naar omgezien
                               mresult.canUnlink       = mresult.canWrite("WEB_MLDFOF");
                               break;
                       case 3: // Ingezien ('te accepteren') komt alleen nog voor als BO op edit drukt maar niet saved
                               mresult.canUnlink       = mresult.canWrite("WEB_MLDBOF");
                               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; // Bijna status onafhankelijk
                   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;
                               mresult.canVakgChange   = mresult.canWrite("WEB_MLDFOF");
                               mresult.canStdmChange   = mresult.canWrite("WEB_MLDFOF") && !is_wf_root;
                               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       = (mresult.canWrite("WEB_MLDFOF") && S("mld_rejected_is_open") == 1);
                               mresult.canChangeUrole  = 'fo';
                               mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !is_planned_action && !S("mld_disable_continuation"); //mldfof_write;
                               mresult.canVakgChange   = mresult.canWrite("WEB_MLDFOF");
                               mresult.canStdmChange   = !is_wf_root;
                               mresult.canKostChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                               mresult.canFlexChange   = true;
                               mresult.canPlaatsChange = true;
                               mresult.canAflChange    = true;
                               // Alleen FO kan melding aanpassen. FE toevoegen voor canPrioChange heeft geen zin.
                               mresult.canPrioChange   = (!planbaar && mresult.canWrite("WEB_MLDFOF"));
                               mresult.canOmsChange    = mresult.canWrite("WEB_MLDFOF");
                               mresult.canAfhandChange = mresult.canWrite("WEB_MLDFOF");
                               mresult.canWriteDatums  = mresult.canWrite("WEB_MLDFOF");
                               break;
                       case 2: // Ingevoerd ('nieuw'), bo heeft er nog niet naar omgezien
                               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;
                               mresult.canReject       = ((mresult.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult.canWrite("WEB_MLDBO3")) &&
                                                         (!is_wf_step || (is_wf_step && mld.wfIsRejectable(wfstep))) &&
                                                         !is_planned_action;
                               mresult.canForward      = (mresult.canWrite("WEB_MLDBOF") && !is_planned_action);
                               mresult.canClose        = (mresult.canWrite("WEB_MLDBOF") || (mresult.canWrite("WEB_MLDFOF") && (params && params.verynew)) && !is_wf_root && !is_planned_action);
                               mresult.canVakgChange   = (mresult.canWrite("WEB_MLDFOF") || mresult.canFEwrite || mresult.canWrite("WEB_MLDBOF"));
                               mresult.canStdmChange   =  !is_wf_root;
                               mresult.canKostChange   = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                               mresult.canFlexChange   = true;
                               mresult.canPlaatsChange = true;
                               mresult.canAflChange    = true;
                               mresult.canPersChange   = mresult.canWrite("WEB_MLDFOF");
                               mresult.canPrioChange   = (!planbaar && mresult.canWrite("WEB_MLDFOF") || (mresult.canFEwrite && frontendprio));
                               mresult.canTerugzet     = (is_fo_melding && mresult.canWrite("WEB_MLDBOF") && !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));
                               mresult.canAddOpdr      = mresult.canWrite("WEB_ORDBOF");
                               mresult.canSLAChange    = mresult.canWrite("WEB_MLDBOF");
                               break;
                       case 3: // Ingezien ('te accepteren') komt alleen nog voor als BO op edit drukt maar niet saved
                               // FO kan alleen omschrijving aanpassen
                               mresult.canChange       = ((mresult.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult.canWrite("WEB_MLDFOF"));
                               mresult.canChangeUrole  = mresult.canWrite("WEB_MLDBOF")? 'bo' : 'fo';
                               mresult.canAccept       = ((mresult.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult.canWrite("WEB_MLDBO3")) && !is_planned_action;
                               mresult.canReject       = ((mresult.canWrite("WEB_MLDBOF") && !activeMLDBO3) || mresult.canWrite("WEB_MLDBO3")) &&
                                                         (!is_wf_step || (is_wf_step && mld.wfIsRejectable(wfstep))) &&
                                                         !is_planned_action;
                               mresult.canForward      = (mresult.canWrite("WEB_MLDBOF") && !is_planned_action); // willekeurige vakgroep
                               mresult.canClose        = (mresult.canWrite("WEB_MLDBOF") && !is_wf_root && !is_planned_action);
                               mresult.canVakgChange   = (mresult.canWrite("WEB_MLDBOF")); // vakgroep waar je zelf schrijfrechten op hebt
                               mresult.canStdmChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")) && !is_wf_root;
                               mresult.canKostChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                               mresult.canFlexChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                               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 && (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")));
                               mresult.canTerugzet     = (is_fo_melding && mresult.canWrite("WEB_MLDBOF") && !is_planned_action);
                               mresult.canOmsChange    = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")|| mresult.canWrite("WEB_MLDBO3"));
                               mresult.canAfhandChange = mresult.canWrite("WEB_MLDBOF");
                               mresult.canWriteDatums  = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                               mresult.canAddOpdr      = mresult.canWrite("WEB_ORDBOF");
                               mresult.canSLAChange    = mresult.canWrite("WEB_MLDBOF");
                               break;
                       case 4: // Geaccepteerd ('In behandeling') (expliciet mld_accept_save.asp of als backoffice bewerkt en opslaat)
                               mresult.canStdmChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3")) && !is_wf_root
                               mresult.canKostChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3") || mresult.canFEwrite);
                               mresult.canFlexChange   = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                               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 && mresult.canStdmChange);
                               mresult.canTerugzet     = (!hasclosedopdrachten && !is_wf_root && is_fo_melding && mresult.canWrite("WEB_MLDBOF") && !is_planned_action);
                               /* GEEN BREAK !! */
                       case 7: // Uitgegeven
                               /* Waarden hierna gelden dus voor zowel 4 als 7 */
                               // FO kan alleen omschrijving aanpassen
                               mresult.canChange       = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDFOF"));
                               mresult.canChangeUrole  = mresult.canWrite("WEB_MLDBOF")? 'bo' : 'fo';
                               mresult.canForward      = (!is_wf_root &&
                                                          (S("mld_forward_if_active") == 1 || (keten && !hasopdrachten)) && // Een melding met opdrachten mag niet meer doorgestuurd worden (MAYF#36363).
                                                          mresult.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")) &&
                                                         !is_wf_root && (!is_planned_action || (is_planned_action && opdr_action_aantal == 0)); // Als de laatste geplande actie is geweest mag de melding afgemeld worden.
                               mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !is_planned_action && !S("mld_disable_continuation"); //mldfof_write;
                               mresult.canFlexChange   = (mresult.canWrite("WEB_MLDBOF"));
                               // FOF kan alleen omschrijving aanpassen
                               mresult.canOmsChange    = mresult.canWrite("WEB_MLDFOF");
                               mresult.canAfhandChange = mresult.canWrite("WEB_MLDBOF");
                               mresult.canWriteDatums  = (mresult.canWrite("WEB_MLDBOF") || mresult.canWrite("WEB_MLDBO3"));
                               mresult.canAddOpdr      = mresult.canWrite("WEB_ORDBOF");
                               mresult.canSLAChange    = mresult.canWrite("WEB_MLDBOF");
                               break;
                       case 5: // Afgemeld
                               mresult.canAfrond       = mresult.canWrite("WEB_MLDAFR") && !hasopenopdrachten;
                               mresult.canSLAChange    = mresult.canAfrond;
                               mresult.canFixMelding   = mresult.canFixSLA;
                               mresult.canChange       = mresult.canAfrond;
                               mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !is_planned_action && !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;
                               break;
                       case 6: // Admin voltooid
                               mresult.canContinue     = (mresult.canWrite("WEB_MLDFOF") || mresult.canWrite("WEB_MLDBOF")) && mresult_no_disc.canWrite("WEB_MLDFOF") && !is_planned_action && !S("mld_disable_continuation");
                               mresult.canFixSLA       = false;
                               break;
                   }
               }

               // (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.
               if (!params.dontcarelink &&  !is_wf_step && (mresult.canFOwrite || mresult.canBOwrite) &&
                   mresult.canChange && !is_planned_action) // misschien canLink als nog geen opdrachten of bestellingen
               {
                   var sql = "SELECT 1 FROM mld_opdr WHERE mld_melding_key = " + pmld_melding_key
                           + " UNION ALL SELECT 1 FROM bes_bestelling WHERE mld_melding_key = " + pmld_melding_key
                           + " 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) {
               var msql = "SELECT sm.mld_ins_discipline_key"
                        + "     , m.mld_alg_onroerendgoed_keys"
                        + "     , o.mld_statusopdr_key"
                        + "     , o.prs_perslid_key"
                        + "     , m.prs_perslid_key melding_user_key"
                        + "     , mto.mld_typeopdr_kosten"
                        + "     , mto.mld_typeopdr_decentraal"
                        + "     , mto.mld_typeopdr_isofferte"
                        + "     , mld_typeopdr_afmelden_extern"
                        + "     , mto.mld_typeopdr_matchtype"
                        + "     , mto.mld_typeopdr_kosten_verplicht"
                        // Als de opdracht geen kostenplaats heeft, ga dan uit van de kostenplaats van de melding
                        + "     , prs.getkpverantwoordelijke (o.prs_kostenplaats_key, " + S("prs_approvemethod") + ", -1) fiatteur_kp_key"
                        + "     , (SELECT kg.prs_perslid_key"
                        + "          FROM prs_kostenplaats k"
                        + "             , prs_kostenplaatsgrp kg"
                        + "         WHERE k.prs_kostenplaatsgrp_key = kg.prs_kostenplaatsgrp_key(+)"
                        + "           AND k.prs_kostenplaats_key = o.prs_kostenplaats_key) fiatteur_kpg_key"
                        + "     , mu.type"
                        + "     , mu.intern"
                        + "     , o.mld_uitvoerende_keys"
                        + "     , fac.gettrackinguserkey('ORDFOK', " + pmld_opdr_key + ") fiat_trackinguser_key"
                        + "     , fac.gettrackingdate('ORDFIA', o.mld_opdr_key) trackdateFIA"
                        + "     , fac.gettrackingdate('ORDFOK', o.mld_opdr_key) trackdateFOK"
                        + "     , o.mld_opdr_kosten"
                        + "     , mto.mld_typeopdr_zichtbaarfe"
                        + "     , o.mld_opdr_teverzenden"
                        + "     , o.mld_opdr_verzonden"
                        + "     , o.mld_statusopdr_key_refiat"
                        + "     , o.mld_opdr_approved"
                        + "     , o.mld_opdr_approved_refiat"
                        + "     , mdp.mld_disc_params_offerteauto"
                        + "     , sm.mld_stdmelding_opdrtypevast"
                        + "     , m.mld_melding_key"
                        + "     , o.mld_opdr_bedrijfopdr_volgnr"
                        + "     , o.fac_activiteit_key"
                        + "     , o.mld_opdr_approved"
                        + "     , mto.mld_typeopdr_gvs"
                        + "     , mdp.mld_disc_params_opdr_kosten"
                        + "     , 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"
                        //Opdracht mag niet meer gecanceld worden indien de opdracht een actuele factuur heeft met de status Ingevoerd(2), Akkoord(6) of Verwerkt(7).
                        + "     , (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"
                        + "     , m.mld_melding_afgerond"
                        + "  FROM mld_opdr o"
                        + "     , mld_typeopdr mto"
                        + "     , mld_melding m"
                        + "     , mld_stdmelding sm"
                        + "     , ins_tab_discipline d"
                        + "     , mld_disc_params mdp"
                        + "     , prs_kostenplaats k"
                        + "     , prs_kostenplaatsgrp kg"
                        + "     , 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_discipline_key = mdp.mld_ins_discipline_key"
                        + "   AND o.prs_kostenplaats_key = k.prs_kostenplaats_key(+)" // kostenplaats van de opdracht kan leeg zijn
                        + "   AND o.mld_typeopdr_key = mto.mld_typeopdr_key"
                        + "   AND k.prs_kostenplaatsgrp_key = kg.prs_kostenplaatsgrp_key(+)"
                        + "   AND o.mld_uitvoerende_keys = mu.mld_uitvoerende_key"
                        + "   AND o.mld_opdr_key = " + pmld_opdr_key
               var moRs = Oracle.Execute(msql);
               var opdr_status = moRs("mld_statusopdr_key").Value;
               var fiatteur_kp_key = moRs("fiatteur_kp_key").Value;
               var fiatteur_kpg_key = moRs("fiatteur_kpg_key").Value;
               var uitv_type = moRs("type").Value;
               var uitv_intern = moRs("intern").Value == 1;
               var uitv_key = moRs("mld_uitvoerende_keys").Value;
               var fiat_trackinguser_key = moRs("fiat_trackinguser_key").Value;
               var tracking_present = moRs("fiat_trackinguser_key").Value? true : false;
               var t_cost = moRs("mld_opdr_kosten").Value;
               var mld_opdr_teverzenden = moRs("mld_opdr_teverzenden").Value == 1;  // Dan stuurt PutOrders deze
               var mld_opdr_verzonden = moRs("mld_opdr_verzonden").Value;
               var refiat = (moRs("mld_statusopdr_key_refiat").Value || 0) > 0;
               var approved = moRs("mld_opdr_approved").Value;
               var approved_refiat = moRs("mld_opdr_approved_refiat").Value;
               // Is er tijdens de refiat al door de budgethouder (kostenplaatverantwoordelijke) gefiatteerd.
               var refiat_is_approvedby_kp = refiat &&                                                                    // Refiat van de opdracht
                                             opdr_status == 3 &&                                                          // Opdracht staat "Ter fiattering"
                                             moRs("trackdateFIA").Value != null && moRs("trackdateFOK").Value != null &&  // Er is al gefiatteerd
                                             moRs("trackdateFIA").Value < moRs("trackdateFOK").Value;                     // De eerste fiatteur heeft opnieuw gefiatteerd.
               var typehas_cost = moRs("mld_typeopdr_kosten").Value == 1;
               var decentraal = moRs("mld_typeopdr_decentraal").Value;
               var isofferte = moRs("mld_typeopdr_isofferte").Value == 1;
               var afmelden_extern = moRs("mld_typeopdr_afmelden_extern").Value;
               var typeopdr_matchtype = moRs("mld_typeopdr_matchtype").Value;
               var typeopdr_kosten_verplicht = moRs("mld_typeopdr_kosten_verplicht").Value || 0; // Opdracht kosten verplicht (bitwise) bij (0 = niet verplicht, 1 = save + 2 = afmelden, 4 = afronden).
               var opdrkosten_verplicht = moRs("mld_disc_params_opdr_kosten").Value || 0;
               var offerteauto = moRs("mld_disc_params_offerteauto").Value == 1;
               var opdrtypevast = moRs("mld_stdmelding_opdrtypevast").Value == 1;
               var mld_key = moRs("mld_melding_key").Value;
               var mld_opdr_bedrijfopdr_volgnr = moRs("mld_opdr_bedrijfopdr_volgnr").Value;
               var is_planned_action = moRs("fac_activiteit_key").Value != null;
               var opdr_approved = moRs("mld_opdr_approved").Value || -1;
               var gvs = moRs("mld_typeopdr_gvs").Value || 0;
               var bestellimiet = moRs("mld_disc_params_bestellimiet").Value || 0;
               var bestellimiet2 = moRs("mld_disc_params_bestellimiet2").Value || 0;
               var bestellimiet3 = moRs("mld_disc_params_bestellimiet3").Value || 0;
               var bestellimiet4 = moRs("mld_disc_params_bestellimiet4").Value || 0;
               var bestellimiet5 = moRs("mld_disc_params_bestellimiet5").Value || 0;
               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.
               var mld_afgerond = moRs("mld_melding_afgerond").Value == 1;
               // tracking_present   KP     KPN    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 && !refiat_is_approvedby_kp))
               { // Geen tracking of als nieuw fiatteren bij refiat als setting is gezet.
                 if (fiatteur_kp_key) // Als KP (A) aanwezig (desnoods via n-laagsmethode via afdelingsboom) dan KP testen als isVerantwoordelijke
                   isVerantwoordelijke = (user.isCollega(fiatteur_kp_key));
                 else if (fiatteur_kpg_key) // Als alleen KPN (B) aanwezig dan KPN testen als isVerantwoordelijke
                   isVerantwoordelijke = (user.isCollega(fiatteur_kpg_key));
               }
               else
               { // tracking aanwezig
                 if (fiatteur_kp_key) // Als KP (A) aanwezig dan KPN (B) testen als isVerantwoordelijke
                   isVerantwoordelijke = (user.isCollega(fiatteur_kpg_key) && fiat_trackinguser_key != fiatteur_kpg_key);
                 // Kostenplaats(groep)verantwoordelijke mag na approven de bestelopdracht inzien.
                 isApprovedRead = (user.isCollega(fiatteur_kp_key) || user.isCollega(fiatteur_kpg_key));
               }

               var mresult = user.func_enabled("MLD",
                                               moRs("mld_ins_discipline_key").Value,
                                               moRs("mld_alg_onroerendgoed_keys").Value, // TODO: Wat als geen INS_SRTDISCIPLINE_ALG?
                                               moRs("prs_perslid_key").Value,
                                               false, // pessimist
                                               isVerantwoordelijke); // isVerantwoordelijke dan optional

               // Algemeen niveau
               mresult.haveORDSUPrights = user.checkAutorisation("WEB_ORDSUP", true) != null;
               mresult.haveORDFINrights = user.checkAutorisation("WEB_ORDFIN", true) != null;
               mresult.haveORDOAPrights = user.checkAutorisation("WEB_ORDOAP", true) != null;

               // Op button niveau
               // ORDUSE zijn meldrachten: heb ik de (melding en) opdracht aangemaakt?
               mresult.canFEread = mresult.canRead("WEB_ORDUSE") && user.isCollega(moRs("prs_perslid_key").Value);
               mresult.canFEwrite = mresult.canWrite("WEB_ORDUSE") && user.isCollega(moRs("prs_perslid_key").Value);
               // 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 (moRs("mld_typeopdr_zichtbaarfe").Value == 1 && user.isCollega(moRs("melding_user_key").Value))
               {
                   mresult.canFEread |= mresult.canRead("WEB_MLDUSE");
                   mresult.canFEwrite |= mresult.canWrite("WEB_MLDUSE");
               }
               moRs.Close();

               var lopende_offertes = false;
               var uitvOpdrNaOfferte = false;
               if (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_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_bedrijfopdr_volgnr;
                 }
                 ooRs.Close();
               }

               // -- CONTROLE LEESRECHTEN --
               // Al ik een contactpersoon ben dan heb ik alleen rechten om mijn eigen opdrachten van mijn eigen bedrijf te zien/wijzigen
               mresult.iamContact = mld.iamContact(); // Ben ik een contactpersoon?
               mresult.iamBedrijfContact = false; // Aan bedrijf toegekend en ik ben contactpersoon van dat bedrijf? Bijv. vertaaldiensten UWVA
               if (!uitv_intern) // Extern Bedrijf.
               { // Ik ga er van uit dat je NIET als vervanger van een contactpersoon van een ander bedrijf wordt aangewezen.
                 mresult.iamBedrijfContact = mld.iamContact(uitv_key); // Ben ik contactpersoon van het uitvoerende bedrijf?
               }
               mresult.canReadAny = mresult.canRead("WEB_ORDBOF") ||
                                    (mresult.iamContact? (mresult.canRead("WEB_ORDBO2") && mresult.iamBedrijfContact) : mresult.canRead("WEB_ORDBO2")) ||
                                    mresult.canRead("WEB_ORDAFR") ||
                                    mresult.canRead("WEB_ORDFIN") ||
                                    mresult.canRead("WEB_ORDSUP") ||
                                    (mresult.canRead("WEB_MLDORD") && user.isCollega(uitv_key)) ||
                                    mresult.canFEread ||
                                    isVerantwoordelijke ||
                                    isApprovedRead;

               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 authparamsFINUSE = user.checkAutorisation("WEB_FINUSE", true);
               var authparamsFINFOF = user.checkAutorisation("WEB_FINFOF", true);
               var authparamsFINBOF = user.checkAutorisation("WEB_FINBOF", 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 && ((authparamsFINUSE && authparamsFINUSE.PRSwritelevel < 9) || (authparamsFINFOF && authparamsFINFOF.PRSwritelevel)); // Kan rechtstreeks vanuit opdrachten een factuur aanmaken.
               mresult.canListFactuur = typehas_cost && has_facturen && (authparamsFINUSE || authparamsFINFOF || authparamsFINBOF || user.isBudgethouder()); // Mag lijst met facturen zien die bij deze opdracht horen.

               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.canSend = false;         // Handmatig versturen (als Putorders dat niet doet)
               mresult.canAccept = false;       // Accepteren (door uitvoerder)
               mresult.canReject = false;       // Afwijzen
               mresult.canCancel = false;       // Annuleren
               mresult.canClose = false;        // Afmelden
               mresult.canFinish = false;       // Afronden
               mresult.hadFinishRights = false; // Had ik in status "Technisch Voltooid/Afgemeld(6)" de rechten om de opdracht financieel te voltooien.
               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

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

               // Op invoerveld niveau
               mresult.canVeldChange = false;     // Invoervelden uitgezonderd uitvoerende, dienst, kostenplaats, opdrachtdatum en einddatum: (opdr_status!=6 || authparamsORDFIN)
               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.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.hadUrenMatChange = false;  // Had ik in status "Technisch Voltooid/Afgemeld(6)" de rechten om Uren en materialen te wijzigen.
               mresult.canOpdrTypeChange = false; // Opdrachttype: canVeldChange maar van offertopdrachten mag je het opdrachttype niet aanpassen (!isofferte).

               // Mag ik dankzij BO2 afmelden (en een beetje bewerken)
               var myBO2Change = mresult.canWrite("WEB_ORDBO2"); // dat is wel het minste

               // Setting mld_typeopdr_afmelden_extern: Afmelder (ORDBO2) mag externe opdrachten (0=Niet zien, 1=Zien, 2=Afmelden)
               // Als ik een interne (decentraal/intern) uitvoerder ben mag ik de externe opdrachten niet zien als mld_typeopdr_afmelden_extern==0.
               // De voorwaarde en setting geldt niet als:
               // 1) de opdracht toegekend is aan een persoon. Dan mag ik alleen eigen opdrachten zien.
               // 2) de opdracht toegekend is aan het eigen bedrijf. Opdrachten van het eigen bedrijf mag ik alleen zien.
               // 3) ik de contactpersoon ben van het uitvoerende externe bedrijf. Dan mag ik alleen opdrachten van mijn eigen bedrijf zien.
               // Let op!!! Deze voorwaarde geldt dus alleen voor de WEB_ORDBO2 rechten.
               if (mresult.iamContact)
                 myBO2Change = myBO2Change && mresult.iamBedrijfContact
               else if (myBO2Change && !uitv_intern && afmelden_extern < 2 && !mresult.iamBedrijfContact)
                 myBO2Change = false;

               var myBO2FieldChange = (myBO2Change && !mresult.iamBedrijfContact);

               __Log("myBO2Change: " + myBO2Change);

               switch (opdr_status)
               {
                   case 1: // Afgewezen
                           mresult.canChange         = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canChangeUrole    = "bo";
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canVeldChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canFlexChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUitvChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canDatesChange    = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canKostChange     = (mresult.canWrite("WEB_ORDBOF") && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canOpmChange      = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUrenMatChange  = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canOpdrTypeChange = (mresult.canWrite("WEB_ORDBOF") && !isofferte && !opdrtypevast);
                           break;
                   case 2: // Niet akkoord
                           mresult.canChange         = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canChangeUrole    = "bo";
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canVeldChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canFlexChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUitvChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canDatesChange    = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canKostChange     = (mresult.canWrite("WEB_ORDBOF") && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canOpmChange      = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUrenMatChange  = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canSeeARFlex      = (isofferte && mresult.haveORDSUPrights);
                           mresult.canOpdrTypeChange = (mresult.canWrite("WEB_ORDBOF") && !isofferte && !opdrtypevast);
                           break;
                   case 3: // Ter fiattering
                           mresult.canChange         = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canChangeUrole    = "bo";
                           mresult.canApprove        = (isVerantwoordelijke && !is_planned_action);
                           mresult.canReject         = (isVerantwoordelijke && !is_planned_action);
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canVeldChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canFlexChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUitvChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canDatesChange    = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canKostChange     = (mresult.canWrite("WEB_ORDBOF") && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canOpmChange      = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUrenMatChange  = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canOpdrTypeChange = (mresult.canWrite("WEB_ORDBOF") && !isofferte && !opdrtypevast);
                           break;
                   case 4: // Gefiatteerd
                           mresult.canChange         = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canSend           = (mresult.canWrite("WEB_ORDBOF")) && uitv_type == "B" && !mld_opdr_teverzenden && !is_planned_action;  // Handmatig versturen (als Putorders dat niet doet)
                           mresult.canChangeUrole    = "bo";
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canVeldChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canFlexChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUitvChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canDatesChange    = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canKostChange     = (mresult.canWrite("WEB_ORDBOF") && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canOpmChange      = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canOpdrTypeChange = (mresult.canWrite("WEB_ORDBOF") && !isofferte && !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         = (mresult.canWrite("WEB_ORDBOF") && (decentraal < 2) ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key))) &&
                                                       !is_planned_action;
                           mresult.canSend           = (mresult.canWrite("WEB_ORDBOF") &&  // Handmatig versturen (als Putorders dat niet doet)
                                                                   uitv_type == "B" &&
                                                                   mld_opdr_verzonden == null &&
                                                                   !mld_opdr_teverzenden &&
                                                                   !is_planned_action)
                           // GEEN break!
                   case 8: // en geaccepteerd
                           mresult.canChange         = (mresult.canWrite("WEB_ORDBOF") && (decentraal < 2) ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key)));
                           if (mresult.canWrite("WEB_ORDBOF")) mresult.canChangeUrole   = "bo";
                           mresult.canCancel         = (mresult.canWrite("WEB_ORDBOF") ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change)) &&
                                                       !is_planned_action &&  /* AAFM#23455 */
                                                       !noCancel;  /* AAZC#28894 */
                           mresult.canClose          = (mresult.canWrite("WEB_ORDBOF") && (decentraal < 2) ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key))) &&
                                                       !is_planned_action;
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canVeldChange     = (mresult.canWrite("WEB_ORDBOF") ||
                                                        (mresult.canWrite("WEB_ORDBO2") && myBO2FieldChange));
                           mresult.canFlexChange     = (mresult.canWrite("WEB_ORDBOF") || mresult.canWrite("WEB_ORDBO2"));
                           mresult.canUitvChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canDatesChange    = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canKostChange     = (mresult.canWrite("WEB_ORDBOF") && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canOpmChange      = (mresult.canWrite("WEB_ORDBOF") ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key)));
                           mresult.canUrenMatChange  = (mresult.canWrite("WEB_ORDBOF") ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key)));
                           mresult.canSeeARFlex      = (isofferte && mresult.haveORDSUPrights);
                           mresult.canChangeARFlex   = (isofferte && mresult.haveORDSUPrights);
                           mresult.canOpdrTypeChange = (mresult.canWrite("WEB_ORDBOF") && !isofferte && !opdrtypevast);
                           break;
                   case 6: // Technisch Voltooid/Afgemeld
                           mresult.canChange         = (mresult.haveORDFINrights || mresult.haveORDSUPrights ||
                                                       (myBO2Change && mresult.canWrite("WEB_ORDAFR")) ||  /* AANS#22655 */
                                                        (typehas_cost && mresult.canWrite("WEB_ORDAFR")) ||
                                                        (isofferte && mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights));
                           mresult.couldClose        = (mresult.canWrite("WEB_ORDBOF") && (decentraal < 2) ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key)));
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canFlexChange     = (mresult.haveORDFINrights || mresult.haveORDSUPrights) ||
                                                       (myBO2Change && mresult.canWrite("WEB_ORDAFR") && !isofferte);  /* AANS#22655 */
                           mresult.canKostChange     = (mresult.haveORDFINrights && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canFinish         = (!isofferte && typehas_cost && mresult.canWrite("WEB_ORDAFR") && !is_planned_action);
                           mresult.canAcceptOffer    = (isofferte && (!lopende_offertes || !offerteauto) &&
                                                        mresult.haveORDOAPrights && mresult.canRead("WEB_ORDBOF") &&
                                                        !(uitvOpdrNaOfferte && offerteauto) && !is_planned_action);
                           mresult.canRejectOffer    = (isofferte && mresult.haveORDOAPrights &&
                                                        mresult.canRead("WEB_ORDBOF") && !(uitvOpdrNaOfferte && offerteauto) &&
                                                        !is_planned_action);
                           mresult.canOpmChange      = (mresult.haveORDSUPrights || mresult.canAcceptOffer || mresult.canRejectOffer) ||
                                                       (myBO2Change && mresult.canWrite("WEB_ORDAFR"));  /* AANS#22655 */
                           mresult.canUrenMatChange  = (mresult.canFinish || mresult.haveORDFINrights) ||
                                                       (myBO2Change && mresult.canWrite("WEB_ORDAFR"));  /* AANS#22655 */
                           mresult.canSeeARFlex      = (isofferte && (mresult.haveORDSUPrights || (mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights)));
                           mresult.canChangeARFlex   = (isofferte && (mresult.haveORDSUPrights || (mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights)));
                           break;
                   case 9: // Kostentechnisch voltooid gemeld (doorgaans door uitvoerende)
                           mresult.canChange         = (mresult.haveORDFINrights || mresult.haveORDSUPrights ||
                                                        (isofferte && mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights));
                           mresult.hadFinishRights   = (!isofferte && typehas_cost && mresult.canWrite("WEB_ORDAFR") && !is_planned_action);
                           mresult.couldClose        = (mresult.canWrite("WEB_ORDBOF") && (decentraal < 2) ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change) ||
                                                       (mresult.canWrite("WEB_MLDORD") && user.isCollega(uitv_key)));
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canFlexChange     = (mresult.haveORDFINrights || mresult.haveORDSUPrights);
                           mresult.canKostChange     = (mresult.haveORDFINrights && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canUrenMatChange  = (mresult.haveORDFINrights);
                           mresult.hadUrenMatChange  = (mresult.canFinish || mresult.haveORDFINrights) ||
                                                       (myBO2Change && mresult.canWrite("WEB_ORDAFR"));
                                                       if (mresult.iamBedrijfContact && mresult.hadUrenMatChange)
                                                       {
                                                         if (t_cost > S("mld_max_kosten_extern"))
                                                           mresult.hadUrenMatChange = false;
                                                       }
                           mresult.canSeeARFlex      = (isofferte && (mresult.haveORDSUPrights || (mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights)));
                           mresult.canChangeARFlex   = (isofferte && (mresult.haveORDSUPrights || (mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights)));
                           break;
                   case 10: // Nog goedkeur
                           mresult.canChange         = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canChangeUrole    = "bo";
                           mresult.canGoedkeur       = mresult.canWrite("WEB_ORDGOE") && !is_planned_action &&   // Heb ik de rechten om goed te keuren op dit niveau 1?
                                                       ((((S("mld_opdr_approval_all") == 0 && t_cost >= bestellimiet) || (S("mld_opdr_approval_all") == 1 && t_cost <= bestellimiet2)) &&
                                                         opdr_approved <= bestellimiet) ||
                                                        (t_cost >= gvs && opdr_approved < 0));
                           mresult.canGoedkeur2      = mresult.canWrite("WEB_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 && t_cost >= bestellimiet2 && (opdr_approved == bestellimiet2 || mresult.canGoedkeur)) ||
                                                        (S("mld_opdr_approval_all") == 1 && t_cost <= bestellimiet3 && opdr_approved <= bestellimiet2));
                           mresult.canGoedkeur3      = mresult.canWrite("WEB_ORDGO3") && !is_planned_action &&
                                                       ((S("mld_opdr_approval_all") == 0 && t_cost >= bestellimiet3 && (opdr_approved == bestellimiet3 || mresult.canGoedkeur2)) ||
                                                        (S("mld_opdr_approval_all") == 1 && t_cost <= bestellimiet4 && opdr_approved <= bestellimiet3));
                           mresult.canGoedkeur4      = mresult.canWrite("WEB_ORDGO4") && !is_planned_action &&
                                                       ((S("mld_opdr_approval_all") == 0 && t_cost >= bestellimiet4 && (opdr_approved == bestellimiet4 || mresult.canGoedkeur3)) ||
                                                        (S("mld_opdr_approval_all") == 1 && t_cost <= bestellimiet5 && opdr_approved <= bestellimiet4));
                           mresult.canGoedkeur5      = mresult.canWrite("WEB_ORDGO5") && !is_planned_action &&
                                                       ((S("mld_opdr_approval_all") == 0 && t_cost >= bestellimiet5 && (opdr_approved >= bestellimiet5 || mresult.canGoedkeur4)) ||
                                                        (S("mld_opdr_approval_all") == 1 && t_cost > bestellimiet5 && opdr_approved <= bestellimiet5)) &&
                                                       t_cost > opdr_approved;
                           mresult.canReject         = (mresult.canGoedkeur ||
                                                        mresult.canGoedkeur2 ||
                                                        mresult.canGoedkeur3 ||
                                                        mresult.canGoedkeur4 ||
                                                        mresult.canGoedkeur5);
                           mresult.canCopy           = (mresult.canWrite("WEB_ORDBOF") && !is_planned_action && !mld_afgerond);
                           mresult.canVeldChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canFlexChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUitvChange     = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canDatesChange    = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canKostChange     = (mresult.canWrite("WEB_ORDBOF") && S("mld_ord_show_kostenplaats") == 1);
                           mresult.canOpmChange      = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canUrenMatChange  = (mresult.canWrite("WEB_ORDBOF"));
                           mresult.canOpdrTypeChange = (mresult.canWrite("WEB_ORDBOF") && !isofferte && !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 || t_cost <= bestellimiet2 || opdr_approved > 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 || t_cost <= bestellimiet3 || opdr_approved > 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 || t_cost <= bestellimiet4 || opdr_approved > 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 || t_cost <= bestellimiet5 || opdr_approved > bestellimiet5);
                           else if (mresult.canGoedkeur5) // Kan ik dit contract volledig fiatteren en acfief maken?
                             mresult.finalapproval = true;
                           break;
                   case 7: // Verwerkt
                           mresult.couldClose        = (mresult.canWrite("WEB_ORDBOF") ||
                                                       (mresult.canWrite("WEB_ORDBO2") && myBO2Change));
                           mresult.canSeeARFlex      = (isofferte && (mresult.haveORDSUPrights || (mresult.canRead("WEB_ORDBOF") && mresult.haveORDOAPrights)));
                           break;
              }

              if (mresult.iamBedrijfContact && mresult.canUrenMatChange)
              {
                if (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, dis_key, opdr_key)
      {
        var amount = opdrachtbedrag; // Indien geen pgblimiet dan gehele opdracht bedrag

        // Opvragen PGB limiet
        var pgblimiet = budget.get_pgblimiet(prs_key, dis_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, dis_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, dis_key, opdr_key)
      {
        var amount = opdrachtbedrag; // Indien geen agblimiet dan gehele bestel bedrag

        // Opvragen AGB limiet
        var agblimiet = budget.get_agblimiet(kp_key, dis_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, dis_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, dis_key), prs_key, dis_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, dis_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, dis_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: "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.afdeling().prs_kostenplaats_key() || -1;
                    fields.push({ dbs: "prs_kostenplaats_key",    typ: "key",      val: kostenplaats_key },
                                { dbs: "mld_kosten_klant",        typ: "check",    val: stdm_info.ins_srtdiscipline_kostenklant==1?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;
            },

       // Ben ik contactpersoon van *een* bedrijf (maakt niet uit welke)
       // of specifiek van bedrijf_key
       iamContact: function _iamContact(bedrijf_key)
       {
           var sql = "SELECT prs_bedrijf_key"
                   + "  FROM prs_contactpersoon"
                   + " WHERE prs_perslid_key = " + user_key
                   + "   AND prs_contactpersoon_verwijder IS NULL";
           if (bedrijf_key)
              sql += " AND prs_bedrijf_key = " + bedrijf_key;
           var oRs = Oracle.Execute(sql);
           var isEof = oRs.Eof;
           oRs.Close();
           return !isEof;
       },

       // 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);
       },

       generate_relobject_editblock: function (mld_key, params)
       { // Als we met één object binnenkomen tonen we de knop niet
         if (params.ins_key < 0 && (mld_key <= 0 || params.canChange))
         {
           var rwparams = { datatype: "button",
                            html: "title='" + L("lcl_mld_objects_select") + "' onclick='" + params.onclickobj + "'" + (params.disableobjects? " disabled" : ""),
                            endicon: "fa-hand-pointer-o fa-inverse hasIcon"
                          }
           RWFIELDTR("r_objs_button", "button", L("lcl_mld_objects"), L("lcl_mld_objects") + "(" + params.aantalobj + ")", rwparams);
         }
%>
         <tr>
           <td>
           </td>
           <td>
<%
             var plaatsaanduiding = (S("prs_wpprefix_objectid") == 1
                                    ? " CASE"
                                      + " WHEN o.prs_werkplek_omschrijving IS NOT NULL"
                                      + " THEN ' ' || o.prs_werkplek_omschrijving"
                                      + " ELSE ''"
                                      + " END"
                                    : "''");
             if (mld_key > 0)
             {
               var sql = "SELECT d.ins_deel_key"
                       + "     , ins_deel_omschrijving || " + plaatsaanduiding + " || ' (' || " + lcl.xsql('s.ins_srtdeel_omschrijving', 's.ins_srtdeel_key') + " || ')' 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_v_aanwezigdeel d"
                       + "     , ins_srtdeel s"
                       + "     , mld_melding_object m"
                       + "     , ins_v_alg_overzicht o"
                       + " 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 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"
                       + "     , ins_deel_omschrijving || " + plaatsaanduiding + " || ' (' || " + lcl.xsql('s.ins_srtdeel_omschrijving', 's.ins_srtdeel_key') + " || ')' 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_v_aanwezigdeel d"
                       + "     , ins_srtdeel s"
                       + "     , ins_v_alg_overzicht o"
                       + " WHERE d.ins_deel_key = " + params.ins_key
                       + "   AND d.ins_srtdeel_key = s.ins_srtdeel_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: mld_melding.srtinst_verplicht,
                            extraParamValue: "uitvoertijd" // uitvoertijd is hier in uren
                          });
%>           <input type='hidden' name='has_r_objs' value='1'>
           </td>
         </tr>
         <script>
           $(document).ready(function ()
           {
             $('#r_objs').attr("size", ($("#r_objs")[0].options.length == 0? 1 : $("#r_objs")[0].options.length));
           });
         </script>
<%     },

       generate_relobject_block: function (mld_key)
       {
         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 d.ins_deel_key"
                 + "     , ins_deel_omschrijving || " + plaatsaanduiding + " || ' (' || " + lcl.xsql('s.ins_srtdeel_omschrijving', 's.ins_srtdeel_key') + " || ')' deel "
                 + "  FROM ins_deel d"
                 + "     , ins_srtdeel s"
                 + "     , mld_melding_object m"
                 + "     , ins_v_alg_overzicht o"
                 + " 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 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)
         {
           BLOCK_START("mldIns", L("lcl_gerelateerdeobjecten"));
           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>
<%
           while( !oRs.eof ) {
            %><input class="fld details" readonly value="<%=safe.htmlattr(oRs("deel").Value)%>" onclick='showObjDetail(<%=oRs("ins_deel_key").Value%>, "bo")'><%
             oRs.MoveNext();
             if (!oRs.eof)
                 Response.Write("<br/>");
           }
           BLOCK_END();
         }
         oRs.close();
       },

       dienst_controle: function (stdm_key, locatiekey, gebouwkey, ruimtekey, prs_key_voor)
       {
           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')
               + "  FROM mld_stdmelding ms"
               + "     , prs_dienst pd"
               + " WHERE mld_stdmelding_key = " + stdm_key
               + "   AND pd.prs_dienst_key(+) = ms.prs_dienst_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 prs_bedrijf_key = -1;

           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"
                   + "  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 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);
               if (vereisdienst && oRs("aantal") == 0)
                   abort_with_warning(L("lcl_mld_dienstunavailablehere") + prs_dienst_desc);

               if (oRs("aantal") == 1)
                   prs_bedrijf_key = oRs("prs_bedrijf_key").Value; // straks mogelijk vanzelf opdracht
           }

           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);
               if (oRs("aantal").Value > 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"));
                   }
               }
           }
       	  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 track_oms = L("lcl_linked_to").format(mld.mld_prefix(child_key)+child_key, mld.mld_prefix(parent_key)+parent_key);
         mld.trackmeldingupdate(child_key, track_oms);

         // Probeer de status gelijk aan die van de parent te zetten
         // Merk op dat de trigger ook nog kan ingrijpen: als je hem op 7 probeert
         // te zetten kan het zo maar 4 worden.
         var sql = "SELECT mld_melding_status"
                 + "  FROM mld_melding m"
                 + " WHERE mld_melding_key = " + parent_key;
         var oRs = Oracle.Execute(sql);
         var mldstatus = oRs("mld_melding_status").Value;
         oRs.Close();
         // pikt de package niet altijd (2 naar 7) mld.setmeldingstatus(child_key, mldstatus);
         sql = "UPDATE   mld_melding"
             + "   SET   mld_melding_status = " + (mldstatus==6?5:mldstatus) // niet rechtstreeks verwerkt
             + " WHERE   mld_melding_key = " + child_key;
         //fac.trackaction (eventcode, r.mld_melding_key, puserkey, NULL, NULL);
         var err = Oracle.Execute(sql, true);
         if (err.friendlyMsg)
            return err.friendlyMsg;
         else
            return "";
       },

       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"
                                 + "       , v.mld_srtkenmerk_omschrijving"
                                 + "       , k.mld_kenmerk_verplicht_status"
                                 + "    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 s.mld_stdmelding_key = m.mld_stdmelding_key"
                                 + "     AND s.mld_ins_discipline_key = d.ins_discipline_key"
                                 + "     AND ((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_kenmerktype <> 'M'"
                                 + "     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 = " + status
                   + "   AND mkw.waarde IS NULL";
           var oRs = Oracle.Execute(sql);
           var ontbreekt = [];
           while (!oRs.eof)
           {
               ontbreekt.push(oRs("mld_srtkenmerk_omschrijving").Value);
               oRs.MoveNext();
           }
           oRs.Close();
           // Levert array op met kenmerken die ingevuld hadden moeten zijn.
           return ontbreekt;
       },

       hasRequiredStatusEmptyOpdr: function(opdr_key, status)
       {
           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"
                                 + "       , v.mld_srtkenmerk_omschrijving"
                                 + "       , k.mld_kenmerk_verplicht_status"
                                 + "    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"
                                 + "     AND k.mld_kenmerk_niveau = '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
                   + "   AND okw.mld_kenmerk_verplicht_status = " + status
                   + "   AND okw.waarde IS NULL";
           var oRs = Oracle.Execute(sql);
           var ontbreekt = [];
           while (!oRs.eof)
           {
               ontbreekt.push(oRs("mld_srtkenmerk_omschrijving").Value);
               oRs.MoveNext();
           }
           oRs.Close();
           // Levert array op met kenmerken die ingevuld hadden moeten zijn.
           return ontbreekt;
       },

       srtdisc_sql: function (autfunction, params)
       {
           params = params || {};
           autfunc = ((typeof autfunction == "object" && autfunction instanceof Array)
                     ? safe.quoted_sql_join(autfunction)
                     : safe.quoted_sql(autfunction)
                     );
           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', 'ins_srtdiscipline_key')
                + "  FROM ins_v_aanwezigsrtdiscipline sd"
                + " WHERE ins_srtdiscipline_module = 'MLD'"
                + "   AND EXISTS (SELECT ''"
                + "                 FROM mld_discipline td"
                + (params.filter_from ? params.filter_from : "")
                + "                WHERE td.ins_srtdiscipline_key = sd.ins_srtdiscipline_key"
                + (params.filter_where ? params.filter_where : "")
                + "                 AND ins_discipline_key IN("
                + "           SELECT ins_discipline_key"
                + "             FROM fac_v_webgebruiker g, fac_functie f "
                + "            WHERE g.fac_functie_key = f.fac_functie_key "
                + "              AND f.fac_functie_code IN (" + autfunc + ")"
                + "              AND (g.fac_gebruiker_alg_level_write < 9 AND g.fac_gebruiker_prs_level_write < 9)"
                + "              AND g.prs_perslid_key = " + user_key + ")"
                + "              AND td.ins_discipline_key IN("
                + "           SELECT mld_ins_discipline_key"
                + "             FROM mld_stdmelding "
                + "            WHERE mld_stdmelding_verwijder IS NULL "
                + "              AND (mld_stdmelding_vervaldatum IS NULL "
                + "                 OR mld_stdmelding_vervaldatum > TRUNC (SYSDATE)) "
                + (autfunction == "WEB_MLDUSE" ? " AND mld_stdmelding_notfrontend = 0) " : ")")
           if (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...
               mySRTsql += "  AND sd.ins_srtdiscipline_ins = 1"
                        + "   AND td.ins_discipline_key IN (SELECT msm.mld_ins_discipline_key"
                        + "        FROM mld_stdmelding msm,"
                        + "             ins_srtgroep isg,"
                        + "             ins_srtdeel isd,"
                        + "             ins_deel insd"
                        + "       WHERE mld_stdmelding_verwijder IS NULL"
                        + "         AND insd.ins_deel_key = " + params.ins_key
                        + "         AND isd.ins_srtdeel_key = insd.ins_srtdeel_key"
                        + "         AND isg.ins_srtgroep_key = isd.ins_srtgroep_key"
                        + (autfunction == "WEB_MLDUSE" ? " AND mld_stdmelding_notfrontend = 0 " : "")
                        + "         AND (   msm.ins_srtinst_niveau = 'S' AND ins_srtinst_key = insd.ins_srtdeel_key"
                        + "              OR msm.ins_srtinst_niveau = 'G' AND ins_srtinst_key = isg.ins_srtgroep_key"
                        + "              OR msm.ins_srtinst_niveau = 'D' AND ins_srtinst_key = isg.ins_discipline_key"
                        //       + "        OR msm.ins_srtinst_niveau IS NULL" // is wel héél algemeen
                        + "             )"
                        + "     )";
            }
            mySRTsql += " )"
                      + "   AND sd.ins_srtdiscipline_key <> " + S("kto_srtdiscipline_key")
                      + " ORDER BY 2";
            return mySRTsql;
       },

       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);
             if (dienst == -1 && !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 = mld.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(kenmerkEmpty, mld_key, status)
           { // Zijn er nog kenmerken die nu wel verplicht zijn?
             var kvsAfwezig = mld.hasRequiredStatusEmptyMelding(mld_key, status);
             if (kvsAfwezig.length)
             {
               var mldnr = mld.mld_prefix(mld_key) + mld_key;
               kenmerkEmpty.push(L("lcl_mld_req_status_empty").format(kvsAfwezig.join(", "), mldnr) );
             }
             return kenmerkEmpty;
           },

       getReqStatusEmptyOpdr:
           function _getReqStatusEmptyOpdr(kenmerkEmpty, opdr_key, status)
           { // Zijn er nog kenmerken die nu wel verplicht zijn?
             var kvsAfwezig = mld.hasRequiredStatusEmptyOpdr(opdr_key, status);
             if (kvsAfwezig.length)
             {
               var mld_opdr = mld.mld_opdr_info(opdr_key);
               var mldnr = mld.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.room_key == -1);
                           break;
                 case "V": emptyRequiredFields = (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.show_bes && !mld_melding.deladdress);
             // Objecten.
             if (mld_melding.show_ins && mld_melding.srtinst_verplicht)
             { // 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"
                     + "     , msk.mld_srtkenmerk_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 ALL"
                     + "        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"
                     + "       ) s"
                     + " WHERE mkm.mld_kenmerk_verwijder IS NULL"
                     + "   AND mkm.mld_stdmelding_key = s.ref_mld_stdmelding_key"
                     + "   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 (   (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 DESC";

             return sql;
           }

      }

%>
