<% /*
     $Revision$
     $Id$

    File:               res_list.inc
    Description:        Show an overview of reservations in list-form,
                        which meets with the given requirements
    Parameters:
        urole           user role (fe, fo, bo, mi)
        outputmode      behave in an output mode, print to 0 = screen, 1 = printer, 2 = excel, etc.
        showall         show all orders which meets with the given requirements
        compact         leaner presentation, as used in subframes (1)
        mld_key         search for reservations belonging to the given mld_key
        datefrom        search for reservations at the selected date-month-year
        dateto          search for reservations at the selected date-month-year
        res_key         search for reservation with the given reservation key
        reg_key_arr     search for contracts with the given regios
        dist_key_arr    search for contracts with the given districts
        loc_key_arr     search for reservations for the selected locations
        bld_key_arr     search for reservations for the selected buildings
        floor_key_arr   search for reservations for the selected floors
        act_key_arr     search for reservations witch the selected activity
        srtact          search for reservations witch the selected srt activity
        searchtext      search for reservations with the searchtext in description or remark
        kp              search for reservations with the given account text in account description
        requestor_key   search for reservations for selected requestor
        host_key        search for reservations for selected host
        dep_key         search for reservations for the selected department
        roomcatalogue_key_arr    search for reservations with the selected room categories/types
        obj_key_arr     search for reservations with the selected objects categories/types
        art_key_arr     search for reservations with the selected articles categories/types
        article_arr     search for reservations with the selected articles
        artgroup        search for reservations with the selected article group
        resstatus       search for reservations with the selected reservation FO status
        roomcat         search for room reservations
        objcat          search for object reservations
        artcat          search for article reservations
        res_actual      search for actual reservations
        res_deleted     search for res_deleted reservations
        res_open        search for reservations which are open (2)
        res_finished    search for reservations which are finished (5)
        res_closed      search for reservations which are closed (6)
        res_approved    search for reservations which are approved
        res_notapproved search for reservations which are not approved
        res_tobeapproved search for reservations which heave to be approved
        res_noshowonly  show noshow's only
        sortout         sort out the reservations by
        groupres        groupres the reservations by
    Context:            Search action from res_fefo_search.asp or res_bomi_search form
    Note:
    TODO:
    de afhankelijkheden van urole moeten er uit! Deze functie levert een lijst op die voldoet aan de criteria
    en gegeven de user en de autorisatie. Punt!

*/
%>

<!-- #include file="../Shared/discx3d.inc" -->
<!-- #include file="../Shared/resultset_table_v2.inc" -->
<!-- #include file="../Shared/rater.inc" -->
<!-- #include file="./res.inc" -->
<!-- #include file="../Shared/getkenmerksql.inc" -->

<%
FCLTHeader.Requires({ plugins:["jQuery"],
                      js: ["../res/res_list.js", "jquery-ui.js"]
                    });

function res_list (pautfunction, params)
{ // VALIDATE AND PREPARE
  // Als een parameter niet gedefinieerd of null is, dan doet-ie niks
  // anders wordt die verondersteld een zinvolle waarde te hebben
  // NB: -1 is vaak geen zinvolle waarde; null had het dan moeten zijn!

  // Valid and supported parameters are:
  // params.urole           : the usuals two-letter lowercase string
  // params.outputmode      : print to 0 = screen, 1 = printer, 2 = excel, etc.
  // params.showall         : boolean (true | false)
  // params.datefrom        : date
  // params.dateto          : date
  // params.res_key         : key
  // params.reg_key_arr     : Array met keys
  // params.dist_key_arr    : Array met keys
  // params.loc_key_arr     : Array met keys
  // params.bld_key_arr     : Array met keys
  // params.floor_key_arr   : Array met keys
  // params.room_key_arr    : Array met keys
  // params.act_key_arr     : Array met keys
  // params.suppress_cont   : boolean (true | false)
  // params.searchtxt       : wildcard string
  // params.dep_key         : key
  // params.kp              : wildcard string
  // params.requestor_key   : key
  // params.host_key        : key
  // params.dep_key         : key
  // params.room_key_arr    : Array met keys
  // params.roomcatalogue_key_arr    : Array met keys
  // params.obj_key_arr     : Array met keys
  // params.art_key_arr     : Array met keys
  // params.article_arr     : Array met keys
  // params.artgroup        : string met keys
  // params.resstatus       : key
  // params.roomcat         : boolean (true | false)
  // params.objcat          : boolean (true | false)
  // params.artcat          : boolean (true | false)
  // params.res_actual      : boolean (true | false)
  // params.res_deleted     : boolean (true | false)
  // params.res_open        : boolean (true | false)
  // params.res_finished    : boolean (true | false)
  // params.res_closed      : boolean (true | false)
  // params.res_approved    : boolean (true | false)
  // params.res_notapproved : boolean (true | false)
  // params.sortout         : key
  // params.groupres        : key

  // De functie checkAutorisation(autfunction) geeft een Response.End indien er geen autorisatie voor autfunction wordt gevonden
  var authparams = user.checkAutorisation(pautfunction);
  var authparamsRESNOS = user.checkAutorisation("WEB_RESNOS", true);

  var urole = params.urole;
  var fronto = (urole == "fo");
  var backo = (urole == "bo");
  var minfo = (urole == "mi"); // NOT APPLICABLE?
  var frontend = (urole == "fe" || (!fronto && !backo && !minfo));

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

  var mld_key = params.mld_key || -1;
  var datefrom = params.datefrom;
  var dateto = params.dateto;
  var res_key = params.res_key;
  var reg_key_arr = params.reg_key_arr || [];
  var dist_key_arr = params.dist_key_arr || [];
  var loc_key_arr = params.loc_key_arr || [];
  var bld_key_arr = params.bld_key_arr || [];
  var floor_key_arr = params.floor_key_arr || [];
  var room_key_arr = params.room_key_arr || [];
  var act_key_arr = params.act_key_arr || [];
  var suppress_cont = params.suppress_cont;
  var srtact = params.srtact;
  var searchtext = params.searchtext;
  var dep_key = params.dep_key;
  var kp = params.kp;
  var requestor_key = params.requestor_key;
  var host_key = params.host_key;
  var roomcatalogue_key_arr = params.roomcatalogue_key_arr || [];
  var obj_key_arr = params.obj_key_arr || [];
  var art_key_arr = params.art_key_arr || [];
  var article_arr = params.article_arr || [];
  var artgroup = params.artgroup;
  var resstatus = params.resstatus;
  var roomcat = params.roomcat || res_key > 0;
  var objcat = params.objcat || res_key > 0;
  var artcat = params.artcat || res_key > 0 || params.groupres == 7 || params.groupres == 8 || params.groupres == 15;
  var res_actual = "res_actual" in params ? params.res_actual : true;
  var res_deleted = "res_deleted" in params ? params.res_deleted : false;
  var res_open = params.res_open;
  var res_finished = params.res_finished;
  var res_closed = params.res_closed;
  var res_approved = params.res_approved;
  var res_notapproved = params.res_notapproved;
  var res_tobeapproved = params.res_tobeapproved;
  var sortout = params.sortout;
  var groupres = params.groupres;
  var flags = params.flags || [];
  var opdr_key = params.opdr_key || -1;


  // PF: ik heb het vermoeden dat deze inmiddels overbodig is (en params.resourcetypes bestaat niet gegarandeerd ook)
  //if (inArray(4, params.resourcetypes)) // Personen. Vooralsnog alleen onder opdrachten zonder alg-scope
  //  params.restype = "O";
  var restype = params.restype;

  // Als er wel artikelen zijn geselecteerd maar geen verbruiksartikel catalogus, dan de catalogussen erbij zoeken zodat we daar ook op kunnen filteren.
  // Anders komen ook nog alle ruimte en object reserveringen in de lijst.
  var article_disc_arr = [];
  article_disc_arr = article_disc_arr.concat(art_key_arr);
  if (art_key_arr.length == 0 && article_arr.length > 0)
  {
    var sql = "SELECT ra.res_discipline_key"
            + "  FROM res_artikel ra"
            + " WHERE ra.res_artikel_key IN (" + article_arr.join(",") + ")";
    oRs = Oracle.Execute(sql);
    while (!oRs.eof)
    {
      article_disc_arr.push(oRs("res_discipline_key").Value);
      oRs.MoveNext();
    }
  }

  var sql_tz = "SELECT ''"
             + "  FROM alg_locatie"
             + " WHERE     alg_locatie_timezone IS NOT NULL"
             + "       AND alg_locatie_timezone <> " + safe.quoted_sql(S("fac_server_timezone"));
  var oRs_tz = Oracle.Execute(sql_tz);
  var any_tz = !oRs_tz.EOF;
  oRs_tz.Close();

  // Berekenen is duur en niet altijd nodig
  var withprices = (groupres == 4
                 || groupres == 5
                 || groupres == 6
                 || groupres == 7
                 || groupres == 8
                 || groupres == 9
                 || groupres == 10
                 || groupres == 11
                 || groupres == 12
                 || groupres == 13
                 || groupres == 14
                 || groupres == 15);


	// Fast check to see if we remarks are used. To show/hide the colums
	var sql= "SELECT 1 FROM res_srtactiviteit WHERE res_srtactiviteit_metopmerk = 1";
	oRs = Oracle.Execute(sql);
	 var hasAnyOpmerkingen = !oRs.eof;
	oRs.close();

%>

  <html>
    <head>
<%
      FCLTHeader.Generate({ outputmode: outputmode });
%>
      <script type="text/javascript">

        $(function() {
          $(".clickParent").parent().on("click", function(e) { e.stopPropagation(); $(this).find("> .clickParent").trigger("click"); });
        });

        var urole = "<%=urole%>";
        var groupres = "<%=groupres%>";
        var user_naam = "<%=safe.jsstring(user.naam())%>";
        var todayString = "<%=toDateString(new Date())%>";
        var customerId = "<%=customerId%>";
        var user_key = "<%=user_key%>";
        // For BO/MI functions
        var res_closed = (<%=res_closed? 1 : 0%> == 1)
      </script>

    </head>
    <body id="listbody">

<%

      // Functie fncolFlags kan in alle overzichten worden gebruikt.
      function fncolFlags(oRs)
      {
        var reskey = oRs("rsv_ruimte_key").Value; // rsv_ruimte_key
        var flagkey = oRs("res_rsv_ruimte_flag").Value || 0;
        var ttl = L("lcl_res_flag" + flagkey);
        var displ = flagkey||"";

        if (print || excel)
        {
            if (flagkey != 0) displ = safe.html(ttl);  // else blijft-ie gewoon leeg
        }
        else  // maak er dan nog leuke plaatjes van
        {
            var flagIcon = "<span id='resflagimg"+reskey+"' flagkey='"+flagkey+"' class='resflag"+flagkey+"'>" + I("fa-fclt-flag" + (flagkey == 0? "0" : "")) + "</span>";
            // Met hidden flagkey voor sortering. 999 zorgt dat bij 1 keer sorteren de gevlagde direct bovenaan staan
            displ = "<div class='clickParent' " + ((backo || fronto) ? "onclick='toggleResFlag(event, " + reskey +");'":"")
                  + " title='"+safe.htmlattr(ttl)+"'>"
                  + flagIcon
                  + "<span style='display:none'>"+(flagkey||999)+"</span></div>";
        }
        return displ;
      }

      function fncolOordeel(oRs)
      {
        var result = null;
        var displ_val = oRs("oordeel").Value;
        var displ_txt = oRs("oordeel_opm").Value;
        if (displ_val && displ_val != 0)
        {
          if (excel || print)
            result = "<span id='oordeel' title='" + safe.htmlattr(displ_txt)+"'>" + displ_val + "</span>";
          else
            result = rating.stars(displ_val, {rating: {id: "oordeel", note: displ_txt}});
        }
        return result;
      }

      function fncolOordeelAvg(oRs)
      {
        var result = null;
        var displ_val = oRs("oordeel").Value;
        if (displ_val && displ_val != 0)
        {
          if (excel || print)
            result = "<span id='oordeel'>" + safe.displayfloat(displ_val, 1) + "</span>";
          else
            result = rater(displ_val, {readonly: true});
        }
        return result;
      }

      function fncustomSort(oRs)
      {
        var a = "0000000000"+oRs("res_reservering_key").Value;
        var b = "00000"+oRs("res_rsv_ruimte_volgnr").Value;
        return a.slice(-10) +"_"+ b.slice(-5);
      }

      /***** Build sql *****/

      function getAnyFlex()
      { // Fast check to see if we have any listable flex at all, to prevent superfluous column
        var anyflex_result = {anyflex: false};
        var sql = "SELECT DISTINCT"
                + "       COALESCE (" + lcl.xsql("k.res_kenmerk_omschrijving", "k.res_kenmerk_key")
                + "              ,  " + lcl.xsql("sk.res_srtkenmerk_omschrijving", "sk.res_srtkenmerk_key") + ") res_kenmerk_omschrijving"
                + "     , sk.res_srtkenmerk_kenmerktype"
                + "  FROM res_srtkenmerk sk, res_kenmerk k"
                + " WHERE BITAND (res_kenmerk_inlijst, 1) = 1"
                + "   AND sk.res_srtkenmerk_key = k.res_srtkenmerk_key"
                + "   AND k.res_kenmerk_niveau NOT IN ('P', 'O')"
                + "   AND k.res_kenmerk_verwijder IS NULL"
                + "   AND sk.res_srtkenmerk_verwijder IS NULL";
        var oRs = Oracle.Execute(sql);
        if (!oRs.eof)
        {
          var multiflex = false;
          var bijlageflex = (oRs("res_srtkenmerk_kenmerktype").Value == "M");
          var flexlabel = oRs("res_kenmerk_omschrijving").Value;
          oRs.MoveNext();
          if (!oRs.Eof)
          {
            multiflex = true;
            flexlabel = L("lcl_flexlist");

            while (!oRs.eof)
            {
              if (oRs("res_srtkenmerk_kenmerktype").Value == "M")
                  bijlageflex = true;
              oRs.MoveNext();
            }
          }

          var sql_flex   = ", (SELECT LISTAGG("
                + (multiflex
                  ? "COALESCE (" + lcl.xsql("k.res_kenmerk_omschrijving", "k.res_kenmerk_key")
                    + "      , " + lcl.xsql("skr.res_srtkenmerk_omschrijving", "skr.res_srtkenmerk_key") + ")"
                    + " || ':'|| CHR(160) ||"
                  : "")
                + "            CASE"
                + "            WHEN skr.res_srtkenmerk_kenmerktype = 'R' OR skr.res_srtkenmerk_kenmerktype = 'r' OR skr.res_srtkenmerk_kenmerktype = 'S'"
                + "            THEN flx.getdomeinwaarde (skr.fac_kenmerkdomein_key, km.res_kenmerkreservering_waarde)"
                + "            WHEN skr.res_srtkenmerk_kenmerktype = 'N'"
                + "             AND skr.res_srtkenmerk_lengte = 1 "
                + "             AND skr.res_srtkenmerk_nmin = 0 "
                + "             AND skr.res_srtkenmerk_nmax = 1 "
                + "             AND (skr.res_srtkenmerk_dec = 0 OR skr.res_srtkenmerk_dec IS NULL) "
                + "            THEN DECODE (km.res_kenmerkreservering_waarde, "
                + "                         0, " + safe.qL("lcl_check_0") + ", "
                + "                         1, " + safe.qL("lcl_check_1") + ", "
                + "                         km.res_kenmerkreservering_waarde)"
                + "            ELSE km.res_kenmerkreservering_waarde"
                + "            END, CHR(13)) "
                + "           WITHIN GROUP (ORDER BY res_kenmerk_volgnummer)"
                + "      FROM res_srtkenmerk skr,  res_kenmerk k, res_kenmerkwaarde km, res_rsv_ruimte rr"
                + "     WHERE rr.res_reservering_key = rec2.res_reservering_key"
                + "       AND rr.res_rsv_ruimte_key = rec2.res_rsv_ruimte_key"
                + "       AND km.res_rsv_ruimte_key = rr.res_rsv_ruimte_key"
                + "       AND k.res_kenmerk_key = km.res_kenmerk_key"
                + "       AND BITAND(k.res_kenmerk_inlijst,1) = 1"
                + "       AND skr.res_srtkenmerk_key = k.res_srtkenmerk_key"
                + "       AND skr.res_srtkenmerk_verwijder IS NULL"
                + "       AND k.res_kenmerk_verwijder IS NULL"
                + "       AND km.res_kenmerkwaarde_verwijder IS NULL) flex";
          anyflex_result.anyflex = true;
          anyflex_result.multiflex = multiflex;
          anyflex_result.bijlageflex = bijlageflex;
          anyflex_result.flexlabel = flexlabel;
          anyflex_result.sql_flex = sql_flex;
        }
        oRs.close();
        return anyflex_result;
      }

      // WITH-aliassen eerst
      thePerslid = " thePerslid AS"
                 + " (SELECT prs_perslid_key"
                 + ", prs_perslid_telefoonnr"
                 + ", prs_perslid_mobiel"
                 + ", prs_afdeling_key"
                 + ", " + S("prs_pers_string")  + " naam FROM prs_perslid p)";

      theResrsv = " theResrsv AS"
                + " (SELECT xrr.*"
                + "    FROM res_rsv_ruimte xrr, res_reservering xr"
                + "   WHERE xrr.res_reservering_key = xr.res_reservering_key";

      theGroup = " theGroup AS"
               + " (SELECT g_rrd.res_rsv_ruimte_key, g_rd.res_discipline_key, g_id.ins_srtdeel_key, g_rd.res_deel_omschrijving"
               + "       , 1 isbulk"
               + "       , MAX(g_rd.res_deel_key) res_deel_key"
               + "       , COUNT(*) bulk_aantal"
               + " FROM " + (res_deleted || res_key > 0 ? "res_rsv_deel" : "res_v_aanwezigrsv_deel") + " g_rrd"
               + "       , res_deel g_rd"
               + ",        ins_deel g_id"
               + "   WHERE g_rrd.res_deel_key = g_rd.res_deel_key"
               + "     AND g_rd.res_ins_deel_key = g_id.ins_deel_key"
               + (backo || minfo // Dirty alleen voor FE & FO tonen en niet voor BO & MI
                 ? "     AND g_rrd.res_rsv_deel_dirtlevel = 0"
                 : "")
               + "     AND COALESCE(g_rd.res_deel_bulkreserveerbaar,0) = 1"
               + "   GROUP BY g_rrd.res_rsv_ruimte_key, g_rd.res_discipline_key, g_id.ins_srtdeel_key, g_rd.res_deel_omschrijving"
               + "  UNION"
               + "  SELECT g_rrd.res_rsv_ruimte_key, g_rd.res_discipline_key, g_id.ins_srtdeel_key, g_rd.res_deel_omschrijving"
               + "       , 0 isbulk"
               + "       , g_rd.res_deel_key"
               + "       , NULL  bulk_aantal"
               + " FROM " + (res_deleted || res_key > 0 ? "res_rsv_deel" : "res_v_aanwezigrsv_deel") + " g_rrd"
               + "       , res_deel g_rd"
               + ",        ins_deel g_id"
               + "   WHERE g_rrd.res_deel_key = g_rd.res_deel_key"
               + "     AND g_rd.res_ins_deel_key = g_id.ins_deel_key"
               + (backo || minfo // Dirty alleen voor FE & FO tonen en niet voor BO & MI
                 ? "     AND g_rrd.res_rsv_deel_dirtlevel = 0"
                 : "")
               + "     AND COALESCE(g_rd.res_deel_bulkreserveerbaar, 0) = 0"
               + " )";

      if (opdr_key > 0)
        theResrsv += " AND xrr.mld_opdr_key = " + opdr_key;
      if (mld_key > 0)
        theResrsv += " AND xr.mld_melding_key = " + mld_key;

      if (res_key)
        theResrsv += " AND xrr.res_reservering_key = " + res_key;
      else
      { // If there is no res_key then determine sql_date
        // If from and to are given both are used
        // If only one of from and to are give, this is used as a (1) day, not an half open interval
        // 20-10-2009 9:46:28/PF
        datefrom = datefrom || dateto;
        dateto = dateto || datefrom;
        if (datefrom && dateto)
        {
          var ora_date1 = datefrom.beginToSQL();
          var ora_date2 = dateto.endToSQL();
          // Er staan indexen op TRUNC(res_rsv_ruimte_van,'DD') en TRUNC(res_rsv_ruimte_tot,'DD')
          // waardoor onderstaande met de redundante 'TRUNC's een stuk sneller is
          // Hmm, bij nader inzien lijken de indexen niet veel verschil te maken. Haal echter
          // hieronder een (redundante) vergelijking weg en het wordt langzamer
          theResrsv += " AND xrr.res_rsv_ruimte_van < " +  ora_date2
                     + "  AND xrr.res_rsv_ruimte_tot > " + ora_date1
                     + "  AND TRUNC(xrr.res_rsv_ruimte_van, 'DD') <= " + dateto.endToSQL(true)
                     + "  AND TRUNC(xrr.res_rsv_ruimte_tot, 'DD') >= " + datefrom.beginToSQL(true)
                     + (suppress_cont
                       ? " AND (TRUNC(xrr.res_rsv_ruimte_van, 'DD') >= " + datefrom.beginToSQL(true) + " OR TRUNC(xrr.res_rsv_ruimte_tot, 'DD') <= " + dateto.endToSQL(true) + ")"
                       : "");
        }
        if (resstatus)
          theResrsv += " AND xrr.res_status_fo_key = " + resstatus;

        // Aanvrager
        if (requestor_key)
          theResrsv += " AND xrr.res_rsv_ruimte_contact_key = " + requestor_key;

        if (searchtext) // search text in description and remark
          theResrsv += " AND (UPPER(xrr.res_rsv_ruimte_omschrijving) LIKE "+safe.quoted_sql_wild("%" + searchtext + "%")
                     + " OR UPPER(xrr.res_rsv_ruimte_opmerking) LIKE "+safe.quoted_sql_wild("%" + searchtext + "%") + ")";

        if (host_key)
          theResrsv += " AND xrr.res_rsv_ruimte_host_key = " + host_key;

        // Flags
        if (params.flags && params.flags.length > 0 && params.flags.length < S("res_reservering_flags"))
        {
            theResrsv += " AND xrr.res_rsv_ruimte_flag IN (" + params.flags.join(",") + ")";
        }
      }

      if (frontend) //  Altijd de FE-autorisatie erop
      {
        var prsKeys = user.collegakeylist();

        theResrsv += " AND (xrr.res_rsv_ruimte_contact_key IN (" + prsKeys + ")"
                   + "  OR xrr.res_rsv_ruimte_host_key IN (" + prsKeys + "))";
      }

      theResrsv += ")";

      // Make ResultsetTable for bo or mi
      /***** Build sql *****/
      //var res_key = 0;
      var sql_reg = "";
      var sql_dist = "";
      var sql_loc = "";
      var sql_bld = "";
      var sql_floor = "";
      var sql_room = "";
      var sql_act = "";
      var sql_dept = "";
      var sql_account = "";
      var sql_name = "";
      var sql_room_key = "";
      var sql_obj_key = "";
      var sql_art_key = "";
      var sql_article = "";
      var status_sql = "";

      var r_anyflex = getAnyFlex();
      if (r_anyflex.anyflex)
      {
        var anyflex = r_anyflex.anyflex;
        var multiflex = r_anyflex.multiflex;
        var bijlageflex = r_anyflex.bijlageflex;
        var flexlabel = r_anyflex.flexlabel;
      }

      if (!res_key && (!(opdr_key > 0) || (frontend || fronto)))
      {
        if (dep_key)
        {
          sqln = "SELECT ab.niveau"
               + " FROM prs_v_afdeling_boom ab"
               + " WHERE ab.prs_afdeling_key = " + dep_key;
          oRsn = Oracle.Execute(sqln);
          var niveau = oRsn("niveau").Value;

          sql_dept  += " AND phost.prs_afdeling_key IN (SELECT ab.prs_afdeling_key"
                     + "                                 FROM prs_v_afdeling_boom ab"
                     + (frontend || fronto
                       ? "                                  , prs_v_afdeling d"
                       : "")
                     + "                                WHERE ab.prs_afdeling_key" + niveau + " = " + dep_key
                     + (frontend || fronto
                       ? "                                AND d.prs_afdeling_key = ab.prs_afdeling_key"
                       : "")
                     + "                               )";
        }

        if (kp)
          sql_dept = " AND k.prs_kostenplaats_upper LIKE " + safe.quoted_sql_wild(kp);

        if (reg_key_arr.length)
          sql_reg = " AND di.alg_regio_key IN (" + reg_key_arr.join(",") + ")";

        if (dist_key_arr.length)
          sql_dist = " AND ruimte_geg.alg_district_key IN (" +  dist_key_arr.join(",") + ")";

        if (loc_key_arr.length)
          sql_loc = " AND ruimte_geg.alg_locatie_key IN (" + loc_key_arr.join(",") + ")";

        if (bld_key_arr.length)
          sql_bld = " AND ruimte_geg.alg_gebouw_key IN (" + bld_key_arr.join(",") + ")";

        if (floor_key_arr.length)
          sql_floor = " AND ruimte_geg.alg_verdieping_key IN (" + floor_key_arr.join(",") + ")";

        if (room_key_arr.length) {
          sql_room = " AND (  ruimte_geg.alg_ruimte_key IN (" + room_key_arr.join(",") + ")"
                   + "     OR res_geg.res_ruimte_key IN"
                          + " (SELECT r.res_ruimte_key"
                          + "    FROM res_alg_ruimte r"
                          + "   WHERE r.alg_ruimte_key IN (" + room_key_arr.join(",") + ")"
                          + " )"
                   + "     )";
        }

        // Activiteit
        if (act_key_arr.length > 0)
          sql_act = " AND ract.res_activiteit_key IN (" + act_key_arr.join(", ") + ")";
        else if (srtact)
          sql_act = " AND ract.res_srtactiviteit_key = " + srtact;

        // Flags
        if (params.flags && params.flags.length > 0 && params.flags.length < S("res_reservering_flags"))
        {
          sql_flag = " AND rrr.res_rsv_ruimte_flag IN (" + params.flags.join(",") + ")";
        }

        if (roomcatalogue_key_arr.length)
          sql_room_key = " AND res_discipline_key IN (" + roomcatalogue_key_arr.join(",") + ")";

        if (obj_key_arr.length)
          sql_obj_key = " AND rd.res_discipline_key IN (" + obj_key_arr.join(",") + ")";

        if (art_key_arr.length)
          sql_art_key = " AND ra.res_discipline_key IN (" + art_key_arr.join(",") + ")";

        if (article_arr.length)
          sql_article = " AND rra.res_artikel_key IN (" + article_arr.join(",") + ")";

        // deze controle hoeft echt niet, als de parameter er is moet je die gebruiken. if (!(frontend || fronto))
        if (!(res_open && res_finished && res_closed))
        {
          // als alles aangevinkt is, hoef je er niet op te filteren
          var bostatussen = [];

          if (res_open)
            bostatussen.push(2);
          if (res_finished)
            bostatussen.push(5);
          if (res_closed)
            bostatussen.push(6);
          if (bostatussen.length > 0)
              status_sql += " AND res_geg.res_status_bo_key IN (" + bostatussen.join(",")+ ")";
        }

        var approve_sql = [];
        if (res_approved)
        {
          approve_sql.push("rrr.res_rsv_ruimte_afgerond = 1");
        }
        if (res_notapproved)
        {
          approve_sql.push("rrr.res_rsv_ruimte_afgerond = 0");
        }
        if ((frontend || fronto) && res_tobeapproved)
        {
          switch (S("res_approval"))
          {
            case 0: // geen approval
                    break;
            case 1: // goedkeuren na reserveringdatum
                    approve_sql.push("rrr.res_rsv_ruimte_afgerond = 0"
                                    +" AND (res_geg.res_reservering_tot < TRUNC(SYSDATE, 'DD'))");
                    break;
            case 2: // goedkeuren na afmelden
                    approve_sql.push("rrr.res_rsv_ruimte_afgerond = 0"
                                    +" AND (  (rrr.res_rsv_ruimte_prijs IS NOT NULL AND res_geg.res_status_bo_key = 5)"
                                    +    " OR (rrr.res_rsv_ruimte_prijs IS     NULL AND res_geg.res_status_bo_key IS NULL))");
                    break;
          }
        }
      }

      // Artikel groep. Ook uitvoeren als resnum is meegegeven
      var sql_art_group = "";
      if (artgroup)
        sql_art_group = " AND UPPER(ra.res_artikel_groep) IN (" + safe.quoted_sql_join(artgroup, true) + ")";

      var sql = "";
      // New res structure
      // Volgens mij willen we 1 regel per reservering hier; wat doen we dan met de mogelijk varierende kolommen?
      var sql_select = "SELECT rrr.res_reservering_key"
                     + "     , res_geg.res_voorziening"
                     + "     , opstelalg.res_ruimte_opstel_default"
                     + "     , res_geg.res_reservering_van datumvan"
                     + "     , res_geg.res_reservering_tot datumtot"
                     + "     , pcontact.naam aanvrager"
                     + "     , res_geg.res_ins_discipline_key"
                     + "     , res_rsv_ruimte_omschrijving omschrijving"
                     + "     , res_rsv_ruimte_opmerking opmerking"
                     + "     , res_geg.res_rsv_ruimte_key rsv_ruimte_key"
                     + "     , res_geg.res_item_key"
                     + (groupres == -1 || groupres == 4
                       ? "     , res_geg.aantal_art_kenm"
                       : "")
                     + ((groupres == 1) // Bij groupering op deelreservering is het afmelden afhankelijk van de laagste bo status
                       ? "   , (SELECT MIN(res_status_bo_key)"
                         + "      FROM (SELECT rrr.res_rsv_ruimte_key"
                           + "               , rrr.res_status_bo_key"
                           + "            FROM res_v_aanwezigrsv_ruimte rrr"
                           + "          UNION ALL"
                           + "          SELECT rrd.res_rsv_ruimte_key"
                           + "               , rrd.res_status_bo_key"
                           + "            FROM res_v_aanwezigrsv_deel rrd"
                           + "          UNION ALL"
                           + "          SELECT rra.res_rsv_ruimte_key"
                           + "               , rra.res_status_bo_key"
                           + "            FROM res_v_aanwezigrsv_artikel rra) bostatus"
                         + "             WHERE bostatus.res_rsv_ruimte_key = res_geg.res_rsv_ruimte_key)"
                       : "   , res_geg.res_status_bo_key")
                       + "     res_status_bo_key"
                     + "     , res_rsv_ruimte_flag"
                     + "     , CASE WHEN res_geg.isbulk = 1"
                     + "            THEN res_geg.bulk_aantal"
                     + "            ELSE rrr.res_rsv_ruimte_bezoekers"
                     + "       END bezoekers"
                     + "     , phost.naam gastheer"
                     + "     , pcontact.prs_perslid_telefoonnr"
                     + "     , pcontact.prs_perslid_mobiel"
                     + "     , COALESCE((SELECT k.prs_kostenplaats_nr "
                       + "                 FROM prs_kostenplaats k"
                       + "                WHERE rrr.prs_kostenplaats_key = k.prs_kostenplaats_key), '') kostenplaats"
                     + "     , prs_kostenplaats_omschrijving  kostenplaatsomschr"
                     + "     , res_geg.aantal aantal"
                     + "     , res_geg.rsv_ruimte_aantal"                                     // 29 Hogere nummers worden alleen op naam gebruikt, zoals het hoort :-)
                     + "     , res_geg.prijs verwerkt_prijs"
                     + "     , rrr.res_activiteit_key"
                     + "     , " + lcl.xsqla("ract.res_activiteit_omschrijving", "ract.res_activiteit_key")
                     + "     , ract.res_activiteit_meteindtijd"
                     + "     , ract.res_activiteit_upper"  // for sorting
                     + "     , res_geg.stuks_prijs stuks_prijs"
                     + "     , res_geg.btwtarief btwtarief"
                     + "     , phost.prs_afdeling_key"
                     + "     , (SELECT " + S("prs_dep_string")
                     + "         FROM prs_v_afdeling d"
                     + "         WHERE phost.prs_afdeling_key = d.prs_afdeling_key ) organisatie"
                     + "     , artikelnummer"
                     + "     , CASE WHEN COALESCE (res_rsv_ruimte_bezoekers_shown, res_rsv_ruimte_bezoekers) < res_rsv_ruimte_bezoekers"
                     + "            THEN 1"
                     + "            ELSE rrr.res_rsv_ruimte_noshow "
                     + "       END noshow"
                     + "     , artikel_groep"
                     + "     , res_geg.rcv_type rcv_type"
                     + "     , res_geg.res_type res_type"
                     + "     , res_geg.keycolumn keycolumn"
                     + "     , (SELECT COUNT('1')"
                       + "        FROM res_rsv_deel rrd"
                       + "       WHERE rrd.res_rsv_ruimte_key = res_geg.res_rsv_ruimte_key"
                       + "         AND bez_bezoekers_key IS NULL"
                       + "     ) + "
                       + "     (SELECT COUNT('2')"
                       + "        FROM res_rsv_artikel"
                       + "       WHERE res_rsv_ruimte_key = res_geg.res_rsv_ruimte_key) nrObjects"
                     + ((groupres == 7) || (groupres == 8)
                       ? "   , res_artikel_key artikel_key"
                       : "")
                     + ((groupres == 9 || groupres == 14)
                       ? "   , rrr.prs_kostenplaats_key kostenplaats_key"
                       : "")
                     + ((groupres == 12)
                       ? "   , (SELECT ks.prs_kostensoort_oms"
                         + "      FROM prs_kostensoort ks, ins_tab_discipline d"
                         + "     WHERE d.ins_discipline_key = res_geg.res_ins_discipline_key"
                         + "       AND d.prs_kostensoort_key = ks.prs_kostensoort_key) prs_kostensoort_oms "
                         + " , (SELECT d.prs_kostensoort_key"
                         + "      FROM ins_tab_discipline d"
                         + "     WHERE d.ins_discipline_key = res_geg.res_ins_discipline_key) prs_kostensoort_key"
                       : "")
                     + ((groupres == 13)
                       ? "   , (SELECT " + lcl.xsql("ksg.prs_kostensoortgrp_oms", "ksg.prs_kostensoortgrp_key")
                         + "      FROM prs_kostensoortgrp ksg"
                         + "         , prs_kostensoort ks"
                         + "         , ins_tab_discipline d"
                         + "     WHERE ksg.prs_kostensoortgrp_key = ks.prs_kostensoortgrp_key"
                         + "       AND d.ins_discipline_key = res_geg.res_ins_discipline_key"
                         + "       AND d.prs_kostensoort_key = ks.prs_kostensoort_key) prs_kostensoortgrp_oms"
                         + " , (SELECT ks.prs_kostensoortgrp_key"
                         + "      FROM prs_kostensoort ks"
                         + "         , ins_tab_discipline d"
                         + "     WHERE d.ins_discipline_key = res_geg.res_ins_discipline_key"
                         + "       AND d.prs_kostensoort_key = ks.prs_kostensoort_key) prs_kostensoortgrp_key"
                       : "")
                     + "     , rrr.res_rsv_ruimte_volgnr"
                     + "     , rrr.res_rsv_ruimte_key"
                     + "     , rrr.res_rsv_ruimte_ordernr"
                     + "     , res_geg.res_ruimte_key"
                     + "     , sa.res_srtactiviteit_prefix"
                     + "     , COALESCE(rrr.res_rsv_ruimte_bezoekers_shown, -1) bezoekers_shown"
                     + "     , res_geg.ingang"
                     + "     , res_geg.startr"
                     + "     , res_geg.verval"
                     + "     , res_geg.ins_alg_ruimte_key_org"
                     + "     , res_geg.res_rsv_ruimte_satisfaction"
                     + "     , res_geg.res_rsv_ruimte_satisfaction_op"
                     + "     , rrr.res_rsv_ruimte_afgerond"
                     + "     , CASE"
                       + "     WHEN res_rsv_ruimte_afgerond = 0"
                       + "     THEN 1"
                       + "     ELSE 0"
                       + "     END approval"
                     + "     , rrr.res_rsv_ruimte_cat_appr"
                     + (frontend || fronto
                       ? "   , rrr.res_rsv_ruimte_verwijder"
                         + " , res_geg.dirtlevel"
                         + " , res_geg.res_reservering_ispool"
                         + " , res_geg.res_status_fo_key"

                       : "");
      if (!(frontend || fronto))
        sql_select += (opdr_key > 0
                      ? "  , 0 ins_srtdeel_uitleenbaar"
                        + ", NULL ins_discipline_key"
                      : "  , res_geg.ins_srtdeel_uitleenbaar"
                        + ", res_geg.ins_discipline_key");
      if (any_tz) {
        sql_select += ", DECODE(l.alg_locatie_timezone"
                    + "       , " + safe.quoted_sql(S("fac_server_timezone")) + ", NULL"
                    + "       , NULL, NULL"
                    + "       , l.alg_locatie_timezone) alg_locatie_timezone";
      }

      var sql_select_obj_restype_O = sql_select
                                   + ", NULL alg_district_key"
                                   + ", NULL alg_locatie_key"
                                   + ", '' locatie"
                                   + ", '' alg_locatie_adres"
                                   + ", '' alg_gebouw_naam"
                                   + ", NULL alg_gebouw_key"
                                   + ", NULL alg_verdieping_key"
                                   + ", NULL alg_ruimte_key"
                                   + ", '' res_ruimte_nr"
                                   + ", '' alg_ruimte_aanduiding"
                                   + ", 'O' categorie"
                                   + (frontend || fronto
                                     ? ", 2 approved_status"
                                     : ""); // dummy

      sql_select += ", ruimte_geg.alg_locatie_key"
                  + ", l.alg_district_key"
                  + ", l.alg_locatie_code locatie"
                  + ", ruimte_geg.alg_locatie_adres"
                  + ", ruimte_geg.alg_gebouw_naam"
                  + ", ruimte_geg.alg_gebouw_key"
                  + ", ruimte_geg.alg_verdieping_key"
                  + ", ruimte_geg.alg_ruimte_key"
                  + ", COALESCE(opstelalg.res_ruimte_nr, ruimte_geg.alg_ruimte_aanduiding)"
                  + "  || CASE WHEN res_geg.res_ruimte_key IS NULL"
                     + "  THEN DECODE( ruimte_geg.alg_ruimte_omschrijving"
                     + "             , NULL, ''"
                     + "             , ' (' || ruimte_geg.alg_ruimte_omschrijving || ')'"
                     + "             )"
                     + "  ELSE ''"
                     + "  END  res_ruimte_nr" //res_ruimte_nr is al vertaald
                  + ", " + ( minfo
                           ? "COALESCE(opstelalg.res_ruimte_nr, ruimte_geg.alg_ruimte_omschrijving)"
                           : "ruimte_geg.alg_ruimte_aanduiding"
                           ) + " alg_ruimte_aanduiding"
                  + ", res_geg.res_type categorie"
                  + (frontend || fronto
                    ? ", res_geg.approved_status"
                    : "");

      var sql_from = " FROM res_rsv_ruimte rrr"
                   + "    , res_activiteit ract"
                   + "    , res_srtactiviteit sa"
                   + "    , thePerslid phost"
                   + "    , thePerslid pcontact"
                   + "    , (SELECT rro.res_ruimte_opstel_key"
                     + "          , " + lcl.xsqla("rr.res_ruimte_nr", "rr.res_ruimte_key")
                     + "          , MIN(rar.alg_ruimte_key) alg_ruimte_key"
                     + "          , rro.res_ruimte_opstel_default"
                     + "       FROM res_ruimte_opstelling rro, res_alg_ruimte rar, res_ruimte rr"
                     + "      WHERE rro.res_ruimte_key = rar.res_ruimte_key"
                     + "        AND rr.res_ruimte_key = rar.res_ruimte_key"
                     + "        AND rar.res_alg_ruimte_verwijder is null"
                     + (roomcatalogue_key_arr.length // Als er ruimten (ruimte catalogi) zijn geselecteerd dan wil ik alleen daarvan de objecten en artikelen zien (AAXX#69681).
                       ? " AND rr.res_discipline_key IN (" + roomcatalogue_key_arr.join(",") + ")"
                       : "")
                     + "     GROUP BY rro.res_ruimte_opstel_key"
                     + "            , " + lcl.xsql("rr.res_ruimte_nr", "rr.res_ruimte_key")
                     + "            , rro.res_ruimte_opstel_default"
                     + "    ) opstelalg"
                   + "    , prs_kostenplaats k"
                   + "       , prs_v_afdeling_boom boom";

      var sql_from_obj_restype_O = sql_from
                                 + ", mld_opdr o";

      sql_from += ", alg_v_ruimte_gegevens_all ruimte_geg"  // DB12
                + ", alg_locatie l"
                + ", alg_district di";

      var sql_where = " WHERE res_geg.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                    + "   AND rrr.res_activiteit_key = ract.res_activiteit_key"
                    + "   AND ract.res_srtactiviteit_key = sa.res_srtactiviteit_key"
                    + "   AND res_rsv_ruimte_host_key = phost.prs_perslid_key"
                    + "   AND res_rsv_ruimte_contact_key = pcontact.prs_perslid_key"
                    + "   AND rrr.res_ruimte_opstel_key = opstelalg.res_ruimte_opstel_key(+)"
                    + "   AND rrr.prs_kostenplaats_key = k.prs_kostenplaats_key(+)"
                    + "   AND pcontact.prs_afdeling_key = boom.prs_afdeling_key"
                    + (!res_key && !(opdr_key > 0)
                      ? sql_act
                        + sql_name
                        + status_sql
                        + (approve_sql.length > 0? " AND (" + approve_sql.join(" OR ") + ")" : "")
                        + sql_dept
                        + sql_account
                      : "");

      if ((frontend || fronto) && !res_key)
      {
        if (!res_actual && !res_deleted) // Ongeldige actuele reserveringen
          sql_where += " AND rrr.res_rsv_ruimte_dirtlevel > 0"
                     + " AND rrr.res_rsv_ruimte_verwijder IS NULL";
        else if (!res_deleted)
          sql_where += " AND rrr.res_rsv_ruimte_verwijder IS NULL";
        else if (!res_actual)
          sql_where += " AND rrr.res_rsv_ruimte_verwijder IS NOT NULL";
      }
      else if (!res_key)
        sql_where += " AND rrr.res_rsv_ruimte_verwijder IS NULL";

      if (params.res_noshowonly)
      {
        sql_where += " AND (rrr.res_rsv_ruimte_noshow = 1";
        sql_where += "   OR COALESCE(res_rsv_ruimte_bezoekers_shown, res_rsv_ruimte_bezoekers) < res_rsv_ruimte_bezoekers)";
      }

      sql_where += getKenmerkSql("RES", "rrr.res_rsv_ruimte_key", true);

      var sql_where_obj_restype_O = sql_where
                                  + " AND rrr.mld_opdr_key = o.mld_opdr_key";

      sql_where += (!res_key && !(opdr_key > 0)
                   ? sql_reg
                     + sql_dist
                     + sql_loc
                     + sql_bld
                     + sql_floor
                     + sql_room
                   : "")
                 + " AND ruimte_geg.alg_ruimte_key = COALESCE(rrr.alg_ruimte_key, opstelalg.alg_ruimte_key)"
                 + " AND l.alg_locatie_key = ruimte_geg.alg_locatie_key"
                 + " AND l.alg_district_key = di.alg_district_key";

      var sql_from_art_part = "SELECT " + (groupres == 1? "'CV'" : "'C'") + " AS res_type"
                            + "     , 'CV' AS rcv_type"
                            + "     , rra.res_rsv_ruimte_key"
                            + "     , (SELECT rro.res_ruimte_key"
                              + "        FROM res_ruimte_opstelling rro"
                              + "       WHERE rrr.res_ruimte_opstel_key = rro.res_ruimte_opstel_key) AS res_ruimte_key"
                            + "     , rra.res_rsv_artikel_key AS res_item_key"
                            + (groupres == -1 || groupres == 4
                              ? "   , (SELECT COUNT(ka.res_kenmerkartikel_key)"
                                + "      FROM res_kenmerkartikel ka"
                                + "     WHERE ka.res_rsv_artikel_key = rra.res_rsv_artikel_key) aantal_art_kenm"
                              : "")
                            + (groupres == 1
                              ? "   , rrr.res_rsv_ruimte_van AS res_reservering_van"
                              : "   , rra.res_rsv_artikel_levering AS res_reservering_van")
                            + (groupres == -1
                              ? "   , COALESCE(rra.res_rsv_artikel_afhalen, res_rsv_ruimte_tot)"
                              : "   , res_rsv_ruimte_tot") + " AS res_reservering_tot"
                            + "     , rra.res_rsv_artikel_aantal AS aantal"
                            + (groupres == 15
                              ? "   , LTRIM(" + lcl.xsql("rd.ins_discipline_omschrijving", "ra.res_discipline_key") + ")"
                              : "   , CASE WHEN ra.res_artikel_vrije_omschrijving = 1"
                              + "          THEN LTRIM(rra.res_rsv_artikel_omschrijving)"
                              + "          ELSE LTRIM(" + lcl.xsql("ra.res_artikel_omschrijving", "ra.res_artikel_key") + ")"
                              + "     END ||"
                              + "     CASE WHEN " + lcl.xsql("ra.res_artikel_eenheid", "ra.res_artikel_key") + " IS NULL"
                              + "          THEN ''"
                              + "          ELSE ' ('|| " + lcl.xsql("ra.res_artikel_eenheid", "ra.res_artikel_key") + " || ')'"
                              + "     END"
                              ) + " AS res_voorziening"
                            + "     , NULL"
                            + "     , ra.res_discipline_key AS res_ins_discipline_key"
                            + "     , rra.res_status_bo_key"
                            + "     , ra.res_artikel_key AS res_artikel_key"
                            + "     , "+ (withprices ? "res.getartikelprijs(rra.res_rsv_artikel_key)" : "NULL") + " AS prijs"
                            + "     , ra.res_artikel_prijs AS stuks_prijs"
                            + "     , ra.res_artikel_btw AS btwtarief"
                            + "     , to_number(null) AS rsv_ruimte_aantal"
                            + "     , ra.res_artikel_nr AS artikelnummer"
                            + "     , ra.res_artikel_groep AS artikel_groep"
                            + "     , rra.res_rsv_artikel_key keycolumn"
                            + "     , CASE"
                              + "     WHEN (ra.res_artikel_ingangsdatum IS NULL OR ra.res_artikel_ingangsdatum <= rrr.res_rsv_ruimte_van)"
                              + "     THEN 1"
                              + "     ELSE 0"
                              + "     END ingang"
                            + "     , 1 startr"
                            + "     , CASE"
                              + "     WHEN (ra.res_artikel_vervaldatum IS NULL OR ra.res_artikel_vervaldatum > rrr.res_rsv_ruimte_tot)"
                              + "     THEN 1"
                              + "     ELSE 0"
                              + "     END verval"
                            + "     , NULL ins_alg_ruimte_key_org"
                            + "     , rrr.res_rsv_ruimte_satisfaction"
                            + "     , rrr.res_rsv_ruimte_satisfaction_op"
                            + "     , rra.res_rsv_artikel_approved"
                            + (frontend || fronto
                              ? "   , rra.res_rsv_artikel_dirtlevel dirtlevel"
                                + " , 0 res_reservering_ispool"
                                + " , rrr.res_status_fo_key"
                                + " , CASE"
                                  + " WHEN (SELECT COUNT(ra.res_rsv_artikel_approved)"
                                  + "         FROM res_rsv_artikel ra"
                                  + "        WHERE ra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                                  + "          AND ra.res_rsv_artikel_approved = 0) > 0"
                                  + " THEN 0"
                                  + " WHEN (SELECT COUNT(ra.res_rsv_artikel_approved)"
                                  + "        FROM res_rsv_artikel ra"
                                  + "       WHERE ra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                                  + "         AND ra.res_rsv_artikel_approved = 1) > 0"
                                  + " THEN 1"
                                  + " ELSE 2"
                                  + " END approved_status"
                              : "   , 0 ins_srtdeel_uitleenbaar"
                                + " , NULL ins_discipline_key")
                            + "     , NULL bulk_aantal"
                            + "     , 0    isbulk"
                            + "  FROM " + (res_deleted || res_key > 0 ? "res_rsv_artikel" : "res_v_aanwezigrsv_artikel") + " rra"
                            + "     , theResrsv rrr"
                            + "     , res_artikel ra"
                            + "     , res_discipline rd"
                            + " WHERE rra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                            + (backo || minfo // Dirty alleen voor FE & FO tonen en niet voor BO & MI
                              ? "   AND rra.res_rsv_artikel_dirtlevel = 0"
                              : "")
                            + "   AND rra.res_artikel_key = ra.res_artikel_key"
                            + "   AND ra.res_discipline_key = rd.ins_discipline_key"
                            + "   AND rra.res_rsv_artikel_approved < 2"
                            + (groupres == 1 && (roomcat || frontend || fronto)
                              ? " AND rrr.alg_ruimte_key IS NOT NULL"
                              : "")
                            + sql_art_key
                            + sql_article
                            + sql_art_group;

      var sql_from_obj_part = "SELECT " + (groupres == 1? "'CV'" : "'V'") + " AS res_type"
                            + "     , 'CV' AS rcv_type"
                            + "     , rrd.res_rsv_ruimte_key"
                            + "     , (SELECT rro.res_ruimte_key"
                            + "          FROM res_ruimte_opstelling rro"
                            + "         WHERE rrr.res_ruimte_opstel_key = rro.res_ruimte_opstel_key) AS res_ruimte_key"
                            + "     , rrd.res_rsv_deel_key AS res_item_key"
                            + (groupres == -1 || groupres == 4
                              ? "     , 0 aantal_art_kenm"
                              : "")
                            + (groupres == 1
                              ? "   , rrr.res_rsv_ruimte_van AS res_reservering_van"
                              : "   , rrd.res_rsv_deel_van AS res_reservering_van")
                            + (groupres == 1
                              ? "   , rrr.res_rsv_ruimte_tot AS res_reservering_tot"
                              : "   , rrd.res_rsv_deel_tot AS res_reservering_tot")
                            + "     , to_number(null) AS aantal"
                            + "     , " + lcl.xsql("rd.res_deel_omschrijving", "rd.res_deel_key")
                             + "      || CASE WHEN " + lcl.xsql("rd.res_deel_eenheid", "rd.res_deel_key") + " IS NULL"
                             + "              THEN ''"
                             + "              ELSE ' ('|| " + lcl.xsql("rd.res_deel_eenheid", "rd.res_deel_key") + " || ')'"
                             + "              END AS res_voorziening"
                            + "     , NULL"
                            + "     , rd.res_discipline_key AS res_ins_discipline_key"
                            + "     , rrd.res_status_bo_key"
                            + "     , TO_NUMBER(null) AS res_artikel_key"
                            + "     , " + (withprices? "res.getdeelprijs(rrd.res_rsv_deel_key)" : "NULL") + " AS prijs"
                            + "     , rd.res_deel_prijs AS stuks_prijs"
                            + "     , to_number(null) AS btwtarief"
                            + "     , to_number(null) AS rsv_ruimte_aantal"
                            + "     , null AS artikelnummer"
                            + "     , '' AS artikel_groep"
                            + "     , rrd.res_rsv_deel_key keycolumn"
                            + "     , 1 ingang"
                            + "     , 1 startr"
                            + "     , CASE"
                              + "     WHEN (rd.res_deel_vervaldatum IS NULL OR rd.res_deel_vervaldatum > rrr.res_rsv_ruimte_tot)"
                              + "     THEN 1"
                              + "     ELSE 0"
                              + "     END verval"
                            + (opdr_key > 0
                              ? "   , -1 ins_alg_ruimte_key_org"
                              : "   , id.ins_alg_ruimte_key_org")
                            + "   , rrr.res_rsv_ruimte_satisfaction"
                            + "   , rrr.res_rsv_ruimte_satisfaction_op"
                            + (frontend || fronto
                              ? " , rrd.res_rsv_deel_dirtlevel dirtlevel"
                                + ", 0 res_reservering_ispool"
                                + ", rrr.res_status_fo_key"
                                + " , CASE"
                                  + " WHEN (SELECT COUNT(ra.res_rsv_artikel_approved)"
                                  + "         FROM res_rsv_artikel ra"
                                  + "        WHERE ra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                                  + "          AND ra.res_rsv_artikel_approved = 0) > 0"
                                  + " THEN 0"
                                  + " WHEN (SELECT COUNT(ra.res_rsv_artikel_approved)"
                                  + "        FROM res_rsv_artikel ra"
                                  + "       WHERE ra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                                  + "         AND ra.res_rsv_artikel_approved = 1) > 0"
                                  + " THEN 1"
                                  + " ELSE 2"
                                  + " END approved_status"
                              : "")
                            + (frontend || fronto || opdr_key > 0
                              ? ""
                              : "  , isd.ins_srtdeel_uitleenbaar"
                                + ", id.ins_discipline_key")
                            + "    , grp.bulk_aantal"
                            + "    , grp.isbulk"
                            + " FROM " + (res_deleted || res_key > 0 ? "res_rsv_deel" : "res_v_aanwezigrsv_deel") + " rrd"
                            + "    , theResrsv rrr"
                            + "    , theGroup  grp"
                            + "    , res_deel rd"
                            + (opdr_key > 0
                             ? ""
                             : "   , ins_deel id"
                               + " , ins_srtdeel isd")
                           + " WHERE rrd.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key "
                           + "   AND rrd.res_deel_key = rd.res_deel_key "
                           + "   AND rrd.res_deel_key = rd.res_deel_key"
                           + "   AND rrd.res_deel_key = grp.res_deel_key"
                           + "   AND rrd.res_rsv_ruimte_key = grp.res_rsv_ruimte_key"
                           + (S("vis_parking_key") != -1
                             ? " AND rd.res_discipline_key != " + S("vis_parking_key")
                             : "")
                           + (backo || minfo // Dirty alleen voor FE & FO tonen en niet voor BO & MI
                             ? "   AND rrd.res_rsv_deel_dirtlevel = 0"
                             : "");
                    if (opdr_key <= 0)
                       sql_from_obj_part += "   AND rd.res_ins_deel_key = id.ins_deel_key"
                                          + "   AND id.ins_srtdeel_key = isd.ins_srtdeel_key"
                                          + (groupres == 1 && (roomcat || frontend || fronto)
                                            ? " AND rrr.alg_ruimte_key IS NOT NULL"
                                            : "");
                    sql_from_obj_part += sql_obj_key;

      var sql_from_room_part = "SELECT 'R' AS res_type"
                             + "     , 'R' AS rcv_type"
                             + "     , rrr.res_rsv_ruimte_key"
                             + "     , rro.res_ruimte_key"
                             + "     , rrr.res_rsv_ruimte_key AS res_item_key"
                             + (groupres == -1 || groupres == 4
                               ? "     , 0 aantal_art_kenm"
                               : "")
                             + "     , rrr.res_rsv_ruimte_van AS res_reservering_van"
                             + "     , rrr.res_rsv_ruimte_tot AS res_reservering_tot"
                             + "     , TO_NUMBER(null) AS aantal"
                             + "     , " + lcl.xsql("ro.res_opstelling_omschrijving", "ro.res_opstelling_key") + " AS res_voorziening"
                             + "     , rro.res_ruimte_opstel_default AS res_ruimte_opstel_default"
                             + "     , rr.res_discipline_key AS res_ins_discipline_key"
                             + "     , rrr.res_status_bo_key"
                             + "     , to_number(null) AS res_artikel_key"
                             + "     , "+ (withprices ? "res.getruimteprijs(rrr.res_rsv_ruimte_key) - COALESCE(rrr.res_rsv_ruimte_korting, 0)" : "NULL") + " AS prijs"
                             + "     , to_number(null) AS stuks_prijs"
                             + "     , to_number(null) AS btwtarief"
                             + "     , 1 AS rsv_ruimte_aantal"
                             + "     , null AS artikelnummer"
                             + "     , '' AS artikel_groep"
                             + "     , rrr.res_rsv_ruimte_key keycolumn"
                             + "     , 1 ingang"
                             + "     , CASE WHEN (rr.res_ruimte_startdatum  IS NULL OR rr.res_ruimte_startdatum <= rrr.res_rsv_ruimte_tot)"
                                    + "     THEN 1"
                                    + "     ELSE 0"
                                    + "     END startr"
                             + "     , CASE WHEN (rr.res_ruimte_vervaldatum IS NULL OR rr.res_ruimte_vervaldatum > rrr.res_rsv_ruimte_tot)"
                                    + "     THEN 1"
                                    + "     ELSE 0"
                                    + "     END verval"
                             + "     , NULL ins_alg_ruimte_key_org"
                             + "     , rrr.res_rsv_ruimte_satisfaction"
                             + "     , rrr.res_rsv_ruimte_satisfaction_op"
                             + "     , rrr.res_rsv_ruimte_dirtlevel dirtlevel"
                             + (frontend || fronto
                               ? "   , rr.res_ruimte_nr"
                                 + " , r.res_reservering_ispool"
                                 + " , rrr.res_status_fo_key"
                                 + " , CASE"
                                   + " WHEN (SELECT COUNT(ra.res_rsv_artikel_approved)"
                                   + "         FROM res_rsv_artikel ra"
                                   + "        WHERE ra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                                   + "          AND ra.res_rsv_artikel_approved = 0) > 0"
                                   + " THEN 0"
                                   + " WHEN (SELECT COUNT(ra.res_rsv_artikel_approved)"
                                   + "        FROM res_rsv_artikel ra"
                                   + "       WHERE ra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                                   + "         AND ra.res_rsv_artikel_approved = 1) > 0"
                                   + " THEN 1"
                                   + " ELSE 2"
                                   + " END approved_status"
                               : "   , 0 ins_srtdeel_uitleenbaar"
                                 + " , NULL ins_discipline_key")
                             + "     , NULL bulk_aantal"
                             + "     , 0    isbulk"
                             + "  FROM theResrsv rrr"
                             + "     , res_reservering r"
                             + "     , res_ruimte_opstelling rro"
                             + "     , res_ruimte rr"
                             + "     , res_opstelling ro"
                             + " WHERE rrr.res_reservering_key = r.res_reservering_key"
                             + "   AND rrr.res_ruimte_opstel_key = rro.res_ruimte_opstel_key"
                             + "   AND rro.res_ruimte_key = rr.res_ruimte_key"
                             + (backo || minfo
                               ? "   AND rrr.res_rsv_ruimte_dirtlevel = 0"   // Geen dirty ruimtes voor de BO en MI
                               : "")
                             + "   AND rro.res_opstelling_key = ro.res_opstelling_key "
                             + sql_room_key;

      //===================================================

      // 1) Voorwaarde dat het ruimte en object gedeelte van de reserveringen geselecteerde verbruiksartikelen catalogi moeten bevatten.
      var sql_from_roomobj_art = "";
      var sql_where_roomobj_art = "";
      if (art_key_arr.length || article_arr.length || sql_art_group)
      {
        sql_from_roomobj_art = ", (SELECT DISTINCT rra.res_rsv_ruimte_key"
                          + "        , ra.res_discipline_key AS res_ins_discipline_key"
                          + "        , rra.res_status_bo_key"
                          + "     FROM res_v_aanwezigrsv_artikel rra"
                          + "        , theResrsv rrr"
                          + "        , res_artikel ra"
                          + "        , res_discipline rd"
                          + "    WHERE rra.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                          + (backo || minfo // Dirty alleen voor FE & FO tonen en niet voor BO & MI
                            ? "      AND rra.res_rsv_artikel_dirtlevel = 0"
                            : "")
                          + "      AND rra.res_artikel_key = ra.res_artikel_key"
                          + "      AND ra.res_discipline_key = rd.ins_discipline_key"
                          + "      AND rra.res_rsv_artikel_approved < 2"
                          + (art_key_arr.length
                            ? "    AND ra.res_discipline_key IN (" + art_key_arr.join(",") + ")"
                            : "")
                          + (article_arr.length
                            ? "    AND rra.res_artikel_key IN (" + article_arr.join(",") + ")"
                            : "")
                          + (artgroup
                            ? " AND UPPER(ra.res_artikel_groep) IN (" + safe.quoted_sql_join(artgroup, true) + ")"
                            : "")
                          + ") res_geg_a";

        sql_where_roomobj_art = "  AND res_geg_a.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                              + "  AND res_geg_a.res_status_bo_key < 5"
                              + (art_key_arr.length
                                ? " AND res_geg_a.res_ins_discipline_key IN (" + art_key_arr.join(",") + ")"
                                : "");
      }

      // 2) Voorwaarde dat het ruimte en artikel gedeelte van de reserveringen geselecteerde voorzieningen catalogi moeten bevatten.
      var sql_from_roomart_obj = "";
      var sql_where_roomart_obj = "";
      if (obj_key_arr.length)
      {
        sql_from_roomart_obj = ", (SELECT DISTINCT rrd.res_rsv_ruimte_key"
                          + "        , rd.res_discipline_key AS res_ins_discipline_key"
                          + "        , rrd.res_status_bo_key"
                          + "     FROM res_v_aanwezigrsv_deel rrd"
                          + "        , theResrsv rrr"
                          + "        , res_deel rd"
                          + "        , ins_deel id"
                          + "        , ins_srtdeel isd"
                          + "    WHERE rrd.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                          + "      AND rrd.res_deel_key = rd.res_deel_key"
                          + (S("vis_parking_key") != -1
                            ? " AND rd.res_discipline_key != " + S("vis_parking_key")
                            : "")
                          + (backo || minfo // Dirty alleen voor FE & FO tonen en niet voor BO & MI
                            ? "      AND rrd.res_rsv_deel_dirtlevel = 0"
                            : "")
                          + "      AND rd.res_ins_deel_key = id.ins_deel_key"
                          + "      AND id.ins_srtdeel_key = isd.ins_srtdeel_key"
                          + "      AND rd.res_discipline_key IN (" + obj_key_arr.join(",") + ")) res_geg_o";

        sql_where_roomart_obj = "  AND res_geg_o.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key"
                              + "  AND res_geg_o.res_status_bo_key < 5"
                              + "  AND res_geg_o.res_ins_discipline_key IN (" + obj_key_arr.join(",") + ")";
      }

      // 3) Voorwaarde dat het object en artikel gedeelte van de reserveringen geselecteerde ruimten catalogi moeten bevatten zit wel in het opstelalg tabel gedeelte.

      var art_waar = (groupres == 1
                       ? ", ruimte_geg.alg_ruimte_aanduiding"
                         + " || DECODE(ruimte_geg.alg_ruimte_omschrijving"
                         + "         , NULL, ''"
                         + "         , ' (' || ruimte_geg.alg_ruimte_omschrijving || ')'"
                         + "          )" // Per reservering, zichtbaar voor losse voorziening reservering.
                       : ", COALESCE(" + lcl.xsql("opstelalg.res_ruimte_nr", "res_geg.res_ruimte_key") + ", ruimte_geg.alg_ruimte_aanduiding)") // Niet gegroepeerd.
      art_waar += " waar"

      sql_from_art_part = sql_select
                        + "          , res_geg.res_rsv_artikel_approved"
                        + (frontend || fronto
                          ? art_waar
                          : "")
                        + sql_from
                        + " , (" + sql_from_art_part + ") res_geg"
                        + sql_from_roomart_obj
                        + sql_where
                        + sql_where_roomart_obj;

      // apply 3D authorization to the locations and to the organisations (both ALG and PRS)
      if (!frontend)
      {
        var disc_art_arr = [];
        if (!res_key && opdr_key <= 0 && article_disc_arr.length)
          disc_art_arr = disc_art_arr.concat(article_disc_arr);
        sql_from_art_part = discx3d(sql_from_art_part,
                                    "res_geg.res_ins_discipline_key",
                                    "di.alg_regio_key",
                                    "l.alg_district_key",
                                    "(ruimte_geg.alg_locatie_key+0)", // Voorkom slechte performance voor CRO033
                                    "ruimte_geg.alg_gebouw_key",
                                    "ruimte_geg.alg_verdieping_key",
                                    "ruimte_geg.alg_ruimte_key",
                                    "boom.prs_bedrijf_key",
                                    "boom.prs_afdeling_key",
                                    pautfunction,
                                    disc_art_arr,
                                    2,
                                    null,
                                    [2]); // artikelen
      }

      if (restype == "O")
        var obj_waar = ", mld_opdr_id";
      else
        var obj_waar = (groupres == 1
                       ? ", ruimte_geg.alg_ruimte_aanduiding"
                         + " || DECODE(ruimte_geg.alg_ruimte_omschrijving"
                         + "         , NULL, ''"
                         + "         , ' (' || ruimte_geg.alg_ruimte_omschrijving || ')'"
                         + "          )" // Per reservering, zichtbaar voor losse voorziening reservering.
                       : ", COALESCE(" + lcl.xsql("opstelalg.res_ruimte_nr", "res_geg.res_ruimte_key") + ", ruimte_geg.alg_ruimte_aanduiding)") // Niet gegroepeerd.
      obj_waar += " waar"

      sql_from_obj_part = ((frontend || fronto) && restype == "O"
                          ? sql_select_obj_restype_O
                          : sql_select)
                        + "          , (SELECT MIN(ra1.res_rsv_artikel_approved)"
                        + "               FROM res_rsv_artikel ra1"
                        + "              WHERE ra1.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key) res_rsv_artikel_approved"
                        + (frontend || fronto
                          ? obj_waar
                          : "")
                        + ((frontend || fronto) && restype == "O"
                          ? sql_from_obj_restype_O
                          : sql_from)
                        + " , (" + sql_from_obj_part + ") res_geg"
                        + sql_from_roomobj_art
                        + ((frontend || fronto) && restype == "O"
                          ? sql_where_obj_restype_O
                          : sql_where)
                        + sql_where_roomobj_art;

      if (!frontend)
      {
        var disc_obj_arr = [];
        if (!res_key && opdr_key <= 0 && obj_key_arr.length)
          disc_obj_arr = disc_obj_arr.concat(obj_key_arr);
        sql_from_obj_part = discx3d(sql_from_obj_part,
                                    "res_geg.res_ins_discipline_key",
                                    "di.alg_regio_key",
                                    "l.alg_district_key",
                                    "(ruimte_geg.alg_locatie_key+0)", // Voorkom slechte performance voor CRO033
                                    "ruimte_geg.alg_gebouw_key",
                                    "ruimte_geg.alg_verdieping_key",
                                    "ruimte_geg.alg_ruimte_key",
                                    "boom.prs_bedrijf_key",
                                    "boom.prs_afdeling_key",
                                    pautfunction,
                                    disc_obj_arr,
                                    2,
                                    null,
                                    [1, 4, 5]); // objecten/personen/werkplekken
      }

      sql_from_room_part = sql_select
                         + "  , (SELECT MIN(ra1.res_rsv_artikel_approved)"
                         + "       FROM res_rsv_artikel ra1"
                         + "      WHERE ra1.res_rsv_ruimte_key = rrr.res_rsv_ruimte_key) res_rsv_artikel_approved"
                         + (frontend || fronto
                           ? ", COALESCE(" + lcl.xsql("res_geg.res_ruimte_nr", "res_geg.res_ruimte_key") + ", ruimte_geg.alg_ruimte_aanduiding) waar"
                           : "")
                         + sql_from
                         + "  , (" + sql_from_room_part + ") res_geg"
                         + sql_from_roomobj_art
                         + sql_from_roomart_obj
                         + sql_where
                         + sql_where_roomobj_art
                         + sql_where_roomart_obj;

      if (!frontend)
      {
        var disc_room_arr = [];
        if (!res_key && opdr_key <= 0 && roomcatalogue_key_arr.length)
          disc_room_arr = disc_room_arr.concat(roomcatalogue_key_arr);
        sql_from_room_part = discx3d(sql_from_room_part,
                                     "res_geg.res_ins_discipline_key",
                                     "di.alg_regio_key",
                                     "l.alg_district_key",
                                     "(ruimte_geg.alg_locatie_key+0)", // Voorkom slechte performance voor CRO033
                                     "ruimte_geg.alg_gebouw_key",
                                     "ruimte_geg.alg_verdieping_key",
                                     "ruimte_geg.alg_ruimte_key",
                                     "boom.prs_bedrijf_key",
                                     "boom.prs_afdeling_key",
                                     pautfunction,
                                     disc_room_arr,
                                     2,
                                     null,
                                     [3]); // ruimtes
      }

      var sql_from_total = "";
      if (res_key || (opdr_key > 0 || (frontend || fronto || compact)) || (roomcat && groupres != 7 && groupres != 8 && groupres != 15)) // Niet als je groepeert op artikel
      {
        sql_from_total += "/* Ruimtes */ " + sql_from_room_part;
        if (res_key || (opdr_key > 0 || (frontend || fronto || compact)) || objcat || artcat)
          sql_from_total += " \nUNION ALL\n "
      }

      if (res_key || (opdr_key > 0 || (frontend || fronto || compact)) || (objcat && groupres != 7 && groupres != 8 && groupres != 15)) // Niet als je groepeert op artikel
      {
        sql_from_total += "/* Objecten */ " + sql_from_obj_part
                        + (roomcatalogue_key_arr.length
                          ? " AND res_geg.res_ruimte_key IS NOT NULL" // Niet als er ruimten (ruimte catalogi) zijn geselecteerd. Dan wil ik geen losse objecten zien (AAXX#69681).
                          : "");
        if (res_key || (opdr_key > 0 || (frontend || fronto || compact)) || artcat)
          sql_from_total += " \nUNION ALL\n "
      }

      if (res_key || (opdr_key > 0 || (frontend || fronto || compact)) || artcat)
        sql_from_total += "/* Artikelen */ " + sql_from_art_part
                       + (roomcatalogue_key_arr.length
                         ? " AND res_geg.res_ruimte_key IS NOT NULL" // Niet als er ruimten (ruimte catalogi) zijn geselecteerd. Dan wil ik geen losse artikelen zien (AAXX#69681).
                         : "");

      sql = "WITH " + thePerslid + "," + theResrsv + "," + theGroup + sql_from_total;

      var sql_order = "";
      if (groupres == 1)
      { // Groepering "Per reservering".
        if (frontend || fronto)
          sql_order = " ORDER BY " + (datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()? " datumvan" : " TO_CHAR(datumvan, 'HH24:MI:SS')") + " desc, waar, datumvan desc, res_type DESC, res_voorziening";
        else if (sortout == 1) // locatie, tijd
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " locatie, " + (datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()? " datumvan" : " TO_CHAR(datumvan, 'HH24:MI:SS')") + ", rsv_ruimte_key, rcv_type DESC, res_reservering_key, categorie DESC";
        else if (sortout == 2) // plaats
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " locatie, rsv_ruimte_key, rcv_type DESC, datumvan";
        else if (sortout == 3) // reservering
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " res_reservering_key, rsv_ruimte_key, rcv_type DESC, datumvan";
        else if (sortout == 4) // gastheer
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " gastheer, rsv_ruimte_key, rcv_type DESC, datumvan";
        else if (sortout == 5) // tijd
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + (datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()? " datumvan" : " TO_CHAR(datumvan, 'HH24:MI:SS')") + ", rsv_ruimte_key, rcv_type DESC, locatie, categorie DESC, bezoekers DESC";
        else
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " res_reservering_key DESC, rsv_ruimte_key, rcv_type DESC, locatie, categorie DESC, datumvan, res_ruimte_nr, bezoekers DESC";
      }
      else
      {
        if (frontend || fronto)
          sql_order = " ORDER BY " + (datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()? " datumvan" : " TO_CHAR(datumvan, 'HH24:MI:SS')") + " desc, waar, datumvan desc, res_type DESC, res_voorziening";
        else if (sortout == 1) // locatie, tijd
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " locatie, " + (datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()? " datumvan" : " TO_CHAR(datumvan, 'HH24:MI:SS')") + ", res_ruimte_nr, rcv_type DESC, res_reservering_key, categorie DESC";
        else if (sortout == 2) // plaats
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " locatie, res_ruimte_nr, datumvan, res_reservering_key, categorie DESC";
        else if (sortout == 3) // reservering
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " res_reservering_key, datumvan, res_ruimte_nr, categorie DESC";
        else if (sortout == 4) // gastheer
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + " gastheer, datumvan, res_ruimte_nr, res_reservering_key, categorie DESC";
        else if (sortout == 5) // tijd
          sql_order = " ORDER BY" + (excel? " res_activiteit_upper," : "")
                    + (datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()? " datumvan" : " TO_CHAR(datumvan, 'HH24:MI:SS')") + ", locatie, res_ruimte_nr, res_reservering_key, categorie DESC";
      }

      // Voor groeperingen het resultaat nu eerst filteren zodat je maar 1 regel per deelreservering overhoud.
      // Reserveringen met meerdere objecten (res_item_key) samen nemen in 1 regel
      if (groupres == 1)
      {
        // Voor groepering nog verder filteren
        sql = " SELECT DISTINCT res_reservering_key"
            + "      , locatie"
            + "      , alg_locatie_adres"
            + "      , alg_gebouw_key"
            + "      , alg_gebouw_naam"
            + "      , alg_verdieping_key"
            + "      , alg_ruimte_key"
            + "      ," + lcl.xsqla("res_ruimte_nr", "res_ruimte_key")    // PF: weet zo niet of deze niet hierboven al vertaald is?!
            + "      , alg_ruimte_aanduiding"
            + "      , datumvan"
            + "      , datumtot"
            + "      , aanvrager"
            + "      , omschrijving"
            + "      , opmerking"
            + "      , rsv_ruimte_key"
            + "      , NULL res_item_key"
            + "      , res_status_bo_key"
            + "      , res_rsv_ruimte_flag"
            + "      , CASE categorie"
              + "      WHEN 'V' THEN 'CV'"
              + "      WHEN 'C' THEN 'CV'"
              + "      WHEN 'CV' THEN 'CV'"
              + "      ELSE 'R'"
              + "      END categorie"
            + "      , bezoekers"
            + "      , gastheer"
            + "      , prs_perslid_telefoonnr"
            + "      , prs_perslid_mobiel"
            + "      , kostenplaats"
            + "      , kostenplaatsomschr"
            + "      , rsv_ruimte_aantal"
            + "      , verwerkt_prijs"
            + "      , rcv_type"
            + "      , res_type"
            + "      , rsv_ruimte_key keycolumn"
            + "      , nrobjects"
            + "      , res_rsv_ruimte_volgnr"
            + "      , res_rsv_ruimte_key"
            + "      , res_rsv_ruimte_ordernr"
            + "      , res_ruimte_key"
            + "      , res_activiteit_key"
            + "      , res_activiteit_upper"
            + "      , res_srtactiviteit_prefix"
            + "      , bezoekers_shown"
            + "      , ingang"
            + "      , startr"
            + "      , verval"
            + "      , ins_alg_ruimte_key_org"
            + "      , res_ruimte_opstel_default"
            + "      , resgroup.res_activiteit_omschrijving"
            + "      , resgroup.res_activiteit_meteindtijd"
            + "      , res_rsv_ruimte_afgerond"
            + "      , res_rsv_ruimte_cat_appr"
            + "      , res_rsv_artikel_approved"
            + "      , CASE categorie"
              + "      WHEN 'V' THEN " + safe.quoted_sql(L("lcl_reserved_object"))
              + "      WHEN 'C' THEN " + safe.quoted_sql(L("lcl_reserved_object"))
              + "      WHEN 'CV' THEN " + safe.quoted_sql(L("lcl_reserved_object"))
              + "      ELSE res_voorziening"
              + "      END res_voorziening"
            + (frontend || fronto
              ? "    , approval"
                + "  , approved_status"
                + "  , res_rsv_ruimte_verwijder"
                + "  , waar"
                + "  , dirtlevel"
                + "  , res_reservering_ispool"
                + "  , res_status_fo_key"
              : "")
            + "   FROM ("
            + sql
            + "        ) resgroup"
      }

      var res_keyColumn = ""
      var res_columns = new Array();

      // Deprecated: overal waar verderop 'new columnData' wordt gebruikt kan ook/beter de
      //             'new Column' gebruikt worden. Dan heb je namelijk alle properties tot
      //             je beschikking. Voor het gemak even backwards compatible.
      function columnData(caption, content, datatype, total, decimals)
      {
          return new Column({caption: caption, content: content, datatype: datatype, total: total, decimals: decimals});
      }

      select_oordeel = ", SUM(res.res_rsv_ruimte_satisfaction) sum_satisfaction"
                     + ", COUNT(res.res_rsv_ruimte_satisfaction) cnt_satisfaction"
                     + ", AVG(res.res_rsv_ruimte_satisfaction) oordeel"
                     + ", MAX(res_rsv_ruimte_satisfaction_op) oordeel_opm";

      if (groupres == 6)
      { // locatie
        res_keyColumn = "alg_locatie_key";
        res_columns[res_columns.length] = new columnData(L("lcl_location"), "locatie")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = "SELECT l.alg_locatie_key " + res_keyColumn
            + "     , l.alg_locatie_omschrijving locatie"
            + "     , COUNT(distinct res.res_rsv_ruimte_key) aantalres"
            + "     , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + " FROM (" + sql + ") res"
            + "     , alg_locatie l "
            + " WHERE res.alg_locatie_key = l.alg_locatie_key"
            + " GROUP BY l.alg_locatie_key"
            + "        , l.alg_locatie_omschrijving";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 10)
      { // gebouw
        res_keyColumn = "alg_gebouw_key";
        res_columns[res_columns.length] = new columnData(L("lcl_building"), "gebouw")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = " SELECT g.alg_gebouw_key " + res_keyColumn
            + "      , l.alg_locatie_code || '-' || g.alg_gebouw_naam gebouw"
            + "      , COUNT(distinct res.res_rsv_ruimte_key) aantalres"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + "  FROM (" + sql + ") res"
            + "     , alg_locatie l"
            + "     , alg_gebouw g"
            + " WHERE res.alg_gebouw_key = g.alg_gebouw_key"
            + "   AND g.alg_locatie_key = l.alg_locatie_key"
            + " GROUP BY g.alg_gebouw_key"
            + "        , l.alg_locatie_code || '-' || g.alg_gebouw_naam";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 11)
      { // activiteit
        res_keyColumn = "res_activiteit_key";
        res_columns[res_columns.length] = new columnData(L("lcl_activity"), "activiteit")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = " SELECT a.res_activiteit_key " + res_keyColumn
            + "      , " + lcl.xsql('a.res_activiteit_omschrijving', 'a.res_activiteit_key') + " activiteit"
            + "      , COUNT(distinct res.res_rsv_ruimte_key) aantalres"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + "  FROM (" + sql + ") res"
            + "     , res_activiteit a"
            + " WHERE res.res_activiteit_key = a.res_activiteit_key"
            + " GROUP BY a.res_activiteit_key"
            + "        , " + lcl.xsql('a.res_activiteit_omschrijving', 'a.res_activiteit_key');
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 12)
      { // kostensoort
        res_keyColumn = "prs_kostensoort_key";
        res_columns[res_columns.length] = new columnData(L("lcl_charge_type"), "kostensoort")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = " SELECT COALESCE(res.prs_kostensoort_key, 0) " + res_keyColumn
            + "      , res.prs_kostensoort_oms kostensoort"
            + "      , COUNT(distinct res.res_rsv_ruimte_key) aantalres"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + "  FROM (" + sql + ") res"
            + " GROUP BY res.prs_kostensoort_key"
            + "        , res.prs_kostensoort_oms";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 13)
      { // kostensoortgrp
        res_keyColumn = "prs_kostensoortgrp_key";
        res_columns[res_columns.length] = new columnData(L("lcl_charge_type_group"), "kostensoortgrp")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = " SELECT COALESCE(res.prs_kostensoortgrp_key, 0) " + res_keyColumn
            + "      , " + lcl.xsql('res.prs_kostensoortgrp_oms','res.prs_kostensoortgrp_key') + " kostensoortgrp"
            + "      , COUNT(distinct res.res_rsv_ruimte_key) aantalres"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + "  FROM (" + sql + ") res"
            + " GROUP BY res.prs_kostensoortgrp_key"
            + "        , res.prs_kostensoortgrp_oms";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 7)
      { // artikelen
        res_keyColumn = "artikel_key";
        res_columns[res_columns.length] = new columnData(L("lcl_res_art_desc"), "artikelomschrijving")
        res_columns[res_columns.length] = new columnData(L("lcl_res_item_price"), "artikelprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_btw_percentage"), "artikelbtw", "float", false)
        res_columns[res_columns.length] = new columnData(L("lcl_res_art_nr"), "artikelaantal", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        sql = " SELECT res.artikel_key " + res_keyColumn
            + "      , res.res_voorziening artikelomschrijving"
            + "      , res.stuks_prijs artikelprijs"
            + "      , res.btwtarief artikelbtw"
            + "      , SUM(res.aantal) artikelaantal"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + "  FROM (" + sql + ") res"
            + " WHERE categorie = 'C'"
            + " GROUP BY artikel_key"
            + "        , res_voorziening"
            + "        , stuks_prijs"
            + "        , btwtarief";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 8)
      { // artikelnummer
        res_keyColumn = "artikel_key";
        res_columns[res_columns.length] = new columnData(L("lcl_res_art_number"), "artikel")
        res_columns[res_columns.length] = new columnData(L("lcl_res_art_nr"), "artikelaantal", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        sql = " SELECT res.artikel_key " + res_keyColumn
            + "      , res.artikelnummer || ' - ' ||"
              + "     (SELECT MIN(" + lcl.xsql("res_artikel_omschrijving", "res_artikel_key") + ")"
              + "        FROM res_v_aanwezigartikel"
              + "       WHERE res_artikel_nr = res.artikelnummer)"
              + "     || ' ' ||"
              + "     CASE (SELECT COUNT(" + lcl.xsql("res_artikel_omschrijving", "res_artikel_key") + ") FROM res_v_aanwezigartikel WHERE res_artikel_nr = res.artikelnummer)"
              + "     WHEN 1"
              + "     THEN ''"
              + "     ELSE '...'"
              + "     END artikel"
            + "     , SUM(res.aantal) artikelaantal"
            + "     , SUM(res.verwerkt_prijs) totaalprijs"
            + "  FROM (" + sql + ") res"
            + " WHERE categorie = 'C'"
            + " GROUP BY artikel_key"
            + "        , artikelnummer";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 15)
      { // catalogus
        res_keyColumn = "discipline_key";
        res_columns[res_columns.length] = new columnData(L("lcl_res_catalogus"), "catalogusomschrijving")
        res_columns[res_columns.length] = new columnData(L("lcl_res_art_nr"), "artikelaantal", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        sql = " SELECT res.res_ins_discipline_key " + res_keyColumn
            + "      , res.res_voorziening catalogusomschrijving"
            + "      , SUM(res.aantal) artikelaantal"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + " FROM (" + sql + ") res"
            + " WHERE categorie = 'C'"
            + " GROUP BY res_ins_discipline_key"
            + "        , res_voorziening";
        sql_order = " ORDER BY 1";
      }
      else if (groupres == 9 || groupres == 14)
      { // kostenplaats
        if (groupres == 9)
        {
          res_keyColumn = "kostenplaats_key";
        }
        else
        {
          res_keyColumn = "prs_afdeling_key";
          res_columns[res_columns.length] = new columnData(L("lcl_department"), "organisatie")
        }
        res_columns[res_columns.length] = new columnData(L("lcl_res_account"), "kostenplaats")
        res_columns[res_columns.length] = new columnData(L("lcl_res_accountname"), "kostenplaatsomschr")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = " SELECT COALESCE(res.kostenplaats_key, 0) kostenplaats_key"
            + "      , res.kostenplaats"
            + "      , res.kostenplaatsomschr"
            + "      , res.prs_afdeling_key"
            + "      , res.organisatie"
            + "      , COUNT(DISTINCT res.res_rsv_ruimte_key) aantalres"
            + "      , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + " FROM (" + sql + ") res"
            + " GROUP BY kostenplaats_key"
            + "        , kostenplaats"
            + "        , kostenplaatsomschr"
            + "        , prs_afdeling_key"
            + "        , organisatie";
        sql_order = " ORDER BY organisatie, kostenplaats";
      }
      else if (groupres == 5)
      { // district
        res_keyColumn = "alg_district_key";
        res_columns[res_columns.length] = new columnData(L("lcl_district"), "district")
        res_columns[res_columns.length] = new columnData(L("lcl_res_res_nr"), "aantalres", "number", true)
        res_columns[res_columns.length] = new columnData(L("lcl_total"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new columnData(L("lcl_res_oordeel"), fncolOordeelAvg, "float", true, 1)
        sql = "SELECT d.alg_district_key " + res_keyColumn
            + "     , d.alg_district_omschrijving district"
            + "     , COUNT(distinct res.res_rsv_ruimte_key) aantalres"
            + "     , SUM(res.verwerkt_prijs) totaalprijs"
            + select_oordeel
            + "  FROM (" + sql + ") res"
            + "     , alg_district d"
            + " WHERE res.alg_district_key = d.alg_district_key"
            + " GROUP BY d.alg_district_key"
            + "        , d.alg_district_omschrijving";
        sql_order = " ORDER BY 2";
      }
      else if (groupres == 4)
      { // De default als groepering als niets gekozen
        // minfo reserveringen
        res_keyColumn = "res_reservering_key";
        if (S("res_reservering_flags") > 0)
          res_columns[res_columns.length] = new Column({caption: (outputmode == 0 ? I("fa-fclt-flag0") : L("lcl_res_flags")), content: fncolFlags, align: "center"})
        res_columns[res_columns.length] = new Column( {caption: L("lcl_resnr"), content: "rkey", customSort: fncustomSort})
        res_columns[res_columns.length] = new columnData(L("lcl_location"), "locatie")
        res_columns[res_columns.length] = new columnData(L("lcl_room_n"), "ruimte_aanduiding")
        res_columns[res_columns.length] = new Column( {caption: L("lcl_date"), content: fncolDatum, customSort: fncolDatumSort, datatype: "date", nowrap: true});
        res_columns[res_columns.length] = new columnData(L("lcl_res_starttime"), fncolVan, "time")
        res_columns[res_columns.length] = new columnData(L("lcl_res_endtime"), fncolTot, "time")
        res_columns[res_columns.length] = new columnData(L("lcl_prs_organisatie"), "organisatie")
        if (S("res_allow_for_others"))
          res_columns[res_columns.length] = new columnData(L("lcl_host"), "gastheer")
        res_columns[res_columns.length] = new columnData(L("lcl_res_account"), "kostenplaats")
        res_columns[res_columns.length] = new columnData(L("lcl_res_accountname"), "kostenplaatsomschr")
        res_columns[res_columns.length] = new columnData(L("lcl_descr"), "omschrijving")
        res_columns.push (new Column({caption: L("lcl_config_instance"), content: fnrowConfiguration, keepKeyRepeat: true}));
        res_columns[res_columns.length] = new columnData(L("lcl_remark"), "opmerking")
        res_columns.push (new Column({caption: L("lcl_res_pers_n"), content: fnrowVisitorsF, datatype: "number", total: true}));
        res_columns.push (new Column({caption: L("lcl_res_no_show"), content: "noshow", datatype: "number"}));
        res_columns[res_columns.length] = new columnData(L("lcl_res_rsv_kosten"), "totaalprijs", "currency", true)
        res_columns[res_columns.length] = new Column( {caption: L("lcl_res_oordeel"), content: fncolOordeel, total: true})
        if (anyflex)
          res_columns[res_columns.length] = new Column( {caption: flexlabel, content: fncolFlexBijlagen, colName: "fncolFlexBijlagen" });
        if (excel || print)
          res_columns[res_columns.length] = new Column( {caption: L("lcl_fac_like_remark"), content: "oordeel_opm"})

        sql = "SELECT res_srtactiviteit_prefix || res.res_reservering_key || '/' || res.res_rsv_ruimte_volgnr rkey"
            + "     , res.res_reservering_key " + res_keyColumn
            + "     , res.res_rsv_ruimte_volgnr"
            + "     , res.locatie locatie"
            + "     , res.alg_ruimte_aanduiding ruimte_aanduiding"
            + "     , MIN(res.datumvan) datumvan"
            + "     , MAX(res.datumtot) datumtot"
            + "     , res.organisatie organisatie"
            + (S("res_allow_for_others")
              ? "   , res.gastheer gastheer"
              : "")
            + "     , res.kostenplaats kostenplaats"
            + "     , res.kostenplaatsomschr kostenplaatsomschr"
            + "     , res.omschrijving omschrijving"
            + "     , res.opmerking opmerking"
            + "     , res.res_rsv_ruimte_satisfaction oordeel"
            + "     , res.res_rsv_ruimte_satisfaction_op oordeel_opm"
            + "     , res.res_rsv_ruimte_flag"
            + "     , bezoekers"
            + "     , res.startr"
            + "     , res.verval"
            + "     , res.res_ruimte_opstel_default"
            + "     , SUM(res.aantal) aantal"
            + "     , res.res_voorziening"
            + "     , MAX(res.noshow) noshow"
            + "     , SUM(res.verwerkt_prijs) totaalprijs"
            + "     , MAX(res.rsv_ruimte_key) rsv_ruimte_key"
            + "     , MAX(res.rsv_ruimte_key) res_rsv_ruimte_key"
            + "     , MAX(res.alg_ruimte_key) alg_ruimte_key"
            + "     , MAX(res.categorie) categorie"
            + "     , MAX(res.res_item_key) res_item_key"
            + "     , MAX(res.res_ruimte_key) res_ruimte_key"
            + "     , res.res_activiteit_meteindtijd"
            + "     , aantal_art_kenm"
            + "  FROM (" + sql + ") res"
            + " GROUP BY res_srtactiviteit_prefix || res_reservering_key || '/' || res.res_rsv_ruimte_volgnr"
            + "        , res.res_reservering_key"
            + "        , res.res_reservering_key || '/' || res.res_rsv_ruimte_volgnr"
            + "        , res_rsv_ruimte_volgnr"
            + "        , locatie"
            + "        , alg_ruimte_aanduiding"
            + "        , datumvan"
            + "        , organisatie"
            + (S("res_allow_for_others")
              ? "      , gastheer"
              : "")
            + "        , kostenplaats"
            + "        , kostenplaatsomschr"
            + "        , omschrijving"
            + "        , opmerking"
            + "        , res.res_rsv_ruimte_satisfaction"
            + "        , res.res_rsv_ruimte_satisfaction_op"
            + "        , noshow"
            + "        , res_ruimte_key"
            + "        , res_rsv_ruimte_flag"
            + "        , bezoekers"
            + "        , startr"
            + "        , verval"
            + "        , res_ruimte_opstel_default"
            + "        , aantal"
            + "        , res_voorziening"
            + "        , res_activiteit_meteindtijd"
            + "        , aantal_art_kenm";
        sql_order = " ORDER BY res_reservering_key"
                  + "        , res_rsv_ruimte_volgnr";
      }

      // Extra wrapper omdat ADO anders komt met 'Operation not allowed when object is closed'
      // Blijkbaar snapt die de WITH constructie vooraan niet zo
      if ((groupres > 1) && (groupres != 4))
      {
        sql = "SELECT * FROM (" + sql + ") " + sql_order;
      }
      else
      {
        sqltrack = (minfo
                   ? ", TO_DATE('01-01-1970', 'DD-MM-YYYY')"
                   : ", (SELECT MAX(t.fac_tracking_datum)"
                     + "     FROM fac_tracking t"
                     + "        , fac_srtnotificatie sn"
                     + "    WHERE t.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                     + "      AND t.fac_tracking_refkey = rsv_ruimte_key" // rsv_ruimte_key voor groupres=4 en <=1
                     + "      AND sn.fac_srtnotificatie_xmlnode = 'reservering')")
                 + " recentdatum";
        sqltrack = ", TO_DATE('01-01-1970', 'DD-MM-YYYY') recentdatum";

        Oracle.Execute("ALTER SESSION SET optimizer_features_enable = '11.2.0.4'"); // FCLT#70539 anders te traag
        Oracle.Execute("ALTER SESSION SET \"_optimizer_use_feedback\" = false"); // FCLT#70539 anders te traag
        sql = "SELECT /*+ CURSOR_SHARING_EXACT */ rec2.*"
            + (anyflex ? r_anyflex.sql_flex : "")
            + sqltrack
            + " FROM (" + sql + ") rec2 " + sql_order;
      }

      /***** End build sql *****/

      var count = 0;
      var descr = "";
      var remark = "";
      var total = new Array;


      /*****************************************************************
       * Callback functies ResultsetTable for FE, FO, BO and MI
       ****************************************************************/
      function isMeerdaags(oRs)
      {
        var datefrom = new Date(oRs("datumvan").value);
        var dateto   = new Date(oRs("datumtot").value);
        return (dateto.midnight().getTime() != datefrom.midnight().getTime());
      }

      function fncolDatum(oRs)
      {
        if (isMeerdaags(oRs))
          return L("lcl_res_multidays");
        else
          return toDateString(new Date(oRs("datumvan").value), excel); // excel-->noDay
      }

      function fncolDatumSort(oRs)
      {
        return new Date(oRs("datumvan").value).getTime() / 1000;
      }

      function fncolVan(oRs)
      {
        var datefrom = new Date(oRs("datumvan").value);
        var dt = toTimeString(datefrom);
        if (isMeerdaags(oRs))
            dt += "<br>" + toDateString(datefrom, excel); // excel-->noDay
        return dt;
      }

      function fncolTot(oRs)
      {
        var met_eindtijd = oRs("res_activiteit_meteindtijd").Value == 1;
        var has_date = (oRs("datumtot").Value != null); // ophaaltijd van artikel hoeft niet ingevuld te zijn.
        var dt = "";

        if (has_date && met_eindtijd)
        {
            var dateto = new Date(oRs("datumtot").Value);
            dt = toTimeString(dateto);
            if (isMeerdaags(oRs) && !excel) // excel heeft wel een eigen datumkolom
            {
                dt += "<br>" + toDateString(dateto, excel); // excel-->noDay
            }
        }
        return dt;
      }

      if (frontend || fronto)
      { // fe or fo without grouping
        /*****************************************************
         * Callback functies ResultsetTable for FE and FO only
         ****************************************************/

        var recent = new Date();
        recent.setMinutes(recent.getMinutes() - S("res_reservering_recent"));
        function fnrowClassF(oRs)   // tr-class
        {
          var rowclass = "";
          if (oRs("res_rsv_ruimte_verwijder").Value != null)
          {  // verwijderd
            rowclass = "deleted";
          }

          if (oRs("startr").Value == 0 || oRs("verval").Value == 0 || oRs("dirtlevel").Value != 0)
          {  // dirty!
            if (frontend)
            {
              rowclass += " listfatal";
            }
            else
            {
              rowclass += " res_fatal";
            }
          }

          //var res_recent = new Date(oRs("recentdatum").Value);
          // Ik zou dit liever in de hoofdquery meenemen maar Oracle12 komt daar slecht uit
          // Hier per regel ophalen is netto veel sneller
          var sql = "SELECT MAX(t.fac_tracking_datum) recentdatum"
                  + "  FROM fac_tracking t"
                  + "     , fac_srtnotificatie sn"
                  + " WHERE t.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                  + "   AND t.fac_tracking_refkey = " + oRs("rsv_ruimte_key").Value
                  + "   AND sn.fac_srtnotificatie_xmlnode = 'reservering'";
          var roRs = Oracle.Execute(sql);
          var res_recent = new Date(roRs("recentdatum").Value);
          roRs.Close();

          if (res_recent > recent)
          {
            rowclass += " updated";
          }


          return rowclass;
        }

        var fsql = "SELECT COUNT(dp.res_ins_discipline_key) aantal"
                 + "  FROM res_disc_params dp"
                 + " WHERE dp.res_disc_params_threshold < 9999999";
        var oRs = Oracle.Execute(fsql);
        var hasFiat = oRs("aantal").Value > 0; // Zijn er disciplines waarbij een fiaterings treshold is ingesteld?
        oRs.Close();

        function fncolFiat(oRs)
        { // Moet er een hokje met een kleur erin getoond worden? Alleen als er met een drempelwaarde wordt gewerkt voor een discipline en het bedrag boven de drempelwaarde ligt.
          var res_type = oRs("res_type").Value;
          var res_rsv_ruimte_cat_appr = oRs("res_rsv_ruimte_cat_appr").Value;
          if (res_type == "V" ||
              res_rsv_ruimte_cat_appr == 0)
            return "";

          var ttl;
          var icon;
          var displ = "";
          var resRsvRuimteKey = oRs("rsv_ruimte_key").value; // rsv_ruimte_key
          var approved_status = oRs("approved_status").Value;
          switch (approved_status)
          {
            case 0: ttl = L("lcl_res_ter_fiat");
                    icon = "fa-exclamation-circle";
                    break;
            case 1: ttl = L("lcl_res_goedgekeurd");
                    icon = "fa-check-circle";
                    break;
            case 2: ttl = L("lcl_res_afgewezen"); // Deze zal niet voorkomen in de query.
                    icon = "fa-times-circle";
                    break;
          }
          var fiatimg = "<span id='resfiatimg" + resRsvRuimteKey + "' class='resfiat" + approved_status + "' title='" + safe.htmlattr(ttl) + "'>" + I(icon+" fa-lg", {"fastyle":"fas"}) + "</span>";
          displ = "<div class='resfiatdiv' title='" + safe.htmlattr(ttl) + "'>" + fiatimg + "</div>";
          return displ;
        }

        function fnrowDataF(oRs)
        {
          var resKey = oRs("res_reservering_key").value; // Reservering key
          var resVolgnr = oRs("res_rsv_ruimte_volgnr").value; // Reservering volgnummer
          var resRsvRuimteKey = oRs("rsv_ruimte_key").value; // rsv_ruimte_key

          var data = {resKey: resKey, resVolgnr: resVolgnr, resRsvRuimteKey: resRsvRuimteKey};

          return JSON.stringify(data);
        }

        function fncolStatus(oRs)
        {
          var foStatKey = oRs("res_status_fo_key").value;

          if (oRs("dirtlevel").Value != 0  && frontend)
            foStatKey = -1;

          return res.getfostatustext(foStatKey);
        }

        function fnHasInlineDetails(oRs)
        {
          if (   (frontend || fronto)                           // Alleen deze rollen zien verwijderde reserveringen
              && oRs("res_rsv_ruimte_verwijder").Value != null) // Verwijderd
          {
            return null;
          }
          if (oRs("nrObjects").value > 0)
            return oRs("nrObjects").value + " " + L("lcl_res_reserved_objects");
          return null;
        }

        function fncolResNr(oRs)
        {
          var content = (oRs("res_srtactiviteit_prefix").value? oRs("res_srtactiviteit_prefix").value : "") + String(oRs("res_reservering_key").value)
          if (oRs("res_reservering_ispool").Value == 1)
            content = L("lcl_respool_prefix") + content;
          else
            content = content + "/" + oRs("res_rsv_ruimte_volgnr").value;
          return safe.html(content);
        }

        function fnrowVisitorsF(oRs)
        {
          return (oRs("bezoekers").value != 0? oRs("bezoekers").value : "");
        }

        function fncolHostRequestor(oRs)
        {
          var requestor = oRs("aanvrager").value
          if (S("res_allow_for_others") && !excel && oRs("gastheer").value == requestor)
            	requestor = "";
          return safe.html(requestor);
        }

        /*********************************************************
         * End callback functies ResultsetTable for FE and FO only
         ********************************************************/
        var rsParms = {keyColumn: "rsv_ruimte_key",
                       ID: "restable",
                       buttons: [],
                       rowClass: fnrowClassF,
                       rowData: fnrowDataF,
                       sql: sql,
                       filterParams: params,
                       outputmode: outputmode,
                       title: L("lcl_reservation_title"),
                       inlineDetails: (groupres == 1? "inlineVoorzieningUrl" : null),
                       hasInlineDetails: (groupres == 1? fnHasInlineDetails : null),
                       multiActionEnabler: true,
                       showAll: showall
                      };
        var buttonsFE = [];
        if (frontend) {
          var calendarurl = "appl/shared/fullcalendar.asp?worker=reslist";
          if (datefrom) {
            calendarurl += "&date_from=" + datefrom.getTime();
          }
          if (dateto) {
            calendarurl += "&date_to=" + dateto.getTime();
          }
          buttonsFE = [{ icon: "fa-calendar-alt", title: L("lcl_calendar"), action: "FcltMgr.openDetail('" + calendarurl + "', '" + safe.jsstring(L("frm_resframe")) + "')" }];
          rsParms.buttons = rsParms.buttons.concat(buttonsFE);
        }

        if (fronto)
        {
          rsParms.tabs_code = "res_list-" + urole;
          var buttonsFO = [];
          if (mld_key > 0) // zijn de RESFOF-rechten hier al zeker? De add zelf controleert sowieso ook nog.
            buttonsFO.push({ icon: "fa-plus",  title: L("lcl_add"), action: "resAdd("+mld_key+")" });
          if (!compact)
          {
            buttonsFO.push({ icon: "fa-list-ul",  title: L("lcl_mld_legenda"), action: "openLegenda()" });
            buttonsFO.push({ icon: "fa-columns",  title: L("lcl_scf_columns"), action: "openColumns()"});
          }
          if (params.fnStep)
            buttonsFO.push({ icon: "fa-fclt-refresh", title: L("lcl_refresh"), action: params.fnStep + "(0, 0)" });

          rsParms.buttons = rsParms.buttons.concat(buttonsFO);
        }

        var rst = new ResultsetTable(rsParms);

        // Kolommen
        if (!frontend && S("res_reservering_flags") > 0)
          rst.addColumn(new Column({caption: (outputmode == 0 ? I("fa-fclt-flag0") : L("lcl_res_flags")), content: fncolFlags, colName: "fncolFlags", colText: L("lcl_res_flags"), align: "center"}));
        if (fronto && hasFiat)
          rst.addColumn(new Column({caption: I("fa-circle"), content: fncolFiat, colName: "fncolFlags", colText: L("lcl_res_fiatstatus"), align: "center"}));
        rst.addColumn(new Column({caption: L("lcl_resnr"), content: fncolResNr, colName: "fncolResNr", customSort: fncustomSort }));
        if (frontend || fronto)
          rst.addColumn(new Column({caption: L("lcl_activity"), content: "res_activiteit_omschrijving"}));
        if (restype == "O") // personen altijd onder opdracht
          rst.addColumn(new Column({caption: L("lcl_mld_opdr_number"), content: "waar", hasActions: true}));
        else
          rst.addColumn(new Column({caption: L("lcl_room_n"), content: "waar", hasActions: true}));

        if (S("mld_print_loc_address") >= 1)
          rst.addColumn(new Column({caption: L("lcl_location_address"), content: "alg_locatie_adres", purpose: PRINTING_ONLY}));
  	    if (S("mld_print_loc_address") == 2)
          rst.addColumn(new Column({caption: L("lcl_building"), content: "alg_gebouw_naam", purpose: PRINTING_ONLY})); // cannot combine & PRINTING_ONLY

        // Compacter op scherm als datefrom==dateto
        if (res_key || opdr_key > 0 || mld_key > 0 || outputmode != 0 || outputmode == 0 && datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime())
        {
          rst.addColumn(new Column({caption: L("lcl_date"), content: excel?"datumvan":fncolDatum, colName: "fncolDatum", customSort: fncolDatumSort, datatype: "date", nowrap: true}));
        }
        rst.addColumn(new Column({caption: L("lcl_from"), content: fncolVan, colName: "fncolVan", datatype: "time", nowrap: true}));
        if (excel)
          rst.addColumn(new Column({caption: L("lcl_to"), content: "datumtot", colName: "fncolDatum", datatype: "date"}));
        rst.addColumn(new Column({caption: L("lcl_to"), content: fncolTot, colName: "fncolTot", datatype: "time"}));
        if (excel)
        { // Aparte kolommen voor aantal/config en aantal/voorzieningen
          rst.addColumn(new Column({caption: L("lcl_res_opstelling"), content: fnrowOpstelling, colName: "fnrowOpstelling"}));
          if (groupres != 1)
            rst.addColumn(new Column({caption: L("lcl_res_aantalvoorziening"), content: "aantal", datatype: "number"}));
          rst.addColumn(new Column({caption: L("lcl_reserved_object"), content: fnrowObject, colName: "fnrowObject"}));
        }
        else
          rst.addColumn(new Column({caption: L("lcl_config_instance"), content: fnrowConfiguration, colName: "fnrowConfiguration", colText: L("lcl_res_opstelling"), keepKeyRepeat: true}));
        rst.addColumn(new Column({caption: L("lcl_room_status"), content: fncolStatus, colName: "fncolStatus"}));
        if (restype != "O") // personen altijd onder opdracht
        {
          rst.addColumn(new Column({caption: L("lcl_res_pers_n"), content: fnrowVisitorsF, colName: "fnrowVisitorsF", datatype: "number"}));
          if (S("res_allow_for_others"))
          {
            rst.addColumn(new Column({caption: L("lcl_host"), content: "gastheer"}));
          }
          rst.addColumn(new Column({caption: L("lcl_res_requestor"), content: fncolHostRequestor, colName: "fncolHostRequestor", combine: (S("res_allow_for_others")?true:false)}));
        }
        rst.addColumn(new Column({caption: L("lcl_descr"), content: "omschrijving"}));
        if (S("res_approval") > 0)
          rst.addColumn(new Column({caption: L("lcl_res_approval"), content: fncolResApproved, colName: "fncolResApproved"}));
        if (anyflex)
          rst.addColumn(new Column({caption: flexlabel, content: fncolFlexBijlagen, colName: "fncolFlexBijlagen" }));

        // Acties
        rst.addAction({ action: "resEdit", caption: L("lcl_edit"), isDefault: true});
        rst.addAction({ action: "resMultiDelete", caption: L("lcl_delete"), single: false, multi: true, multiOnce: true});
        if (frontend && S("res_approval") != 0)
          rst.addAction({ action: "resMultiApprove", caption: L("lcl_res_catgoedkeur"), single: false, multi: true, multiOnce: true});

        var count = rst.processResultset();
      }
      else if (groupres > 1)
      { // minfo with grouping
        /*****************************************************************
         * Callback functies ResultsetTable for only MI with grouping
         ****************************************************************/
        var recent = new Date();
        recent.setMinutes(recent.getMinutes() - S("res_reservering_recent"));
        function fnrowClassM(oRs)   // tr-class
        {
          var class1 = "";
          if (groupres == 4 && !minfo)
          {
            var cnt_recent = new Date(oRs("recentdatum").value);
            // Ik zou dit liever in de hoofdquery meenemen maar Oracle12 komt daar slecht uit
            // Hier per regel ophalen is netto veel sneller
            var sql = "SELECT MAX(t.fac_tracking_datum) recentdatum"
                    + "  FROM fac_tracking t"
                    + "     , fac_srtnotificatie sn"
                    + " WHERE t.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                    + "   AND t.fac_tracking_refkey = " + oRs("rsv_ruimte_key").Value
                    + "   AND sn.fac_srtnotificatie_xmlnode = 'reservering'";
            var roRs = Oracle.Execute(sql);
            var cnt_recent = new Date(roRs("recentdatum").Value);

            if (cnt_recent > recent)
            {
              class1 += " updated ";
            }
          }
          return class1;
        }
        function fnrowDataM(oRs)
        {
          var data = { resKey : oRs(res_keyColumn).value }; // Reservering key
          if (res_keyColumn == "res_reservering_key")
          {
            data.resVolgnr = oRs("res_rsv_ruimte_volgnr").value; // Reservering volgnummer
            data.resRsvRuimteKey = oRs("rsv_ruimte_key").value; // rsv_ruimte_key
          }

          return JSON.stringify(data);
        }

        function fncolDistrict(oRs)
        {
          var content = oRs("locatie").Value;
          return content;
        }

        var tot_aantal_art = 0;
        var tot_aantal_res = 0;
        var tot_artikelprijs = 0;
        var tot_totaalprijs = 0;
        var sum_satisfaction = 0;
        var cnt_satisfaction = 0;
        var aantal_oordeel = 0;
        function fntotalCalc(oRs)
        {
          if (groupres == 4 && (oRs("oordeel").Value))
          { // Totaal oordeel is alle cijfers opgeteld gedeeld door het aantal beoordelingen.
            sum_satisfaction += oRs("oordeel").Value;
            aantal_oordeel++;
          }
          if (groupres != 4 && groupres != 7 && groupres != 8 && groupres != 15)
          {
            tot_aantal_res += parseInt(oRs("aantalres").Value, 10);

            // Totaal oordeel is alle cijfers opgeteld gedeeld door het aantal beoordelingen.
            sum_satisfaction += oRs("sum_satisfaction").Value;
            cnt_satisfaction += oRs("cnt_satisfaction").Value;
          }
          if (groupres == 7 || groupres == 8 || groupres == 15)
          {
            tot_aantal_art += parseInt(oRs("artikelaantal").Value, 10);
            if (groupres == 7)
            {
              tot_artikelprijs += parseFloat((oRs("artikelprijs").Value? oRs("artikelprijs").Value : 0), 10);
            }
          }
          tot_totaalprijs += oRs("totaalprijs").Value;
        }

        function fntotalShow(column, nrlines)
        {
          function doOordeel(cnt_satisfaction, sum_satisfaction)
          {
            var result = cnt_satisfaction > 0? sum_satisfaction/cnt_satisfaction : 0;
            if (excel || print)
              result = (result!=0? safe.displayfloat(sum_satisfaction/cnt_satisfaction, 1) : "");
            else
              result = rater(result, {readonly: true});
            return result;
          }

          var result = "";
          switch (column.caption)
          {
            case L("lcl_res_art_nr")    : result = tot_aantal_art; break;
            case L("lcl_res_res_nr")    : result = tot_aantal_res; break;
            case L("lcl_res_oordeel")   : if (groupres == 4)
                                            result = aantal_oordeel > 0? doOordeel(aantal_oordeel, sum_satisfaction) : "";
                                          else
                                            result = cnt_satisfaction > 0? doOordeel(cnt_satisfaction, sum_satisfaction) : "";
                                          break;
            case L("lcl_res_item_price"): result = safe.curr(tot_artikelprijs); break;
            case L("lcl_res_rsv_kosten"):
            case L("lcl_total")         : result = safe.curr(tot_totaalprijs); break;
          }
          return result;
        }

        /*********************************************************************
         * End callback functies ResultsetTable for only MI with grouping
         ********************************************************************/
        var rsParms = { keyColumn: res_keyColumn,
                        ID: "restable",
                        rowClass: fnrowClassM,
                        rowData: fnrowDataM,
                        sql: sql,
                        filterParams: params,
                        outputmode: outputmode,
                        title: L("lcl_reservation_title"),
                        showAll: showall,
                        totalCalc: fntotalCalc,
                        totalShow: fntotalShow
                      };

        // with no grouping or group "reservation", ask for additional characteristics when output is to excel
        if (groupres == 4 || groupres == 1)
        {
          rsParms.flexModule = "RES";
          rsParms.flexId = "rsv_ruimte_key";
        }
        var rst = new ResultsetTable(rsParms);

        // Kolommen
        for (var i = 0; i < res_columns.length; i++)
        {
          rst.addColumn(res_columns[i]);
        }

        // Acties
        if (groupres == 4) {
          rst.addAction({action: "resEdit", caption: L("lcl_edit"), isDefault: true});
        }

        var count = rst.processResultset();

      }
      else
      { // (BO: grouping and no grouping)
        /***********************************************************************
         * Callback functies ResultsetTable for only BO grouping and no grouping
         **********************************************************************/
        var recent = new Date();
        recent.setMinutes(recent.getMinutes() - S("res_reservering_recent"));

        function fnrowClassB(oRs)   // tr-class
        {
          // resR of resC of resV
          var class1 = "res" + oRs("res_type").value + (oRs("ingang").value == 0 || oRs("startr").Value == 0 || oRs("verval").value == 0? " res_fatal " : "");

          //var cnt_recent = new Date(oRs("recentdatum").value);
          // Ik zou dit liever in de hoofdquery meenemen maar Oracle12 komt daar slecht uit
          // Hier per regel ophalen is netto veel sneller
          var sql = "SELECT MAX(t.fac_tracking_datum) recentdatum"
                  + "  FROM fac_tracking t"
                  + "     , fac_srtnotificatie sn"
                  + " WHERE t.fac_srtnotificatie_key = sn.fac_srtnotificatie_key"
                  + "   AND t.fac_tracking_refkey = " + oRs("rsv_ruimte_key").Value
                  + "   AND sn.fac_srtnotificatie_xmlnode = 'reservering'";
          var roRs = Oracle.Execute(sql);
          var cnt_recent = new Date(roRs("recentdatum").Value);
          roRs.Close();

          if (cnt_recent > recent)
          {
            class1 += " updated ";
          }

          var datenow = new Date();
          var datefrom = new Date(oRs("datumvan").Value);
          var dateto = new Date(oRs("datumtot").Value);
          if (datenow < datefrom)
              class1 += " resfuture ";
          else if (datenow > dateto)
              class1 += " respast ";
          else
              class1 += " resactive ";

          class1 += (oRs("res_status_bo_key").Value >= 5 ? " resafgemeld " : " resnietafgemeld ");
          return class1;
        }

        function fnrowData(oRs)
        {
          var resKey = oRs("res_reservering_key").value; // Reservering key
          var resVolgnr = oRs("res_rsv_ruimte_volgnr").value; // Reservering volgnummer
          var resRsvRuimteKey = oRs("rsv_ruimte_key").value; // rsv_ruimte_key
          var resPartkey = oRs("res_item_key").value; // rsv_ruimte_key, rsv_deel_key of rsv_artikel_key
          var resPartType = oRs("categorie").value; // reserveringstype ('C', 'V', 'R')

          var resVanDatumMidnight = new Date(oRs("datumvan").Value).midnight(); // rsv_ruimte_van datum om middernacht
          var now = new Date();
          var resFuture = (resVanDatumMidnight > now? 1 : 0);
          var dateto = new Date(oRs("datumtot").Value);
          var resReleaseEquipment = S("res_release_equipment_on_close") == 1 && now < dateto;
          if (resReleaseEquipment) { // Hebben we uberhaupt equipment?
            var sql_V = "SELECT 'dummy'"
                      + "  FROM res_rsv_deel"
                      + " WHERE res_rsv_deel_tot > SYSDATE"
                      + "   AND res_rsv_deel_verwijder IS NULL"
                      + "   AND res_rsv_ruimte_key = " + resRsvRuimteKey;
            var oRs_V = Oracle.Execute(sql_V);
            var hasAnyActiveDelen = !oRs_V.EoF;
            oRs_V.Close();
            resReleaseEquipment = hasAnyActiveDelen;
          }

          var data = {resKey: resKey, resVolgnr: resVolgnr, resRsvRuimteKey: resRsvRuimteKey,
                      resPartkey: resPartkey, resPartType: resPartType, resFuture: resFuture,
                      res_rsv_deel_key: resPartkey, resReleaseEquipment: resReleaseEquipment};

          return JSON.stringify(data);
        }

        function fnrowActionEnabler(oRs)
        {
          var data = { eEdit   : true, // Altijd aanwezig
                       eClose  : false,
                       eNoShow : false,
                       eLendOut: false,
                       eReceive: false,
                       eAdapt: false
                     }

          var besStatusBO = oRs("res_status_bo_key").value;
          if (oRs("res_status_bo_key").value < 5)
          { // Als de catering nog niet is goedgekeurd of afgewezen kan de reservering nog niet worden afgemeld.
            var res_type = oRs("categorie").Value;
            var res_rsv_ruimte_cat_appr = oRs("res_rsv_ruimte_cat_appr").Value;
            var approved_status = oRs("res_rsv_artikel_approved").Value;
            var firstFiat = res_rsv_ruimte_cat_appr == 1 && approved_status == 0;

            data.eClose = !firstFiat;
            // Voor noshow-optie wordt ivm performance globaal gekeken of het mag. De feitelijke
            // actie controleert definitief en verfijnder
            data.eNoShow = true;
          }
          if (groupres != 1 && oRs("ins_srtdeel_uitleenbaar").Value == 1)
          {
            // TODO: We negeren de 3D scope vooralsnog. Veel te ingewikkeld met org-velden en dergelijke
            //       Eerst maar even parktijkgeluiden afwachten
            //       user.checkAutorisation cache't per discipline dus dat is te overzien.
            // LET OP: Hier dus de ins_discipline_key, niet de res_ins_discipline_key
            var authparams = user.checkAutorisation("WEB_INSFOF", true, oRs("ins_discipline_key").Value);
            if (authparams && authparams.PRSwritelevel < 9)
            {
              data.eLendOut = oRs("ins_alg_ruimte_key_org").value == null;
              data.eReceive = !data.eLendOut;
              data.eAdapt = data.eReceive;
            }
          }
          return data;
        }

        function fncolCompleteRes(oRs)
        {
          var content = "<div id='afm" + oRs("keycolumn").value + "'></div>";
          if (oRs("res_status_bo_key").Value >= 5)
          {
            if (!excel)
              content = I("fa-check-square") + "<div style='display:none'>"+oRs("res_status_bo_key").Value+"</div>";
            else
              content = L("lcl_Yes");
          }
          return content;
        }

        function fnrowResNr(oRs)
        {
          return safe.html(oRs("res_srtactiviteit_prefix").value? oRs("res_srtactiviteit_prefix").value : "") + String(oRs("res_reservering_key").value) + "/" + oRs("res_rsv_ruimte_volgnr").value;
        }

        function fnrowVisitors(oRs)
        {
          var bezoekers_shown = oRs("bezoekers_shown").value;
          return (oRs("bezoekers").value && oRs("bezoekers").value != 0? (bezoekers_shown >= 0? bezoekers_shown + "/" : "") + oRs("bezoekers").value : "");
        }

        function fnrowOpstelling(oRs)
        {
          return ((oRs('categorie').value == 'R')? safe.html(oRs("res_voorziening").value) : "");
        }

        function getFlexArticle(poRs)
        { // Artikel kenmerk ophalen.
          var sqlFlex = "";
          var flexData = [];
          var flex = "";
          if ((groupres == -1 || groupres == 4) && poRs("aantal_art_kenm").Value > 0)
          {
            sqlFlex = getSqlFlex("RESA", poRs("res_item_key").Value, true);
            flexData = getFlexData(sqlFlex, poRs("res_item_key").Value, { showProperties: true, onlyWithValue: true }); // Alleen flexkenmerken met een waarde ophalen.
            if (flexData.length && !excel)
              flex = "<div class='resartflexlist'>";
            for (var i = 0; i < flexData.length; i++)
            {
              flex += (i || excel? "<br>" : "") // Met <br> krijg je een nieuwe rij in excel.
                    + (!excel? "<span>" : "")
                    + safe.html(flexData[i].header)
                    + ": " +  safe.html(flexData[i].value) + (!excel? "</span>" : "");
            }
            if (flexData.length && !excel)
              flex += "</div>";
          }

          return flex;
        }

        function fnrowObject(oRs)
        { // Excel.
          var c_flex = getFlexArticle(oRs);
          return ((oRs("categorie").value != "R")? safe.html(oRs("res_voorziening").value) + c_flex : "");
        }

        function fnrowNrObject(oRs)
        {
          var c_flex = getFlexArticle(oRs);
          return ((oRs("categorie").value != "R")? (oRs("aantal").Value? oRs("aantal").Value + " * " : "") + safe.html(oRs("res_voorziening").value) + c_flex : "");
        }

        function fnrowConfiguration(oRs)
        { // Print.
          var isDefault = true;
          if (oRs("categorie").Value == 'R')
          {
            isDefault = (oRs("res_ruimte_opstel_default").Value == "1");
          }
          if (groupres == 1)
          {
            if (oRs("categorie").Value == 'R')
            {
              // TODO: ik wil hier een span class toevoegen om afwijking van de
              // defaultopstelling te markeren. Ik vind het echter nu nogal ondoorzichtig
              // waar die kolomwaarde vandaan zou moeten komen.
              c_inst = oRs("res_voorziening").Value;
            }
            else
            {
              c_inst = L("lcl_reserved_object");
            }
          }
          else
          {
            if (oRs("aantal").Value == null)
            {
              c_inst = oRs("res_voorziening").Value;
            }
            else
            {
              c_inst = oRs("aantal").Value + " * " + oRs("res_voorziening").Value;
            }
          }

          var c_flex = getFlexArticle(oRs);

          if (!isDefault)
          {
            return "<span class='afwijkopstel'>" + safe.html(c_inst) + c_flex + "</span>";
          }
          else
          {
            return safe.html(c_inst) + c_flex;
          }
        }

        function fncolResApproved(oRs)
        {
          var approved_txt = "";
          if (oRs("res_rsv_ruimte_afgerond").Value == 1)
          {
            approved_txt = L("lcl_res_resappr");
          }
          else
          {
            if (frontend)
            {
              if (oRs("approval").Value == 1)
                approved_txt = L("lcl_res_tobeapproved");
              //else 'nog niet goed te keuren'
            }
            else
              approved_txt = L("lcl_res_notapproved");
          }
          return approved_txt;
        }

        function fncolFlexBijlagen(oRs)
        {
          var flexval = oRs("flex").Value;
          var bijlagen_aantal = 0;
          if (bijlageflex)
          {
            var rsv_ruimte_key = oRs("res_rsv_ruimte_key").Value;
            var bijlagen_oms = "";
            var bijlagen_lijst = [];

            var sql = "SELECT k.res_kenmerk_key"
                    + "     , skr.res_srtkenmerk_omschrijving" // suspect
                    + "     , CASE"
                    + "       WHEN BITAND(k.res_kenmerk_inlijst,1) = 1"
                      + "     THEN 1"
                      + "     ELSE 0"
                    + "       END in_overzicht_tonen"
                    + "  FROM res_rsv_ruimte rrr"
                    + "     , res_srtkenmerk skr"
                    + "     , res_kenmerk k"
                    + " WHERE rrr.res_activiteit_key = k.res_activiteit_key"
                    + "   AND k.res_srtkenmerk_key = skr.res_srtkenmerk_key"
                    + "   AND skr.res_srtkenmerk_kenmerktype = 'M'"
                    + "   AND k.res_kenmerk_verwijder IS NULL"
                    + "   AND skr.res_srtkenmerk_verwijder IS NULL"
                    + "   AND rrr.res_rsv_ruimte_key = " + rsv_ruimte_key;
            var oRs_k = Oracle.Execute(sql);

            while (!oRs_k.eof)
            {
              if (oRs_k("in_overzicht_tonen").Value == 1)
              {
                var kenmerk_key = oRs_k("res_kenmerk_key").Value;
                var bijlagen_oms = oRs_k("res_srtkenmerk_omschrijving").Value;  // suspect
                var bestanden = flexProps("RES", rsv_ruimte_key, kenmerk_key, "M", {getFiles: true});
                var km_aantal = bestanden.files.length;
                for (i=0; i<km_aantal; i++)
                {
                  bijlagen_lijst.push(bestanden.files[i].name);
                }
                bijlagen_aantal += km_aantal;
              }
              oRs_k.MoveNext();
            }

            oRs_k.Close();
          }
          return (flexval ? safe.html(flexval.replace(/\r/g, "\n")+ "\n") : "")
               + (bijlagen_aantal > 0
                 ? "<span title='" + safe.htmlattr(bijlagen_lijst.join("\n")) + "'>"
                   + safe.html(bijlagen_oms) + ": " + bijlagen_aantal
                   + "</span>"
                 : "");
        }

        var fsql = "SELECT COUNT(dp.res_ins_discipline_key) aantal"
                 + "  FROM res_disc_params dp"
                 + " WHERE dp.res_disc_params_threshold < 9999999";
        var oRs = Oracle.Execute(fsql);
        var hasFiat = oRs("aantal").Value > 0; // Zijn er disciplines waarbij een fiaterings treshold is ingesteld?
        oRs.Close();

        function fncolFiatBO(oRs)
        { // Moet er een hokje met een kleur erin getoond worden? Alleen als er met een drempelwaarde wordt gewerkt voor een discipline en het bedrag boven de drempelwaarde ligt.
          // Als er nog catering gefiatteerd moet worden, dan wordt ook voor de ruimte en objecten regels een orange blokje getoond.
          var res_rsv_ruimte_cat_appr = oRs("res_rsv_ruimte_cat_appr").Value;
          if (res_rsv_ruimte_cat_appr == 0)
            return "";

          var ttl;
          var icon;
          var displ = "";
          var resRsvRuimteKey = oRs("rsv_ruimte_key").value; // rsv_ruimte_key
          var approved_status = oRs("res_rsv_artikel_approved").Value;
          switch (approved_status)
          {
            case 0: ttl = L("lcl_res_ter_fiat");
                    icon = "fa-exclamation-circle";
                    break;
            case 1: ttl = L("lcl_res_goedgekeurd");
                    icon = "fa-check-circle";
                    break;
            case 2: ttl = L("lcl_res_afgewezen"); // Deze zal niet voorkomen in de query.
                    icon = "fa-times-circle";
                    break;
          }
          var fiatimg = "<span id='resfiatimg" + resRsvRuimteKey + "' class='resfiat" + approved_status + "' title='" + safe.htmlattr(ttl) + "'>" + I(icon + " fa-lg", {"fastyle" : "fas"}) + "</span>";
          displ = "<div class='resfiatdiv' title='" + safe.htmlattr(ttl) + "'>" + fiatimg + "</div>";
          return displ;
        }

        /***************************************************************************
         * End callback functies ResultsetTable for only BO grouping and no grouping
         **************************************************************************/
        var buttons = [];
        buttons.push({ icon: "fa-columns",   title: L("lcl_scf_columns"), action: "openColumns()"});
        buttons.push({ icon: "fa-list-ul",   title: L("lcl_mld_legenda"), action: "openLegenda()" });
        if (params.fnStep)
          buttons.push({ icon: "fa-fclt-refresh", title: L("lcl_refresh"), action: params.fnStep + "(0, 0)" });

        var rst = new ResultsetTable({keyColumn: "keycolumn",
                                      ID: "restable",
                                      tabs_code: "res_list-" + urole,
                                      buttons: buttons,
                                      rowClass: fnrowClassB,
                                      rowData: fnrowData,
                                      rowActionEnabler: fnrowActionEnabler,
                                      sql: sql,
                                      flexModule: "RES",
                                      flexId: "rsv_ruimte_key", // keycolumn is soms res_rsv_deel_key
                                      flexGroupId: "res_activiteit_key",
                                      filterParams: params,
                                      outputmode: outputmode,
                                      title: L("lcl_reservation_title"),
                                      inlineDetails: ((backo || minfo) && groupres == 1)? "inlineVoorzieningUrl" : null,
                                      hasInlineDetails: ((backo || minfo) && groupres == 1)? fnHasInlineDetails : null,
                                      showAll: showall,
                                      suppressKeyRepeat: print?"rsv_ruimte_key":null // suppress fields when no key-change
                                     });
        // Kolommen
        // AAFM#14872/PF: Deze locatiekolom is wat dubbelop. We spreken af dat we die
        //                eerst maar eens niet meer tonen. Als er gefundeerde klachten komen is
        //                deze snel genoeg combined terug te halen
        //rst.addColumn(new Column({caption: L("lcl_location"), content: "locatie"}));
        rst.addColumn(new Column({caption: (excel?L("lcl_res_resafm"):I("fa-check-square")),
                                  content: fncolCompleteRes, colName: "fncolCompleteRes", colText: L("lcl_res_resafm") }));
        if (S("res_reservering_flags") > 0)
          rst.addColumn(new Column({caption: "o", content: fncolFlags, colName: "fncolFlags", align: "center"}));

        if (hasFiat)
          rst.addColumn(new Column({caption: I("fa-circle"), content: fncolFiatBO, colName: "fncolFlags", colText: L("lcl_res_fiatstatus"), align: "center"}));

        if (S("mld_print_loc_address") >= 1)
          rst.addColumn(new Column({caption: L("lcl_location_address"), content: "alg_locatie_adres", purpose: PRINTING_ONLY}));
        if (S("mld_print_loc_address") == 2)
          rst.addColumn(new Column({caption: L("lcl_building"), content: "alg_gebouw_naam", purpose: PRINTING_ONLY})); // cannot combine & PRINTING_ONLY

        rst.addColumn(new Column({caption: L("lcl_room_n"), content: "res_ruimte_nr", combine: false, hasActions: true}));
        // Compacter op scherm als datefrom==dateto
        if (res_key || opdr_key > 0 || mld_key > 0 || outputmode != 0 || (outputmode == 0 && datefrom && dateto && datefrom.midnight().getTime() != dateto.midnight().getTime()))
        { // Compact als begin==eind
          rst.addColumn(new Column({caption: L("lcl_date"), content: excel?"datumvan":fncolDatum, colName: "fncolDatum", customSort: fncolDatumSort, datatype: "date", nowrap: true}));
        }
        rst.addColumn(new Column({caption: L("lcl_res_starttime"), content: fncolVan, colName: "fncolVan", datatype: "time", keepKeyRepeat: true}));
        if (excel)
          rst.addColumn(new Column({caption: L("lcl_to"), content: "datumtot", colName: "fncolDatum", datatype: "date"}));
        rst.addColumn(new Column({caption: L("lcl_res_endtime"), content: fncolTot, colName: "fncolTot", datatype: "time"}));

        rst.addColumn(new Column({caption: L("lcl_resnr"), content: fnrowResNr, colName: "fnrowResNr", customSort: fncustomSort}));
        rst.addColumn(new Column({caption: L("lcl_count"), content: fnrowVisitors, colName: "fnrowVisitors"}));

        // Aparte kolommen voor opstelling en aantal/voorzieningen.
        rst.addColumn(new Column({caption: L("lcl_res_opstelling"), content: fnrowOpstelling, colName: "fnrowOpstelling", keepKeyRepeat: true}));
        if (excel)
        {
          if (groupres != 1)
            rst.addColumn(new Column({caption: L("lcl_res_aantalvoorziening"), content: "aantal", datatype: "number"}));
          rst.addColumn(new Column({caption: L("lcl_reserved_object"), content: fnrowObject, colName: "fnrowObject"}));
        }
        else if (groupres != 1)
          rst.addColumn(new Column({caption: L("lcl_reserved_object"), content: fnrowNrObject, colName: "fnrowNrObject", combine: true, keepKeyRepeat: true}));

        if (S("res_allow_for_others") && S("res_bo_show_host") == 1)
          rst.addColumn(new Column({caption: L("lcl_host"), content: "gastheer"}));
        rst.addColumn(new Column({caption: L("lcl_res_requestor"), content: "aanvrager"}));
        if (S("res_bo_show_telnr") == 1)
        {
          rst.addColumn(new Column({caption: L("lcl_res_requestor_phone"), content: "prs_perslid_telefoonnr"}));
          rst.addColumn(new Column({caption: L("lcl_prs_person_mobile"), content: "prs_perslid_mobiel", combine: true}));
        }
        if (S("res_bo_show_kpn") == 1)
        {
          rst.addColumn(new Column({caption: L("lcl_res_account"), content: "kostenplaats"}));
          rst.addColumn(new Column({caption: L("lcl_res_accountname"), content: "kostenplaatsomschr", combine: true}));
        }
        if (S('show_ordernr') == 3 && outputmode != 0)
          rst.addColumn(new Column({caption: L("lcl_mld_inf_Ordernr"), content: "res_rsv_ruimte_ordernr" }));
        rst.addColumn(new Column({caption: L("lcl_descr"), content: "omschrijving"}));
        if (hasAnyOpmerkingen)
          rst.addColumn(new Column({caption: L("lcl_remark"), content: "opmerking"}));

        if (outputmode != 0)
          rst.addColumn(new Column({caption: L("lcl_activity"), content: "res_activiteit_omschrijving"}));
        if (S("res_approval") > 0)
          rst.addColumn(new Column({caption: L("lcl_res_approval"), content: fncolResApproved, colName: "fncolResApproved"}));
        if (anyflex)
          rst.addColumn(new Column({caption: flexlabel, content: fncolFlexBijlagen, colName: "fncolFlexBijlagen" }));

        // Acties
        rst.addAction({action: "resEdit", caption: L("lcl_edit"), isDefault: true});
        if (authparams.PRSwritelevel < 9 && authparams.ALGwritelevel < 9) // grove controle
          rst.addAction({action: "resClose", caption: L("lcl_close"), enabler: "eClose", multi: true, multiOnce: true});

        rst.addAction({ action: "resMultiPrint", caption: L("lcl_print"), single: false, multi: true, multiOnce: true});

        if (S("res_noshow_detailed") == 1 &&
            authparamsRESNOS &&
            authparamsRESNOS.PRSwritelevel < 9 &&
            authparamsRESNOS.ALGwritelevel < 9)
        {
          rst.addAction({action: "resNoShow", caption: L("lcl_res_no_show"), enabler: "eNoShow"});
        }

        rst.addAction({ action: "insCheckOut", caption: L("lcl_obj_lend_out"), enabler: "eLendOut"});
        rst.addAction({ action: "insCheckIn", caption: L("lcl_obj_receive"), enabler: "eReceive"});
        // te druk rst.addAction({ action: "insAdapt", caption: L("lcl_ins_adapt"), enabler: "eAdapt"});

        var count = rst.processResultset();
      }

      if (!excel && !print)
      {
%>
        <script type="text/javascript">

          $(function()
          {
            $(".clickParent").parent().on("click", function(e)
                                                   {
                                                     e.stopPropagation();
                                                     $(this).find("> .clickParent").trigger("click");
                                                   });
          });
          <!-- LEGENDA  -->
          function openLegenda()
          {
            var myPosition = "right top+30";
            if (elems.$originalHeaderRow && elems.$originalHeaderRow.length)
                myPosition = "right-15 top+"+(parseInt(elems.$fcltFrameHeader.css("top"))+30);
            params = { width: 250,
                       minWidth: 250,
                       minHeight: 10,
                       resizable: false,
                       position: {my: "right top", at: myPosition},
                       title: L("lcl_ins_controle_legenda"),
                       create: FcltMgr.fnCreateCloseButton("div#legenda")
                     };
		      $('div#legenda').dialog(params).dialog('open');
            FcltMgr.resized();
          }
        </script>
        <div id="legenda" style="display:none; line-height: 30px;">
          <table id="meldinglegenda">
            <tr class="resR">
              <td title="<%= L("lcl_res_legenda_resr_tt") %>"><%= L("lcl_res_legenda_resr") %></td>
            </tr>
            <tr class="resC">
              <td title="<%= L("lcl_res_legenda_resc_tt") %>"><%= L("lcl_res_legenda_resc") %></td>
            </tr>
            <tr class="resV">
              <td title="<%= L("lcl_res_legenda_resv_tt") %>"><%= L("lcl_res_legenda_resv") %></td>
            </tr>
            <tr class="updated">
              <td title="<%= L("lcl_res_legenda_updated_tt") %>"><%= L("lcl_res_legenda_updated") %></td>
            </tr>
            <tr class="res_fatal">
              <td title="<%= L("lcl_res_legenda_fatal_tt") %>"><%= L("lcl_res_legenda_fatal") %></td>
            </tr>
            <tr class="resactive">
              <td title="<%= L("lcl_res_legenda_active_tt") %>"><%= L("lcl_res_legenda_active") %></td>
            </tr>
            <tr class="respast">
              <td title="<%= L("lcl_res_legenda_past_tt") %>"><%= L("lcl_res_legenda_past") %></td>
            </tr>
<%          // Vlag 0 tonen we niet
            for (var flagkey=1; flagkey < S('res_reservering_flags'); flagkey++)
            {
              %><tr><td>
                <span class="resflag<%=flagkey%>"><%=I("fa-fclt-flag")%></span>&nbsp;
                <%=L("lcl_res_flag"+flagkey)%>
              </td></tr><%
            }
%>
          </table>
        </div>
<%
      } // !print && !excel
%>
    </body>
  </html>
<%
}
%>
