<%
 /*
    $Revision$
    $Id$

    File:               bes.inc
    Description:        bas-module functies

    Context:
    Note:

*/ %>
<%
    bes =
    {
        setbestellingstatus:
           function (bes_key, bes_bestellingstatus_key)
           {
               var sql = "BEGIN bes.setbestellingstatus(" + bes_key + ", " + bes_bestellingstatus_key + ", " + user_key + "); END;"
               Oracle.Execute(sql);
               // Deze zet de status en doet dan bijpassende tracking en notificatie
               // zou leuk zijn om true of false op te leveren naar gelang de status echt anders is geworden
           },
        updatebestellingstatus:
           function (bes_key)
           {
               var sql = "BEGIN bes.updatebestellingstatus(" + bes_key + ", " + user_key + "); END;"
               Oracle.Execute(sql);
               // Deze zet de controleert de status van de bestelling op basis van de status van de regels
               // en doet dan ook bijpassende tracking en notificatie
           },
        updatebestelopdrstatus:
           function (besopdr_key)
           {
               var sql = "BEGIN bes.updatebestelopdrstatus(" + besopdr_key + ", " + user_key + "); END;"
               Oracle.Execute(sql);
               // Deze zet de controleert de status van de bestelopdracht op basis van de status van de regels
               // en doet dan ook bijpassende tracking en notificatie
           },
        autoapprovefactuur:
           function (opdr_key)
           { // Zijn er bijbehorende facturen die al zijn ingevoerd met de status "Ingevoerd(2)" die nog geapproved moeten worden?
             sql = "SELECT f.fin_factuur_key"
                 + "  FROM fin_factuur f"
                 + " WHERE f.bes_bestelopdr_key = " + opdr_key
                 + "   AND f.fin_factuur_statuses_key = 2"
                 + " ORDER BY f.fin_factuur_key";
             var oRs = Oracle.Execute(sql);
             while (!oRs.eof)
             { // Autofiatteer de facturen als dat zo ingesteld is.
               // Functie kijkt zelf of autofiatteren aanstaat.
               sql = "BEGIN fin.autoapprovefactuur(" + oRs("fin_factuur_key").Value + "); END;";
               Oracle.Execute(sql);
               oRs.MoveNext();
             }
             oRs.Close();
           },
        getbesbestellingstatustext:
           function(p)
           {
              var statustekst = "??";
              switch (p) { // grofweg op volgorde timeline
                  case 2: { statustekst = L("lcl_bes_new"); break; }
                  case 3: { statustekst = L("lcl_bes_gefiatteerd"); break; }  // Door kostenplaats (en/of -groep) verantwoordelijke
                  case 4: { statustekst = L("lcl_bes_geaccepteerd"); break; } // Door backoffice (afdeling inkoop)
                  case 5: { statustekst = L("lcl_bes_besteld"); break; }      // Opdrachten zijn aangemaakt
                  case 1: { statustekst = L("lcl_bes_afgewezen"); break; }
                  case 6: { statustekst = L("lcl_bes_geleverd"); break; }
                  case 7: { statustekst = L("lcl_bes_verwerkt"); break; }
                  case 8: { statustekst = L("lcl_bes_is_bescan"); break; }
              }
              if (Session("logging")>0)
                statustekst += " ("+String(p)+")";
              return statustekst;
           },
        getbesopdrstatustext:
           function(p)
           {
              var statustekst = "??";
              switch (p) { // grofweg op volgorde timeline
                  case 2: { statustekst = L("lcl_bes_ord_new"); break; }           // JGL: niet gebruikt trouwens
                  case 3: { statustekst = L("lcl_bes_ord_inbehandeling"); break; } // JGL: Moet nog verstuurd worden
                  case 5: { statustekst = L("lcl_bes_ord_onbevestigd"); break; }   // JGL: wel verstuurd maar nog 'Ter acceptatie bij de leverancier'
                  case 4: { statustekst = L("lcl_bes_ord_inbestelling"); break; }  // JGL: Leverancier heeft hem bevestigd
                  case 1: { statustekst = L("lcl_bes_ord_afgewezen"); break; }     // Afgewezen door leverancier
                  case 6: { statustekst = L("lcl_bes_ord_geleverd"); break; }
                  case 7: { statustekst = L("lcl_bes_ord_verwerkt"); break; }
                  case 8: { statustekst = L("lcl_bes_ord_geannuleerd"); break; }
              }
              if (Session("logging")>0)
                statustekst += " ("+String(p)+")";
              return statustekst;
           },

        trackbestellingaccepteren:
           function (opdr_key, ptxt)
           {
                shared.trackaction('BESACP', opdr_key, ptxt);
           },

        // Alle (BES) informatie van een disciplnie
        disc_info: function _disc_info(disc_key, autfunction)
        {
            var sql = "SELECT " + lcl.xsqla('ins_discipline_omschrijving', 'bd.ins_discipline_key')
                    + "     , bes_disc_params_retour"
                    + "     , bes_disc_params_retour_url"
                    + "     , bes_disc_params_levopm_url"
                    + "     , bes_disc_params_leverdagen"
                    + "     , bes_disc_params_punchouturl"
                    + "     , bes_disc_params_punch_bedr_key"
                    + "     , bes_disc_params_logo_url"
                    + "     , bes_disc_params_autoacceptrfo"
                    + "     , bes_disc_params_auto_order"
                    + "     , bes_disc_params_min_bedrag"
                    + "     , bes_disc_params_bestellimiet"
                    + "     , bes_disc_params_bestellimiet2"
                    + "     , bes_disc_params_bestellimiet3"
                    + "     , bes_disc_params_bestellimiet4"
                    + "     , bes_disc_params_bestellimiet5"
                    + "     , ins_discipline_kpnverplicht"
                    + "     , bes_disc_params_pgb"
                    + "     , bes_disc_params_herfiat"
                    + "     , bes_disc_params_herfiatpct"
                    + "     , bes_disc_params_herfiatmarge"
                    + "     , (SELECT COUNT(sd.bes_srtdeel_key)"
                    + "          FROM bes_v_aanwezigsrtgroep sg"
                    + "             , bes_v_aanwezigsrtdeel sd"
                    + "         WHERE bd.ins_discipline_key = sg.ins_discipline_key"
                    + "           AND sg.bes_srtgroep_key = sd.bes_srtgroep_key"
                    + "           AND sd.bes_staffeltabel_key IS NOT NULL) staffelgroepitems"
                    + "     , bes_disc_params_maxartikel"
                    + "     , bes_disc_params_kpautorisatie"
                    + "     , bes_disc_params_for_others"
                    + "     , bes_disc_params_freeartikel"
                    + "  FROM bes_discipline bd, bes_disc_params bdp"
                    + " WHERE bd.ins_discipline_key = " + disc_key
                    + "   AND bdp.bes_ins_discipline_key = bd.ins_discipline_key";

            var oRs = Oracle.Execute(sql);
            var result = { disc_key                       : disc_key,
                           discipline_omschrijving        : oRs("ins_discipline_omschrijving").Value,
                           discipline_kpnverplicht        : oRs("ins_discipline_kpnverplicht").Value == '1',
                           disc_params_retour             : oRs("bes_disc_params_retour").Value == '1',
                           disc_params_retour_url         : oRs("bes_disc_params_retour_url").Value,
                           disc_params_levopm_url         : oRs("bes_disc_params_levopm_url").Value,
                           disc_params_leverdagen         : oRs("bes_disc_params_leverdagen").Value || 0,
                           disc_params_punchouturl        : oRs("bes_disc_params_punchouturl").Value,
                           disc_params_punch_bedr_key     : oRs("bes_disc_params_punch_bedr_key").Value,
                           disc_params_logo_url           : oRs("bes_disc_params_logo_url").Value,
                           disc_params_autoacceptrfo      : oRs("bes_disc_params_autoacceptrfo").Value,
                           disc_params_auto_order         : oRs("bes_disc_params_auto_order").Value,
                           disc_params_min_bedrag         : oRs("bes_disc_params_min_bedrag").Value,
                           disc_params_bestellimiet       : oRs("bes_disc_params_bestellimiet").Value || 0,
                           disc_params_bestellimiet2      : oRs("bes_disc_params_bestellimiet2").Value || 0,
                           disc_params_bestellimiet3      : oRs("bes_disc_params_bestellimiet3").Value || 0,
                           disc_params_bestellimiet4      : oRs("bes_disc_params_bestellimiet4").Value || 0,
                           disc_params_bestellimiet5      : oRs("bes_disc_params_bestellimiet5").Value || 0,
                           disc_params_pgb                : oRs("bes_disc_params_pgb").Value,
                           disc_params_herfiat            : oRs("bes_disc_params_herfiat").Value || 0,
                           disc_params_herfiatpct         : oRs("bes_disc_params_herfiatpct").Value,
                           disc_params_herfiatmarge       : oRs("bes_disc_params_herfiatmarge").Value,
                           staffelgroepitems              : oRs("staffelgroepitems").Value,
                           maxartikel                     : oRs("bes_disc_params_maxartikel").Value? oRs("bes_disc_params_maxartikel").Value : -1,
                           kpautorisatie                  : oRs("bes_disc_params_kpautorisatie").Value == 1,
                           disc_params_for_others         : oRs("bes_disc_params_for_others").Value == 1,
                           isFreeArticle                  : oRs("bes_disc_params_freeartikel").Value == 1, // {0=ouderwets, 1=vrij artikelen, 2=met suggest voor bestaande (future)}
                           can_concept                    : oRs("bes_disc_params_herfiat").Value > 0 // 5.1.2 functionaliteit
                         }
            oRs.Close();
            if (autfunction)
                result.authparams = user.checkAutorisation(autfunction, true, disc_key);
            return result;
        },

        generateBesInfoBlock: function (bes_bestelling, show_leverancier, mode) //edit_leverancier)
        {
          if (bes_bestelling.bes_key == -1)
          {
            BLOCK_START("besInfo" , L("lcl_mld_new_bestelling"));
            RWTEXTAREATR("lev_opm", "fldtxt", L("lcl_bes_bestelling_lev_opm"), bes_bestelling.lev_opm, {html: "rows='3'"} );
          }
          else
          {
            BLOCK_START("besInfo" , L("lcl_bes_key") + "&nbsp;" + S("bes_bestelling_prefix") + bes_bestelling.bes_key + (bes_bestelling.parent_key? "*" : ""));
              if (bes_bestelling.satisfaction)
                  AFIELDTR("fld", L("lcl_res_beoordeling"), "", "", {rating: {score: bes_bestelling.satisfaction, note: bes_bestelling.satisfaction_op} });

              ROFIELDTR("fld", L("lcl_bes_discipline"), bes_disc_info.discipline_omschrijving);
              if (bes_bestelling.prs_bedrijf_key > 0 && show_leverancier)
              {
                    FCLTbedrijfselector("lev_key_ro", // supplier
                                       "sg_lev",
                                      { companyKey: bes_bestelling.prs_bedrijf_key,
                                        label: L("lcl_bes_Supplier"),
                                        filtercode: "",
                                        readonly: true,
                                        moreinfo: true
                                      });
              }

              // Zijn wij een incidentele bestelling via een melding?
              if (bes_bestelling.mld_key != null)
              {
                  var params = { infoPointer: { Url: "appl/mld/mld_melding.asp?urole=" + urole + "&mld_key=" + bes_bestelling.mld_key,
                                                Title: L("lcl_complain") + " " + bes_bestelling.mld_key
                                              }
                               }
                  ROFIELDTR("fld", L("lcl_bes_onbe_call"), bes_bestelling.mld_prefix+bes_bestelling.mld_key, params);
              }

              ROFIELDTR ("fld", L("lcl_date_time"), toDateTimeString(bes_bestelling.rfoDate));
              var params = { infoPointer: { Url: "appl/shared/status_info.asp?bes_key=" + bes_bestelling.bes_key + "&urole=" + urole,
                                Title: L("lcl_status_details") + " A-" + bes_bestelling.bes_key
                              }
                           };

              ROFIELDTR (bes_bestelling.rfoStatus==1 ? 'fld rejected' : 'fld', L("lcl_bes_RFO_status"), bes_bestelling.rfoStatusText, params);
              ROTEXTAREATR("fldremark", bes_bestelling.rfoStatus == 1? L("lcl_bes_reject_remark") : L("lcl_bes_remark"), bes_bestelling.rfoOpmerking, {id: "opmerk", html: "rows='8'", suppressEmpty: true});

              var fiat_key = bes_bestelling.bes_bestelling_fiat_user;
              if (bes_bestelling.rfoStatus == 2) // (nog) ter fiattering
              {
                // Binnenkort eens uitwerken: deze zijn gelijk (onderscheid zou al eerder gemaakt moeten zijn
                // door de fiat_key uit te sluiten van nieuwe fiatteurs). Komt met 5.1.0 nader
                fiat_key = bes_bestelling.fiatteur_key; // Die moet fiatteren
              }
              if (fiat_key)
              {
                    FCLTpersoonselector(
                        "Fiatteur",
                        "sgFiatteur",
                      { perslidKey: fiat_key,
                        label: (bes_bestelling.rfoStatus == 2?L("lcl_bes_toapprove"):L("lcl_bes_approver")),
                        readonly: true,
                        moreinfo: !frontend
                      });
              }

              var l_orders = [];
              var l_orders_key = [];
              sql_boi = "(SELECT bo.bes_bestelopdr_id, " +
                        "        bes_bestelopdr_status, " +
                        "        bes_bestelopdr_item_key, " +
                        "        bo.bes_bestelopdr_key " +
                        "   FROM BES_BESTELOPDR_ITEM boi, " +
                        "        BES_BESTELOPDR bo " +
                        "  WHERE bo.BES_BESTELOPDR_key = boi.BES_BESTELOPDR_key " +
                        "  GROUP BY bo.bes_bestelopdr_id, bes_bestelopdr_status, bes_bestelopdr_item_key, bo.bes_bestelopdr_key)";
              // Door welke bestelopdracht(en) wordt deze aanvraag afgehandeld?
              sql = "SELECT DISTINCT boi.bes_bestelopdr_id"
                  + "     , boi.bes_bestelopdr_status"
                  + "     , boi.bes_bestelopdr_key"
                  + "  FROM bes_bestelling_item bi"
                  + "     , " + sql_boi + " boi"
                  + " WHERE bi.bes_bestelopdr_item_key = boi.bes_bestelopdr_item_key"
                  + "   AND bi.bes_bestelling_key =" + bes_bestelling.bes_key
                  + " ORDER BY 1";
                  oRs = Oracle.Execute(sql);
              while(!oRs.eof)
              {
                var txt = S("bes_bestelopdr_prefix") + oRs("bes_bestelopdr_id").Value;
                if (oRs("bes_bestelopdr_status").Value == 1) // afgewezen
                    txt += " (" + bes.getbesopdrstatustext(oRs("bes_bestelopdr_status").Value) + ")";
                if (bes_bestelling.parent_key)
                    txt += "*"; // wij zijn een change dus de opdracht ook
                l_orders.push(txt);
                l_orders_key.push(oRs("bes_bestelopdr_key").Value);
                oRs.MoveNext();
              }
              oRs.Close();

              // Bestelling opdrachten. Dat kunnen er in de praktijd meerdere zijn.
              if (l_orders_key.length > 0)
              {
%>              <tr>
                  <td class="label"><label><%=L("lcl_bes_orders") + ":"%></label></td>
                  <td> <%
                    for (var i = 0; i < l_orders_key.length; i++)
                    {
                      var params = { infoPointer: { Url: "appl/bes/bes_opdr.asp?urole=" + urole + "&ordernr=" + l_orders_key[i] },
                                                    //xTitle: L("lcl_bes_bestelling") + " " + bes_bestelling.rfoRetourVan,
                                     suppressEmpty: true };
                      ROFIELD ("fld", null, l_orders[i],  params);
                      if (i < (l_orders_key.length - 1))
                      {
%>                      <br><%
                      }
                    }
%>                </td> <%
%>              </tr> <%
              }

              // Origineel weergeven indien aanwezig
              if (bes_bestelling.parent_key)
              {
                params = { infoPointer: { Url: "appl/bes/bes_bestelling.asp?urole=" + urole + "&bes_key=" + bes_bestelling.parent_key,
                           Title: L("lcl_bes_bestelling") + " " + S("bes_bestelling_prefix") + bes_bestelling.parent_key,
                           suppressEmpty: true }}
                ROFIELDTR ("fld", L("lcl_bes_origineel"), S("bes_bestelling_prefix") + bes_bestelling.parent_key,  params);
              }
              // Huidige wijziging weergeven indien aanwezig
              if (bes_bestelling.change_key)
              {
                params = { infoPointer: { Url: "appl/bes/bes_bestelling.asp?urole=" + urole + "&bes_key=" + bes_bestelling.change_key,
                           Title: L("lcl_bes_bestelling") + " " + S("bes_bestelling_prefix") + bes_bestelling.change_key,
                           suppressEmpty: true }}
                ROFIELDTR ("fld", L("lcl_bes_change"), S("bes_bestelling_prefix") + bes_bestelling.change_key +"*",  params);
              }

              // Waar worden we door geretourneerd?
              l_retours = [];
              l_retourk = [];
              sql = "SELECT bes_bestelling_key"
                  + "  FROM bes_bestelling"
                  + " WHERE bes_bestelling_retourvan_key = " + bes_bestelling.bes_key
                  + " ORDER BY bes_bestelling_key";
              oRs = Oracle.Execute(sql);
              while(!oRs.eof) {
                l_retours.push(S("bes_bestelling_prefix") + oRs("bes_bestelling_key").Value);
                l_retourk.push(oRs("bes_bestelling_key").Value);
                oRs.MoveNext();
              }
              oRs.Close();

              if (l_retours.length) {
                  var params = {};
                  if (l_retourk.length == 1)
                  {
                    params = { infoPointer: { Url: "appl/bes/bes_bestelling.asp?urole=" + urole + "&bes_key=" + l_retourk[0],
                                              Title: L("lcl_bes_bestelling") + " " + l_retours[0]
                                            }
                             }
                  }
                  ROFIELDTR ("fld rejected", L("lcl_bes_retour_nr"), l_retours.join(","), params);
              }

              // Waar zijn we een retour van?
              if (bes_bestelling.rfoRetourVan != null)
              {
                var params = { infoPointer: { Url: "appl/bes/bes_bestelling.asp?urole=" + urole + "&bes_key=" + bes_bestelling.rfoRetourVan,
                                              Title: L("lcl_bes_bestelling") + " " + bes_bestelling.rfoRetourVan
                                            }
                             }
                ROFIELDTR ("rejected", L("lcl_bes_retour_of"), S("bes_bestelling_prefix") + bes_bestelling.rfoRetourVan, params);
              }

              // MGE: l_orders_key is in de praktijk nu nog altijd 1 key
              if (l_orders_key.length >0) {
                  sql = "SELECT c.cnt_contract_key"
                      + "  FROM cnt_contract c"
                      + " WHERE c.bes_bestelopdr_key IN (" + l_orders_key.join(",") + ")";
                  oRs = Oracle.Execute(sql);
                  if (!oRs.eof)
                  {
                    var params = { infoPointer: { Url: "appl/cnt/cnt_contract.asp?urole=" + urole + "&cnt_key=" + oRs("cnt_contract_key").Value,
                                   Title: L("lcl_contract") + " " + S("bes_bestelling_prefix") + bes_bestelling.bes_key,
                                   suppressEmpty: true }}
                    ROFIELDTR ("fld", L("lcl_contract"), S("bes_bestelling_prefix") + bes_bestelling.bes_key,  params);
                  }
              }

              if (mode == "RW")
                RWTEXTAREATR("lev_opm", "fldtxt", L("lcl_bes_bestelling_lev_opm"), bes_bestelling.lev_opm, {html: "rows='3'"} );
              else
                ROTEXTAREATR("fldtxt", L("lcl_bes_bestelling_lev_opm"), bes_bestelling.lev_opm, {suppressEmpty: true} );
            }
            BLOCK_END();
        },

        bestelling_info: function _bestelling_info(bes_key)
        {
            var srtdeel_arr = [];
            var amount_arr = [];
            var sql = "SELECT bi.bes_srtdeel_key"
                    + "     , bi.bes_bestelling_item_aantal"
                    + "  FROM bes_bestelling_item bi"
                    + " WHERE bi.bes_bestelling_key = " + bes_key;
            var oRs = Oracle.Execute(sql);

            if (oRs.Eof)
                shared.record_not_found("BES: Record not found");

            while(!oRs.eof)
            {
              srtdeel_arr.push(oRs("bes_srtdeel_key").Value);
              amount_arr.push(oRs("bes_bestelling_item_aantal").Value);
              oRs.MoveNext();
            }
            oRs.Close();

            var staffel_info = bes.staffel_info(srtdeel_arr, amount_arr);

            // Kan ik zelf fiatteren?: true:  totaalbedrag <= can_selfapprove
            //                         false  totaalbedrag > can_selfapprove
            // deze mag/hoeft niet meer te fiatteren
            var exclude_fiatter =
                "COALESCE(b.bes_bestelling_fiat_user, " + (staffel_info.totaalbedrag <= S("can_selfapprove")? -1 : "b.prs_perslid_key") + ") ";

            // Get info of existing BES_BESTELLING
            var sql = "SELECT b.bes_bestelling_status"
                    + "     , b.bes_bestelling_datum"
                    + "     , b.prs_perslid_key"
                    + "     , b.prs_perslid_key_voor"
                    + "     , p.prs_afdeling_key"
                    + "     , b.prs_kostenplaats_key"
                    + "     , (SELECT " + S("prs_kpn_string")
                    + "          FROM prs_kostenplaats k"
                    + "         WHERE k.prs_kostenplaats_key = b.prs_kostenplaats_key) prs_kostenplaats_omschr"
                    + "     , b.bes_bestelling_plaats"
                    + "     , b.bes_bestelling_status"
                    + "     , b.bes_bestelling_ordernr"
                    + "     , m.mld_adres_naam"
                    + "     , m.mld_adres_key"
                    + "     , b.bes_bestelling_leverdatum"
                    + "     , b.bes_bestelling_retourvan_key"
                    + "     , prs.getkpverantwoordelijke (b.prs_kostenplaats_key, " + S("prs_approvemethod") + ", " + exclude_fiatter + ") fiatteur_key"
                    + "     , b.bes_bestelling_fiat_user"
                    + "     , b.bes_bestelling_korting"
                    + "     , b.bes_bestelling_levkosten"
                    + "     , b.mld_melding_key"
                    + "     , b.bes_bestelling_opmerking"
                    + "     , b.bes_bestelling_lev_opm"
                    + "     , b.fac_activiteit_key"
                    + "     , b.bes_bestelling_parentkey"
                    + "     , b.bes_bestelling_satisfaction"
                    + "     , b.bes_bestelling_satisfaction_op"
                    + "     , (SELECT b1.bes_bestelling_key"
                    + "          FROM bes_bestelling b1"
                    + "         WHERE b1.bes_bestelling_parentkey = b.bes_bestelling_key) change_key"
                    + "     , b.bes_bestelling_approved"
                    + "  FROM bes_bestelling b"
                    + "     , prs_perslid p"
                    + "     , mld_adres m"
                    + " WHERE b.bes_bestelling_key = " + bes_key
                    + "   AND p.prs_perslid_key = b.prs_perslid_key"
                    + "   AND m.mld_adres_key(+) = b.mld_adres_key_lev";

            var oRs = Oracle.Execute(sql);
            if (oRs.Eof)
                shared.record_not_found("BES: Record not found");

            var bes_bestelling =
            {
                bes_key             : bes_key,
                //rfoStatusText       : oRs("status").Value,
                rfoStatusText       : ((oRs("bes_bestelling_status").Value == 6 && (oRs("bes_bestelling_retourvan_key").Value && oRs("bes_bestelling_retourvan_key").Value > 0))
                                      ? L("lcl_bes_collected")
                                      : bes.getbesbestellingstatustext(oRs("bes_bestelling_status").Value)),
                rfoDate             : new Date(oRs("bes_bestelling_datum").Value),
                kostenplaats_key    : oRs("prs_kostenplaats_key").Value||-1,
                kostenplaats_omschr : oRs("prs_kostenplaats_omschr").Value||"",
                perslid_key         : oRs("prs_perslid_key").Value, // Persoon die de bestelling aanmaakt
                afdeling_key        : oRs("prs_afdeling_key").Value, // Afdeling van de persoon die de bestelling aanmaakt
                perslid_key_voor    : oRs("prs_perslid_key_voor").Value, // Aanvrager/invoerder/contactpersoon
                rfoStatus           : oRs("bes_bestelling_status").Value,
                orderNr             : oRs("bes_bestelling_ordernr").Value,
                afleverruimte       : oRs("bes_bestelling_plaats").Value,
                rfoDeliverydate     : new Date(oRs("bes_bestelling_leverdatum").Value),
                rfoRetourVan        : oRs("bes_bestelling_retourvan_key").Value,
                fiatteur_key        : oRs("fiatteur_key").Value, // degene die het moet doen
                bes_bestelling_fiat_user : oRs("bes_bestelling_fiat_user").Value, // degene die al geweest is
                rfoBesKosten        : oRs("bes_bestelling_korting").Value,
                rfoLevKosten        : oRs("bes_bestelling_levkosten").Value,
                rfoOpmerking        : oRs("bes_bestelling_opmerking").Value,
                lev_opm             : oRs("bes_bestelling_lev_opm").Value,
                mld_adres_naam      : oRs("mld_adres_naam").Value,
                mld_adres_key       : oRs("mld_adres_key").Value,
                fac_activiteit_key  : oRs("fac_activiteit_key").Value? oRs("fac_activiteit_key").Value : -1,
                mld_key             : oRs("mld_melding_key").Value,
                parent_key          : oRs("bes_bestelling_parentkey").Value,
                satisfaction        : oRs("bes_bestelling_satisfaction").Value,
                satisfaction_op     : oRs("bes_bestelling_satisfaction_op").Value,
                change_key          : oRs("change_key").Value,
                approved            : oRs("bes_bestelling_approved").Value? oRs("bes_bestelling_approved").Value : -1
            }
            oRs.close();

            // Nu de info die indirect uit de bestelaanvraag regels afgeleid moet worden
            // Merk op dat het datamodel bestellingen uit meerdere catalogi ondersteund maar
            // de interface niet. Daarom kan hieronder de MAX(bsg.ins_discipline_key) om één record te krijgen
            var sql = "SELECT MAX(bsg.ins_discipline_key) ins_discipline_key"
                    + "     , SUM(bi.bes_bestelling_item_aantal * bi.bes_bestelling_item_prijs) totaal"
                    + "     , SUM(bi.bes_bestelling_item_aantalontv) aantalontv"
                    + "     , MAX(bsg.bes_srtgroep_key) bes_srtgroep_key" // Wordt gebruikt tbv. singlegroep en dan is er maar eentje
                    + "     , MAX(bes_disc_params_singlegroep) singlegroep"
                    + "     , MAX ((SELECT ks.prs_kostensoort_btw"
                      + "             FROM prs_kostensoort ks"
                      + "            WHERE ks.prs_kostensoort_key = COALESCE(bsg.prs_kostensoort_key, bd.prs_kostensoort_key))) inclbtw"
                    + "     , MAX(COALESCE(bes_srtdeel_wijzigdagen, 9999)) bes_srtdeel_wijzigdagen"
                    + "     , MAX(COALESCE(bes_srtdeel_annuleerdagen, 9999)) bes_srtdeel_annuleerdagen"
                    + "     , MAX(bdp.bes_disc_params_contract) bes_disc_params_contract"
                    + "     , MIN(bsd.prs_bedrijf_key) prs_bedrijf_key"
                    + "     , COUNT(DISTINCT prs_bedrijf_key) aantal_bedrijf"
                    + "  FROM bes_bestelling_item bi"
                    + "     , bes_srtdeel bsd"
                    + "     , bes_srtgroep bsg"
                    + "     , bes_discipline bd"
                    + "     , bes_disc_params bdp"
                    + " WHERE bi.bes_srtdeel_key = bsd.bes_srtdeel_key"
                    + "   AND bsd.bes_srtgroep_key = bsg.bes_srtgroep_key"
                    + "   AND bsg.ins_discipline_key = bd.ins_discipline_key"
                    + "   AND bsg.ins_discipline_key = bdp.bes_ins_discipline_key"
                    + "   AND bes_bestelling_key = " + bes_bestelling.bes_key;
            oRs = Oracle.Execute(sql);

            if (oRs("ins_discipline_key").Value == null)
                shared.internal_error("BES: no item lines.");

            bes_bestelling.dis_key      = oRs("ins_discipline_key").Value,
            bes_bestelling.srtgroep     = oRs("bes_srtgroep_key").Value,
            bes_bestelling.singlegroep  = oRs("singlegroep").Value == 1,
            bes_bestelling.inclBTW      = oRs("inclBTW").Value || 0,
            bes_bestelling.totaal       = oRs("totaal").Value || 0;
            bes_bestelling.aantalontv   = oRs("aantalontv").Value || 0;
            if (oRs("aantal_bedrijf").Value == 1) // Anders te ingewikkeld
                bes_bestelling.prs_bedrijf_key   = oRs("prs_bedrijf_key").Value;
            bes_bestelling.isAbonnement = oRs("bes_disc_params_contract").Value == 1; // Bij abonnement bestellingen mag er maar 1 bestelregel zijn en is er dus 1 srtgroep.
            // Let op: Als bes_srtdeel_wijzigdagen niet gezet dan wordt bes_bestelling.wijzig_tot
            // ook niet gezet en hebben we oude <5.1.1 gedrag (meestal niet te wijzigen)
            if (oRs("bes_srtdeel_wijzigdagen").Value != 9999)
            {
                bes_bestelling.wijzig_tot = new Date(bes_bestelling.rfoDeliverydate);
                bes_bestelling.wijzig_tot.setDate(bes_bestelling.wijzig_tot.getDate() - oRs("bes_srtdeel_wijzigdagen").Value);
                __Log("Wijzigen tot " + bes_bestelling.wijzig_tot);
            }
            if (oRs("bes_srtdeel_annuleerdagen").Value != 9999)
            {
                bes_bestelling.annuleer_tot = new Date(bes_bestelling.rfoDeliverydate);
                bes_bestelling.annuleer_tot.setDate(bes_bestelling.annuleer_tot.getDate() - oRs("bes_srtdeel_annuleerdagen").Value);
                __Log("Annuleren tot " + bes_bestelling.annuleer_tot);
            }
            oRs.close();

            // Nu de info die indirect uit de bestelopdracht regels afgeleid moet worden
            var sql = "SELECT MAX(bo.bes_bestelopdr_status) bes_bestelopdr_status"
                    + "     , MAX (boi.bes_bestelopdr_item_key) isordered"
                    + "      FROM bes_bestelopdr bo"
                    + ",          bes_bestelopdr_item boi"
                    + ",          bes_bestelling_item bi"
                    + "     WHERE bo.bes_bestelopdr_key = boi.bes_bestelopdr_key"
                    + "       AND boi.bes_bestelopdr_item_key = bi.bes_bestelopdr_item_key"
                    + "       AND bi.bes_bestelling_key = " + bes_bestelling.bes_key;
            oRs = Oracle.Execute(sql);
            bes_bestelling.rfoBestelOpdrStatus = oRs("bes_bestelopdr_status").Value||0,
            bes_bestelling.isordered = oRs("isordered").Value||0,
            oRs.close();

            if (bes_bestelling.mld_key)
            {   // MLD.INC includen voor mld.mld_prefix() is te veel eer
                sql = "SELECT sd.ins_srtdiscipline_prefix mld_prefix"
                    + "  FROM mld_melding m"
                    + ",      mld_stdmelding sm"
                    + ",      mld_discipline d"
                    + ",      ins_srtdiscipline sd"
                    + " WHERE sd.ins_srtdiscipline_key = d.ins_srtdiscipline_key"
                    + "   AND d.ins_discipline_key = sm.mld_ins_discipline_key"
                    + "   AND sm.mld_stdmelding_key = m.mld_stdmelding_key"
                    + "   AND m.mld_melding_key = " + bes_bestelling.mld_key;
                  oRs = Oracle.Execute(sql);
                  bes_bestelling.mld_prefix = oRs("mld_prefix").Value||"";
                  oRs.close()
            }

            return bes_bestelling;
        },

        bestelopdracht_info: function (opdr_key)
        {
          var bes_key_str = [];
          // Welke bestelaanvragen worden door deze bestelopdracht afgehandeld?
          sql = "SELECT DISTINCT bes_bestelling_key"
              + "  FROM bes_bestelling_item bi"
              + "     , bes_bestelopdr_item boi"
              + " WHERE boi.bes_bestelopdr_item_key = bi.bes_bestelopdr_item_key"
              + "   AND boi.bes_bestelopdr_key = " + opdr_key;
          oRs = Oracle.Execute(sql);
          while (!oRs.eof)
          {
            bes_key_str.push(oRs("bes_bestelling_key").Value);
            oRs.MoveNext();
          }
          oRs.Close();

          // Get info of existing BES_BESTELOPDR
          sql = "SELECT bd.prs_bedrijf_key"
              + "     , bd.prs_bedrijf_naam"
              + "     , " + lcl.xsqla('d.ins_discipline_omschrijving', 'd.ins_discipline_key')
              + "     , " + lcl.xsqla('s.bes_srtdeel_omschrijving', 's.bes_srtdeel_key')
              + "     , " + lcl.xsqla('s.bes_srtdeel_eenheid', 's.bes_srtdeel_key')
              + "     , COALESCE(bes_bestelopdr_item_inkprijs, boi.bes_bestelopdr_item_prijs) item_prijs"
              + "     , boi.bes_bestelopdr_item_aantal"
              + "     , boi.bes_bestelopdr_item_aantalontv"
              + "     , COALESCE(bes_bestelopdr_item_inkprijs, boi.bes_bestelopdr_item_prijs) * boi.bes_bestelopdr_item_aantal prijs"
              + "     , boi.bes_bestelopdr_item_omschrijv"
              + "     , boi.bes_bestelopdr_item_key"
              + "     , COALESCE(b.mld_adres_key_lev,-1) mld_adres_key_lev"
              + "     , COALESCE(b.mld_adres_key_fac,-1) mld_adres_key_fac"
              + "     , b.bes_bestelopdr_id"
              + "     , b.bes_bestelopdr_opmerking"
              + "     , b.bes_bestelopdr_key"
              + "     , b.prs_perslid_key"
              + "     , (SELECT bst.bes_bestelling_retourvan_key "
              + "          FROM bes_bestelling bst "
              + "         WHERE bst.bes_bestelling_key = bi.bes_bestelling_key) bes_bestelling_retourvan_key"
              + "     , " + S("prs_pers_string") + " naam"
              + "     , p.prs_perslid_upper"
              + "     , b.bes_bestelopdr_delivery_opmerk"
              + "     , b.bes_bestelopdr_korting"
              + "     , b.bes_bestelopdr_levkosten"
              + "     , bes_bestelopdr_status"
              + "     , (SELECT ks.prs_kostensoort_btw"
              + "          FROM prs_kostensoort ks"
              + "         WHERE ks.prs_kostensoort_key = COALESCE(g.prs_kostensoort_key, d.prs_kostensoort_key)) inclbtw"
              + "     , s.bes_srtdeel_nr"
              + "     , d.ins_discipline_key"
              + "  FROM bes_v_aanwezigdiscipline d"
              + "     , bes_srtgroep g"
              + "     , bes_disc_params bdp"
              + "     , bes_srtdeel s"
              + "     , prs_bedrijf bd"
              + "     , bes_bestelopdr b"
              + "     , bes_bestelling_item bi"
              + "     , bes_bestelopdr_item boi"
              + "     , prs_perslid p"
              + " WHERE d.ins_discipline_key = g.ins_discipline_key"
              + "   AND d.ins_discipline_key = bdp.bes_ins_discipline_key"
              + "   AND g.bes_srtgroep_key = s.bes_srtgroep_key"
              + "   AND s.bes_srtdeel_key = bi.bes_srtdeel_key"
              + "   AND boi.bes_bestelopdr_key = b.bes_bestelopdr_key"
              + "   AND boi.bes_bestelopdr_item_key = bi.bes_bestelopdr_item_key"
              + "   AND b.prs_bedrijf_key = bd.prs_bedrijf_key"
              + "   AND b.prs_perslid_key = p.prs_perslid_key"
              + "   AND b.bes_bestelopdr_key = " + opdr_key
              + " ORDER BY 2, 3, 4";

          var oRs = Oracle.Execute(sql);
          if (oRs.Eof)
              shared.record_not_found("BES: Record not found");

          var bes_bestelopdr =
          {
            opdr_key              : opdr_key,
            bestelopdr_id         : oRs("bes_bestelopdr_id").Value,
            bes_key_str           : bes_key_str,
            prs_bedrijf_key       : oRs("prs_bedrijf_key").Value,
            prs_bedrijf_naam      : oRs("prs_bedrijf_naam").Value,
            mld_adres_key_lev     : oRs("mld_adres_key_lev").Value,
            mld_adres_key_fac     : oRs("mld_adres_key_fac").Value,
            opmerking             : oRs("bes_bestelopdr_opmerking").Value,
            delivery_opmerk       : oRs("bes_bestelopdr_delivery_opmerk").Value,
            inclBTW               : oRs("inclBTW").Value,
            status                : oRs("bes_bestelopdr_status").Value,
            statustxt             : bes.getbesopdrstatustext(oRs("bes_bestelopdr_status").Value),
            prs_perslid_naam      : oRs("naam").Value, // Aangemaakt door
            perslid_key           : oRs("prs_perslid_key").Value,
            dis_key               : oRs("ins_discipline_key").Value,
            korting               : parseFloat((oRs("bes_bestelopdr_korting").Value? oRs("bes_bestelopdr_korting").Value : 0).toFixed(2)),
            levkosten             : parseFloat((oRs("bes_bestelopdr_levkosten").Value? oRs("bes_bestelopdr_levkosten").Value : 0).toFixed(2))
          }
          if(oRs("bes_bestelopdr_status").Value == 6 && oRs("bes_bestelling_retourvan_key").Value > 0)
              bes_bestelopdr.statustxt = L("lcl_bes_collected");

          var totaal = 0;
          bes_bestelopdr.artikel_arr = new Array();
          while (!oRs.eof)
          { // Nu de artikelregels
            var catalogus_omschr = oRs("ins_discipline_omschrijving").Value;
            var omschr = oRs("bes_srtdeel_omschrijving").Value
                       + " (" + S("currency_pref") + safe.curr(oRs("item_prijs").Value)
                       + S("currency_suff") + "/" + (oRs("bes_srtdeel_eenheid").Value || "") + ")"
            var aantal = oRs("bes_bestelopdr_item_aantal").Value;
            var aantalontv = oRs("bes_bestelopdr_item_aantalontv").Value || 0;
            var prijs = parseFloat((oRs("prijs").Value? oRs("prijs").Value : 0).toFixed(2));
            var item_key = oRs("bes_bestelopdr_item_key").Value;
            var item_prijs = parseFloat((oRs("item_prijs").Value? oRs("item_prijs").Value : 0).toFixed(2));
            var artikelnr = oRs("bes_srtdeel_nr").Value;
            bes_bestelopdr.artikel_arr.push({ catalogus_omschr: catalogus_omschr,
                                              omschr:           omschr,
                                              aantal:           aantal,
                                              aantalontv:       aantalontv,
                                              prijs:            prijs,
                                              item_key:         item_key,
                                              item_prijs:       item_prijs,
                                              artikelnr:        artikelnr
                                            });
            totaal += prijs;
            oRs.MoveNext();
          }
          bes_bestelopdr.totaal = totaal;
          oRs.close();

          return bes_bestelopdr;
        },

        func_enabled_bestelling: // Wat mag ik zoal op deze specifieke bestelling?
            function _func_enabled_bestelling(bes_bestelling, params) // bes_bestelling is een bestelling_info hash
            {
              params = params || {};
              var isVerantwoordelijke = (bes_bestelling.fiatteur_key == user_key || user.isCollega(bes_bestelling.fiatteur_key));
              isVerantwoordelijke |= (bes_bestelling.bes_bestelling_fiat_user == user_key || user.isCollega(bes_bestelling.bes_bestelling_fiat_user));

              var bresult = user.func_enabled2("BES",
                                               { ins_discipline_key: bes_bestelling.dis_key,
                                                 alg_key: null,
                                                 prs_key: bes_bestelling.perslid_key,
                                                 checkOptimistic: false, // pessimist
                                                 isOptional: isVerantwoordelijke,  // isVerantwoordelijke dan optional
                                                 knownread: params.knownread
                                               }
                                              );
              bresult.isVerantwoordelijke = isVerantwoordelijke;

              bresult.canReadAny = bresult.canRead("WEB_BESBOF") ||
                                   bresult.canRead("WEB_BESBAC") ||
                                   bresult.canRead("WEB_BESFOF") ||
                                   bresult.canRead("WEB_BESUSE") ||
                                   isVerantwoordelijke;

              // (als alleen) Frontend-rechten-->we controleren nog strenger
              bresult.canReadFEOnly = false;
              if (    bresult.canReadAny
                  && !bresult.canRead("WEB_BESBOF")
                  && !bresult.canRead("WEB_BESBAC")
                  && !bresult.canRead("WEB_BESFOF")
                  && !isVerantwoordelijke
                  )
              {   // frontend controles
                  bresult.canReadFEOnly = true;
                  if (   bes_bestelling.perslid_key != user_key
                      && bes_bestelling.perslid_key_voor != user_key
                      && !user.isCollega(bes_bestelling.perslid_key))
                  {
                      bresult.canReadAny = false; // Legaal bijv. via google-zoekveldje
                  }
              }

              bresult.canReadFOF = bresult.canRead("WEB_BESFOF");
              bresult.canReadBOF = bresult.canRead("WEB_BESBOF");

              var eigenBestelling = bes_bestelling.perslid_key == user_key || user.isCollega(bes_bestelling.perslid_key);
              // Als ik nog voor voor_wijzig // voor_annuleer zit mag de fe vaak nog wel wijzigen/ annuleren
              var voor_annuleer = bes_bestelling.annuleer_tot && bes_bestelling.annuleer_tot > (new Date);
              var voor_wijzig = bes_bestelling.wijzig_tot && bes_bestelling.wijzig_tot > (new Date);

              // Op button niveau
              bresult.canChange   = false; // Wijzig knop tonen
              bresult.canAccept   = false; // BO Accepteren
              bresult.canReject   = false; // BO Afwijzen
              bresult.canSubmit   = false; // Echt bestellen (vaak automatisch), maakt opdracht aan
              bresult.canApprove  = false; // Fiatteren financieel
              bresult.canDelete   = false; // Algemeen verwijderen
              bresult.canFactuur  = false;  // Facturen bekijken
              // TODO: Hoe is retour functie-autorisatie afhankelijk? canWrite("WEB_BESUSE") || canWrite("WEB_BESFOF")?
              var bes_disc_info = bes.disc_info(bes_bestelling.dis_key); // alle discipline informatie
              var _canRetour = (bes_disc_info.disc_params_retour == 1 && bes_bestelling.rfoRetourVan == null) &&
                                (bresult.canWrite("WEB_BESUSE") || bresult.canWrite("WEB_BESFOF"));
              bresult.canRetourURL  = false;  // (Deels) retour via site leverancier
              bresult.canRetourBES  = false;  // (Deels) retour via negatieve levering

              var isPunchout = !bresult.isFreeArticle && bes_disc_info.disc_params_punchouturl;
              bresult.canMainChange = false; // 'Bovenste stuk', voormalig lower_part
              bresult.canItemsChange = false; // Mag ik toevoegen en aantallen verhogen

              bresult.isChange = bes_bestelling.parent_key > 0;
              bresult.hasChange = bes_bestelling.change_key > 0;
              if (!bresult.hasChange) // Als de bestelaanvraag een change heeft mag je er niets meer mee.
              {
                // Sinds 5.1.2 is canDelete duaal: 'vroeg' wordt de bestelaanvraag echt verwijderd
                //                                 'laat' wordt er een annuleringsopdrachtaanvraag naar de leverancier gestuurd
                // Verder: FO mag eigenlijk heel lang wijzigen als bes_bestelling.wijzig_tot maar is gezet:
                //         het is aan de leverancier om al dan niet te weigeren
                switch (bes_bestelling.rfoStatus) // (*aanvraag* status)
                {
                    case 1: // Afgewezen/verworpen. Je kunt hem effectie wijzigen en weer opnieuw aanbieden
                            bresult.canDelete     = bresult.canWrite("WEB_BESFOF") ||
                                                    bresult.canWrite("WEB_BESBOF");
                            bresult.canMainChange = eigenBestelling || bresult.canWrite("WEB_BESFOF") || bresult.canWrite("WEB_BESBOF");
                            bresult.canItemsChange = bresult.canMainChange && !isPunchout;
                            break;
                    case 2: // Nieuw, ter fiattering
                            bresult.canApprove     = (bes_bestelling.bes_bestelling_fiat_user != user_key) && isVerantwoordelijke;
                            bresult.canDelete      = bresult.canWrite("WEB_BESBOF") ||
                                                     (bresult.canWrite("WEB_BESFOF") && bes_bestelling.annuleer_tot) ||
                                                     (eigenBestelling && voor_annuleer);
                            bresult.canMainChange  = bresult.canApprove  || //  fiatteur mag ook aanpassen
                                                     bresult.canWrite("WEB_BESBOF") ||
                                                     (bresult.canWrite("WEB_BESFOF") && bes_bestelling.wijzig_tot) ||
                                                     (eigenBestelling && voor_wijzig);
                            bresult.canItemsChange = bresult.canMainChange && !isPunchout;
                            break;
                    case 3: // Gefiatteerd
                            var t_cost = bes_bestelling.totaal - bes_bestelling.rfoBesKosten + bes_bestelling.rfoLevKosten;
                            var bes_approved = bes_bestelling.approved;
                            var bestellimiet = bes_disc_info.disc_params_bestellimiet;
                            var bestellimiet2 = bes_disc_info.disc_params_bestellimiet2;
                            var bestellimiet3 = bes_disc_info.disc_params_bestellimiet3;
                            var bestellimiet4 = bes_disc_info.disc_params_bestellimiet4;
                            var bestellimiet5 = bes_disc_info.disc_params_bestellimiet5;
                            bresult.canAccept      = bresult.canWrite("WEB_BESBOF") &&                                  // Heb ik de rechten om goed te keuren op dit niveau 1?
                                                     ((S("bes_approval_all") == 0 && t_cost >= bestellimiet) ||         // Zijn de kosten hoger als de limiet
                                                      (S("bes_approval_all") == 1 && t_cost <= bestellimiet2)) &&       // Zijn de kosten onder mijn limiet om volledig goed te keuren
                                                     bes_approved <= bestellimiet;                                      // Welke goedkeur? 1, 2, 3, 4 of 5?
                            bresult.canAccept2     = bresult.canWrite("WEB_BESGO2") &&
                                                     // Setting bes_approval_all is
                                                     // 0: Het approved bedrag is eigen bestellimiet of vorige goedkeur niveau rechten heb ik al (dan direct niveau hoger)
                                                     // 1: Het approved bedrag is kleiner of gelijk aan eigen bestellimiet
                                                     ((S("bes_approval_all") == 0 && t_cost >= bestellimiet2 && (bes_approved == bestellimiet2 || bresult.canAccept)) ||
                                                      (S("bes_approval_all") == 1 && t_cost <= bestellimiet3 && bes_approved <= bestellimiet2));
                            bresult.canAccept3     = bresult.canWrite("WEB_BESGO3") &&
                                                     ((S("bes_approval_all") == 0 && t_cost >= bestellimiet3 && (bes_approved == bestellimiet3 || bresult.canAccept2)) ||
                                                      (S("bes_approval_all") == 1 && t_cost <= bestellimiet4 && bes_approved <= bestellimiet3));
                            bresult.canAccept4     = bresult.canWrite("WEB_BESGO4") &&
                                                     ((S("bes_approval_all") == 0 && t_cost >= bestellimiet4 && (bes_approved == bestellimiet4 || bresult.canAccept3)) ||
                                                      (S("bes_approval_all") == 1 && t_cost <= bestellimiet5 && bes_approved <= bestellimiet4));
                            bresult.canAccept5     = bresult.canWrite("WEB_BESGO5") &&
                                                     ((S("bes_approval_all") == 0 && t_cost >= bestellimiet5 && (bes_approved >= bestellimiet5 || bresult.canAccept4)) ||
                                                      (S("bes_approval_all") == 1 && t_cost > bestellimiet5 && bes_approved <= bestellimiet5)) &&
                                                     t_cost > bes_approved;
                            bresult.canDelete      =     bresult.canWrite("WEB_BESBOF")
                                                     || (bresult.canWrite("WEB_BESFOF") && bes_bestelling.annuleer_tot)
                                                     || (eigenBestelling && voor_annuleer);
                            bresult.canReject      = bresult.canAccept ||
                                                     bresult.canAccept2 ||
                                                     bresult.canAccept3 ||
                                                     bresult.canAccept4 ||
                                                     bresult.canAccept5;
                            bresult.canMainChange  = (bresult.canWrite("WEB_BESBOF") ||
                                                      (bresult.canWrite("WEB_BESFOF") && bes_bestelling.wijzig_tot) ||
                                                      (eigenBestelling && voor_wijzig))
                                                     && !bresult.isChange; // Change bestelaanvraag kan alleen gewijzigd worden als status = 2
                            bresult.canItemsChange = bresult.canMainChange && !isPunchout;
                            break;
                    case 4: // Geaccepteerd door BO
                            bresult.canDelete      = bresult.canWrite("WEB_BESBOF") ||
                                                     (bresult.canWrite("WEB_BESFOF") && bes_bestelling.annuleer_tot) ||
                                                     (eigenBestelling && voor_annuleer);
                            bresult.canSubmit      = bresult.canWrite("WEB_BESBOF") && !bes_bestelling.isordered;
                            bresult.canRetourURL   = _canRetour && (bes_disc_info.disc_params_retour_url != null);
                            bresult.canMainChange  = (bresult.canWrite("WEB_BESBOF") ||
                                                      (bresult.canWrite("WEB_BESFOF") && bes_bestelling.wijzig_tot) ||
                                                      (eigenBestelling && voor_wijzig)) &&
                                                     !bresult.isChange; // Change bestelaanvraag kan alleen gewijzigd worden als status = 2
                            bresult.canItemsChange = bresult.canMainChange && !isPunchout;
                            break;
                    case 5: // Besteld (lees: opdracht is aangemaakt/ligt bij leverancier)
                            if (bes_bestelling.aantalontv == 0)// Als er artikelen ontvangen zijn houdt het op
                            {
                                bresult.canDelete      = bresult.canWrite("WEB_BESBOF") ||
                                                         (bresult.canWrite("WEB_BESFOF") && bes_bestelling.annuleer_tot) ||
                                                         (eigenBestelling && voor_annuleer);
                                bresult.canDelete &= bes_disc_info.can_concept;
                            }
                            bresult.canRetourURL   = _canRetour && (bes_disc_info.disc_params_retour_url != null);
                            // Als iemand wijzigt zal het een change-opdracht worden!
                            bresult.canMainChange  = (bresult.canWrite("WEB_BESBOF") ||
                                                      (bresult.canWrite("WEB_BESFOF") && bes_bestelling.annuleer_tot) ||
                                                      (eigenBestelling && voor_wijzig)) &&
                                                     !bresult.isChange && // Change bestelaanvraag kan niet meer gewijzigd worden
                                                     bes_disc_info.can_concept;

                            bresult.canItemsChange = bresult.canMainChange && !isPunchout;
                            break;
                    case 6: // Geleverd (TV)
                            bresult.canMainChange  = bresult.canWrite("WEB_BESFOF")||user.checkAutorisation("WEB_ORDFIN", true); // Bijvoorbeeld kostenplaats te wijzigen
                            bresult.canRetourURL   = _canRetour && (bes_disc_info.disc_params_retour_url != null);
                            bresult.canRetourBES   = _canRetour && !bresult.canRetourURL;
                            break;
                    case 7: // Verwerkt (AV)
                            break;
                    case 8: // Geannuleerd, sinds 5.1.2 (was: mixed?)
                            break;
                }
                bresult.canChange = bresult.canItemsChange || bresult.canMainChange; // Dan komt de knop
              }

              return bresult;
            },

        func_enabled_bestelopdracht: // Wat mag ik zoal op deze specifieke bestel opdracht?
            function _func_enabled_bestelopdracht(opdr_key) // bes_bestelopdr is een bestelopdr_info hash
            {
              var sql = "SELECT DISTINCT bo.prs_perslid_key"
                      + "     , g.ins_discipline_key"
                      + "     , bo.bes_bestelopdr_status"
                      + "     , ma.alg_locatie_key"
                      + "  FROM bes_bestelopdr bo"
                      + "     , bes_bestelopdr_item boi"
                      + "     , bes_bestelling_item bi"
                      + "     , bes_srtdeel s"
                      + "     , bes_srtgroep g"
                      + "     , mld_adres ma"
                      + " WHERE bo.bes_bestelopdr_key = boi.bes_bestelopdr_key"
                      + "   AND boi.bes_bestelopdr_item_key = bi.bes_bestelopdr_item_key"
                      + "   AND bi.bes_srtdeel_key = s.bes_srtdeel_key"
                      + "   AND s.bes_srtgroep_key = g.bes_srtgroep_key"
                      + "   AND bo.mld_adres_key_lev = ma.mld_adres_key"
                      + "   AND bo.bes_bestelopdr_key = " + opdr_key;
              var oRs = Oracle.Execute(sql);
              var perslid_key = oRs("prs_perslid_key").Value; // De aanmaker van de bestelopdracht.
              var dis_key = oRs("ins_discipline_key").Value;
              var alg_locatie_key = oRs("alg_locatie_key").Value;
              var bestelopdr_status = oRs("bes_bestelopdr_status").Value;
              oRs.Close();

              var bresult = user.func_enabled2("BES",
                                               { ins_discipline_key: dis_key,
                                                 loc_key: alg_locatie_key,
                                                 prs_key: perslid_key,
                                                 checkOptimistic: false, // pessimist
                                                 isOptional: false
                                               }
                                              );


              bresult.canReadAny = bresult.canRead("WEB_BESBOF") || bresult.canRead("WEB_BESBOR") || bresult.canRead("WEB_BESBAC"); // Bestel opdracht alleen zichtbaar voor backoffice
              bresult.canReadBOF = bresult.canRead("WEB_BESBOF");
              bresult.canReadBOR = bresult.canRead("WEB_BESBOR");

              // Op button niveau
              bresult.canChange  = false; // Wijzigen
              bresult.canAccept  = false; // Accepteren
              bresult.canReject  = false; // Afwijzen
              bresult.canSend    = false; // Markeer als verzonden
              bresult.canDeliver = false; // Levering

              switch (bestelopdr_status) // Opdracht status
              {
                case 1: // Afgewezen.
                        bresult.canChange  = bresult.canWrite("WEB_BESBOF");
                        break;
                case 2: // Nieuw, niet gebruikt
                        break;
                case 3: // In Behandeling.
                        bresult.canChange  = bresult.canWrite("WEB_BESBOF");
                        bresult.canSend    = bresult.canWrite("WEB_BESBOF");
                        break;
                case 4: // In Bestelling (Bevestigd)
                        bresult.canChange  = bresult.canWrite("WEB_BESBOF");
                        bresult.canDeliver = bresult.canWrite("WEB_BESBOR"); // Afvinken goederenontvangst met WEB_BESBOR rechten
                        break;
                case 5: // Ter Bevestiging (Verzonden)
                        bresult.canAccept  = bresult.canWrite("WEB_BESBOF");
                        bresult.canReject  = bresult.canWrite("WEB_BESBOF");
                        break;
                case 6: // Geleverd
                        break;
                case 7: // Verwerkt
                        break;
                case 8: // Geannuleerd
                        break;
              }

              return bresult;
            },

        staffel_info: function _staffel_info(srtdeel_keys, itemaantal_arr)
        {
            var lsgnaamstring = [];
            var lsgkeystring = [];
            var lsgkortingstring = [];
            var lsgaantalstring = [];
            var lsgeenheidstring = [];
            var litemprijsstring = [];
            var first = true;
            var prs_bedrijf_key;
            var liakorting = 0;
            var subbedrag = 0;
            var subkorting = 0;
            var subtotaal = 0;
            var totaalbedrag = 0;
            var opdrachtkorting;
            var opdrachtkortingbedrag;
            var grenswaardetot;
            var grenswaardevanaf;
            var bes_kosten;
            var bes_limiet;

            function StaffelGroep(naam, aantal, eenheid, korting, groep, bestelbedrag)
            {
              this.naam = naam;
              this.aantal = aantal;
              this.eenheid = eenheid;
              this.korting = korting;
              this.groep = groep;
              this.bestelbedrag = bestelbedrag;
            }

            var ItemArray = new Array();
            var staffelGroepArray = new Array();

            // Je hebt eerst totaal aantallen per staffelgroep nodig om korting van een (groeps) artikel te kunnen berekenen.
            for (var i = 0; i < srtdeel_keys.length; i++)
            {
              sql = "SELECT sd.bes_staffeltabel_key staffelgroep"
                  + ",      bst.bes_staffeltabel_naam staffelgroepnaam"
                  + ",      COALESCE(bes.getsrtdeelprijs(sd.bes_srtdeel_key, NULL) , 0) prijs"
                  + ",      bst.bes_staffeltabel_groep groep"
                  + "," + lcl.xsql('sd.bes_srtdeel_eenheid','sd.bes_srtdeel_key') +" eenheid"
                  + ",      sd.prs_bedrijf_key"
                  + "  FROM bes_srtdeel sd"
                  + ",      bes_staffeltabel bst"
                  + " WHERE sd.bes_staffeltabel_key = bst.bes_staffeltabel_key(+)"
                  + "   AND sd.bes_srtdeel_key = " + srtdeel_keys[i];
              var oRs = Oracle.Execute(sql);
              if (!oRs.eof)
              {
                // Oplaan bedrijf waar alle artikelen worden besteld. Moet voor elke artikel hetzelfde zijn.
                prs_bedrijf_key = oRs("prs_bedrijf_key").Value;
                if (!prs_bedrijf_key)
                    __DoLog("Artikel wordt niet door een bedrijf geleverd.", "#FFFF00")

                // Opslaan van staffelgroep van een item
                ItemArray.push({ item_key    : srtdeel_keys[i],
                                 aantal      : itemaantal_arr[i],
                                 prijs       : oRs("prijs").Value,
                                 eenheid     : oRs("eenheid").Value,
                                 staffelgroep: oRs("staffelgroep").Value
                                });
                // Opslaan van totaalaantallen van een staffelgroep
                if (oRs("staffelgroep").Value)
                {
                  if (staffelGroepArray[oRs("staffelgroep").Value])
                  {
                    staffelGroepArray[oRs("staffelgroep").Value].aantal += itemaantal_arr[i];
                    staffelGroepArray[oRs("staffelgroep").Value].bestelbedrag += (oRs("prijs").Value *  itemaantal_arr[i]);
                  }
                  else
                  {
                    staffelGroepArray[oRs("staffelgroep").Value] =
                            new StaffelGroep(oRs("staffelgroepnaam").Value,
                                              itemaantal_arr[i],
                                              oRs("eenheid").Value,
                                              0,
                                              oRs("groep").Value,
                                              (oRs("prijs").Value *  itemaantal_arr[i], 10))
                  }
                }
              }
              oRs.Close();
            }

            // Nu kunnen we totale kortingen per staffelgroep uitrekenen
            // Daarnaast itemprijsstring opbouwen. Nodig bij het opslaan van de juiste betaalde prijs van een artikel (bes_edit_bestelling_save)
            for (var j in ItemArray)
            {
              if (ItemArray[j] != null && ItemArray[j].item_key && ItemArray[j].staffelgroep != null) // Item moet staffelgroep hebben
              {
                sql = "SELECT BES.calcartikelkortingsprijs(" + ItemArray[j].item_key + ", " + (staffelGroepArray[ItemArray[j].staffelgroep].groep == 1? staffelGroepArray[ItemArray[j].staffelgroep].aantal : ItemArray[j].aantal) + ") kortingsprijs"
                    + " FROM DUAL";
                var oRs = Oracle.Execute(sql);

                if (!oRs.eof)
                {
                  staffelGroepArray[ItemArray[j].staffelgroep].korting += ItemArray[j].aantal * (ItemArray[j].prijs - parseFloat(oRs("kortingsprijs").Value, 10));
                  litemprijsstring.push(oRs("kortingsprijs").Value);
                  first = false;
                }
                oRs.Close();
              }
              else // geen staffelkortingen voor dit artikel. Wel in de itemprijsstring opnemen
              {
                litemprijsstring.push(ItemArray[j].prijs);
                first = false;
              }
              subbedrag += ItemArray[j].aantal * ItemArray[j].prijs;
            }

            // Groepeer staffelgegevens in een string die verzonden kan worden
            first = true;
            for (var sg in staffelGroepArray)
            {
              if (staffelGroepArray[sg] != null && staffelGroepArray[sg].aantal)
              {
                if (staffelGroepArray[sg].groep == 0)
                { // Individuele artikelkorting
                  liakorting +=  parseFloat(staffelGroepArray[sg].korting);
                  subkorting += staffelGroepArray[sg].korting;
                }
                else
                { // Groepskorting
                  lsgnaamstring.push(staffelGroepArray[sg].naam);
                  lsgkeystring.push(sg);
                  lsgkortingstring.push(staffelGroepArray[sg].korting);
                  lsgaantalstring.push(staffelGroepArray[sg].aantal);
                  lsgeenheidstring.push(staffelGroepArray[sg].eenheid);
                  subkorting += staffelGroepArray[sg].korting;
                  first = false;
                }
              }
            }

            // Bereken subtotaal: Bestelbedrag - artikel en groepskoringen
            subtotaal = subbedrag - subkorting;

            // Opdrachtkorting, opdrachtkortingbedrag en onderlimiet bepalen
            sql = "SELECT BES.calcopdrachtkortingbedrag(" + prs_bedrijf_key + ", " + subtotaal + ") opdrachtkortingbedrag"
                + " FROM DUAL"
            var oRs = Oracle.Execute(sql);
            opdrachtkortingbedrag = oRs("opdrachtkortingbedrag").Value;
            oRs.Close();

            sql = "SELECT BES.calcopdrachtkorting(" + prs_bedrijf_key + ", " + subtotaal + ") opdrachtkorting FROM DUAL";
            oRs = Oracle.Execute(sql);
            // Korting tot grenswaarde
            opdrachtkorting = oRs("opdrachtkorting").Value;
            oRs.Close();

            // Nieuw subtotaal: Bestelbedrag - alle kortingen
            subtotaal = subtotaal - opdrachtkortingbedrag;

            sql = "SELECT prs_staffel_grenswaarde grenswaarde"
                + " FROM prs_staffel s"
                + " WHERE prs_staffel_korting = " + opdrachtkorting
                + " AND prs_bedrijf_key = " + prs_bedrijf_key;
            oRs = Oracle.Execute(sql);
            if (!oRs.eof)
            {
              // Korting tot grenswaarde
              grenswaardetot = oRs("grenswaarde").Value;
            }
            oRs.Close();

            // Nu grenswaarde bepalen vanaf
            sql = "SELECT COALESCE(MAX(prs_staffel_grenswaarde), 0) grenswaarde"
                + " FROM prs_staffel s"
                + (grenswaardetot
                  ? " WHERE prs_staffel_grenswaarde < " + grenswaardetot
                  : " WHERE prs_staffel_grenswaarde IS NOT NULL")
                + " AND prs_bedrijf_key = " + prs_bedrijf_key;
            oRs = Oracle.Execute(sql);
            if (!oRs.eof)
            {
              // Korting vanaf grenswaarde
              grenswaardevanaf = oRs("grenswaarde").Value;
            }
            oRs.Close();

            // Extra (transport) kosten en onderlimiet bepalen
            sql = "SELECT CASE"
                + " WHEN (prs_bedrijf_bes_limiet - " + subtotaal + ") <= 0" // Subtotaal: Bestelbedrag - alle kortingen
                + " THEN 0"
                + " ELSE COALESCE(prs_bedrijf_bes_kosten, 0)"
                + " END bes_kosten"
                + ", COALESCE(prs_bedrijf_bes_limiet, 0) bes_limiet"
                + " FROM prs_bedrijf"
                + " WHERE prs_bedrijf_key = " + prs_bedrijf_key;
            oRs = Oracle.Execute(sql);
            if (!oRs.eof)
            {
              // Extra (transport) kosten
              bes_kosten = oRs("bes_kosten").Value;
              bes_limiet = oRs("bes_limiet").Value;
            }
            oRs.Close();

            // Totaalbedrag
            totaalbedrag = subtotaal + bes_kosten;

             var result = { sgnaamstring         : lsgnaamstring,
                            sgkeystring          : lsgkeystring,
                            sgkortingstring      : lsgkortingstring,
                            sgaantalstring       : lsgaantalstring,
                            sgeenheidstring      : lsgeenheidstring,
                            itemprijsstring      : litemprijsstring,
                            opdrachtkorting      : opdrachtkorting,
                            opdrachtkortingbedrag: opdrachtkortingbedrag,
                            grenswaardevanaf     : grenswaardevanaf,
                            grenswaardetot       : grenswaardetot,
                            bes_kosten           : bes_kosten,
                            bes_limiet           : bes_limiet,
                            prs_bedrijf_key      : prs_bedrijf_key,
                            iakorting            : liakorting,
                            totaalbedrag         : totaalbedrag
                         };

            return result;
        },

      // Geeft het PGB overschrijdingsbedrag van de PGB-limiet terug
      get_pgb_exceed_amount: function(bestelbedrag, prs_key, dis_key, bes_key)
      {
        var amount = bestelbedrag; // Indien geen pgblimiet dan gehele bestel bedrag

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

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

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

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

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

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

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

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

      // Moet bij wijzigen van de bestelaanvraag, de bestelaanvraag hergefiatterd worden door de budgethouder of backoffice?
      herfiatteren: function(bes_bestelling, bes_disc_info, nieuwtotaal)
      { // Bepalen wanneer gefiatteerd moet worden:
        // Mutaties als al besteld?: 0=Niet toestaan
        //                           1=Toestaan, herfiatteren zie criteria
        //                           2=Toestaan, herfiatteren als nieuwe (altijd)
        //                           3=Toestaan, herfiatteren niet nodig (nooit)
        if (bes_disc_info.disc_params_herfiat == 0)
          // 5.1.1 gedrag: Altijd als nieuw.
          // Als er nog niets besteld (status 2, 3, 4) is dan altijd herfiatteren, als er al besteld is kan er niet eens gewijzigd worden (geen potloodje).
          return true;
        if (bes_disc_info.disc_params_herfiat == 2)
          return true;
        if (bes_disc_info.disc_params_herfiat == 3)
          return false
        // Alleen als bedrag verhoogd
        if (bes_disc_info.disc_params_herfiatpct > 0) // Herfiattering noodzakelijk indien >%
          return ((nieuwtotaal - bes_bestelling.totaal) / bes_bestelling.totaal)*100 > bes_disc_info.disc_params_herfiatpct;
        else if (bes_disc_info.disc_params_herfiatmarge > 0) // Herfiattering noodzakelijk indien >€
          return (nieuwtotaal - bes_bestelling.totaal) > bes_disc_info.disc_params_herfiatmarge;
        else
          return true;
      },

      // Levert de 'Is ter fiattering aangeboden bij approver' op.
      sendNeedApprovalNotification: function(bes_key, approver)
      {
        if (approver == null)
            return false;

        // These notifications are now sent on behalf of the system, what might be the local FM organisation
        var sql = "SELECT l.alg_locatie_email"  // null as a string
                + " FROM mld_adres ma, alg_locatie l, bes_bestelling b"
                + " WHERE b.mld_adres_key_lev = ma.mld_adres_key"
                + " AND ma.alg_locatie_key = l.alg_locatie_key"
                + " AND b.bes_bestelling_key = " + bes_key;
        var oRs = Oracle.Execute(sql);
        if (!oRs.eof) {
            var lsender = oRs(0).Value;
        } else {
            var lsender = null;
        }
        // notify approver and requestor by message & mail as configured in fac_srtnotificatie with BESAPx
        shared.trackaction("BESAP2", bes_key);

        Oracle.Execute("BEGIN fac.putnotificationsrtprio(NULL, " + approver + ", 'BESAP1', " + bes_key + ", NULL, NULL, NULL, NULL, NULL, 2, " + (lsender ? safe.quoted_sql(lsender) : "NULL") + "); END;");

        sql = "SELECT prs_perslid_naam_full FROM prs_v_perslid_fullnames WHERE prs_perslid_key = " + approver;
        oRs = Oracle.Execute(sql);
        if (!oRs.eof)
          return L("lcl_bes_RFO_regApprov") + oRs("prs_perslid_naam_full").Value;
        else
          return L("lcl_bes_RFO_regApprov");
      },

      makeOrders: function (puserkey, pbestelling_key)
      {
        var sql = "BEGIN bes.makeorders("+ puserkey + ", " + pbestelling_key + "); END;";
        Oracle.Execute(sql);
        // Note: BES.MAKEORDERS notificeert zelf de leveranciers.
      },

      changeOrders: function (puserkey, pbestelling_key)
      {
        var sql = "BEGIN bes.changeorders("+ puserkey + ", " + pbestelling_key + "); END;";
        Oracle.Execute(sql);
      },

      bestelopdracht: function (bes_bestelling)
      {
        var l_orders_txt = [];
        var l_orders_key = [];
        sql_boi = "(SELECT bo.bes_bestelopdr_id, " +
                  "        bes_bestelopdr_status, " +
                  "        bes_bestelopdr_item_key, " +
                  "        bo.bes_bestelopdr_key " +
                  "   FROM BES_BESTELOPDR_ITEM boi, " +
                  "        BES_BESTELOPDR bo " +
                  "  WHERE bo.BES_BESTELOPDR_key = boi.BES_BESTELOPDR_key " +
                  "  GROUP BY bo.bes_bestelopdr_id, bes_bestelopdr_status, bes_bestelopdr_item_key, bo.bes_bestelopdr_key)";
        // Door welke bestelopdracht(en) wordt deze aanvraag afgehandeld?
        sql = "SELECT DISTINCT boi.bes_bestelopdr_id"
            + "     , boi.bes_bestelopdr_status"
            + "     , boi.bes_bestelopdr_key"
            + "  FROM bes_bestelling_item bi"
            + "     , " + sql_boi + " boi"
            + " WHERE bi.bes_bestelopdr_item_key = boi.bes_bestelopdr_item_key"
            + "   AND bi.bes_bestelling_key =" + bes_bestelling.bes_key
            + " ORDER BY 1";
            oRs = Oracle.Execute(sql);
        while(!oRs.eof)
        {
          var txt = S("bes_bestelopdr_prefix") + oRs("bes_bestelopdr_id").Value;
          if (oRs("bes_bestelopdr_status").Value == 1) // afgewezen
              txt += " (" + bes.getbesopdrstatustext(oRs("bes_bestelopdr_status").Value) + ")";
          if (bes_bestelling.parent_key)
              txt += "*"; // wij zijn een change dus de opdracht ook
          l_orders_txt.push(txt);
          l_orders_key.push(oRs("bes_bestelopdr_key").Value);
          oRs.MoveNext();
        }
        oRs.Close();
        result = { key : l_orders_key
                 , txt : l_orders_txt
                 };
        return result;
      },

      verwijderBestelling: function (bes_key, bestelopdr_key)
      {
        var message;
        var sql = "DELETE bes_bestelling WHERE bes_bestelling_key = " + bes_key;
        var err = Oracle.Execute(sql, true);
        if (err.friendlyMsg)
          message = err.friendlyMsg;

        // check of bestelaanvraag is verwijderd
        if (message == "")
        { // DELETE is niet echt trackbaar
          success = true;
          // bestelaanvraag is verwijderd. Verwijder nu ook de rest
          // JGL: Is dat niet allemaal automatisch meegecascadeerd?
          // Verwijder bestelaanvraag items
          sql = "DELETE bes_bestelling_item WHERE bes_bestelling_key = " + bes_key;
          Oracle.Execute(sql);

          // Indien een bestelopdracht aanwezig is dan bestelopdracht + bestelopdracht items verwijderen.
          if (bestelopdr_key > 0)
          {
            // Verwijder bestelopdracht items
            sql = "DELETE bes_bestelopdr_item WHERE bes_bestelopdr_key = " + bestelopdr_key;
            Oracle.Execute(sql);

            // Verwijder bestelopdracht
            sql = "DELETE bes_bestelopdr WHERE bes_bestelopdr_key = " + bestelopdr_key
            Oracle.Execute(sql);
          }
          message = L("lcl_bes_deleted_1") + S("bes_bestelling_prefix") + bes_key + L("lcl_bes_deleted_2");
        }
        return message;
      },
      // returns bes_srtdeel_key
      upsert_deel: function _upsert_deel(dis_key, params)
      {
          if (!("srtdeel_btw" in params))
            params.srtdeel_btw = 21.0;
          if (!("srtgroep_omschrijving" in params) && params.srtgroep_key > 0)
          { // upsert_srtdeel werkt alleen op basis van omschrijving, helaas (nog) niet op srtgroep_key
            var sql = "SELECT bes_srtgroep_omschrijving"
                    + "  FROM bes_srtgroep"
                    + " WHERE bes_srtgroep_key = " + params.srtgroep_key;
            var oRs = Oracle.Execute(sql);
            params.srtgroep_omschrijving = oRs("bes_srtgroep_omschrijving").Value;;
            oRs.Close()
          }
          var sql = "BEGIN bes.upsert_srtdeel "
                  + "     ( " + dis_key
                  + "     , " + safe.quoted_sql(params.srtgroep_omschrijving, 60)        // bes_srtgroep_omschrijving
                  + "     , " + safe.quoted_sql(params.srtdeel_omschrijving, 100)        // bes_srtdeel_omschrijving
                  + "     , " + params.srtdeel_prijs
                  + "     , " + params.srtdeel_btw
                  + "     , " + safe.quoted_sql(params.srtdeel_eenheid, 30)       // bes_srtdeel_eenheid
                  + "     , " + safe.quoted_sql(params.srtdeel_nr, 32) // bes_srtdeel_nr
                  + "     , " + (params.bedrijf_key || -1)
                  + "     , NULL "                                       // vervaldatum
                  + "     , ''"
                  + "     , 1 "
                  + "     , " + safe.quoted_sql(params.opmerking, 2000) + "); END;";

          Oracle.Execute(sql);
          // JGL: Het zou fijn zijn als upsert_srtdeel een functie wordt en gewoon
          //       de bes_srtdeel_key oplevert. Dan wordt het volgende veel simpeler:
          // PF: Maar dat kan helemaal niet, want een select mag geen DML e.d doen.
          // Wel beter zou zijn bes.get_upsertkey(), nader te definieren.

          // Zoek aangemaakte item terug.
          sql = "SELECT bes_srtdeel_key "
              + "  FROM bes_srtdeel sd, bes_srtgroep sg "
              + " WHERE sg.ins_discipline_key = " + dis_key
              + "   AND sg.bes_srtgroep_key = sd.bes_srtgroep_key "
              + "   AND sg.bes_srtgroep_omschrijving = " + safe.quoted_sql(params.srtgroep_omschrijving, 60) /* NOXLAT */
              + "   AND UPPER(sd.bes_srtdeel_omschrijving) = " + safe.quoted_sql_upper(params.srtdeel_omschrijving, 100)  /* NOXLAT */
              + "   AND sd.bes_srtdeel_eenheid " + (params.srtdeel_eenheid? "= " + safe.quoted_sql(params.srtdeel_eenheid, 30): " IS NULL")
              + "   AND sd.bes_srtdeel_nr = " + safe.quoted_sql(params.srtdeel_nr, 32)
              + " ORDER BY sd.bes_srtdeel_key DESC ";

          var oRs = Oracle.Execute(sql);
          var bes_srtdeel_key = oRs("bes_srtdeel_key").Value;
          oRs.Close()
          return bes_srtdeel_key;
      }
    }
%>
