<% /*
    $Revision$
    $Id$

    File:           model_issues.inc

    Description:    Melding model
    Parameters:
    Context:

    Notes:          TODO on demand: PUT/POST/DELETE
                    TODO test autorisatie-toepassing (MGE?)
*/

%>
<!-- #include file="../Shared/discx3d.inc" -->
<!-- #include file="../mld/mld.inc" -->
<!-- #include file="../mld/mld_edit_note.inc" -->
<!-- #include file="model_issueobjects.inc"-->
<!-- #include file="model_issuetypes.inc"-->
<!-- #include file="model_notes.inc"-->
<!-- #include file="model_orders.inc"-->
<!-- #include file="./model_custom_fields.inc"-->
<!-- #include file="./model_fac_tracking.inc"-->
<!-- #include file="./model_mld_kenmerk.inc"-->
<%

function fnextendedStatus (oRs, field, model)
{
  var xstatus = mld.getextendedmldstatus(oRs("mld_melding_status").Value, oRs("mld_melding_key").Value);
  return xstatus;
}

function model_issues(mld_key, params)
{
    params = params || {};
    this.module =       "MLD";
    this.table =        "mld_melding";
    this.primary =      "mld_melding_key";
    this.records_name = "issues";
    this.record_name =  "issue";
    this.fields =
            {"id"         : { dbs: "mld_melding_key",                              typ: "key" },
             "name"       : { dbs: "mld_melding_id",                               typ: "varchar",  sql: "ins_srtdiscipline.ins_srtdiscipline_prefix||mld_melding.mld_melding_key", label: L("lcl_call_number"), readonly: true },
             "contact"    : { dbs: "prs_perslid_key",                              typ: "key",      foreign: "prs_perslid",                label: L("lcl_mld_name"),          track: true },
             "requestor"  : { dbs: "prs_perslid_key_voor",                         typ: "key",      foreign: "prs_perslid",                label: L("lcl_mld_call_for"),      track: true },
             "extcontact" : { dbs: "mld_melding_naam_ext",                         typ: "varchar",                                         label: L("lcl_mld_naam_ext"),      track: true },
             "extemail"   : { dbs: "mld_melding_email_ext",                        typ: "varchar",                                         label: L("lcl_mld_email_ext"),     track: true },
             "extphone"   : { dbs: "mld_melding_tel_ext",                          typ: "varchar",                                         label: L("lcl_mld_tel_ext"),       track: true },

             "issuedate"  : { dbs: "mld_melding_datum",                            typ: "datetime",                                        label: L("lcl_mld_date_time"),     track: true,  filter: "range" },
             "enddate"    : { dbs: "mld_melding_einddatum",                        typ: "datetime",                                        label: L("lcl_mld_enddate"),       track: true},
             "actiondate" : { dbs: "mld_melding_actiedatum",                       typ: "datetime",                                        label: L("lcl_mld_actiondate"),    track: true},
             "treatmentteam":{dbs: "mld_ins_discipline_key",                       typ: "key",      foreign: "mld_discipline",             label: L("mld_processing_group"),   track: true },
             "issuetype"  : { dbs: "mld_stdmelding_key",                           typ: "key",      foreign: "mld_stdmelding",             label: L("lcl_complain"),          track: true },
             "description": { dbs: "mld_melding_omschrijving",                     typ: "clob",     len: S("mld_melding_oms_maxlen"),      label: L("lcl_descr"),             track: true,  filter: "like" },
             "remark"     : { dbs: "mld_melding_opmerking",                        typ: "varchar",                                         label: L("lcl_remark"),            track: true},
             "subject"    : { dbs: "mld_melding_onderwerp",                        typ: "varchar",                                         label: L("lcl_mld_subject"),       track: true, len: 200},
             "status"     : { dbs: "mld_melding_status",                           typ: "key",      foreign: mld.getmldstatustext,         label: L("lcl_status"),            track: true,  filter: mld.getStatusSql },
             "conceptstatus": { dbs: "mld_melding_conceptstatus",                  typ: "number",                                          label: L("lcl_mld_conceptstatus"), track: true},
             "flag"       : { dbs: "mld_melding_flag",                             typ: "key", /* geen echte key, wel key-gedrag */        label: L("lcl_mld_flags"),         track: true },
             "origin"     : { dbs: "mld_meldbron_key",                             typ: "key",      foreign: { tbl: "mld_meldbron",
                                                                                                               key: "mld_meldbron_key",
                                                                                                               desc: "mld_meldbron_omschrijving" },
                                                                                                                                           label: L("lcl_mld_meldbron"),      track: true },
             "department" : { dbs: "prs_afdeling_key",                             typ: "key",      foreign: "prs_afdeling",               label: L("lcl_mld_afdeling"),      track: true },
             "account"    : { dbs: "prs_kostenplaats_key",                         typ: "key",      foreign: "prs_kostenplaats",           label: L("lcl_account"),           track: true },
             "handler"    : { dbs: "mld_melding_behandelaar_key",                  typ: "key",      foreign: "prs_perslid",                label: L("lcl_mld_behandelaar"),   track: true },
             "processor"  : { dbs: "mld_melding_behandelaar2_key",                 typ: "key",      foreign: "prs_perslid",                label: L("lcl_mld_processor"),     track: true },
             "location"   : { dbs: "mld_alg_locatie_key",                          typ: "key",      foreign: "alg_locatie",                label: L("lcl_location"),          track: true },
             "address"    : { dbs: "mld_adres_key",                                typ: "key",      foreign: "mld_v_afleveradres",         label: L("lcl_delivery_address"),  track: true },
             "building"   : { dbs: "alg_v_allonroerendgoed.alg_gebouw_key",        typ: "key",      foreign: "alg_gebouw",                 label: L("lcl_building"),          track: true },
             "floor"      : { dbs: "alg_v_allonroerendgoed.alg_verdieping_key",    typ: "key",      foreign: "alg_verdieping",             label: L("lcl_floor"),             track: true },
             "room"       : { dbs: "alg_v_allonroerendgoed.alg_ruimte_key",        typ: "key",      foreign: "alg_ruimte",                 label: L("lcl_room"),              track: true },
             "terrain"    : { dbs: "alg_v_allonroerendgoed.alg_terreinsector_key", typ: "key",      foreign: "alg_terreinsector",          label: L("lcl_room"),              track: true },
             "parent"     : { dbs: "mld_melding_parentkey",                        typ: "key",      xforeign: "mld_melding",               label: L("lcl_mld_completion_in"), track: true },
             "continuedfrom": { dbs: "mld_melding_start_key",                      typ: "key",      xforeign: "mld_melding",               label: L("lcl_mld_continue_of"),   track: true },
             "extern_id"  : { dbs: "mld_melding_externnr",                         typ: "varchar",                                         label: L("lcl_mld_externr"),       track: true },
             "extern_sync": { dbs: "mld_melding_externsyncdate",                   typ: "datetime", "withseconds": true,                   label: L("extern_syncdate"),       readonly: !(user.has("WEB_FACTAB") || user.has("WEB_FACXNR")) },
             "kto_key"    : { dbs: "mld_melding_kto_key",                          typ: "key",                                             label: L("lcl_mld_linktoparent"),  track: true },
             "kto_type"   : { dbs: "mld_melding_kto_type",                         typ: "varchar",                                         label: L("lcl_mld_kto"),           track: true },
             "kto"        : { dbs: "mld_melding_kto",                              typ: "number",                                          label: L("lcl_mld_kto_invite"),    track: true },
             "reservation": { dbs: "res_rsv_ruimte_key",                           typ: "key",      foreign: "res_rsv_ruimte",             label: L("lcl_reservation"),       track: true },
             "priority"   : { dbs: "mld_melding_spoed",                            typ: "key",                                             label: L("lcl_mld_urg"),           track: true },
             "xstatus"    : { dbs: "mld_melding_status",
                              val: fnextendedStatus,                               typ: "key",      foreign: mld.getmldstatustext,         label: L("lcl_extended_status"),   track: true, readonly: true },
             "public"     : { dbs: "mld_melding_publiek",                          typ: "check0",                                          label: L("lcl_mld_publiek") },
             "indult"     : { dbs: "mld_melding_indult",                           typ: "check0",                                          label: L("lcl_mld_indult"),        track: true },
             "completed"  : { dbs: "mld_melding_afgerond",                         typ: "check0",                                          label: L("lcl_mld_afgerond"),      track: true },
             "actioncode" : { dbs: "mld_melding_actiecode",                        typ: "number",                                          label: L("lcl_mld_actiecode"),     track: true },
             "dwgx"       : { dbs: "mld_melding_dwgx",                             typ: "float",                                           label: L("lcl_mld_melding_dwg")+" x" },
             "dwgy"       : { dbs: "mld_melding_dwgy",                             typ: "float",                                           label: L("lcl_mld_melding_dwg")+" y" },
             "dwgz"       : { dbs: "mld_melding_dwgz",                             typ: "float",                                           label: L("lcl_mld_melding_dwg")+" z" },
             "gpsx"       : { dbs: "mld_melding_x",                                typ: "float",                                           label: L("lcl_mld_melding_gps")+" x" },
             "gpsy"       : { dbs: "mld_melding_y",                                typ: "float",                                           label: L("lcl_mld_melding_gps")+" y" },
             "gpsz"       : { dbs: "mld_melding_z",                                typ: "float",                                           label: L("lcl_mld_melding_gps")+" z" }
            };

    this.list = { columns: ["id", "name", "requestor", "description"] };

    this.includes =
              { "custom_fields": { model: new model_custom_fields(this, new model_mld_kenmerk('M', { internal: true }),
                                         { pNiveau: "M", readman: true, readuse: true }),
                                   joinfield: "flexparentkey",
                                   "enable_update": true
                                 },
                "tracking":      {
                                   model: new model_tracking(['melding']),
                                   joinfield: "trackingrefkey"
                                 },
                "notes":         {
                                   model: new model_notes("MLD"),
                                   joinfield: "parent"
                                 },
                "orders":        {
                                   model: new model_orders(),
                                   joinfield: "issue"
                                 },
                "issueobjects":  {
                                   model: new model_issueobjects(),
                                   joinfield: "issue",
                                   "enable_update": true
                                 }
              };

    this.REST_GET = function _GET(params)
        {
            // Als je een filter-id meegeeft werken we scopeloos/ heel nauwkeurig
            if (params.filter.id)
            {
                var sql = "SELECT 1 FROM mld_melding WHERE mld_melding_key = " + params.filter.id;
                var oRs = Oracle.Execute(sql);
                if (!oRs.eof)
                {   // XD: zoeken op niet-bestaande key geeft anders een AiAi.
                    var this_mld = mld.func_enabled_melding(params.filter.id);
                    user.auth_required_or_abort(this_mld.canReadAny);
                    if (this_mld.haveOnlyFErights)
                    {
                        this.includes["notes"].model.gparams = { "GET": { wheres: ["BITAND(mld_melding_note_flag,1) = 1"] } };
                    }
                }
                oRs.Close();
            }
            else // In lijst nooit verborgen notities. Veel te ingewikeld met autorisatie
                this.includes["notes"].model.gparams = { "GET": { wheres: ["BITAND(mld_melding_note_flag,1) = 1"] } };

            var query = api2.sqlfields(params, this );
            query.wheres.push("mld_melding.fac_activiteit_key IS NULL");

            if (params.filter.id)
            {
                // klaar verder
            }
            else
            {
                var scope = params.filter.scope || "fe";

                var autfunction = { fe : "WEB_MLDUSE"
                                  , fo : ["WEB_MLDFOF","WEB_MLDBWD","WEB_MLDREJ","WEB_MLDVER"]
                                  , bo : ["WEB_MLDBOF","WEB_MLDAFR","WEB_MLDAFM","WEB_MLDDOO","WEB_MLDACP","WEB_MLDUIT"]
                                  , mi : "WEB_MLDBAC"
                                  } [scope];
                params.authparams = user.checkAutorisation(autfunction, null, null, true); /* pessimistic */

                // Hier kom je niet meer terecht als bovenstaande autorisatiecheck niet tot succes leidt.

                var alg3d = false;
                var prs3d = false;

                if (scope == "fe")
                {
                    query.wheres.push("mld_melding.prs_perslid_key=" + user_key);
                }

                /* You can't go any further back in time than the GUI could (ongeveer)*/
                /* Als er wel een start_issuedate is dan wordt deze toegevoegd in api2.sqlfilter() verderop. */
                if (!params.filter.start_issuedate && S("mld_max_history") > 0)
                {
                    query.wheres.push("mld_melding_datum > SYSDATE - "+ S("mld_max_history"));
                }
                if (!params.filter.status)
                {
                    /* Limitation: if no status filter, then default to the active statusses (all except 1,6,5) */
                    // Zou zo kunnen, params.filter.status = [0,2,3,4,7];, maar eigenlijk is dit logischer
                    query.wheres.push("mld_melding_status IN (0,2,4,7)");

                }
            }

            /* we need the prefix for the name */
            query.tables.push("mld_stdmelding");
            query.wheres.push("mld_melding.mld_stdmelding_key = mld_stdmelding.mld_stdmelding_key");
            query.tables.push("ins_tab_discipline");
            query.wheres.push("mld_stdmelding.mld_ins_discipline_key = ins_tab_discipline.ins_discipline_key");
            query.tables.push("ins_srtdiscipline");
            query.wheres.push("ins_tab_discipline.ins_srtdiscipline_key = ins_srtdiscipline.ins_srtdiscipline_key");

            query.tables.push("alg_v_allonroerendgoed");
            query.wheres.push("mld_melding.mld_alg_onroerendgoed_keys = alg_v_allonroerendgoed.alg_onroerendgoed_keys(+)");

            if (!params.filter.id)
            {
                if (params.authparams.ALGreadlevel > -1)
                {
                    /* required for 3D ALG scopeing */
                    alg3d = true;
                    __Log("ALGreadlevel="+params.authparams.ALGreadlevel);
                    query.tables.push("alg_locatie");  /* opletten: outerjoin denk ik? */
                    query.wheres.push("mld_melding.mld_alg_locatie_key = alg_locatie.alg_locatie_key(+)");
                    query.tables.push("alg_district");
                    query.wheres.push("alg_locatie.alg_district_key = alg_district.alg_district_key(+)");
                }
                if (params.authparams.PRSreadlevel > -1)
                {
                    /* required for 3D PRS scopeing */
                    prs3d = true;
                    __Log("PRSreadlevel="+params.authparams.PRSreadlevel);
                    query.tables.push("prs_perslid");
                    query.tables.push("prs_v_afdeling_boom");
                    query.wheres.push("mld_melding.prs_perslid_key = prs_perslid.prs_perslid_key");
                    query.wheres.push("prs_perslid.prs_afdeling_key = prs_v_afdeling_boom.prs_afdeling_key");
                }
            }

            var wheres = api2.sqlfilter(params, this);
            query.wheres = query.wheres.concat(wheres);

            var sql = "SELECT " + query.selects.join(", ")
                    + "  FROM " + query.tables.join(", ")
                    + " WHERE " + query.wheres.join(" AND " );

            if (!params.filter.id)
            {
                // Over het resultaat moet nog de 3D rasp, altijd
                sql = discx3d (sql,
                             "ins_tab_discipline.ins_discipline_key",
                             (alg3d ? "alg_district.alg_regio_key" : null),
                             (alg3d ? "alg_district.alg_district_key" : null),
                             (alg3d ? "mld_melding.mld_alg_locatie_key" : null),
                             (alg3d ? "alg_v_allonroerendgoed.alg_gebouw_key" : null),
                             (alg3d ? "alg_v_allonroerendgoed.alg_verdieping_key" : null),
                             (alg3d ? "alg_v_allonroerendgoed.alg_ruimte_key" : null),
                             (prs3d ? "prs_bedrijf_key" : null),
                             (prs3d ? "prs_afdeling_key" : null),
                             autfunction,
                             [], /* no additional discipline restrictions */
                             (alg3d && prs3d ? 2 : prs3d ? 1 : 0)
                             );
            }

            sql += " ORDER BY mld_melding_key"; // Order by nodig voor includes
            if (query.orderbys.length)
                sql += ", " + query.orderbys.join(", ");

            var json = api2.sql2json (params, sql, this );

            return json;
        };

    function _pre_analyze_fields (params, jsondata) /* analyseer inkomende jsondata voor POST */
    {
        params.data = {};
        var mld_key   = jsondata.id;

        //
        //
        var stdm_info = mld.mld_stdmeldinginfo(jsondata.issuetype);
        // Startdatum: indien niet meegegeven, neem dan sysdate
        var startdate = (jsondata.issuedate ? jsondata.issuedate : new Date);
        var startwerkdag = parseFloat(S("fac_t_startofworkday"));
        var startwerkdag_uur = Math.floor(startwerkdag);
        var startwerkdag_min = (startwerkdag - Math.floor(startwerkdag)) * 60;
        var startdatebegin = new Date(startdate.getFullYear(), startdate.getMonth(), startdate.getDate(), startwerkdag_uur, startwerkdag_min);
        var sysdate = new Date();
        //
        if (stdm_info.startdatum)
        {   // Situatie 1: Einddatum = TRUNC(startdatum) + 8:00 uur + SLA
            // LET OP!!!: Als setting "mld_disc_params_startdatum" is gezet dan wordt eigenlijk verondersteld dat de SLA in dagen is en niet in uren.
            //            Echter als de startdatum de registratiedatum (bij nieuwe melding dus sysdate) is moet wel voor de begintijd de registratietijd (registratiedatum) genomen worden tijdens het opslaan.
            //            Anders geldt de acceptatietijd (in uren) onterecht al vanaf het begin van de dag.
            if (params.isNew)
            {   // Nieuwe melding.
                // Startdatum is vandaag: starttijd is huidige tijd.
                // Startdatum is niet vandaag: starttijd is begin werkdag.
                var startdate_is_today = (startdate.midnight().getTime() == sysdate.midnight().getTime());
                params.data.startdate = (startdate_is_today? sysdate : startdatebegin);
            }
            else
            { // Bestaande melding
                sql = "SELECT mld_melding_datum"
                    + "  FROM mld_melding"
                    + " WHERE mld_melding_key = " + mld_key;
                oRs = Oracle.Execute(sql);
                var oldstartdate = new Date(oRs("mld_melding_datum").Value);

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

                    var startdatum_is_registratiedatum = (startdate.midnight().getTime() == registratiedatum.midnight().getTime());
                    params.data.startdate = (startdatum_is_registratiedatum? registratiedatum : startdatebegin);
                }
                else
                { // else startdatum niet aanpassen.
                    params.data.startdate = oldstartdate;
                }
                oRs.Close();
            }
        }
        else
        {   // Situatie 2: Einddatum = COALESCE(huidige waarde, sysdate) + SLA
            if (params.isNew)
            {
                params.data.startdate = new Date();
            }
            else
            {
               // startdate = jsondata.issuedate;
            }
        }
        // jsondata.issuedate = startdate;
        // De einddatum is de meegegeven einddatum, maar als die niet wordt meegegeven regelt de trigger dat wel, dus DAN MOET IK HEM NIET MEEGEVEN
        //

        // Onroerendgoed_keys wordt de verfijnste van de opgegeven plaats
        var locatiekey    = (jsondata.location ? jsondata.location : -1);
        var gebouwkey     = (jsondata.building ? jsondata.building : -1);
        var verdiepingkey = (jsondata.floor    ? jsondata.floor    : -1);
        var ruimtekey     = (jsondata.room     ? jsondata.room     : -1);
        var alg_onroerendgoed_keys = -1;

        if (stdm_info.ins_srtdiscipline_alglevel > 2)
        {   // die specifiekere plaats moet dan leegblijven
            if (ruimtekey > 0)
                alg_onroerendgoed_keys = ruimtekey;
            else if (verdiepingkey > 0)
                alg_onroerendgoed_keys = verdiepingkey;
            else if (gebouwkey > 0)
                alg_onroerendgoed_keys = gebouwkey;
        }
        params.data.alg_onroerendgoed_keys = alg_onroerendgoed_keys;
        return params;
    };

    function _analyze_fields (dbfields, params, jsondata) /* analyseer inkomende data, common voor PUT en POST */
    {
    };

    function _validate_fields (dbfields, params, jsondata) /* valideer fields, alle constraints die niet door de database worden afgevangen */
    {
        // als einddatum ingevuld is moet deze groter/gelijk zijn aan de begindatum

        // Zijn behandelteams toegestaan bij deze melding, en is de gekozen discipline een behandelteam?
        if ("treatmentteam" in jsondata && jsondata.treatmentteam > 0)
        {
            var sql;
            if ("issuetype" in jsondata) // Insert MLD
            {
              sql = " SELECT ''"
                  + "   FROM mld_stdmelding stdm, mld_disc_params mdp"
                  + "  WHERE stdm.mld_stdmelding_key = " + jsondata.issuetype
                  + "    AND mdp.mld_ins_discipline_key = stdm.mld_ins_discipline_key"
                  + "    AND BITAND (mdp.mld_disc_params_srtgroep, 4) = 4";
            }
            else if ("id" in jsondata) // Update MLD
            {
              sql = " SELECT ''"
                  + "   FROM mld_melding m, mld_stdmelding stdm, mld_disc_params mdp"
                  + "  WHERE m.mld_melding_key = " + jsondata.id
                  + "    AND stdm.mld_stdmelding_key = m.mld_stdmelding_key"
                  + "    AND mdp.mld_ins_discipline_key = stdm.mld_ins_discipline_key"
                  + "    AND BITAND (mdp.mld_disc_params_srtgroep, 4) = 4";
            }
            var oRs = Oracle.Execute(sql);
            if (oRs.eof)
            {
                delete jsondata.treatmentteam;
                delete dbfields.treatmentteam;
            }
            oRs.Close();

            var behandelTeam = jsondata.treatmentteam;
            if (behandelTeam)
            {
                sql = " SELECT ''"
                    + "   FROM mld_disc_params"
                    + " WHERE mld_ins_discipline_key = " + behandelTeam
                    + "   AND BITAND (mld_disc_params_srtgroep, 2) = 2"
                oRs = Oracle.Execute(sql);
                if (oRs.eof)
                {
                    delete jsondata.treatmentteam;
                    delete dbfields.treatmentteam;
                }
                oRs.Close();
            }
        }
    };

    function _keep_editable_fields(jsondata, mld_info)
    {   // Verwijder voor PUT wat niet gewijzigd mag worden.
        function delete_fld(jsondata, field, condition)
        {
            if (condition)
            {
                delete jsondata[field];
            }
        }

        var sql = "SELECT COUNT (*) cnt"
                + "  FROM mld_stdmelding stdm, mld_discipline md "
                + " WHERE     stdm.mld_ins_discipline_key = md.ins_discipline_key "
                + "       AND stdm.mld_stdmelding_verwijder IS NULL "
                + "       AND md.ins_discipline_verwijder IS NULL "
                + "       AND mld_stdmelding_thirdparty = 0 "
                + "       AND md.ins_srtdiscipline_key = " + mld_info.srtdisc_key;
        var oRs = Oracle.Execute(sql);
        var lAllThirdparty = (oRs("cnt").Value == 0);
        oRs.close();

        var sql = "SELECT 1"
                + "  FROM DUAL"
                + " WHERE EXISTS"
                + "           (SELECT 1"
                + "              FROM mld_disc_params dp1, mld_discipline d1"
                + "             WHERE d1.ins_discipline_key = dp1.mld_ins_discipline_key"
                + "               AND d1.ins_discipline_verwijder IS NULL"
                + "               AND BITAND (dp1.mld_disc_params_srtgroep, 2) = 2)" // Is team?
                + "   AND EXISTS"
                + "           (SELECT 1"
                + "              FROM mld_disc_params dp2, mld_discipline d2"
                + "             WHERE d2.ins_discipline_key = dp2.mld_ins_discipline_key"
                + "               AND d2.ins_discipline_verwijder IS NULL"
                + "               AND BITAND (dp2.mld_disc_params_srtgroep, 4) = 4)" // Has team?
                + "   AND ROWNUM <= 1";
        var oRs = Oracle.Execute(sql);
        var canUseTeams = !oRs.EoF;
        oRs.Close();

        var this_mld = mld.func_enabled_melding(mld_info.mld_key);
        var stdm_info = mld.mld_stdmeldinginfo(mld_info.stdm_key);

        // Uitgebreide condities eerst hier maken.
        var remark_canchange = (  (this_mld.canBOwrite || this_mld.canFOwrite)
                               && (S("mld_afhandeling_restrict_edit") == 0)
                               && ((this_mld.canAfhandChange && S("mld_afhandeling_restrict_edit") == 0) || S("mld_afrond_canremark") == true)
                               );
        var vakg_readonly = (!this_mld.canVakgChange || stdm_info.is_kto_antwoord || S("mld_selector_mode") == 1 || S("mld_selector_mode") == 2) || (stdm_info.slabewaken && mld_info.respijt != 0);
        var stdm_readonly = (!this_mld.canStdmChange || (stdm_info.slabewaken && mld_info.respijt != 0));
        var canPrioChange = (stdm_info.planbaarfe == 0 && (this_mld.canFOwrite || (this_mld.canFEwrite && stdm_info.frontendprio && ( mld_info.mld_status == 1 || mld_info.mld_status == 2)))? true : false);
        var kto_key_readonly = !stdm_info.kanverwijzen || !(stdm_info.ins_srtdiscipline_mldgroup & 2)
        var oms_readonly = ( S("mld_omschrijving_restrict_edit") == 1
                           ? !this_mld.canOmsChange || ((S("mld_rejected_is_open") == 1 && mld_info.mld_status == 1) || mld_info.mld_status == 2 || mld_info.mld_status == -1)
                           : !this_mld.canOmsChange
                           );

        // Nu per veld eventueel verwijderen.
        delete_fld(jsondata, "name",          true);
        delete_fld(jsondata, "remark",        !remark_canchange );
        delete_fld(jsondata, "location",      !(this_mld.canPlaatsChange));
        delete_fld(jsondata, "contact",       !((S("mld_allow_for_others") == 1 || S("mld_allow_for_others") == 2) && this_mld.canPersChange) )
        delete_fld(jsondata, "requestor",     !((S("mld_allow_for_others") == 1 || S("mld_allow_for_others") == 2) && this_mld.canPersChange) )
        delete_fld(jsondata, "department",    (S("mld_use_department") != 1 || !this_mld.canDeptChange) );
        delete_fld(jsondata, "account",       ((stdm_info.hide_kostenplaats || stdm_info.is_kto_antwoord) && !this_mld.canKostChange) );
        delete_fld(jsondata, "ordernr",       ((stdm_info.hide_kostenplaats || stdm_info.is_kto_antwoord) && (S("show_ordernr") == 0 || !this_mld.canKostChange)) );
        delete_fld(jsondata, "naam_ext",      (stdm_info.canholdthirdparty != 1 && !lAllThirdparty) );
        delete_fld(jsondata, "email_ext",     (stdm_info.canholdthirdparty != 1 && !lAllThirdparty) );
        delete_fld(jsondata, "tel_ext",       (stdm_info.canholdthirdparty != 1 && !lAllThirdparty) );
        delete_fld(jsondata, "treatmentteam", vakg_readonly);
        delete_fld(jsondata, "issuetype",     stdm_readonly);
        delete_fld(jsondata, "priority" ,     !canPrioChange);
        delete_fld(jsondata, "issuedate",     (!this_mld.canWriteDatums || !mld_info.show_start_date) );
        delete_fld(jsondata, "actiondate",    !this_mld.canWriteDatums);
        delete_fld(jsondata, "enddate",       !this_mld.canWriteDatums);
        delete_fld(jsondata, "address",       !this_mld.canAflChange);
        delete_fld(jsondata, "handler",       !this_mld.canAfhandChange);
        delete_fld(jsondata, "public",        !mld_info.canbepublished);
        delete_fld(jsondata, "origin",        true);
        delete_fld(jsondata, "indult" ,       !(stdm_info.slabewaken && this_mld.canSLAChange) );
        delete_fld(jsondata, "completed",     !this_mld.canAfrond);
        delete_fld(jsondata, "kto",           !((mld_info.kto_opt & 2) == 2 && mld_info.kto_verstuurd == null && this_mld.canClose) );
        delete_fld(jsondata, "flags",         S("mld_melding_flags") == 0);
        delete_fld(jsondata, "processor",     !canUseTeams );
        delete_fld(jsondata, "kto_key",       kto_key_readonly );
        delete_fld(jsondata, "kto_type",      kto_key_readonly );
        delete_fld(jsondata, "subject",       oms_readonly );
        delete_fld(jsondata, "description",   oms_readonly );
        delete_fld(jsondata, "continuedfrom", true);
    }

    function _validate_close (params, jsondata, the_key) /* uit: mld_close_save.asp */
    {
        var mld_key = the_key;
        var this_mld = mld.func_enabled_melding(mld_key);
        user.auth_required_or_abort(this_mld.canClose); // Als je mag accepteren mag je ook rejecten

        params.data = {};
        params.data.tobeclosed = false;
        params.data.canCloseOpdrOfMld = [];
        var canCloseOpdr = [];
        var reqStatusEmpty = [];
        var noOpdrCloseAtAll = false;
        var futureOpdr = false;

        // Zijn er nog kenmerken die nu wel verplicht zijn?
        var afwezig = mld.hasRequiredStatusEmptyMelding(mld_key, 5); // Melding status "Afgemeld(5)"
        if (afwezig.kenm_ontbreekt.length || afwezig.obj_ontbreekt)
        {
          var mldnr = mld.mld_prefix(mld_key) + mld_key;
          if (afwezig.kenm_ontbreekt.length)
            reqStatusEmpty.push(L("lcl_mld_req_status_empty").format(afwezig.kenm_ontbreekt.join(", "), mldnr));
          if (afwezig.obj_ontbreekt)
            reqStatusEmpty.push(L("lcl_mld_req_obj").format(mldnr));
        }
        // Zijn er nog lopende opdrachten?
        var sql = "SELECT o.mld_opdr_key"
                + "  FROM mld_opdr o"
                + " WHERE o.mld_melding_key = " + mld_key
                + "   AND o.mld_statusopdr_key NOT IN (1, 6, 7, 9)";
        var oRsOM = Oracle.Execute(sql);
        while (!oRsOM.eof)
        {   // Voor elke opdracht van een melding controleren of deze afgemeld mag worden
            var mld_opdr_key = oRsOM("mld_opdr_key").Value;
            sql = "SELECT mld_opdr_einddatum"
                + "  FROM mld_opdr o"
                + " WHERE o.mld_opdr_key = " + mld_opdr_key;
            var oRs = Oracle.Execute(sql);
            // Als Setting S("mld_ord_afmeld_future") niet is gezet (0): Opdrachten waarvan de einddatum in de toekomst ligt mogen niet worden afgemeld.
            var this_opdr = mld.func_enabled_opdracht(mld_opdr_key);
            var mld_opdr_einddatum = oRs("mld_opdr_einddatum").Value != null? new Date(oRs("mld_opdr_einddatum").Value) : null;
            if (!this_opdr.canClose || (S("mld_ord_afmeld_future") != 1 && (mld_opdr_einddatum && (mld_opdr_einddatum > new Date()))))
            {   // Geen autorisatie om alle opdrachten van een melding af te melden of opdrachten in de toekomst
                // met setting S("mld_ord_afmeld_future") niet gezet-->dan geen enkele van die melding
                noOpdrCloseAtAll = true;
                if (S("mld_ord_afmeld_future") != 1 && (mld_opdr_einddatum && (mld_opdr_einddatum > new Date())))
                    futureOpdr = true; // Indien opdrachten in de toekomst en setting S("mld_ord_afmeld_future") niet gezet (0) dan mag je de melding niet afmelden
            }
            oRs.Close();
            params.data.canCloseOpdrOfMld.push(mld_opdr_key);
            oRsOM.MoveNext();
        }
        oRsOM.Close();

        if (!futureOpdr && !noOpdrCloseAtAll)
        {   // Indien opdrachten in de toekomst en setting S("mld_ord_afmeld_future") niet gezet (0) dan mag je de melding niet afmelden
            // EN geen opdrachten of alle opdrachten mogen gesloten worden, dan kan de melding afgemeld worden
            params.data.tobeclosed = true;
        }
        else
        {
            api2.error(500, "Issue can not be closed");
        }
    };

    this.REST_PUT = function (params, jsondata, the_key) /* update issue */
        {
            params = params || {};
            if (!jsondata.id) jsondata.id = the_key;

            var mld_key = jsondata.id;

            // Vul jsondata aan met actuele 'oude' data
            var old_mld = new model_issues(mld_key).data;
            for (var fld in old_mld)
            {
                if (fld != "custom_fields" && !(fld in jsondata))
                    jsondata[fld] = old_mld[fld];
            }
            api2.cleanup_data(this, jsondata); // Doet een generieke dereference van alle foreign's

            var this_mld = mld.func_enabled_melding(mld_key);
            if ("filter" in params && "mode" in params.filter)
                this_mld.canFlexChange |= this_mld.canReadAny && params.filter.mode == "attachment"; // Deze mag altijd
            user.auth_required_or_abort(this_mld.canChange ||
                                        (this_mld.canAccept && jsondata.status == 4) ||
                                        (this_mld.canClose && jsondata.status == 5) ||
                                        (this_mld.canFlexChange && params.custom_fields_only));  // Geen wijzigingen toestaan bij onvoldoende rechten.

            var handler = ("handler" in jsondata ? jsondata.handler : user_key);
            var processor = jsondata.processor;
            var treatmentteam = jsondata.treatmentteam;
            var mld_info = mld.mld_melding_info(mld_key);
            var stdm_info = mld.mld_stdmeldinginfo(mld_info.stdm_key);
            var saveBehandelaar  = false;
            var saveBehandelaar2 = false;
            var saveBehandelteam = false;

            if ("handler" in jsondata || "processor" in jsondata || "treatmentteam" in jsondata)
            {
              // Als je niet accepteert met MLDBO3 rechten en je hebt niet de BO3 notificatie aanstaan dan de behandelaar opslaan.
              // BO notificatie accept 0=niet, 1=bof, 2=bo3, 3=bo3 (aanmaak nieuwe melding) en dan bof (accepteren melding)
              saveBehandelaar = !this_mld.canWrite("WEB_MLDBO3") && mld_info.bonotify < 2 && mld_info.primaire_behandelaar != 0 && // Behandelaar alleen in situatie 1 voor bonotify 0 (niet) en 1 (bof) tracken.
                                ((("handler" in jsondata) && (mld_info.behandel_key || -1) != handler) ||
                                 (this_mld.canVakgBOFwrite && !("handler" in jsondata) && (mld_info.behandel_key || -1) == -1));   // Bij accepteren van meldingen van vakgroepen met behandelteams: onzichtbaar onaangeroerd laten of vullen met de Acceptator (indien canVakgBOFwrite)
              saveBehandelaar2 = !this_mld.canWrite("WEB_MLDBO3") && mld_info.bonotify < 2 &&
                                 (mld_info.behandel2_key || -1) != processor;
              saveBehandelteam = (mld_info.mld_ins_discipline_key || -1) != treatmentteam;
            }

            if (jsondata.status == 4 && this_mld.canAccept)
            { // Accepteren.
              // Zijn er nog kenmerken of objecten die nu wel verplicht zijn?
              reqStatusEmptyMelding = mld.getReqStatusEmptyMelding([], mld_key, 4); // Melding status "In behandeling(4)"
              user.anything_todo_or_abort(!reqStatusEmptyMelding.length, reqStatusEmptyMelding.join("<br />"));

              var datefields = [];

              // Startdatum:
              // De startdatum bepalen die opgeslagen moet worden.
              var params_startdate = { startdate: jsondata.issuedate,
                                       disc_with_startdatum: stdm_info.startdatum };
              var startdate_info = mld.getstartdatesave(mld_key, params_startdate);
              var startdate = startdate_info.startdate;
              datefields.push(startdate_info.startfield);

              // Einddatum corrigeren als deze voor de startdatum is komen te liggen.
              if (jsondata.enddate < startdate)
                jsondata.enddate = startdate;
              // Actiedatum corrigeren als deze voor de startdatum is komen te liggen.
              if (jsondata.actiondate < startdate)
                jsondata.actiondate = startdate;
              // Actiedatum corrigeren als deze na de einddatum is komen te liggen.
              if (jsondata.actiondate > jsondata.enddate)
                jsondata.actiondate = jsondata.enddate;

              // Actiedatum:
              if (stdm_info.show_actiedatum)
              {
                datefields.push({ dbs: "mld_melding_actiedatum", typ: "datetime", val: jsondata.actiondate, track: L("lcl_mld_actiondate") });
              }

              // Einddatum:
              datefields.push({ dbs: "mld_melding_einddatum", typ: "datetime", val: jsondata.enddate, track: stdm_info.planbaar == 2? false: L("lcl_mld_enddate") });

              var remark = jsondata.remark? jsondata.remark : "";

              var params  = { saveBehandelaar: saveBehandelaar,
                              saveBehandelaar2: saveBehandelaar2,
                              saveBehandelteam: saveBehandelteam,
                              remark: remark,
                              handler: handler,
                              processor: processor,
                              treatmentteam: treatmentteam,
                              canFOwrite: this_mld.canFOwrite,
                              canBOwrite: this_mld.canBOwrite,
                              noValidateToken: true,
                              datefields: datefields
                            }
              mld.acceptmelding(mld_key, params);
            }
            else if (jsondata.status == 5 && this_mld.canClose)
            { // Afmelden en opmerking aanpassen.
              mld.setmeldingstatus(mld_key, 5, (("close_notify_caller" in jsondata) ? jsondata.close_notify_caller : (S("mld_close_noti_default_off") ? 0 : 1))); // Status Afgemeld(5) zetten.
              // Melding opmerking ook aanpassen bij het afmelden.
              if ("remark" in jsondata && jsondata.remark)
              {
                sql = "SELECT mld_melding_opmerking"
                    + "  FROM mld_melding"
                    + " WHERE mld_melding_key = " + mld_key;
                oRs = Oracle.Execute(sql);
                var new_opm = (oRs("mld_melding_opmerking").value || "") + "\n" + jsondata.remark;
                oRs.Close();

                var fields =  [ { dbs: "mld_melding_opmerking",  typ: "varchar", val: new_opm, track: L("lcl_mld_inf_Opmerking"), len: 4000 } ];

                var mldUpd = buildTrackingUpdate("mld_melding", " mld_melding_key = " + mld_key, fields, { noValidateToken: true });
                Oracle.Execute(mldUpd.sql);
                if (mldUpd.trackarray.length)
                  mld.trackmeldingupdate(mld_key, L("lcl_mld_is_mldupd") + "\n" + mldUpd.trackarray.join("\n"));
              }
              // Handle workflow actions for completion:
              mld.nextworkflowstep(mld_key, 1);  // 1 = completed.
            }
            else if (  (this_mld.canChange || (this_mld.canFlexChange && params.custom_fields_only))
                    || (jsondata.status == 0 && this_mld.canTerugzet)
                    || (jsondata.status == 1 && this_mld.canReject)
                    || (jsondata.status == 2 && this_mld.canDoorzet)
                    || (jsondata.status == 6 && this_mld.canVerwerk)
                    )
            {
              if (params.custom_fields_only)
              {
                  var mldUpd = { trackarray: [] };
              }
              else
              {
                  params = _pre_analyze_fields(params, jsondata);
                  _keep_editable_fields(jsondata, mld_info);
                  var dbfields = api2.update_fields(params, this, jsondata); // Build updater
                  _analyze_fields(dbfields, params, jsondata);
                  _validate_fields(dbfields, params, jsondata);

                  var wheres = [" mld_melding_key = " + mld_key];
                  var mldUpd = buildTrackingUpdate("mld_melding", wheres.join(" AND " ), dbfields, { noValidateToken: true });

                  var err = Oracle.Execute(mldUpd, true);
                  if (err.friendlyMsg)
                      abort_with_warning(err.friendlyMsg);
              }

              var mldtrack = api2.process_includes(params, this, jsondata, mld_key);

              if (mldUpd.trackarray.length)
              {
                  shared.trackaction("MLDUPD",
                                     mld_key,
                                     L("lcl_mld_is_mldupdtrack").format(mld_key) + (mldUpd.trackarray.length > 0? "\n" : "") + mldUpd.trackarray.join("\n"));
              }

              if (jsondata.status > 0)
              {
                // Alleen als de status WIJZIGT moeten we die ZETTEN. Dat kan een statusverandering zijn
                // of het einde van de concept-fase waardoor de bestaande status echt wordt.
                if (jsondata.status != old_mld["status"]["id"] || (jsondata.conceptstatus == 0 && old_mld["conceptstatus"] != 0))
                {
                    mld.setmeldingstatus(mld_key, jsondata.status);
                    if (jsondata.status == 1)  // Afwijzen: Handle workflow actions for rejection:
                        mld.nextworkflowstep(mld_key, 0);  // 0 = rejected.
                }
              }

              if (saveBehandelaar && jsondata.handler != old_mld["handler"])
                  mld.trackbehandelaar(mld_key, handler, handler == user_key);
              if (saveBehandelaar2 && jsondata.processor != old_mld["processor"])
                  mld.trackbehandelaar2(mld_key, processor, processor == user_key);
              if (saveBehandelteam && jsondata.treatmentteam != old_mld["treatmentteam"])
                  mld.trackAndNotifyBehandelteam(mld_key, treatmentteam);
            }

            return { key: mld_key };
        };

    this.REST_POST = function (params, jsondata) /* new call */
        {
            api2.cleanup_data(this, jsondata); // Doet een generieke dereference van alle foreign's

            //
            // Voor een nieuwe melding moet er een geldige stdmelding zijn.
            if (!jsondata.issuetype)
                api2.error(500, "Missing issuetype")

            var stdm = new model_issuetypes(jsondata.issuetype, { internal: true }).data;

            //
            // Bepaal de kostenplaats, indien verplicht.
            var stdm_info = mld.mld_stdmeldinginfo(jsondata.issuetype);
            var kpkey = (jsondata.account ? jsondata.account : -1);
            if (stdm_info.kpnverplicht && kpkey < 0)
            {   // Kostenplaats is verplicht, maar is niet meegegeven. Bepaal default kostenplaats.
                kpkey = (user.prs_kostenplaats_key() || -1); // User default kostenplaats key
            }
            if (stdm_info.kpnverplicht && kpkey < 0)
            {   // Kon ook geen default kostenplaats vinden.
                api2.error(500, "Account could not be validated");
            }

            if (jsondata.continuedfrom)
            {
                var sql = "SELECT COUNT(m.mld_workflowstep_key) is_workflow"
                        + "  FROM mld_melding m"
                        + " WHERE m.mld_melding_key = " + jsondata.continuedfrom;
                var oRs = Oracle.Execute(sql);
                var isWorkflow = oRs("is_workflow").Value != 0;
                oRs.Close();
                if (isWorkflow)
                    api2.error(500, "Issue is part of workflow. Cannot be continued");
            }

            jsondata.account = kpkey;
            if (!jsondata.issuedate)
                jsondata.issuedate = new Date();
            if (!jsondata.priority)
                jsondata.priority = 3;
            if (!jsondata.treatmentteam)
                jsondata.treatmentteam = stdm_info.default_ins_disc_key;

            if (!jsondata.subject && stdm_info.subject == 3 && (S("ai_enabled") & 1)) { // AI generate the subject
                var omschrijving = shared.stripbbcodes(jsondata.description || "");
                var result = shared.promptAI(omschrijving, { "instructions": L("lcl_mld_ai_subject_instructions").format(stdm_info.mld_stdmelding_omschrijving) });
                if (result.success) {
                    jsondata.subject = result.content;
                    this.fields["subject_ai"] = { dbs: "mld_melding_onderwerp_ai", typ: "varchar", val: jsondata.subject, len: 200 };
                } else {
                    if (result.warning) {
                        __DoLog(result.warning, "#FF0000");
                    }
                }
            }

            //
            if (!jsondata.contact) jsondata.contact = user_key; // Als er geen aanvrager opgegeven is, dan de huidige gebruiker invullen.
            // Als de setting niet is gezet is "Melding voor" gelijk aan contactpersoon.
            if (S("mld_allow_for_others") == 0)
            {
                jsondata.requestor = jsondata.contact;
            }

            params.isNew = true;
            params = _pre_analyze_fields(params, jsondata);

            var this_mld = mld.func_enabled_mld(stdm_info.ins_discipline_key, "D");
            user.auth_required_or_abort(this_mld.canFEwrite || this_mld.canFOwrite);
            //
            jsondata.origin = (jsondata.origin || S("mld_meldbron_key"));
            var dbfields = api2.update_fields(params, this, jsondata); // Build updater
            _analyze_fields(dbfields, params, jsondata);
            _validate_fields(dbfields, params, jsondata);

            dbfields["alg"] =       { dbs: "mld_alg_onroerendgoed_keys", typ: "key",      val: params.data.alg_onroerendgoed_keys > 0 ? params.data.alg_onroerendgoed_keys:  null};
            dbfields["module"] =    { dbs: "mld_melding_module",         typ: "varchar",  val: "MLD" };
            dbfields["issue"] =     { dbs: "mld_melding_key",            typ: "key",      seq: "mld_s_mld_melding_key" };

            var mldIns = buildInsert("mld_melding", dbfields, { noValidateToken: true });
            var new_key = mldIns.sequences["mld_melding_key"];
            Oracle.Execute(mldIns);
            mld.setmeldingstatus(new_key, (stdm.xmld_directklaar? 0 : 2)); // Zorgt ook voor tracking & daarmee notificatie

            params.filter = { id: new_key }; // De nieuwe mld_melding_key.
            var mldtrack = api2.process_includes(params, this, jsondata, new_key);


            if (jsondata.treatmentteam > 0)
                mld.notifybehandelteam(new_key, jsondata.treatmentteam);
            if (jsondata.processor > 0)
                mld.trackbehandelaar2(new_key, jsondata.processor);

            if (stdm_info.xis_kto_answer) // die direct afmelden
                mld.setmeldingstatus(new_key, 5, (("close_notify_caller" in jsondata) ? jsondata.close_notify_caller : (S("mld_close_noti_default_off") ? 0 : 1)));

            // Handle workflow actions for new call:
            mld.nextworkflowstep(new_key, -1);  // -1 = initial (the originating call)

            // Controleer of er automatisch een opdracht aangemaakt moet worden.
            var sql = "BEGIN mld.mld_addautoorder(" + new_key + "); END;"; // Notificeert eventueel ook de ORDNEW naar uitvoerende
            Oracle.Execute(sql);

            return { key: new_key };
        };

    this.search = {
        "filters": ["id"]
    };

    if (mld_key > 0)
    {
        params.filter = params.filter || {};
        params.filter.id = mld_key;
        if (! ("include" in params) )
            params.include = { include: ["custom_fields"]};

        var xxx_array = this.REST_GET(params);
        if (!xxx_array.length)
            shared.record_not_found();
       this.data = xxx_array[0];
    }
}
%>
