<%@language = "javascript" %>
<% /*
     $Revision$
     $Id$

    File:           ins_inspect_save.asp
    Description:    Inspectiedata opslaan
    Parameters:     ins_keys of ins_key (geen verschil)

    Context:        Vanuit
                    1) ins/ins_edit_inspect.asp
                    2) pda/ins_inspect.asp
                    3) mjb/mjb_search_list.asp
    Note:           Parameter mobile doet niets met navigatie, sluiten enzo, die submit gewoon.
                    Resultaat van een submit is een json object

*/
var JSON_Result = true;
%>
<!-- #include file="../Shared/common.inc" -->
<!-- #include file="../Shared/save2db.inc" -->
<!-- #include file="../Shared/kenmerk_common.inc" -->
<!-- #include file="../Shared/discxalg3d.inc" -->
<!-- #include file="ins.inc" -->

<%
//var insp_actie = getFParamInt("inspectie_actie", 0); // Inspectie invoeren of uitstellen.

var ins_key_arr = getFParamKeyArray("ins_keys");
var multi = ins_key_arr.length > 1;

var srtcont_key_arr = getFParamKeyArray("srtcont_key_arr", []); // Inspectiesoorten.

// Scenario's. Wordt alleen vanuit mjb_search_list.asp meegegeven voor het verschuiven van plandatum.
// Scenario's zijn planbaar (savemode is "P") maar worden savemode "E" als het deelsrtcontrole record al bestaat (al ingepland is).
var scen_key_arr = getFParamKeyArray("scen_key_arr", []);

var savemode = getFParam("savemode");

var finish = getFParamInt("finish", 0) == 1; // Inspectie direct afronden.
var groupby = getFParamInt("groupby", 9);
var finishmjob = getFParamInt("finishmjob", 0) == 1;
var catclose = (finishmjob && groupby < 9); // Bulk closen per categorie.
var plan_opm = getFParam("plan_opm", "");

var mjob = getFParamInt("mjob", 0) == 1; // Aanroep vanuit mjob overzichtsscherm.

// Als multi dan moet de ins_deel array even groot zijn als de srtcontrole array en deelsrtcontrole array.
user.auth_required_or_abort(catclose || !multi || (ins_key_arr.length == srtcont_key_arr.length));

var deelsrtcontrole_datum;
var plandatum, moveyears;
var nextdate;
var deelsrtcont_key = -1;

if (savemode == "P") // Inplannen (Plan).
{
  plandatum = getFParamDate("plandatum");
  deelsrtcont_key = getFParamInt("deelsrtcont_key", -1); // Specifieke inspectie die gewijzigd moet worden.
}
else if (savemode == "C") // Afmelden/Afronden (Close).
  deelsrtcontrole_datum = getFParamDate("deelsrtcontrole_datum", new Date);
else if (savemode == "E")
{ // Wijzigen (Edit).
  plandatum = getFParamDate("plandatum", null);

  if (multi)
    abort_with_warning(L("lcl_ins_allow_multi_edit"));

  deelsrtcont_key = getFParamInt("deelsrtcont_key"); // Specifieke inspectie die gewijzigd is.
  deelsrtcontrole_datum = getFParamDate("deelsrtcontrole_datum", new Date); // Datum kan ook aangepast worden.
  var getDeelsrtcontroleDate = Request.Form("deelsrtcontrole_datum").count > 0; // Was de inspectiedatum te wijzigen
}
else if (savemode == "D") // Delete (Move back to original year).
{
  var dlsrtcont_key_arr = getFParamKeyArray("dlsrtcont_key_arr", []); // Inspecties
}
else if (savemode == "R")
{
  moveyears = getFParamInt("plandatum");
  if (multi || isNaN(moveyears) || moveyears % 1 !== 0)
  {
    Response.Clear();
    Response.Write(JSON.stringify({ success: false, savemode: "R", warning: "" }));
    Response.End;
  }
  deelsrtcont_key = getFParamInt("deelsrtcont_key", -1); // Specifieke inspectie die gewijzigd moet worden.
  var silent = true;
}

var warning = "";
var result = {};
var tobehandled = 0;
var ingesloten = [];
var canMsuEdit = false; // Alleen voor het wijzigen van inspectie (insEdit). Er geldt dan altijd !multi.

var inflatiepct = S("mjb_inflation");
var inflatiefactor = 1 + (inflatiepct / 100);
var mjb_start_year = S("mjb_start_year");
var mjb_freeze_year = Math.max(S("mjb_freeze_year"), new Date().getFullYear());

if (catclose)
{
  var dist_key_arr = getFParamKeyArray("dist_key_arr", []); // District
  var loc_key_arr = getFParamKeyArray("loc_key_arr", []); // Locatie
  var bld_key_arr = getFParamKeyArray("bld_key_arr", []); // Gebouw
  var disc_key_arr = getFParamKeyArray("disc_key_arr", []);
  var srtgroep_key_arr = getFParamKeyArray("srtgroep_key_arr", []);
  var srtdeel_key_arr = getFParamKeyArray("srtdeel_key_arr", []);
  var moredetail = getFParamInt("moredetail", 0);
  var srtgebouw_key_arr = getFParamKeyArray("srtgebouw_key_arr", []);
  var groep_str_arr = getFParamArray("groep_str_arr", []); // Groep
  var categorie_key_arr = getFParamKeyArray("categorie_key_arr", []); // Categorie
  var srtcontrole_key_arr = getFParamKeyArray("srtcontrole_key_arr", []); // Taak
  var frequentie_arr = getFParamIntArray("frequentie_arr", []); // Array met frequenties.
  var kp_key_arr = getFParamKeyArray("kp_key_arr", []);
  var incbtw = getFParamInt("incbtw", 0) == 1; // Lijst inclusief BTW weergeven.
  var showunfin = getFParamInt("showunfin", 0) == 1; // Alleen onvoltooide regels.
  var inflatiepct = S("mjb_inflation");
  var inflatiefactor = 1 + (inflatiepct / 100);
  var deel = getFParam("deel", ""); // Identieficatie

  // FORM score velden.
  var fitness_score1_from = getFParamInt("fitness_score1_from", -1);               // Conditie score van.
  var fitness_score1_through = getFParamInt("fitness_score1_through", -1);         // Conditie score t/m.
  var fitness_score1_from_neg = getFParamInt("fitness_score1_from_neg", -1);       // Negatieve afwijking conditie score van.
  var fitness_score1_through_neg = getFParamInt("fitness_score1_through_neg", -1); // Negatieve afwijking conditie score t/m.
  var fitness_score1_from_pos = getFParamInt("fitness_score1_from_pos", -1);       // Positieve afwijking conditie score van.
  var fitness_score1_through_pos = getFParamInt("fitness_score1_through_pos", -1); // Positieve afwijking conditie score t/m.
  var priority_score2_from = getFParamInt("priority_score2_from", -1);             // Prioriteitsscore van.
  var priority_score2_through = getFParamInt("priority_score2_through", -1);       // Prioriteitsscore t/m.

  // FORM status checkboxes.
  var mjbMoved  = getFParamInt("mjbMoved", 0) == 1; // Verschoven.
  var mjbFreezed = getFParamInt("mjbFreezed", 0) == 1; // In behandeling.
  var mjbXcped = getFParamInt("mjbXcped", 0) == 1; // Aangepast.

  var sel_controlemode123 = [];
  var sel_controlemode1 = getFParamInt("sel_controlemode1", -1); // Taakafhandeling 1.
  var sel_controlemode2 = getFParamInt("sel_controlemode2", -1); // Taakafhandeling 2.
  var sel_controlemode3 = getFParamInt("sel_controlemode3", -1); // Taakafhandeling 3.
  if (sel_controlemode1 > 0)
    sel_controlemode123.push(sel_controlemode1);
  if (sel_controlemode2 > 0)
    sel_controlemode123.push(sel_controlemode2);
  if (sel_controlemode3 > 0)
    sel_controlemode123.push(sel_controlemode3);

  var opmerk = getFParam("opmerk", ""); // Opmerking.

  // Start building the query to fetch all objects satisfying
  var mjbparams = { scenario: 1,
                    fulldetails: true,
                    toyear: mjb_freeze_year,
                    jaren: [mjb_freeze_year],
                    //actsit: actsit, // actsit alleen van invloed op scenario_key > 1.
                    keys: ins_key_arr,
                    niveau: groupby,   // Het niveau (betekenis) van de keys (district(1), gebouw(2), discipline(3), groep(4), objectsoort(5), object(6))
                    dist_key_arr: dist_key_arr,
                    loc_key_arr: loc_key_arr,
                    bld_key_arr: bld_key_arr,
                    disc_key_arr: disc_key_arr,
                    srtgroep_key_arr: srtgroep_key_arr,
                    srtdeel_key_arr: srtdeel_key_arr,
                    moredetail: moredetail,
                    srtgebouw_key_arr: srtgebouw_key_arr,
                    groep_str_arr: groep_str_arr,
                    categorie_key_arr: categorie_key_arr,
                    srtcontrole_key_arr: srtcontrole_key_arr,
                    frequentie_arr: frequentie_arr,
                    kp_key_arr: kp_key_arr,
                    incbtw: incbtw,
                    showunfin: showunfin,
                    inflatiefactor: inflatiefactor,
                    deel: deel,
                    fitness_score1_from : fitness_score1_from,
                    fitness_score1_through : fitness_score1_through,
                    fitness_score1_from_neg : fitness_score1_from_neg,
                    fitness_score1_through_neg : fitness_score1_through_neg,
                    fitness_score1_from_pos : fitness_score1_from_pos,
                    fitness_score1_through_pos : fitness_score1_through_pos,
                    priority_score2_from : priority_score2_from,
                    priority_score2_through : priority_score2_through,
                    mjbMoved: mjbMoved,
                    mjbFreezed: mjbFreezed,
                    mjbXcped: mjbXcped,
                    groupby: 9, // Ik wil alle objecten opvragen.
                    sel_controlemode123: sel_controlemode123,
                    finish: true
                  };

  var mjblist_sql = ins.getmjblist_sql(mjbparams);
  // De mjblist_sql bevat nu alle objecten (ins_deel_key) van de aangevinkte regels uit het mjb overzicht en levert voor elk object de waarden voor de insert op.

  var result = { success: true, deelsrtcontrole_datum: deelsrtcontrole_datum, savemode: savemode, warning: "" };

  var oRs = Oracle.Execute(mjblist_sql);
  user.anything_todo_or_abort(!oRs.eof); // We klagen niet over enkele wel en enkele niet

  var dlsrtcont_key_array = [];
  var trackarray = [];
  var update_sql = "BEGIN ";
  while (!oRs.eof)
  {
    var ins_key = oRs("ins_deel_key").Value;
    var srtcont_key = oRs("ins_srtcontrole_key").Value;
    var dlsrtcont_key = oRs("ins_deelsrtcontrole_key").Value;
    var sctype = oRs("ctr_controle_type").Value;
    var nextdate = new Date(oRs("nextdate").Value);
    var cm_oms = oRs("cm_oms").Value;
    var ctr_disc_oms = oRs("ctr_disc_oms").Value;
    var dlsrtcont_opm = oRs("ins_deelsrtcontrole_opmerking").Value || "";
    var sel_controlemode;
    var dlsrtcontr_trackarray = [];
    switch(sctype)
    {
      case 1:  sel_controlemode = sel_controlemode1; break;
      case 2:  sel_controlemode = sel_controlemode2; break;
      case 3:  sel_controlemode = sel_controlemode3; break;
    }
    var nextdate = oRs("nextdate").Value != null? new Date(oRs("nextdate").Value) : null;

    update_sql += "UPDATE ins_deelsrtcontrole"
                + "   SET ins_deelsrtcontrole_opmerking = " + safe.quoted_sql((dlsrtcont_opm != ""? dlsrtcont_opm + "\n" : "") + opmerk)
                + "     , prs_perslid_key = " + user_key
                + "     , ins_deelsrtcontrole_datum = SYSDATE"
                + "     , ins_deelsrtcontrole_datum_org = " + nextdate.toSQL(true)
                + "     , ins_controlemode_key = " + sel_controlemode
                + " WHERE ins_deelsrtcontrole_key = " + dlsrtcont_key
                + ";";
    if (opmerk != "")
      dlsrtcontr_trackarray.push(L("lcl_remark") + ": " +  (dlsrtcont_opm != ""? dlsrtcont_opm : L("lcl_trackfromempty")) + L("lcl_trackto") + (dlsrtcont_opm != ""? dlsrtcont_opm + "\n" : "") + opmerk);
    dlsrtcontr_trackarray.push(L("lcl_ins_controle_datum") + ": " +  L("lcl_trackfromempty") + L("lcl_trackto") + toDateTimeString(new Date()));
    dlsrtcontr_trackarray.push(L("lcl_ins_controle_mode") + ": " +  L("lcl_trackfromempty") + L("lcl_trackto") + cm_oms);

    dlsrtcont_key_array.push(dlsrtcont_key);
    trackarray.push(dlsrtcontr_trackarray)

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

  update_sql += " END;"

  var err = Oracle.Execute(update_sql, true);
  if (err.friendlyMsg)
    result.message = err.friendlyMsg;

  for (var i = 0; i < dlsrtcont_key_array.length; i++)
  {
    // Nu nog de status zetten, tracking genereren en notificaties sturen.
    ins.setinspectstatus(dlsrtcont_key_array[i], 6); // History/Verwerkt/Voltooid(6).

    ins.trackinspectupdate(dlsrtcont_key_array[i], L("lcl_ins_controle_is_upd").format(ctr_disc_oms) + "\n" + trackarray[i].join("\n"));
  }
}
else
{
  // Bepaal de objecten in de selectie die ook echt geinspecteerd kunnen of mogen worden.
  for (var i = 0; i < ins_key_arr.length; i++)
  {
    if (finish)
    { // Als de een-na-laatste een geaccordeerde/gestarte inspectie is met status 2, dan moet deze voltooid worden i.p.v. de laatste.
      // De laatste is dan namelijk een ingeplande inspectie met status 0 die verschoven is t.o.v. de orginele inspectiedatum.
      var sql_f = "SELECT idsc.ins_deelsrtcontrole_key dsc_freezed"
                + "     , aantal"
                + "     , max_dsc"
                + "     , min_dsc"
                + "     , min_status"
                + "  FROM ins_deelsrtcontrole idsc"
                + "     , (SELECT COUNT(idsc2.ins_deelsrtcontrole_key) aantal"
                + "             , MAX(idsc2.ins_deelsrtcontrole_key) max_dsc"
                + "             , MIN(idsc2.ins_deelsrtcontrole_key) min_dsc"
                + "             , MIN(idsc2.ins_deelsrtcontrole_status) min_status"
                + "          FROM ins_deelsrtcontrole idsc2"
                + "         WHERE idsc2.ins_deel_key = " + ins_key_arr[i]
                + "           AND idsc2.ins_srtcontrole_key = " + srtcont_key_arr[i]
                + "           AND idsc2.ins_deelsrtcontrole_status IN (0, 2, 3)"
                + "           AND idsc2.ins_scenario_key = 1)"
                + " WHERE idsc.ins_deel_key = " + ins_key_arr[i]
                + "   AND idsc.ins_srtcontrole_key = " + srtcont_key_arr[i]
                + "   AND idsc.ins_deelsrtcontrole_status IN (2, 3)"
                + "   AND idsc.ins_scenario_key = 1";
      var oRs_f = Oracle.Execute(sql_f);
      if (!oRs_f.eof &&
          oRs_f("aantal").Value == 2 &&
          oRs_f("dsc_freezed").Value == oRs_f("min_dsc").Value &&
          oRs_f("min_status").Value == 0)
      deelsrtcont_key = oRs_f("dsc_freezed").Value;
      oRs_f.Close();
    }
    var dlsrtcont_key = -1;
    var sql = "SELECT *"
            + "  FROM (SELECT xcp.ins_srtcontrole_key"
            + "             , idsc.ins_deelsrtcontrole_key"
            + "             , (SELECT MAX (idsc2.ins_deelsrtcontrole_datum)"
            + "                  FROM ins_deelsrtcontrole idsc2"
            + "                 WHERE idsc2.ins_deel_key = idsc.ins_deel_key"
            + "                   AND idsc2.ins_srtcontrole_key = idsc.ins_srtcontrole_key"
            + (scen_key_arr.length > 0 && scen_key_arr[i] > 1
              ? "                 AND idsc2.ins_scenario_key = " + scen_key_arr[i]
              : "                 AND idsc2.ins_scenario_key = 1")
            + "                ) ins_deelsrtcontrole_datum"
            + "             , idsc.ins_deelsrtcontrole_plandatum"
            + "             , xcp.ins_srtcontrole_eenheid eenheid"
            + "             , xcp.ins_srtcontrole_mode"
            + "             , idsc.ins_deelsrtcontrole_status"
            + "             , xcp.ins_deel_aanmaak"
            + "             , xcp.ctr_discipline_key"
            + "             , xcp.ins_srtcontrole_options options"
            + "             , cd.ins_discipline_omschrijving"
            + "             , isc.ins_srtcontrole_omschrijving"
            + "             , xcp.ins_srtcontroledl_xcp_startdat"
            + "             , CASE"
            + "               WHEN (SELECT COUNT(sdc.ins_deelsrtcontrole_key)"
            + "                       FROM ins_deelsrtcontrole sdc"
            + "                      WHERE sdc.ins_deel_key = idsc.ins_deel_key"
            + "                        AND sdc.ins_srtcontrole_key = idsc.ins_srtcontrole_key"
            + "                        AND sdc.ins_deelsrtcontrole_status = 6"
            + "                        AND sdc.ins_scenario_key = 1) > 0"
            + "               THEN 1"
            + "               ELSE 0"
            + "               END hascontroles"
            + "          FROM ins_v_defined_inspect_xcp xcp"
            + "             , ins_deelsrtcontrole idsc"
            + "             , ctr_v_aanwezigdiscipline cd"
            + "             , ins_srtcontrole isc"
            + "         WHERE xcp.ins_srtcontrole_key = idsc.ins_srtcontrole_key(+)" // Er kan nog voor de eerste keer geinspecteerd moeten worden.
            + "           AND xcp.ctr_discipline_key = cd.ins_discipline_key"
            + "           AND xcp.ins_srtcontrole_key = isc.ins_srtcontrole_key"
            + "           AND xcp.ins_deel_key = " + ins_key_arr[i]
            + "           AND idsc.ins_deel_key(+) = " + ins_key_arr[i]
            + "           AND xcp.ins_srtcontrole_periode > 0"
            + "           AND xcp.ins_srtcontrole_key = " + srtcont_key_arr[i]
            + (deelsrtcont_key > 0
              ? "           AND idsc.ins_deelsrtcontrole_key = " + deelsrtcont_key
              : "")
            + (scen_key_arr.length > 0 && scen_key_arr[i] > 1
              ? "           AND xcp.ins_scenario_key(+) = " + scen_key_arr[i]
                + "         AND idsc.ins_scenario_key(+) = " + scen_key_arr[i]
              : "           AND xcp.ins_scenario_key(+) = 1"
                + "         AND idsc.ins_scenario_key(+) = 1")
             + "      )"
            + " ORDER BY ins_deelsrtcontrole_key DESC";
    var oRs = Oracle.Execute(sql);
    lcl.set_dialect(oRs("ctr_discipline_key").Value, "CTR_DISCIPLINE_KEY");

    // Waarden moeten aanwezig zijn. Mocht dat niet zo zijn dan is er iets fout.
    var ins_srtcontrole_mode = oRs("ins_srtcontrole_mode").Value;
    var ins_deelsrtcontrole_status = oRs("ins_deelsrtcontrole_status").Value != null? oRs("ins_deelsrtcontrole_status").Value : -1; // Als er nog geen inspectie is geweest is de status -1.
    var ins_deel_aanmaak = new Date(oRs("ins_deel_aanmaak").Value);
    var eenheid = oRs("eenheid").Value;
    var ins_deelsrtcontrole_datum_max = oRs("ins_deelsrtcontrole_datum").Value;
    var ins_deelsrtcontrole_key = oRs("ins_deelsrtcontrole_key").Value;
    var isc_options = oRs("options").Value;
    var disc_oms = oRs("ins_discipline_omschrijving").Value;
    var srtcontrole_oms = oRs("ins_srtcontrole_omschrijving").Value;
    var deelsrtcontrole_plandatum = oRs("ins_deelsrtcontrole_plandatum").Value != null? new Date(oRs("ins_deelsrtcontrole_plandatum").Value) : -1;
    var ins_startdatum = oRs("ins_srtcontroledl_xcp_startdat").Value != null? new Date(oRs("ins_srtcontroledl_xcp_startdat").Value) : -1;
    var hascontroles = oRs("hascontroles").Value == 1;

    var this_ins = ins.func_enabled_deel(ins_key_arr[i],
                                         {srtcont_key: srtcont_key_arr[i],
                                          deelsrtcont_key: (ins_deelsrtcontrole_key != null? ins_deelsrtcontrole_key : -1),
                                          scen_key: (scen_key_arr.length > 0? scen_key_arr[i] : 1)
                                         });
    canMsuEdit = savemode == "E" && this_ins.canMsuEdit;
    oRs.Close();

    if (savemode == "R")
    {
      var minyear = mjb_freeze_year || (new Date()).getFullYear();
      if (ins_deelsrtcontrole_status == 0) // Er is nog geen inspectie geweest.
      {
        if (deelsrtcontrole_plandatum != -1)
          plandatum = deelsrtcontrole_plandatum;
        else
          continue;
        savemode = "E"; // bestaat al dus 'edit'
      }
      else
      {
        sql = "SELECT ins.nextcyclusdate (" + ins_key_arr[i] + ", " + srtcont_key_arr[i] + ", 1) nextdate FROM DUAL";
        oRs_nextdate = Oracle.Execute(sql);
        plandatum = new Date(oRs_nextdate("nextdate").Value);
        oRs_nextdate.Close();

        if (ins_deelsrtcontrole_status == -1)
        {
          var aanmaakyear = ins_deel_aanmaak.getFullYear();
          minyear = Math.max(minyear, aanmaakyear);
        }
        else if (ins_deelsrtcontrole_status == 5 || ins_deelsrtcontrole_status == 6)
        {
          var lastinsdate = new Date(ins_deelsrtcontrole_datum_max);
          var lastinsyear = lastinsdate.getFullYear();
          minyear = Math.max(minyear, lastinsyear);
        }
        else // ins_deelsrtcontrole_status == 2 of ins_deelsrtcontrole_status == 3
          continue;

        savemode = "P"; // moet nog ingepland worden
      }
      var newyear = plandatum.getFullYear() + moveyears;
      if (moveyears === 0 || newyear < minyear)
        continue;

      plandatum = new Date(newyear, 11, 31);
    }

    // Inplannen (dlsrtcont_key = -1).
    // Het is de eerste inspectie of de laatste inspectie moet verwerkt(6) zijn, anders kan de inspectie niet ingepland worden.

    // Het planjaar moet na het startjaar ligggen.
    // Als er al een inspectie is geweest dan niet meer naar startdatum kijken.
    // Als er nog geen inspectie is geweest en er is een startdatum ingevuld, dan moet de plandatum verwijderd worden afhankelijk van mjob.
    // Voor mjob = false: als de plandatum eerder is als de startdatum (kan eigenlijk niet ingevoerd worden in edit scherm).
    //      mjob = true:  als de plandatum in hetzelfde jaar of eerder is als de startdatum.
    if(savemode == "P" && ins_deelsrtcontrole_key != null)
    { // Inspectie is al ingepland en heeft dus een inspectie key. Dan deze ook aan dlsrtcont_key toekennen.
      dlsrtcont_key = ins_deelsrtcontrole_key;
    }
    if (savemode == "P" && !(this_ins.canInspPlan || this_ins.canInspPlanMjb || this_ins.canInspPlanMulti)) // Inplannen.
    { // Ik heb geen Plan (inplannen) rechten of de taak was al ingepland.
      if (!hascontroles && ins_startdatum != -1 && ((mjob && plandatum.getFullYear() < ins_startdatum.getFullYear()) || (!mjob && plandatum.getTime() < ins_startdatum.getTime())))
        // Taak is ingepland. Als er nog geen controles zijn en de nieuwe plandatum is eerder dan het startjaar, dan kan de taak NIET daarheen verschoven worden.
        continue;
      else if (ins_deelsrtcontrole_status == 0 && !multi)
        savemode = "E";
      else
        continue;
    }
    else if (savemode == "P" && !hascontroles && ins_startdatum != -1)
    { // Taak is niet ingepland. Eerste controle en er is een startdatum ingevuld.
      // Als er nog geen controles zijn en de nieuwe plandatum is eerder dan het startjaar, dan kan de taak NIET daarheen verschoven worden.
      // Verschuiven naar het startjaar heeft geen zin, want het bedrag staat al in het startjaar. Daarom "<=" in de voorwaarde.
      if ((mjob && plandatum.getFullYear() <= ins_startdatum.getFullYear()) || (!mjob && plandatum.getTime() <= ins_startdatum.getTime()))
        continue; // Plandatum is gelijk voor de startdatum. Plandatum niet opslaan.
    }

    if (savemode == "C") // Afmelden/Afronden.
    { // Is er op de inspectiedatum of op het inspectieuur al geinspecteerd voor dit object en het objectsoort?
      // Voor niet multi is dit al gecontroleerd in ins_edit_inspect.asp. Hier voor de veiligheid opnieuw controleren is niet verkeerd.
      var deelsrtcontrole_midnighttime = deelsrtcontrole_datum.midnight().getTime();
      var deelsrtcontrole_hourtime = deelsrtcontrole_datum; // deelsrtcontrole_datum moet niet worden aangepast door setMinutes(0,0,0).
      var deelsrtcontrole_hourtime = new Date(new Date(parseInt(deelsrtcontrole_hourtime.getTime())).setMinutes(0,0,0)).getTime();
      // Controle of er op de inspectiedatum of op het inspectieuur al inspecties zijn geweest
      // TODO: Wat te doen met extra inspecties. En per week/maand/jaar enz.
      if ((eenheid > 0) && ins_srtcontrole_mode == 0 && // Geldt alleen voor momentmodus.
          (deelsrtcontrole_midnighttime == new Date(ins_deelsrtcontrole_datum_max).midnight().getTime()))
      { // Op dezelfde dag mag niet. Overslaan.
        continue;
      }
      else if ((eenheid == 0) && ins_srtcontrole_mode == 0 && // Geldt alleen voor momentmodus.
               (deelsrtcontrole_hourtime == new Date(new Date(ins_deelsrtcontrole_datum_max).setMinutes(0,0,0)).getTime()))
      { // In dezelfde minuut (tijdstip) mag niet. Overslaan.
        continue;
      }
      else if (new Date(deelsrtcontrole_datum.setSeconds(0, 0)).getTime() == new Date(new Date(ins_deelsrtcontrole_datum_max)).getTime() &&
               ins_srtcontrole_mode == 1)
      { // Een inspectie doen op dezelfde datumtijd (controledatum hetzelfde) mag niet omdat je daarna dan niet meer de volgende inspectie kunt doen.
        // De geplande _org tijd is dan hetzelfde als de laatste inspectie omdat de volgende inspectie dan niet opgeschoven is.
        // Inspecties op dezelfde datumtijd moeten dus afgevangen worden.
        // Dit kan alleen voorkomen in de interval mode.
        continue;
      }

      if (!this_ins.canInspClose && !(this_ins.canInspFinish || this_ins.canInspFinishMjb))
      { // Ik heb geen Close (gereedmelden/afronden) rechten of laatste inspectie is niet verwerkt (dan moet ins_inspect_finish.asp aangeroepen worden). Overslaan.
        continue;
      }
      else if (ins_deelsrtcontrole_status >= 0 && ins_deelsrtcontrole_status != 6)
        dlsrtcont_key = ins_deelsrtcontrole_key;
    }

    if (savemode == "E") // Wijzigen.
    { // Dit is al gecontroleerd in ins_edit_inspect.asp. Hier voor de veiligheid opnieuw controleren is niet verkeerd.
      if (!this_ins.canInspEdit)
      { // Ik heb geen Edit rechten.
        continue;
      }
      else
        dlsrtcont_key = ins_deelsrtcontrole_key;

      // De uitvoerdatum/inspectiedatum moet vallen tussen de uitvoerdatum/inspectiedatum van de vorige en volgende inspectie.
      // De edit mode zorgt ervoor dat er alleen juiste inspectiedatums gekozen kunnen worden, maar het is goed dat het hier ook nog getest wordt.
      var aanmaakdatum = ins_deel_aanmaak;
      var minDate = new Date();
      var maxDate = new Date();
      if (ins_deelsrtcontrole_status >= 5 && getDeelsrtcontroleDate)
      {
        // Vooralsnog kan inspectiedatum niet aangepast worden als de eenheid uren(0) is (readonly).
        sql = "SELECT MAX(idsc.ins_deelsrtcontrole_datum) lastinspectdatum"
            + "     , MAX(idsc.ins_deelsrtcontrole_datum + 1) dag_na_lastinspectdatum"
            + "     , CASE"
            + "       WHEN COALESCE(xcp.ins_srtcontroledl_xcp_eenheid, isc.ins_srtcontrole_eenheid) != 0" // Geen tijd eenheid maar dag, maand of jaar.
            + "       THEN 1" // Dag, maand of jaar.
            + "       ELSE 0" // Tijd.
            + "       END dmj_eenheid"
            + "     , isc.ins_srtcontrole_mode"
            + "  FROM ins_deelsrtcontrole idsc"
            + "     , ins_srtcontrole isc"
            + "     , ins_srtcontroledl_xcp xcp"
            + " WHERE idsc.ins_srtcontrole_key = isc.ins_srtcontrole_key"
            + "   AND idsc.ins_srtcontrole_key = xcp.ins_srtcontrole_key(+)"
            + "   AND idsc.ins_deel_key = xcp.ins_deel_key(+)"
            + "   AND COALESCE(xcp.ins_srtcontroledl_xcp_periode, isc.ins_srtcontrole_periode) > 0"
            + "   AND idsc.ins_deel_key IN (" + ins_key_arr[i] + ")"
            + "   AND idsc.ins_srtcontrole_key IN (" + srtcont_key_arr[i] + ")"
            + "   AND ins_deelsrtcontrole_key < " + dlsrtcont_key
            + "   AND idsc.ins_scenario_key = 1" // Status >= 0 dus kan geen scenario zijn.
            + "   AND xcp.ins_scenario_key(+) = 1"  // Status >= 0 dus kan geen scenario zijn.
            + " GROUP BY isc.ins_srtcontrole_mode"
            + "        , xcp.ins_srtcontroledl_xcp_eenheid"
            + "        , isc.ins_srtcontrole_eenheid";
        var oRs = Oracle.Execute(sql);
        if (!oRs.eof && oRs("lastinspectdatum").Value != null)
        {
          var lastinspectdatum = new Date(oRs("lastinspectdatum").Value); // Kan uiterlijk vandaag zijn.
          var dag_na_lastinspectdatum = new Date(oRs("dag_na_lastinspectdatum").Value); // Kan uiterlijk morgen zijn.
          dmj_eenheid = oRs("dmj_eenheid").Value;
          mode = oRs("ins_srtcontrole_mode").Value;
          if (mode == 0)
          { // Momentmode.
            sql = "SELECT COUNT(*) aantal"
                + "  FROM ins_deelsrtcontrole idsc"
                + " WHERE ins_deel_key = " + ins_key_arr[i]
                + "   AND ins_srtcontrole_key = " + srtcont_key_arr[i]
                + "   AND ins_scenario_key = 1"
                + "   AND TRUNC(ins_deelsrtcontrole_datum) = TRUNC((SELECT ins_deelsrtcontrole_datum"
                + "                                                   FROM ins_deelsrtcontrole idsc1"
                + "                                                  WHERE idsc1.ins_deelsrtcontrole_key = " + dlsrtcont_key + "))";
            oRs2 = Oracle.Execute(sql);
            var same_execution_date = oRs2("aantal").Value;
            oRs2.Close();
            minDate = dmj_eenheid == 1 && same_execution_date == 1? new Date(dag_na_lastinspectdatum.midnight()) : lastinspectdatum;
          }
          else
            // Intervalmode.
            minDate = lastinspectdatum;
        }
        else
          minDate = aanmaakdatum;
        oRs.Close();

        // Vooralsnog kan inspectiedatum niet aangepast worden als de eenheid uren(0) is (readonly).
        sql = "SELECT MIN(COALESCE(idsc.ins_deelsrtcontrole_datum, ins_deelsrtcontrole_plandatum)) firstinspectdatum"
            + "     , MIN(COALESCE(idsc.ins_deelsrtcontrole_datum, ins_deelsrtcontrole_plandatum) - 1) dag_voor_firstinspectdatum"
            + "     , CASE"
            + "       WHEN COALESCE(xcp.ins_srtcontroledl_xcp_eenheid, isc.ins_srtcontrole_eenheid) != 0" // Geen tijd eenheid maar dag, maand of jaar.
            + "       THEN 1" // Dag, maand of jaar.
            + "       ELSE 0" // Tijd.
            + "       END dmj_eenheid"
            + "     , isc.ins_srtcontrole_mode"
            + "  FROM ins_deelsrtcontrole idsc"
            + "     , ins_srtcontrole isc"
            + "     , ins_srtcontroledl_xcp xcp"
            + " WHERE idsc.ins_srtcontrole_key = isc.ins_srtcontrole_key"
            + "   AND idsc.ins_srtcontrole_key = xcp.ins_srtcontrole_key(+)"
            + "   AND idsc.ins_deel_key = xcp.ins_deel_key(+)"
            + "   AND COALESCE(xcp.ins_srtcontroledl_xcp_periode, isc.ins_srtcontrole_periode) > 0"
            + "   AND idsc.ins_deel_key IN (" + ins_key_arr[i] + ")"
            + "   AND idsc.ins_srtcontrole_key IN (" + srtcont_key_arr[i] + ")"
            + "   AND ins_deelsrtcontrole_key > " + dlsrtcont_key
            + "   AND idsc.ins_scenario_key = 1" // Status >= 0 dus kan geen scenario zijn.
            + "   AND xcp.ins_scenario_key(+) = 1"  // Status >= 0 dus kan geen scenario zijn.
            + "   AND idsc.ins_deelsrtcontrole_status >= 5"
            + " GROUP BY isc.ins_srtcontrole_mode"
            + "        , xcp.ins_srtcontroledl_xcp_eenheid"
            + "        , isc.ins_srtcontrole_eenheid";
        oRs = Oracle.Execute(sql);
        if (!oRs.eof)
        {
          firstinspectdatum = new Date(oRs("firstinspectdatum").Value); // Kan uiterlijk vandaag zijn.
          dag_voor_firstinspectdatum = new Date(oRs("dag_voor_firstinspectdatum").Value); // Kan uiterlijk morgen zijn.
          dmj_eenheid = oRs("dmj_eenheid").Value;
          mode = oRs("ins_srtcontrole_mode").Value;
          if (mode == 0)
            // Momentmode.
            maxDate = dmj_eenheid == 1? new Date(dag_voor_firstinspectdatum.setHours(23,59,59,99)) : firstinspectdatum;
          else
            // Intervalmode.
            maxDate = firstinspectdatum;
        }
        //else //maxDate = new Date();
        oRs.Close();

        // Huidige inspectie moet tussen voorgaande en volgende inspectie inliggen.
        if (deelsrtcontrole_datum.getTime() < minDate.getTime() || deelsrtcontrole_datum.getTime() >= maxDate.getTime())
        { // De uitvoerdatum/inspectiedatum valt niet tussen de uitvoerdatum/inspectiedatum van de vorige en volgende inspectie.
          continue;
        }
      }
    }

    ingesloten.push({ins_key: ins_key_arr[i], srtcont_key: srtcont_key_arr[i], dlsrtcont_key: (savemode == "D"? dlsrtcont_key_arr[i] : dlsrtcont_key), dlsrtcont_plandatum: deelsrtcontrole_plandatum,
                     scen_key: (scen_key_arr.length > 0? scen_key_arr[i] : 1), inspectiemode: ins_srtcontrole_mode, inspectiestatus: ins_deelsrtcontrole_status,
                     ins_deel_aanmaak: ins_deel_aanmaak, disc_oms: disc_oms, srtcontrole_oms: srtcontrole_oms, startdatum: ins_startdatum, hascontroles: hascontroles});
    tobehandled++;
  }

  if (tobehandled == 0 && silent)
  {
      Response.Clear();
      Response.Write(JSON.stringify({ success: false, savemode: savemode, warning: "" }));
      Response.End;
  }
  else
    user.anything_todo_or_abort(tobehandled > 0); // We klagen niet over enkele wel en enkele niet

  function saveFlexKenmerkenInspection(pdlsrtcont_key, pinsPresent, pdelete, pingesloten)
  {
    // HIER WORDEN DE SAVEFLEXKENMERKEN GEREGELD
    if (pdelete)
      currentKenmerkenSQL = "SELECT 1 FROM DUAL WHERE 1 = 0"; // Geen flexkenmerken opslaan en alle waarden verwijderen.
    else
      currentKenmerkenSQL = "SELECT kd.ins_kenmerk_key"
                          + "     , kd.ins_kmdeelsrtcontr_waarde"
                          + "     , k.ins_kenmerk_toonbaar"
                          + "     , k.fac_functie_key"
                          + "  FROM ins_kmdeelsrtcontr kd"
                          + "     , ins_kenmerk k"
                          + " WHERE kd.ins_kenmerk_key = k.ins_kenmerk_key"
                          + "   AND kd.ins_kmdeelsrtcontr_verwijder IS NULL"
                          + "   AND kd.ins_deelsrtcontrole_key = " + pdlsrtcont_key;

    var allKenmerkenSQL = "SELECT COALESCE (" + lcl.xsql("k.ins_kenmerk_omschrijving", "k.ins_kenmerk_key")
                        + "              ,  " + lcl.xsql("t.ins_srtkenmerk_omschrijving", "t.ins_srtkenmerk_key") + ") kenmerk_omschrijving"
                        + "     , t.ins_srtkenmerk_kenmerktype kenmerk_kenmerktype"
                        + "     , t.ins_srtkenmerk_systeem     kenmerk_systeem"
                        + "     , k.ins_kenmerk_toonbaar       kenmerk_readonly"
                        + "     , k.ins_kenmerk_uniek          kenmerk_uniek"
                        + "     , fac_kenmerkdomein_key"
                        + "  FROM ins_kenmerk k"
                        + "     , ins_srtkenmerk t"
                        + " WHERE k.ins_srtkenmerk_key = t.ins_srtkenmerk_key"
                        + "   AND k.ins_kenmerk_key = "; /* wordt in saveFlexkenmerken uitgebreid */

    var ftrack = saveFlexKenmerken( pdlsrtcont_key,
                                    { kenmerkTable: "ins_kmdeelsrtcontr",
                                      kenmerkParentKey : "ins_deelsrtcontrole_key",
                                      kenmerkWaarde: "ins_kmdeelsrtcontr_waarde",
                                      kenmerkKey: "ins_kenmerk_key",
                                      kenmerkToonbaar: "ins_kenmerk_toonbaar",
                                      currentKenmerkenSQL: currentKenmerkenSQL,
                                      allKenmerkenSQL: allKenmerkenSQL,
                                      requestQF: Request.Form,
                                      isNew: !pinsPresent,
                                      flexPath: "INS/I",
                                      module: "INS"
                                    }
                                  );

    if (pingesloten && (pingesloten[0].dlsrtcont_key != pdlsrtcont_key))
    {   // Van de eerst geselecteerde inspectie wordt in saveFlexKenmerken de bijlagen van de temp-folder
        // verplaatst naar de juiste filepath en wordt de refkey van deze inspectie in fac_bijlagen gezet.
        // Vervolgens wordt met bulk voltooien de bijlagen gekopieerd van de eerst geselecteerde inspectie.
        var sql = "SELECT b.fac_bijlagen_key"
                + "     , b.fac_bijlagen_refkey"
                + "     , b.fac_bijlagen_kenmerk_key"
                + "     , b.fac_bijlagen_filename"
                + "     , b.fac_bijlagen_root_key"
                + "     , b.fac_bijlagen_module"
                + "     , COALESCE(k.ins_kenmerk_omschrijving, sk.ins_srtkenmerk_omschrijving) omschrijving"
                + "     , k2.ins_kenmerk_key fac_bijlagen_kenmerk_key2" // De kenmerk_key van het bijlagen kenmerk die overeenkomt met die van de eerste inspectie.
                + "     , COALESCE(k2.ins_kenmerk_omschrijving, sk2.ins_srtkenmerk_omschrijving) omschrijving2"
                + "  FROM fac_bijlagen b"
                + "     , ins_kenmerk  k"
                + "     , ins_srtkenmerk sk"
                + "     , ins_kenmerk k2"
                + "     , ins_srtkenmerk sk2"
                + "     , ins_srtcontrole c"
                + "     , ctr_discipline cd"
                + " WHERE b.fac_bijlagen_kenmerk_key = k.ins_kenmerk_key"
                + "   AND k.ins_srtkenmerk_key = sk.ins_srtkenmerk_key"
                + "   AND k.ins_kenmerk_verwijder IS NULL"
                + "  AND k.ins_kenmerk_niveau IN ('T', 'E', 'C')"
                + "   AND b.fac_bijlagen_refkey = " + pingesloten[0].dlsrtcont_key
                // De omschrijvingen van de kenmerken moeten overeenkomen. Er kunnen namelijk meerdere bijlage kenmerken zijn bij een inspectie.
                + "   AND COALESCE(k.ins_kenmerk_omschrijving, sk.ins_srtkenmerk_omschrijving) = COALESCE(k2.ins_kenmerk_omschrijving, sk2.ins_srtkenmerk_omschrijving)"
                + "   AND k2.ins_srtkenmerk_key = sk2.ins_srtkenmerk_key"
                + "   AND k2.ins_kenmerk_verwijder IS NULL"
                + "   AND ((k2.ins_srtinstallatie_key = c.ins_srtcontrole_key"
                + "     AND k2.ins_kenmerk_niveau = 'C')"
                + "     OR (k2.ins_srtinstallatie_key = cd.ins_discipline_key"
                + "     AND k2.ins_kenmerk_niveau = 'E')"
                + "     OR (k2.ins_srtinstallatie_key IS NULL"
                + "     AND k2.ins_kenmerk_niveau = 'T'))"
                + "   AND c.ctr_discipline_key = cd.ins_discipline_key"
                + "   AND cd.ins_discipline_verwijder IS NULL"
                + "   AND k2.ins_kenmerk_niveau IN ('T', 'E', 'C')"
                + "   AND c.ins_srtcontrole_key = (SELECT ins_srtcontrole_key"
                + "                                  FROM ins_deelsrtcontrole "
                + "                                 WHERE ins_deelsrtcontrole_key = " + pdlsrtcont_key + ")"
                + " ORDER BY b.fac_bijlagen_key";
        var oRs = Oracle.Execute(sql);

        while (!oRs.eof)
        {
            sql_exe = "BEGIN flx.copyflexbijlage"
                    + "(" + safe.quoted_sql(oRs("fac_bijlagen_module").Value)
                    + "," + pdlsrtcont_key
                    + "," + oRs("fac_bijlagen_kenmerk_key2").Value
                    + "," + oRs("fac_bijlagen_key").Value
                    + "); END;";
            Oracle.Execute(sql_exe);
            oRs.MoveNext();
        }
        oRs.Close();
    }

    return ftrack;
  }

  if (savemode == "P")
  { // Inplannen inspectie. Er is nog geen inspectierecord aanwezig.
    var result = { success: true, plandatum: plandatum, savemode: savemode, warning: "" };

    if (ingesloten.length == 1)
    { // Vindt het ins_srtcontrole_type.
      var sql = "SELECT ctr_disc_params_controle_type"
              + "  FROM ins_srtcontrole isc,"
              + "       ctr_disc_params cdp"
              + " WHERE ins_srtcontrole_key = " + ingesloten[0].srtcont_key
              + "   AND isc.ctr_discipline_key = cdp.ctr_ins_discipline_key";
      var oRs = Oracle.Execute(sql);
      result.srtcontrole_type = oRs("ctr_disc_params_controle_type").Value;

      oRs.Close();
    }

    for (var i = 0; i < ingesloten.length; i++)
    { // Kijken of er al een inspectie record aanwezig is
      var sql = "SELECT ins_deelsrtcontrole_key"
              + "     , ins_deelsrtcontrole_plandatum"
              + "  FROM ins_deelsrtcontrole"
              + " WHERE ins_deel_key = " + ingesloten[i].ins_key
              + "   AND ins_srtcontrole_key = " + ingesloten[i].srtcont_key
              + "   AND ins_scenario_key = " + ingesloten[i].scen_key
              + "   AND ins_deelsrtcontrole_status = 0";
      var oRs = Oracle.Execute(sql);
      if (!mjob && !oRs.eof)
      { // Er is al een inspectie record aanwezig.
        var insPresent = true;
        // Alleen de plandatum en opmerking kunnen aangepast zijn
        var fields = [{dbs: "ins_deelsrtcontrole_plandatum",      typ: "datetime", val: plandatum},
                      {dbs: "ins_deelsrtcontrole_opmerking",      typ: "varchar",  frm: "opmerk",                   track: L("lcl_remark"),             len: 4000 }
                     ];
        var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + oRs("ins_deelsrtcontrole_key").Value, fields);
        var err = Oracle.Execute(insUpd.sql, true);
        if (ingesloten.length == 1)
          result.deelsrtcontrole_key = oRs("ins_deelsrtcontrole_key").Value;

        // Status hoeft niet aangepast te worden, want de status is al Gepland(0).

        // Tracking bij het object.
        if (ingesloten[i].scen_key == 1)
          // Aanpassing van de plandatum door herplannen van (multi) taken in het periodiek taken scherm.
          ins.trackdeelupdate(ingesloten[i].ins_key,
                              L("lcl_ins_controle_obj_upd").format(ingesloten[i].disc_oms, ingesloten[i].srtcontrole_oms)
                                + "\n" + L("lcl_opdr_plandate") + ": "
                                + oRs("ins_deelsrtcontrole_plandatum").Value + L("lcl_trackto") + toDateTimeString(plandatum),
                              true); // Geen notificatie.
      }
      else
      { // Eerst maar eens een inspectie record aanmaken.
        var insPresent = false;

        // Bereken de volgende orginele inspectiedatum (nextdate).
        // Bij mjob kan de laatste inspectie niet succesvol zijn. Dus ins.nextcyclusdate(ins_key, srtcont_key, scen_key) kan ik hier niet gebruiken.
        // 1) De laatste inspectie is succesvol voltooid: De volgende met ins.nextcyclusdate() te berekenen.
        // 2) De laatste inspectie is NIET succesvol voltooid. De volgende is in het freeze jaar.
        // 3) De laatste inspectie is geaccordeerd/bevroren/gestart(2): De volgende is een periode verder als het freeze jaar.
        // 4) Er is geen inspectie geweest of gestart.
        var nextdate = ins.func_get_nextdate(ingesloten[i].ins_key, ingesloten[i].srtcont_key, ingesloten[i].scen_key, {mjob: mjob});

        var fields = [{dbs: "ins_deelsrtcontrole_key",            typ: "key",      seq: "ins_s_ins_deelsrtcontrole_key"},
                      {dbs: "ins_deel_key",                       typ: "key",      val: ingesloten[i].ins_key},
                      {dbs: "ins_srtcontrole_key",                typ: "key",      val: ingesloten[i].srtcont_key},
                      {dbs: "ins_deelsrtcontrole_opmerking",      typ: "varchar",  frm: "opmerk",                   track: L("lcl_remark"),             len: 4000 },
                      {dbs: "ins_deelsrtcontrole_status",         typ: "key",      val: 0},
                      {dbs: "prs_perslid_key",                    typ: "key",      val: user_key},
                      {dbs: "ins_deelsrtcontrole_plan_opm",       typ: "varchar",  val: plan_opm,                   track: L("lcl_mjb_plan_opmerking"), len: 4000 },
                      {dbs: "ins_deelsrtcontrole_plandatum",      typ: "datetime", val: plandatum},
                      {dbs: "ins_deelsrtcontrole_datum_org",      typ: "datetime", val: nextdate}
                     ];

        if (mjob && ingesloten[i].scen_key > 1)
          fields.push({dbs: "ins_scenario_key",              typ: "key",      val: ingesloten[i].scen_key});

        ins.testInspectInsert(ingesloten[i].ins_key, ingesloten[i].srtcont_key, ingesloten[i].scen_key);
        var insIns = buildInsert("ins_deelsrtcontrole", fields);
        ingesloten[i].dlsrtcont_key = insIns.sequences["ins_deelsrtcontrole_key"];
        var err = Oracle.Execute(insIns.sql, true);
        if (ingesloten.length == 1)
          result.deelsrtcontrole_key = ingesloten[i].dlsrtcont_key;

        if (err.friendlyMsg)
        {
          result.warning = err.friendlyMsg;
          result.success = false;
        }

        // Nu nog de status zetten, tracking genereren en notificaties sturen.
        ins.setinspectstatus(ingesloten[i].dlsrtcont_key, 0); // Gepland(0).

        // Tracking bij het object.
        if (ingesloten[i].scen_key == 1)
          // Aanpassing van de plandatum door verschuiving van het bedrag in het MJOP scherm of door herplannen van (multi) taken in het periodiek taken scherm.
          ins.trackdeelupdate(ingesloten[i].ins_key,
                              L("lcl_ins_controle_obj_upd").format(ingesloten[i].disc_oms, ingesloten[i].srtcontrole_oms)
                                + "\n" + L("lcl_opdr_plandate") + ": "
                                + (mjob && nextdate && nextdate.getFullYear() < mjb_freeze_year
                                  ? mjb_freeze_year
                                  : (nextdate? (mjob? nextdate.getFullYear(): toDateTimeString(nextdate)) : L("lcl_empty")))
                                + L("lcl_trackto") + (mjob? plandatum.getFullYear(): toDateTimeString(plandatum)),
                              true); // Geen notificatie.
      }
      oRs.Close();

      var flextrack = [];
      if (ingesloten[i].dlsrtcont_key > 0)
        // Er is een inspectie gewijzigd of aangemaakt.
        flextrack = saveFlexKenmerkenInspection(ingesloten[i].dlsrtcont_key, insPresent, false, ingesloten);

      if (insPresent && ((insUpd && insUpd.trackarray.length) || flextrack.length))
        ins.trackinspectupdate(ingesloten[i].dlsrtcont_key, L("lcl_ins_controle_is_upd").format(ingesloten[0].disc_oms) + "\n" + insUpd.trackarray.concat(flextrack).join("\n"));
    }
    result.toaster = ingesloten.length === 1 ? L("lcl_ins_scheduled").format(ingesloten[0].disc_oms) : L("lcl_ins_scheduled_m").format(ingesloten.length);
  }
  else if (savemode == "C")
  { // Afmelden inspectie.
    var result = { success: true, deelsrtcontrole_datum: deelsrtcontrole_datum, savemode: savemode, warning: "" };

    for (var i = 0; i < ingesloten.length; i++)
    {
      // Nieuwe inspectie: de ins_deelsrtcontrole_key is NULL of als deze een waarde heeft dan is de status 0 of 2.
      var isNew = ingesloten[i].dlsrtcont_key < 0 || ingesloten[i].inspectiestatus < 5;
      // Is er een inspectie (ins_deelsrtcontrole) record aanwezig (ins_deelsrtcontrole_key is NULL).
      var insPresent = ingesloten[i].dlsrtcont_key > 0;

      // De periodieke taken direct afronden indien mogelijk.
      sql = "SELECT ins_srtcontrole_options"
          + "     , ctr_ismjob"
          + "  FROM ins_v_defined_inspect_xcp"
          + " WHERE ins_deel_key = " + ingesloten[i].ins_key
          + "   AND ins_srtcontrole_key = " + ingesloten[i].srtcont_key
          + "   AND ins_scenario_key = " + ingesloten[i].scen_key;
      oRs = Oracle.Execute(sql);
      var ins_srtcontrole_options = oRs("ins_srtcontrole_options").Value;
      var isMJOB = oRs("ctr_ismjob").Value == 1;
      oRs.Close();
      var hasActionFinish = false;
      if (finish)
      { // Wel even checken of de actie "Afronden" is ingeschakeld voor de periodiek taak of dat het een mjob taak is.
        hasActionFinish = (ins_srtcontrole_options & 8) == 8 || isMJOB == 1;
      }

      if (isNew) // Nieuwe inspectie: de ins_deelsrtcontrole_key is NULL of als deze een waarde heeft dan is de status 0 of 2.
      { // Bepaal de eerste niet successvolle controle methode. Is deze er niet dan kies maar de eerste successvolle controlemode.
        sql = "SELECT ins_controlemode_key"
            + "     , 1"
            + "  FROM ins_controlemode"
            + " WHERE ins_controlemode_success = 0"
            + " UNION "
            + "SELECT ins_controlemode_key"
            + "     , 2"
            + "  FROM ins_controlemode"
            + " WHERE ins_controlemode_success = 1"
            + " ORDER BY 2, 1";
        oRs = Oracle.Execute(sql);
        var controlemode = oRs("ins_controlemode_key").Value;
        oRs.Close();

        ingesloten[i].freezecost = -1;
        var ins_xcp_active_cost = S("ins_xcp_active_cost");
        var costarray = [];
        if (ins_xcp_active_cost & 1) costarray.push("COALESCE(ins_srtcontrole_kosten, 0)");
        if (ins_xcp_active_cost & 2) costarray.push("COALESCE(ins_srtcontrole_kosten2, 0)");
        if (ins_xcp_active_cost & 4) costarray.push("COALESCE(ins_srtcontrole_kosten3, 0)");
        if (ins_xcp_active_cost & 8) costarray.push("COALESCE(ins_srtcontrole_materiaal, 0)");
        var sqlcost = "";
        if (costarray.length > 0)
          sqlcost = "(" + costarray.join(" + ") + ") * ";
        var sql = "SELECT (ins_deel_aantal * "
                +         sqlcost
                + "       (COALESCE(ins_srtcontrole_percentage, 100) / 100)" + ") kosten" // Geen inflatiefactor want accorderen/voltooien is nu.
                + "  FROM ins_v_defined_inspect_xcp"
                + " WHERE ins_deel_key = " + ingesloten[i].ins_key
                + "   AND ins_srtcontrole_key = " + ingesloten[i].srtcont_key
                + "   AND ctr_ismjob = 0";

        var oRs = Oracle.Execute(sql);
        if (!oRs.eof)
            ingesloten[i].freezecost = oRs("kosten").Value;
        oRs.Close();

        // Bepaal eenheid van de soort controle.
        sql = "SELECT COALESCE((SELECT xcp.ins_srtcontroledl_xcp_eenheid"
            + "                   FROM ins_srtcontroledl_xcp xcp"
            + "                  WHERE ins_deel_key = " + ingesloten[i].ins_key
            + "                    AND ins_srtcontrole_key = " + ingesloten[i].srtcont_key
            + "                    AND ins_scenario_key = 1"
            + "                )"
            + "              , (SELECT isc.ins_srtcontrole_eenheid"
            + "                   FROM ins_srtcontrole isc"
            + "                  WHERE ins_srtcontrole_key = " + ingesloten[i].srtcont_key + ")) eenheid"
            + "  FROM DUAL";
        oRs = Oracle.Execute(sql);
        var eenheid = oRs("eenheid").Value;
        oRs.Close();

        // Er moet een taakafhandeling zijn meegegeven. Was deze succesvol?
        var sel_controlemode = getFParamInt("sel_controlemode"); // Taakafhandeling.
        var sql_s = "SELECT ins_controlemode_success"
                + "  FROM ins_controlemode"
                + " WHERE ins_controlemode_key = " + sel_controlemode;
        var oRs_s = Oracle.Execute(sql_s);
        var isSuccess = oRs_s("ins_controlemode_success").Value;
        oRs_s.Close();

        var firstinspect = false;
        // Zijn er inspecties geweest voor dit object of is er een plandatum voor dit object ingevuld zodat we de volgende inspectiedatum kunnen berekenen?
        // Bepaal de orginele controledatum.
        var sql = "SELECT ins_deelsrtcontrole_datum"
                + "     , (idsc.ins_deelsrtcontrole_datum + 1) dag_na_inspectdatum"
                + "  FROM ins_deelsrtcontrole idsc"
                + " WHERE idsc.ins_srtcontrole_key = " + ingesloten[i].srtcont_key
                + "   AND idsc.ins_deel_key = " + ingesloten[i].ins_key
                + "   AND idsc.ins_deelsrtcontrole_datum IS NOT NULL"
                + "   AND idsc.ins_scenario_key = 1" // Afmelden inspectie.
                + " ORDER BY 1 DESC";
        var oRs = Oracle.Execute(sql);
        // Voor MJOB worden de NIET succesvolle inspecties niet meegenomen voor de berekening van de volgende inspectie (ins.nextcyclusdate).
        // We moeten voorkomen dat de volgende inspectie dezelfde ins_deelsrtcontrole_datum_org datum heeft als de voorgaande NIET succesvolle inspectie,
        // Daarom wordt voor de NIET succesvolle inspectie de inspectie datum (ins_deelsrtcontrole_datum) ingevuld voor de ins_deelsrtcontrole_datum_org datum.
        // Voor periodieke en moment modus inspecties tellen de NIET succesvolle inspecties gewoon mee.
        if (oRs.eof || (!isSuccess && isMJOB))
        { // 1) Er zijn nog geen inspecties geweest voor dit object.Volgende inspectiedatum kun je niet berekenen
          // 2) Een niet succesvolle MJOB inspectie
          // => De eerstvolgende inspectiedatum gelijk aan de controledatum stellen.
          firstinspect = true;

          // Bereken de volgende orginele inspectiedatum (nextdate).
          // Bij mjob kan de laatste inspectie niet succesvol zijn. Dus ins.nextcyclusdate(ins_key, srtcont_key, scen_key) kan ik hier niet gebruiken.
          // 1) De laatste inspectie is succesvol voltooid: De volgende met ins.nextcyclusdate() te berekenen.
          // 2) De laatste inspectie is NIET succesvol voltooid. De volgende is in het freeze jaar.
          // 3) De laatste inspectie is geaccordeerd/bevroren/gestart(2): De volgende is een periode verder als het freeze jaar.
          // 4) Er is geen inspectie geweest of gestart.
          var startingpoint = ins.func_get_nextdate(ingesloten[i].ins_key, ingesloten[i].srtcont_key, ingesloten[i].scen_key, {mjob: mjob});
          var nextdate = new Date(startingpoint);
          var start_inspect_interval = new Date(startingpoint); // Vanaf welke datum de inspectie mag plaatsvinden.
        }
        else
        { // Bereken de volgende inspectiedatum.
          // Alleen Active Situatie (AS) soort controle's kunnen afgemeld worden dus voor scenario key moet 1 genomen worden.
          var sql = "SELECT ins.nextcyclusdate (" + ingesloten[i].ins_key + ", " + ingesloten[i].srtcont_key + ", 1, 1) nextdate FROM DUAL"
          var oRs2 = Oracle.Execute(sql);
          var nextdate = new Date(oRs2("nextdate").Value); // De berekende controledatum na de laatste inspectie.
          oRs2.Close();

          // Het eerste record is de laatste inspectie.
          var start_inspect_interval = new Date(oRs("dag_na_inspectdatum").Value); // Vanaf welke datum de inspectie mag plaatsvinden. Kan uiterlijk morgen zijn.
        }
        oRs.Close();

        var isPlanned = false;
        if (insPresent)
        {
          // Is er een plandatum? Dan is dit de volgende inspectiedatum.
          sql = "SELECT ins_deelsrtcontrole_plandatum"
              + "  FROM ins_deelsrtcontrole idsc"
              + " WHERE idsc.ins_deelsrtcontrole_status <= 5"
              + "   AND idsc.ins_deelsrtcontrole_key = " + ingesloten[i].dlsrtcont_key
              + "   AND idsc.ins_srtcontrole_key = " + ingesloten[i].srtcont_key
              + "   AND idsc.ins_deel_key = " + ingesloten[i].ins_key;
          oRs = Oracle.Execute(sql);

          if (!oRs.eof && oRs("ins_deelsrtcontrole_plandatum").Value != null)
          {
            // De plandatum is de volgende inspectiedatum
            // Als het de allereerste inspectie is dan is er nooit sprake van isPlanned.
            isPlanned = !firstinspect;
          }
          oRs.Close();
        }

        // Truncate datums op de dag of het uur afhankelijk van de eenheid.
        // Alleen nodig voor moment modus.
        if (eenheid == 0)
        {
          var deelsrtcontrole_datum_trunc = new Date(new Date(deelsrtcontrole_datum).setMinutes(0, 0, 0));
          var start_inspect_interval_trunc = new Date(new Date(start_inspect_interval).setMinutes(0, 0, 0));
        }
        else
        {
          var deelsrtcontrole_datum_trunc = new Date(deelsrtcontrole_datum.midnight());
          var start_inspect_interval_trunc = new Date(new Date(start_inspect_interval).midnight());
        }

        // Afhankelijk van de modus de inspectie(s) opslaan.
        if (ingesloten[i].inspectiemode == 0)
        { // Moment modus
          // De laatste datum die opgeslagen wordt is uiterlijk de opgegeven controledatum
          // De trunc waarde van de controle datum gebruiken.
          var firstone = true;
          while (firstinspect || isPlanned || (!isPlanned && start_inspect_interval_trunc <= deelsrtcontrole_datum_trunc))
          {
            // Als de allereerste inspectie van een moment modus taak wordt voltooid,
            // dan wordt de org datum niet meer op de uitvoerdatum gezet maar op de eerste van de die maand.
            // In het begin van de maand wil je de inspectie al uit kunnen voeren en niet pas op bijvoorbeeld 31 mei. Anders heb je maar 1 dag de tijd.
            // Dat doe je bij een moment modus taak door de org datum op de 1-ste van de maand te zetten.
            var orgdate = new Date(nextdate);
            if (firstinspect && eenheid == 4)
              orgdate.setDate(1);
            var fields =  [ { dbs: "prs_perslid_key",               typ: "key",      val: user_key,              track: L("lcl_name"),         foreign: "prs_perslid" },
                            { dbs: "ins_deelsrtcontrole_datum",     typ: "datetime", val: deelsrtcontrole_datum, track: L("lcl_ins_controle_datum") }, // De controledatum met tijd opslaan.
                            { dbs: "ins_deelsrtcontrole_plan_opm",  typ: "varchar",  val: plan_opm,              track: L("lcl_mjb_plan_opmerking"), len: 4000 },
                            { dbs: "ins_deelsrtcontrole_datum_org", typ: "datetime", val: orgdate } // De orginele controledatum met tijd opslaan. Kan al gevuld zijn met dezelfde waarde.
                          ];

            if (ingesloten[i].freezecost != -1)
              fields.push({ dbs: "ins_deelsrtcontrole_freezecost", typ: "float", val: ingesloten[i].freezecost });

            if (!insPresent)
            { // Er is nog geen inspectie record aangemaakt. De volgende velden dienen dan nog ingevuld te worden.
              fields.push({ dbs: "ins_deel_key",                  typ: "key",      val: ingesloten[i].ins_key });
              fields.push({ dbs: "ins_srtcontrole_key",           typ: "key",      val: ingesloten[i].srtcont_key });
              fields.push({ dbs: "ins_deelsrtcontrole_key",       typ: "key",      seq: "ins_s_ins_deelsrtcontrole_key" });
            }

            // Kan moeilijk bepalen of dit de laatste inspectie is in de reeks omdat huidige inspectie nog niet opgeslagen is (Veel uitrekenwerk).
            // Gemakkelijker is om altijd de niet succesvolle controlemode op te slaan.
            // Na afloop van de while lus kan dan de controlemode van de laatst opgeslagen inspectie goed gezet worden.
            fields.push({ dbs: "ins_controlemode_key",          typ: "key",      val: controlemode,       track: L("lcl_ins_controle_mode"), foreign: "ins_controlemode" } ); // Controlemode die niet succesvol is

            if (insPresent && firstone) // Alleen voor de alle eerste inspectie kan een inspectie record aanwezig zijn.
            { // Er is al een inspectie record (ins_deelsrtcontrole) aangemaakt. De status is Gepland(0) of In behandeling(2).
              // Plandatum kan gevuld blijven met de huidige waarde.
              var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + ingesloten[i].dlsrtcont_key, fields);
              var err = Oracle.Execute(insUpd.sql, true);
            }
            else
            { // Er is nog geen inspectie record aangemaakt.
              if (!firstone)
                ins.setinspectstatus(ingesloten[i].dlsrtcont_key, 6); // Vorige inspectie record Afronden(6).
              fields.push({dbs: "ins_deelsrtcontrole_status",    typ: "key",      val: (finish && hasActionFinish? 6: 5)});

              ins.testInspectInsert(ingesloten[i].ins_key, ingesloten[i].srtcont_key, 1);
              var insIns = buildInsert("ins_deelsrtcontrole", fields);
              ingesloten[i].dlsrtcont_key = insIns.sequences["ins_deelsrtcontrole_key"];
              var err = Oracle.Execute(insIns.sql, true);
            }
            result.deelsrtcontrole_key = ingesloten[i].dlsrtcont_key;

            if (err.friendlyMsg)
            {
              result.warning = err.friendlyMsg;
              result.success = false;
              break;
            }

            // Nu nog de status zetten, tracking genereren en notificaties sturen.
            ins.setinspectstatus(ingesloten[i].dlsrtcont_key, (finish && hasActionFinish? 6: 5)); // Afgemeld(5), History/Verwerkt/Voltooid(6).

            isPlanned = false;
            insPresent = false; // Als er terug in de while lus wordt gesprongen is er geen inspectie record aanwezig.
            firstone = false;
            firstinspect = false;

            // Bereken de volgende inspectiedatum.
            // De functie ins.nextcyclusdate levert de volgende inspectie datum met tijd op onafhankelijk van de eenheid.
            // Alleen Active Situatie (AS) soort controle's kunnen afgemeld worden dus voor scenario key moet 1 genomen worden.
            sql = "SELECT ins.nextcyclusdate (" + ingesloten[i].ins_key + ", " + ingesloten[i].srtcont_key + ", 1, 1) nextdate FROM DUAL"
            var oRs = Oracle.Execute(sql);
            nextdate = new Date(oRs("nextdate").Value);
            oRs.Close();

            if (eenheid == 0)
              var nextdate_trunc = new Date(new Date(nextdate).setMinutes(0, 0, 0));
            else
              var nextdate_trunc = new Date(nextdate.midnight());

            start_inspect_interval_trunc = nextdate_trunc;
          }
          if (!firstone)
          { // De controlemode en de opmerking van de laatste inspectie nog even op de aangegeven waarde zetten (i.p.v. niet succes waarde (controlemode) en lege waarde (opmerking)).
            var fields =  [ { dbs: "ins_controlemode_key",          typ: "key",      frm: "sel_controlemode", track: L("lcl_ins_controle_mode"), foreign: "ins_controlemode" },
                            { dbs: "ins_deelsrtcontrole_opmerking", typ: "varchar",  frm: "opmerk",           track: L("lcl_remark"),            len: 4000 } ];
            fields.push({ dbs: "ins_deelsrtcontrole_plan_opm",      typ: "varchar",  val: plan_opm,           track: L("lcl_mjb_plan_opmerking"), len: 4000 });
            var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + result.deelsrtcontrole_key, fields);
            var err = Oracle.Execute(insUpd.sql, true);
          }
        }
        else
        { // Interval modus
          var fields =  [ { dbs: "ins_deelsrtcontrole_opmerking", typ: "varchar",  frm: "opmerk",                  track: L("lcl_remark"),       len: 4000 },
                          { dbs: "prs_perslid_key",               typ: "key",      val: user_key,                  track: L("lcl_name"),         foreign: "prs_perslid" },
                          { dbs: "ins_deelsrtcontrole_plan_opm",  typ: "varchar",  val: plan_opm,                  track: L("lcl_mjb_plan_opmerking"), len: 4000 },
                          { dbs: "ins_deelsrtcontrole_datum",     typ: "datetime", val: deelsrtcontrole_datum,     track: L("lcl_ins_controle_datum") }, // De controledatum met tijd opslaan.
                          { dbs: "ins_controlemode_key",          typ: "key",      frm: "sel_controlemode",        track: L("lcl_ins_controle_mode"), foreign: "ins_controlemode" },
                          { dbs: "ins_deelsrtcontrole_datum_org", typ: "datetime", val: nextdate } // De orginele controledatum met tijd opslaan. Kan al gevuld zijn met dezelfde waarde.
                        ];

          if (ingesloten[i].freezecost != -1)
            fields.push({ dbs: "ins_deelsrtcontrole_freezecost", typ: "float", val: ingesloten[i].freezecost });

          if (!insPresent)
          { // Er is nog geen inspectie record aangemaakt. De volgende velden dienen dan nog ingevuld te worden.
            fields.push({ dbs: "ins_deel_key",                  typ: "key",      val: ingesloten[i].ins_key });
            fields.push({ dbs: "ins_srtcontrole_key",           typ: "key",      val: ingesloten[i].srtcont_key });
            fields.push({ dbs: "ins_deelsrtcontrole_key",       typ: "key",      seq: "ins_s_ins_deelsrtcontrole_key" });
            fields.push({ dbs: "ins_deelsrtcontrole_status",    typ: "key",      val: (finish && hasActionFinish? 6: 5) });
          }

          if (insPresent)
          { // Er is al een inspectie record (ins_deelsrtcontrole) aangemaakt. De status is Gepland(0) of In behandeling(2)
            // Plandatum kan gevuld blijven met de huidige waarde.
            var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + ingesloten[i].dlsrtcont_key, fields);
            var err = Oracle.Execute(insUpd.sql, true);
          }
          else
          { // Er is nog geen inspectie record aangemaakt.
            ins.testInspectInsert(ingesloten[i].ins_key, ingesloten[i].srtcont_key, 1);
            var insIns = buildInsert("ins_deelsrtcontrole", fields);
            ingesloten[i].dlsrtcont_key = insIns.sequences["ins_deelsrtcontrole_key"];
            var err = Oracle.Execute(insIns.sql, true);
          }
          result.deelsrtcontrole_key = ingesloten[i].dlsrtcont_key;

          if (err.friendlyMsg)
          {
            result.warning = err.friendlyMsg;
            result.success = false;
            break;
          }

          // Nu nog de status zetten, tracking genereren en notificaties sturen.
          ins.setinspectstatus(ingesloten[i].dlsrtcont_key, (finish && hasActionFinish? 6: 5)); // Afgemeld(5), History/Verwerkt/Voltooid(6).

          isPlanned = false;
        }
      }
      else
      { // uitgevoerde inspectie met de status Afgemeld(5).
        // Datum kan niet meer aangepast worden.
        var fields =  [ { dbs: "ins_deel_key",                  typ: "key",      val: ingesloten[i].ins_key },
                        { dbs: "ins_srtcontrole_key",           typ: "key",      val: ingesloten[i].srtcont_key },
                        { dbs: "ins_controlemode_key",          typ: "key",      frm: "sel_controlemode",        track: L("lcl_ins_controle_mode"), foreign: "ins_controlemode" },
                        { dbs: "prs_perslid_key",               typ: "key",      val: user_key }
                      ];

        if (!multi) // Bij multi de opmerking niet opslaan. De opmerking kon ook niet ingevuld worden.
          fields.push({ dbs: "ins_deelsrtcontrole_opmerking", typ: "varchar",  frm: "opmerk",                  track: L("lcl_remark"),       len: 4000 });

        var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + ingesloten[i].dlsrtcont_key, fields);
        var err = Oracle.Execute(insUpd.sql, true);

        if (err.friendlyMsg)
        {
          result.warning = err.friendlyMsg;
          result.success = false;
        }

        if (finish && hasActionFinish)
          // Nu nog de status History/Verwerkt/Voltooid(6) zetten, tracking genereren en notificaties sturen.
          ins.setinspectstatus(ingesloten[i].dlsrtcont_key, 6); // History/Verwerkt/Voltooid(6).
      }

      var flextrack = [];
      if (ingesloten[i].dlsrtcont_key > 0)
        // Er is een inspectie gewijzigd of aangemaakt.
        flextrack = saveFlexKenmerkenInspection(ingesloten[i].dlsrtcont_key, insPresent, false, ingesloten);

      if (insPresent && ((insUpd && insUpd.trackarray.length) || flextrack.length))
        ins.trackinspectupdate(ingesloten[i].dlsrtcont_key, L("lcl_ins_controle_is_upd").format(ingesloten[0].disc_oms) + "\n" + insUpd.trackarray.concat(flextrack).join("\n"));
    }
    result.toaster = ingesloten.length === 1
                      ? (finish ? L("lcl_ins_finished")   : L("lcl_ins_closed")).format(ingesloten[0].disc_oms)
                      : (finish ? L("lcl_ins_finished_m") : L("lcl_ins_closed_m")).format(ingesloten.length);
  }
  else if (savemode == "E")
  { // Wijzigen inspectie (Edit). Update van de gegevens (plandatum, opmerking en flexkenmerken).
    var result = { success: true, plandatum: plandatum,  deelsrtcontrole_key: ingesloten[0].dlsrtcont_key, savemode: savemode, warning: "" };
    var isScenario = ingesloten[0].scen_key > 1;

    var mjobdelete = false;
    // Kunnen we het plan record verwijderen?
    // Het plan record van een scenario mogen we nooit verwijderen. Daar dan de plandatum leeg maken.
    if (mjob)
    { // Nieuwe plandatum vanuit het mjob scherm ontvangen.
      // Taken die verschoven moeten worden naar een jaar voor het startjaar zijn er al uitgefilterd.

      // Als het jaar van de plandatum hetzelfde is als het jaar van de orginele datum, dan kan het plan record verwijderd worden.
      // Bestand is aangeroepen vanuit mjob scherm (mjob=1) dus ismjob en isjaarlijks zullen altijd true moeten zijn.
      // Toch even checken voor de zekerheid, zodat geen inspecties van periodieke taken worden verwijderd.
      // Is het een mjob discipline en is de eenheid jaarlijks?
      sql = "SELECT cdp.ctr_disc_params_ismjob"
          + "     , isc.ins_srtcontrole_eenheid"
          + "  FROM ins_srtcontrole isc"
          + "     , ctr_disc_params cdp"
          + " WHERE isc.ctr_discipline_key = cdp.ctr_ins_discipline_key"
          + "   AND isc.ins_srtcontrole_key = " + ingesloten[0].srtcont_key;
      oRs = Oracle.Execute(sql);
      var ismjob = !oRs.eof && oRs("ctr_disc_params_ismjob").Value == 1;
      var isjaarlijks = oRs("ins_srtcontrole_eenheid").Value == 4;
      oRs.Close();

      // Zijn er inspecties geweest voor dit object of is er een plandatum voor dit object ingevuld zodat we de volgende inspectiedatum kunnen berekenen?
      var sql = "SELECT ins_deelsrtcontrole_datum"
              + "  FROM ins_deelsrtcontrole idsc"
              + " WHERE idsc.ins_srtcontrole_key = " + ingesloten[0].srtcont_key
              + "   AND idsc.ins_deel_key = " + ingesloten[0].ins_key
              + "   AND idsc.ins_scenario_key = " + ingesloten[0].scen_key
              + "   AND idsc.ins_deelsrtcontrole_datum IS NOT NULL"; // Er is geinspecteerd.
      var oRs = Oracle.Execute(sql);

      var nextdate = null;
      if (!oRs.eof)
      { // Bereken de volgende orginele inspectiedatum (nextdate).
        // Het is schuiven vanuit mjob scherm. De laatste inspectie kan niet succesvol zijn. Dus ins.nextcyclusdate(ins_key, srtcont_key, scen_key) kan ik hier niet gebruiken.
        var nextdate = ins.func_get_nextdate(ingesloten[0].ins_key, ingesloten[0].srtcont_key, ingesloten[0].scen_key, {mjob: mjob});

        // Is jaar plandatum gelijk aan jaar orginele datum?
        var plandatum_jaar = plandatum.getFullYear();
        var nextdate_jaar = nextdate.getFullYear();

        if (ismjob && isjaarlijks && plandatum_jaar == nextdate_jaar)
        { // Verwijder het inspectie record en ga verder met het volgende object.
          mjobdelete = true;
        }
      }
      else
      { // Er zijn nog geen inspecties geweest voor dit object en er is nog geen plandatum voor dit object ingevuld.
        // Volgende inspectiedatum kun je niet berekenen met de functie ins.nextcyclusdate() en is dus onbekend (leeg)

        var plandatum_jaar = plandatum.getFullYear();
        // De inspectiedatums voor taken die nog nooit een inspectie hebben gehad is voor een Vervanging(2) of Certificering(3)
        // n periodes verder dan de registratie/aanmaak datum van het object.
        // Voor een controle is er geen inspectiedatum en wordt er dan altijd "Eerste controle" in beeld getoond.
        // Ofwel een controle inspectie kun je direct vanaf het aanmaken van het object doen.
        // Voor controles(1):
        //    - Als de planning in het mjb_freeze_year jaar is dan kan het inspectierecord verwijderd worden.
        // Voor Vervanging(2) en Certificering(3):
        //    - Valt de laatste niet gedane inspectiedatum tussen of in het mjb_start_year en het mjb_freeze_year,
        //      dan is mjb_freeze_year het inspectie jaar.
        //      Als de planning dan in het inspectie jaar (mjb_freeze_year) is, dan kan het inspectierecord verwijderd worden.
        //    - Valt de laatste niet gedane inspectiedatum NIET tussen of in het mjb_start_year en het mjb_freeze_year,
        //      dan is de laatste niet gedane inspectiedatum + periode het inspectie jaar.
        //      Als de planning dan in hetzelfde jaar als het inspectie jaar (laatste + periode) is, dan kan het inspectierecord verwijderd worden.
        if (ismjob && isjaarlijks)
        {
          sql = "SELECT xcp.ins_srtcontrole_periode"
              + "     , xcp.ctr_controle_type"
              + "     , xcp.ins_deel_aanmaak"  // Aanmaakdatum (ins_deel_aanmaak) is verplicht en heeft dus altijd een waarde.
              + "     , xcp.ins_srtcontroledl_xcp_startdat"
              + "  FROM ins_v_defined_inspect_xcp xcp"
              + " WHERE xcp.ins_deel_key = " + ingesloten[0].ins_key
              + "   AND xcp.ins_srtcontrole_key = " + ingesloten[0].srtcont_key
              + "   AND xcp.ins_scenario_key = " + ingesloten[0].scen_key
          var oRsG = Oracle.Execute(sql);
          var periode = oRsG("ins_srtcontrole_periode").Value;
          var srtcontrole_type = oRsG("ctr_controle_type").Value;
          var aanmaakdatum = new Date(oRsG("ins_deel_aanmaak").Value);
          var aanmaakdatum_jaar =  aanmaakdatum.getFullYear();
          var startdatum = oRsG("ins_srtcontroledl_xcp_startdat").Value != null? new Date(oRsG("ins_srtcontroledl_xcp_startdat").Value) : null;
          var startdatum_jaar = startdatum != null? startdatum.getFullYear() : null;
          var sysdate_jaar = new Date().getFullYear();
          oRsG.Close();

          // Er zijn nog geen inspecties geweest voor dit object en er is nog geen plandatum voor dit object ingevuld.
          if (startdatum != null)
          { // Er is een startdatum ingevuld.
            if (startdatum_jaar >= aanmaakdatum_jaar)
            {
              if ((startdatum_jaar < mjb_freeze_year && plandatum_jaar == mjb_freeze_year) ||
                  (startdatum_jaar >= mjb_freeze_year && plandatum_jaar == startdatum_jaar))
                mjobdelete = true;
            }
            else
            { // Er is een startdatum ingevuld, maar de aanmaakdatum is later (startdatum_jaar < aanmaakdatum_jaar)
              if ((srtcontrole_type == 1 &&                             // 1: Controle.
                   ((aanmaakdatum_jaar < mjb_freeze_year && plandatum_jaar == mjb_freeze_year) ||
                    (aanmaakdatum_jaar >= mjb_freeze_year && plandatum_jaar == aanmaakdatum_jaar)))
                 ||
                  ((srtcontrole_type == 2 || srtcontrole_type == 3) &&  // 2: Vervanging, 3: Certificering.
                    ((aanmaakdatum_jaar + periode < mjb_freeze_year && plandatum_jaar == mjb_freeze_year) ||
                     (aanmaakdatum_jaar + periode >= mjb_freeze_year && plandatum_jaar == aanmaakdatum_jaar + periode))))
                mjobdelete = true;
            }
          }
          else if (aanmaakdatum_jaar >= sysdate_jaar)
          { // Aanmaakdatum is in de toekomst.
            if ((srtcontrole_type == 1 &&                             // 1: Controle.
                 ((aanmaakdatum_jaar < mjb_freeze_year && plandatum_jaar == mjb_freeze_year) ||
                  (aanmaakdatum_jaar >= mjb_freeze_year && plandatum_jaar == aanmaakdatum_jaar)))
               ||
                ((srtcontrole_type == 2 || srtcontrole_type == 3) &&  // 2: Vervanging, 3: Certificering.
                  ((aanmaakdatum_jaar + periode < mjb_freeze_year && plandatum_jaar == mjb_freeze_year) ||
                   (aanmaakdatum_jaar + periode >= mjb_freeze_year && plandatum_jaar == aanmaakdatum_jaar + periode))))
              mjobdelete = true;
          }
          else
          {
            // Is er een geaccordeerde of ter uitvoering staande inspectie? De volgende inspectie is dan een periode verder.
            var sqla = "SELECT ins_deelsrtcontrole_freezedate"
                     + "     , ADD_MONTHS(ins_deelsrtcontrole_freezedate, 12 * " + periode + ") nextdate"
                     + "  FROM ins_deelsrtcontrole idsc"
                     + " WHERE idsc.ins_srtcontrole_key = " + ingesloten[0].srtcont_key
                     + "   AND idsc.ins_deel_key = " + ingesloten[0].ins_key
                     + "   AND idsc.ins_scenario_key = " + ingesloten[0].scen_key
                     + "   AND idsc.ins_deelsrtcontrole_status IN (2, 3)"; // Geaccordeerde/gestarte(2) of ter uitvoering(3) staande inspectie.
            var oRsa = Oracle.Execute(sqla);

            if (!oRsa.eof) // Er is een geaccordeerde inspectie.
            {
              var nextdate = new Date(oRsa("nextdate").Value);
              var nextdate_jaar = nextdate.getFullYear();
              if (nextdate_jaar == plandatum_jaar)
                mjobdelete = true;
            }
            else if (srtcontrole_type == 1 && plandatum_jaar == mjb_freeze_year) // Controles(1).
              mjobdelete = true;
            else if (srtcontrole_type == 2 || srtcontrole_type == 3) // Vervanging(2) of Certificering(3).
            { // Bereken de volgende inspectiedatum.
              // Alleen Active Situatie (AS) soort controle's kunnen gewijzigd worden dus voor scenario key moet 1 (of null) genomen worden.
              sql = "SELECT ins.nextcyclusdate (" + ingesloten[0].ins_key
                  + "                         , " + ingesloten[0].srtcont_key
                  + "                         , " + ingesloten[0].scen_key
                  + "                         , 0) nextdate" // 1-ste vandaag of in de toekomst(0).
                  + "  FROM ins_v_defined_inspect_xcp xcp"
                  + " WHERE xcp.ins_deel_key = " + ingesloten[0].ins_key
                  + "   AND xcp.ins_srtcontrole_key = " + ingesloten[0].srtcont_key
                  + "   AND xcp.ins_scenario_key = " + ingesloten[0].scen_key
              var oRsN = Oracle.Execute(sql);
              var nextdate = new Date(oRsN("nextdate").Value);
              var nextdate_jaar = nextdate.getFullYear();
              var nextdate_jaar_before = nextdate_jaar - periode
              oRsN.Close();

              // Als nextdate_jaar_before of nextdate_jaar binnen mjb_start_year en mjb_freeze_year valt en de planning in het mjb_freeze_year jaar is
              // of
              // als nextdate_jaar_before voor het mjb_start_year jaar valt en nextdate_jaar na het mjb_freeze_year jaar
              // dan kan het inspectie record verwijderd worden.
              if ((((nextdate_jaar_before >= S("mjb_start_year") && nextdate_jaar_before <= mjb_freeze_year) ||
                    (nextdate_jaar >= S("mjb_start_year") && nextdate_jaar <= mjb_freeze_year)) &&
                   plandatum_jaar == mjb_freeze_year) ||
                  ((nextdate_jaar_before < S("mjb_start_year") && nextdate_jaar > mjb_freeze_year) &&
                   plandatum_jaar == nextdate_jaar)
                 )
                mjobdelete = true;
            }
            oRsa.Close();
          }
        }
      }
      oRs.Close();
    }

    if (mjobdelete && !isScenario)
    { // Verwijder het inspectie record.
      var sql = "DELETE FROM ins_deelsrtcontrole"
              + " WHERE ins_deel_key = " + ingesloten[0].ins_key
              + "   AND ins_srtcontrole_key = " + ingesloten[0].srtcont_key
              + "   AND ins_deelsrtcontrole_status = 0"
              + "   AND ins_scenario_key = " + ingesloten[0].scen_key;
      var err = Oracle.Execute(sql, true);
    }
    else
    {
      var fields = [ { dbs: "ins_deelsrtcontrole_opmerking", typ: "varchar",  frm: "opmerk",              track: L("lcl_remark"),       len: 4000 }
                   ];
      fields.push({ dbs: "ins_deelsrtcontrole_plan_opm", typ: "varchar",  val: plan_opm, track: L("lcl_mjb_plan_opmerking"), len: 4000 });

      if (isScenario && mjobdelete)
        fields.push( { dbs: "ins_deelsrtcontrole_plandatum", typ: "datetime", val: "",                    track: L("lcl_opdr_plandate") } );
      else if (mjob)
        fields.push( { dbs: "ins_deelsrtcontrole_plandatum", typ: "datetime", val: plandatum,             track: L("lcl_opdr_plandate") } );
      else // Periodieke taken.
        fields.push( { dbs: "ins_deelsrtcontrole_plandatum", typ: "datetime", frm: "plandatum",           track: L("lcl_opdr_plandate") } );

      if (getDeelsrtcontroleDate)
        fields.push( { dbs: "ins_deelsrtcontrole_datum",     typ: "datetime", val: deelsrtcontrole_datum, track: L("lcl_ins_controle_datum") } );

      if (canMsuEdit)
        fields.push( { dbs: "ins_controlemode_key",          typ: "key",      frm: "sel_controlemode",    track: L("lcl_ins_controle_mode"), foreign: "ins_controlemode" } );

      var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + ingesloten[0].dlsrtcont_key, fields);
      var err = Oracle.Execute(insUpd.sql, true);
    }

    if (err.friendlyMsg)
    {
      result.warning = err.friendlyMsg;
      result.success = false;
    }

    // Tracking bij het object.
    // Aanpassing van de plandatum door verschuiving van het bedrag in het MJOP scherm.
    var dlsrtcont_plandatum = ingesloten[0].dlsrtcont_plandatum == -1? L("lcl_empty") : (mjob? ingesloten[0].dlsrtcont_plandatum.getFullYear() : toDateTimeString(ingesloten[0].dlsrtcont_plandatum));
    if (plandatum && plandatum != dlsrtcont_plandatum && !isScenario)
      ins.trackdeelupdate(ingesloten[0].ins_key,
                          L("lcl_ins_controle_obj_upd").format(disc_oms, srtcontrole_oms)
                            + "\n" + L("lcl_opdr_plandate") + ": " + dlsrtcont_plandatum +  L("lcl_trackto") + (mjob? plandatum.getFullYear() : toDateTimeString(plandatum)),
                          true); // Geen notificatie.

    var flextrack = saveFlexKenmerkenInspection(ingesloten[0].dlsrtcont_key, insPresent, mjobdelete);

    if ((!mjobdelete || (isScenario && mjobdelete)) && (insUpd.trackarray.length || flextrack.length))
      ins.trackinspectupdate(ingesloten[0].dlsrtcont_key, L("lcl_ins_controle_is_upd").format(ingesloten[0].disc_oms) + "\n" + insUpd.trackarray.concat(flextrack).join("\n"));

    // Als er voltooid moet worden, dan moet de status aangepast worden.
    if (finish)
      // De status zetten, tracking genereren en notificaties sturen.
      ins.setinspectstatus(ingesloten[0].dlsrtcont_key, 6); // History/Verwerkt/Voltooid(6).
  }
  else if (savemode == "D")
  { // Verwijderen van het deelsrtcontrole record kan alleen voorkomen voor mjob als een verschoven bedrag weer in het originele jaar wordt gezet (mjob = true).
    var result = { success: true, savemode: savemode, warning: "" };
    var sql = "";
    var err;
    for (var i = 0; i < ingesloten.length; i++)
    {
      if (ingesloten[i].scen_key == 1)
      { // Actuele situatie.
        // Plandatum voor de tracking ophalen.
        var plandatum;
        sql = "SELECT ins_deelsrtcontrole_plandatum"
            + "  FROM ins_deelsrtcontrole"
            + " WHERE ins_deel_key               = " + ingesloten[i].ins_key
            + "   AND ins_srtcontrole_key        = " + ingesloten[i].srtcont_key
            + "   AND ins_deelsrtcontrole_status = 0"
            + "   AND ins_scenario_key           = " + ingesloten[i].scen_key;
        var oRs = Oracle.Execute(sql);
        // Record moet aanwezig zijn.
        var  plandatum = new Date(oRs("ins_deelsrtcontrole_plandatum").Value);
        oRs.Close();

        sql = "DELETE FROM ins_deelsrtcontrole"
            + " WHERE ins_deel_key               = " + ingesloten[i].ins_key
            + "   AND ins_srtcontrole_key        = " + ingesloten[i].srtcont_key
            + "   AND ins_deelsrtcontrole_status = 0"
            + "   AND ins_scenario_key           = " + ingesloten[i].scen_key;

        err = Oracle.Execute(sql, true);

        if (err.friendlyMsg && result.success !== false)
        {
          result.warning = err.friendlyMsg;
          result.success = false;
        }

        // Bereken de volgende orginele inspectiedatum (nextdate).
        // Het is mjob. De laatste inspectie kan niet succesvol zijn. Dus ins.nextcyclusdate(ins_key, srtcont_key, scen_key) kan ik hier niet gebruiken.
        // 1) De laatste inspectie is succesvol voltooid: De volgende met ins.nextcyclusdate() te berekenen.
        // 2) De laatste inspectie is NIET succesvol voltooid. De volgende is in het freeze jaar.
        // 3) De laatste inspectie is geaccordeerd/bevroren/gestart(2): De volgende is een periode verder als het freeze jaar.
        // 4) Er is geen inspectie geweest of gestart.
        var nextdate = ins.func_get_nextdate(ingesloten[i].ins_key, ingesloten[i].srtcont_key, ingesloten[i].scen_key, {mjob: mjob}); // mjob = true

        // Tracking bij het object.
        if (ingesloten[i].scen_key == 1)
          // Aanpassing van de plandatum door verschuiving van het bedrag in het MJOP scherm.
          ins.trackdeelupdate(ingesloten[i].ins_key,
                              L("lcl_ins_controle_obj_upd").format(disc_oms, srtcontrole_oms)
                                + "\n" + L("lcl_opdr_plandate") + ": " + plandatum.getFullYear() +  L("lcl_trackto")
                                + (mjob && nextdate && nextdate.getFullYear() < mjb_freeze_year
                                  ? mjb_freeze_year
                                  : (nextdate? nextdate.getFullYear() : L("lcl_empty"))),
                                true); // Geen notificatie.
      }
      else
      { // Scenario. Dan inspectie record niet verwijderen maar de plandatum leeg maken.
        var fields = [ { dbs: "ins_deelsrtcontrole_plandatum", typ: "datetime", val: "",       track: L("lcl_opdr_plandate") } ];

        var insUpd = buildTrackingUpdate("ins_deelsrtcontrole", " ins_deelsrtcontrole_key = " + ingesloten[i].dlsrtcont_key, fields);
        var err = Oracle.Execute(insUpd.sql, true);

        if (err.friendlyMsg)
        {
          result.warning = err.friendlyMsg;
          result.success = false;
        }

        // Tracking bij het inspectie record van het scenario.
        ins.trackinspectupdate(ingesloten[i].dlsrtcont_key, L("lcl_ins_controle_is_upd").format(ingesloten[i].disc_oms) + "\n" + insUpd.trackarray.join("\n"));
      }
    }
  }
}

Response.Write(JSON.stringify(result));
%>
<% ASPPAGE_END(); %>
