<% /*
    $Revision$
    $Id$

    File:           model_res_ruimte.inc

    Description:    Vanuit CodeCharge gegenereerd model voor res_ruimte

    Context:

    Notes:
*/
%>
<!-- #include file="../Shared/flexfiles.inc"-->
<!-- #include file="../api2/model_res_alg_ruimte.inc" -->
<!-- #include file="../api2/model_res_ruimte_opstelling.inc" -->
<%

function model_res_ruimte()
{
    this.records_name = "bookingrooms";
    this.record_name =  "bookingroom";
    this.table = "res_ruimte";
    this.primary = "res_ruimte_key";
    this.soft_delete = "res_ruimte_verwijder";
    this.soft_expire = "res_ruimte_vervaldatum";
    this.autfunction = "WEB_RESMSU";
    this.record_title = L("res_ruimte");
    this.records_title = L("res_ruimte_m");

    var hasRESMGT = user.has("WEB_RESMGT");

    this.fields = {
        "id": {
            "dbs": "res_ruimte_key",
            "label": L("lcl_key"),
            "typ": "key",
            "required": true,
            "seq": "res_s_res_ruimte_key"
        },
        "name": {
            "dbs": "res_ruimte_nr",
            "label": L("res_ruimte_nr"),
            "typ": "varchar",
            "translate": true,
            "required": true,
            "filter": "like"
        },
        "description": {
            "dbs": "res_ruimte_omschrijving",
            "label": L("res_ruimte_omschrijving"),
            "typ": "memo",
            "no_bb_codes": true,
            "translate": true,
            "filter": "like"
        },
        "sequence": {
            "dbs": "res_ruimte_volgnummer",
            "label": L("res_ruimte_volgnummer"),
            "typ": "number"
        },
        "minbezoekers": {
            "dbs": "res_ruimte_minbezoekers",
            "label": L("res_ruimte_minbezoekers"),
            "typ": "number",
            "required": true,
            "defaultvalue": 0
        },
        "infourl": {
            "dbs": "res_ruimte_info_url",
            "label": L("res_ruimte_info_url"),
            "typ": "varchar"
        },
        "location": { // wordt alleen gebruikt als filter en het tonen van de locatiecode in de lijst
            "dbs": "v_locatie_filter.tbl_res_ruimte_key",
            "label": L("lcl_location"),
            "typ": "key",
            "hidden_fld": true,
            "foreign": {
                "tbl": get_tbl(1),
                "key": "tbl_res_ruimte_key",
                "desc": "alg_locatie_code",
                "selectorforeign": "ALG_RUIMTE",
                "selectorparams": {"startlevel": 2, "eindlevel": 5, "readonlylevel": 1}
            },
            "foreignfiltercode": null,  // Ook facilitor irrelevant
            "showtransit": true
        },
        "bookingdiscipline": {
            "dbs": "res_discipline_key",
            "label": L("res_discipline_key"),
            "typ": "key",
            "foreign": {
                "tbl": "res_discipline",
                "key": "ins_discipline_key",
                "desc": "ins_discipline_omschrijving",
                "where": "ins_discipline_verwijder is null AND ins_discipline_min_level = 3"
            },
            "required": true,
            "showtransit": true
        },
        "catering": {
            "dbs": "res_ruimte_cv",
            "label": L("res_ruimte_cv"),
            "typ":  "check0",
            "multiedit": true
        },
        "open": {
            "dbs": "res_ruimte_begintijd",
            "label": L("res_ruimte_begintijd"),
            "typ": "float",
            "LOV": api2.getTimetable(),
            "emptyoption": L("lcl_res_standaard").format(toTimeString(S("res_t1"),false)),
            "multiedit": true
        },
        "close": {
            "dbs": "res_ruimte_eindtijd",
            "label": L("res_ruimte_eindtijd"),
            "typ": "float",
            "LOV": api2.getTimetable(),
            "emptyoption": L("lcl_res_standaard").format(toTimeString(S("res_t2"),false)),
            "multiedit": true
        },
        "blockstart": {
            "dbs": "res_ruimte_begintijdblok",
            "label": L("res_ruimte_begintijdblok"),
            "typ": "float",
            "LOV": api2.getTimetable(),
            "multiedit": true
        },
        "blockend": {
            "dbs": "res_ruimte_eindtijdblok",
            "label": L("res_ruimte_eindtijdblok"),
            "typ": "float",
            "LOV": api2.getTimetable(),
            "multiedit": true
        },
        "minduration": {
            "dbs": "res_ruimte_min_duur",
            "label": L("res_ruimte_min_duur"),
            "typ": "float",
            "multiedit": true
        },
        "fixedprice": {
            "dbs": "res_ruimte_prijs_vast",
            "label": L("res_ruimte_prijs_vast"),
            "typ": "check",
            "multiedit": true
        },
        "_intpricelabel": {
            "dbs": "",
            "label": "",
            "typ": "label",
            "labelvalue": L("res_ruimte_intprijs_label")
        },
        "intpricehour": {
            "dbs": "res_ruimte_intprijs",
            "label": L("res_ruimte_intprijs"),
            "iscurrency": true,
            "typ": "float"
        },
        "intpricemorning": {
            "dbs": "res_ruimte_intprijs_ochtend",
            "label": L("res_ruimte_intprijs_ochtend"),
            "iscurrency": true,
            "typ": "float"
        },
        "intpriceafternoon": {
            "dbs": "res_ruimte_intprijs_middag",
            "label": L("res_ruimte_intprijs_middag"),
            "iscurrency": true,
            "typ": "float"
        },
        "intpriceevening": {
            "dbs": "res_ruimte_intprijs_avond",
            "label": L("res_ruimte_intprijs_avond"),
            "iscurrency": true,
            "typ": "float"
        },
        "intpriceday": {
            "dbs": "res_ruimte_intprijs_dag",
            "label": L("res_ruimte_intprijs_dag"),
            "iscurrency": true,
            "typ": "float"
        },
        "_extpricelabel": {
            "dbs": "",
            "label": "",
            "typ": "label",
            "labelvalue": L("res_ruimte_extprijs_label")
        },
        "extpricehour": {
            "dbs": "res_ruimte_prijs",
            "label": L("res_ruimte_prijs"),
            "iscurrency": true,
            "typ": "float"
        },
        "extpricemorning": {
            "dbs": "res_ruimte_prijs_ochtend",
            "label": L("res_ruimte_prijs_ochtend"),
            "iscurrency": true,
            "typ": "float"
        },
        "extpriceafternoon": {
            "dbs": "res_ruimte_prijs_middag",
            "label": L("res_ruimte_prijs_middag"),
            "iscurrency": true,
            "typ": "float"
        },
        "extpriceevening": {
            "dbs": "res_ruimte_prijs_avond",
            "label": L("res_ruimte_prijs_avond"),
            "iscurrency": true,
            "typ": "float"
        },
        "extpriceday": {
            "dbs": "res_ruimte_prijs_dag",
            "label": L("res_ruimte_prijs_dag"),
            "iscurrency": true,
            "typ": "float"
        },
        "image": {
            "dbs": "res_ruimte_image",
            "label": L("res_ruimte_image"),
            "typ": "file",
            "module": "RESPHR"
        },
        "waitingarea": {
            "dbs": "res_ruimte_groep",
            "label": L("res_ruimte_groep"),
            "typ": "varchar"
        },
        "visitoraction": {
            "dbs": "bez_actie_key",
            "label": L("bez_actie_key"),
            "typ": "key",
            "foreign": {
                "tbl": "(SELECT a.bez_actie_key"
                     + "      , a.bez_actie_omschrijving ||' ('|| g.bez_actie_groep_omschrijving ||')' bez_actie_omschrijving"
                     + "      , g.bez_actie_groep_omschrijving"
                     + "   FROM bez_actie a"
                     + "      , bez_actie_groep g"
                     + "  WHERE a.bez_actie_groep_key = g.bez_actie_groep_key(+)"
                     + "    AND a.bez_actie_verwijder IS NULL"
                     + "    AND g.bez_actie_groep_verwijder IS NULL"
                     + ")",
                "key": "bez_actie_key",
                "desc": "bez_actie_omschrijving",
                "order": "bez_actie_groep_omschrijving, bez_actie_omschrijving"
            },
            "multiedit": true,
            "LOVinit": ""
        },
        "defaultstatus": {
            "dbs": "res_status_fo_key",
            "label": L("res_status_fo_key"),
            "typ": "key",
            "LOV": L("res_status_fo_keyLOV"),
            "LOVinit": ""
        },
        "friendlyname": {
            "dbs": "res_ruimte_friendlyname",
            "label": L("res_ruimte_friendlyname"),
            "typ": "varchar"
        },
        "startdate": {
            "dbs": "res_ruimte_startdatum",
            "label": L("res_ruimte_startdatum"),
            "typ": "date",
            "multiedit": true
        },
        "expirationdate": {
            "dbs": "res_ruimte_vervaldatum",
            "label": L("res_ruimte_vervaldatum"),
            "typ": "date",
            "multiedit": true
        },
        "externalid": {
            "dbs": "res_ruimte_extern_id",
            "label": L("res_ruimte_extern_id"),
            "typ": "varchar",
            "readonly": !hasRESMGT
        },
        "externalsyncdate": {
            "dbs": "res_ruimte_externsyncdate",
            "label": L("extern_syncdate"),
            "typ": "datetime",
            "hidden_fld": !user.has("WEB_FACFAC")
        },
        "syncdate": {
            "dbs": "x_ruimte_syncdate",
            "sql": "(SELECT s.res_ruimte_syncdate"
                 + "   FROM res_ruimte_sync s"
                 + "  WHERE s.res_ruimte_key = res_ruimte.res_ruimte_key)",
            "label": L("res_ruimte_syncdate"),
            "typ": "datetime",
            "sqlshow": true,
            "hidden_fld": !user.has("WEB_FACFAC")
        },
        "graphhooksecret": {
            "dbs": "res_ruimte_graphhooksecret",
            "label": L("res_ruimte_msgraph"),
            "typ": "varchar",
            "hidden_fld": !user.has("WEB_FACFAC")
        },
        "onlineMeetingProviders": {
            "dbs": "res_ruimte_extern_meeting",
            "label": L("res_ruimte_microsoft_teams"),
            "typ": "number",
            "LOV": L("res_ruimte_microsoft_teamsLOV"),
            "readonly": !hasRESMGT,
            "required": true,
            "defaultvalue": 0,
            "multiedit": true
        },
        "externalFlags": {
            "dbs": "res_ruimte_extern_flags",
            "label": L("res_ruimte_extern_flags"),
            "typ": "number",
            "required": true,
            "defaultvalue": 0,
            "hidden_fld": !user.has("WEB_FACTAB"),
            "multiedit": true
        },
        "maxhorizon": {
            "dbs": "res_ruimte_limiet",
            "label": L("res_ruimte_limiet"),
            "typ": "number",
            "multiedit": true
        }
    };

    this.includes = {
        "physicalrooms": {
            "model": new model_res_alg_ruimte(),
            "joinfield": "bookingroom",
            "enable_update": true,
            "required": true
        },
        "bookingconfigurations": {
            "model": new model_res_ruimte_opstelling(),
            "joinfield": "bookingroom",
            "multiadd": "bookingconfiguration",
            "enable_update": true,
            "required": true
        }
    };

    // res_v_alg_ruimte_gegevens levert voor een koppelzaal meerdere records waardoor de opstelling ook meervoudig wordt weergegeven.
    // Door alleen de onderstaande unieke combinaties te nemen wordt dit opgelost.
    // JGL: liever zou ik dit generieker doen via includes/rooms/locatiekey maar dat werd onwerkbaar complex
    function get_tbl(singlerow, alias)
    {
        var sql = "(SELECT DISTINCT nt.alg_locatie_key"
                + "      , nt.alg_locatie_code"
                + (singlerow ? "" : "      , nt.alg_gebouw_key")
                + (singlerow ? "" : "      , nt.alg_verdieping_key")
                + "      , CASE WHEN nt.alg_ruimte_count = 1 THEN nt.alg_ruimte_key ELSE NULL END alg_ruimte_key"
                + "      , nt.tbl_res_ruimte_key"
                + "   FROM (SELECT r.alg_locatie_key"
                        + "      , r.alg_gebouw_key"
                        + "      , r.alg_verdieping_key"
                        + "      , MIN(r.alg_ruimte_key) alg_ruimte_key"
                        + "      , (SELECT COUNT(*)"
                        + "           FROM res_alg_ruimte"
                        + "          WHERE res_alg_ruimte_verwijder IS NULL"
                        + "            AND res_ruimte_key = r.res_ruimte_key"
                        + "        ) alg_ruimte_count"
                        + "      , r.res_ruimte_key      tbl_res_ruimte_key"
                        + "      , r.res_ruimte_nr       alg_plaatsaanduiding"
                        + "      , l.alg_locatie_code"
                        + "      , r.res_alg_ruimte_key"
                        + "   FROM res_v_alg_ruimte_gegevens r"
                        + "      , alg_locatie l"
                        + "  WHERE r.alg_locatie_key = l.alg_locatie_key"
                        + "  GROUP BY r.alg_locatie_key"
                        + "         , r.alg_gebouw_key"
                        + "         , r.alg_verdieping_key"
                        + "         , r.res_ruimte_key"
                        + "         , r.res_ruimte_nr"
                        + "         , l.alg_locatie_code"
                        + "         , r.res_alg_ruimte_key"
                        + ") nt"
                + ")";
        if (alias)
            sql += " " + alias;
        return sql;
    }

    // Als Extern ID aangepast is moeten we mogelijk webhooks maken en/of verwijderen
    function _updateSubscriptions(result, newjsondata, oldjsondata) {
        if ((S("msgraph_sync_level") & 1) &&                // Willen we uberhaupt luisteren naar MS Graph?
            result && !result.warning && result.key > 0 &&  // De REST POST/PUT is correct afgehandeld
            (   "startdate" in newjsondata ||
                "expirationdate" in newjsondata ||
                "externalid" in newjsondata)) {             // Relevante data is meegegeven (anders kan het sowieso niet veranderd zijn)

            var res_ruimte_key = result.key;
            oldjsondata = oldjsondata || {};

            var windowChanged = (new Date(oldjsondata["startdate"] || null).getTime() != new Date(newjsondata["startdate"]).getTime()) ||           // Startdatum gewijzigd
                                (new Date(oldjsondata["expirationdate"] || null).getTime() != new Date(newjsondata["expirationdate"]).getTime());   // Vervaldatum gewijzigd

            if (((oldjsondata["externalid"] || "") != newjsondata["externalid"] /* Extern ID gewijzigd */ || windowChanged)
                && (oldjsondata["externalid"] || newjsondata["externalid"]) // Ik ben of was een externe ruimte
                && (newjsondata["id"] > -1 || newjsondata["externalid"])) { // Nieuwe ruimtes moeten een nieuw Extern ID hebben ingevuld, anders is deze tak nvt
                // Initialize hook
                var DEZE = this;
                var hook = hookfunc.gethook("utils/exchange/res_to_graph.wsc");
                hook.initialize({
                    DEZE: DEZE,
                    custabspath: Server.MapPath(custpath)
                });
                if (oldjsondata["externalid"]) { // Opschonen moet sowieso gebeuren als dit veld een andere waarde had;
                    // Maak nu ook de res_ruimte_syncstate en res_ruimte_syncdate in de res_ruimte_sync tabel leeg
                    var sql = "UPDATE res_ruimte_sync SET res_ruimte_syncstate = NULL, res_ruimte_syncdate = NULL WHERE res_ruimte_key = " + res_ruimte_key;
                    Oracle.Execute(sql);
                    // En ook de res_ruimte_externsyncdate en res_ruimte_graphhooksecret uit de res_ruimte tabel
                    var sql = "UPDATE res_ruimte SET res_ruimte_externsyncdate = NULL, res_ruimte_graphhooksecret = NULL WHERE res_ruimte_key = " + res_ruimte_key;
                    Oracle.Execute(sql);
                    if (hook.subscription(oldjsondata["externalid"], res_ruimte_key, "D")) {
                        __DoLog("MS Graph subscription deleted for res_ruimte (" + res_ruimte_key + ") with Extern ID: " + oldjsondata["externalid"], "#FF4");
                    } else {
                        __DoLog("Error: Failed to delete MS Graph subscription for res_ruimte (" + res_ruimte_key + ") with Extern ID: " + oldjsondata["externalid"], "#FF0000");
                    }
                }
                if (newjsondata["externalid"]) {
                    if (hook.subscription(newjsondata["externalid"], res_ruimte_key, "C")) {
                        __DoLog("MS Graph subscription created for res_ruimte (" + res_ruimte_key + ") with Extern ID: " + newjsondata["externalid"], "#FF4");
                    } else {
                        __DoLog("Error: Failed to create MS Graph subscription for res_ruimte (" + res_ruimte_key + ") with Extern ID: " + newjsondata["externalid"], "#FF0000");
                    }
                }
                hook = null;
            }
        }
    }

    this._validate_fields = function (dbfields, params, jsondata, the_key)
    {
        if (jsondata.startdate && jsondata.expirationdate)
        {
            if (jsondata.startdate > jsondata.expirationdate)
                abort_with_warning(L("lcl_res_room_datecheck"));
        }
    }

    this.REST_GET  = function _GET(params, jsondata)
    {
        var query = api2.sqlfields(params, this);
        var wheres = api2.sqlfilter(params, this);
        query.tables.push(get_tbl(0, "v_locatie_filter"));
        query.wheres.push("res_ruimte.res_ruimte_key = v_locatie_filter.tbl_res_ruimte_key(+)");
        if (this.gparams && this.gparams.GET && this.gparams.GET.wheres)
        {
            query.wheres = query.wheres.concat(this.gparams.GET.wheres);
        }
        query.wheres = query.wheres.concat(wheres);
        if (this.soft_delete && params.filter.show_deleted != "on" && !params.filter.id) {
            query.wheres.push(this.soft_delete + " IS NULL");
        }
        if (this.soft_expire && params.filter.show_expired != "on" && !params.filter.id) {
            query.wheres.push("(" + this.soft_expire + " IS NULL OR " + this.soft_expire + " > SYSDATE)");
        }

        query.orderbys = ["res_ruimte_nr"].concat(query.orderbys);

        var sql = "SELECT DISTINCT " + query.selects.join(",")
                + "  FROM " + query.tables.join(",");
        if (query.wheres.length)
            sql += " WHERE " + query.wheres.join(" AND ");
        if (query.orderbys.length)
            sql += " ORDER BY " + query.orderbys.join(","); // Nodig om ook nog op res_room_key of res_room_omschrijving te sorteren?
        var json = api2.sql2json(params, sql, this);
        return json;
    };

    this.REST_POST = function _POST(params, jsondata) {
        var result = generic_REST_POST(this)(params, jsondata);
        _updateSubscriptions(result, jsondata, null);
        return result;
    };

    this.REST_PUT    = function _PUT(params, jsondata, the_key) {
        var dbfields = {}; //api2.update_fields(params, this, jsondata); // Build updater
        this._validate_fields(dbfields, params, jsondata, the_key);
        var oldjsondata = {};
        if (S("msgraph_sync_level") & 1) {
            var sql = "SELECT res_ruimte_extern_id, res_ruimte_startdatum, res_ruimte_vervaldatum"
                    + "  FROM res_ruimte"
                    + " WHERE res_ruimte_key = " + the_key;
            var oRs = Oracle.Execute(sql);
            oldjsondata["externalid"] = oRs("res_ruimte_extern_id").Value || "";
            oldjsondata["startdate"] = oRs("res_ruimte_startdatum").Value;
            if (typeof oldjsondata["startdate"] === "date") {
                oldjsondata["startdate"] = new Date(oldjsondata["startdate"]);
            }
            oldjsondata["expirationdate"] = oRs("res_ruimte_vervaldatum").Value;
            if (typeof oldjsondata["expirationdate"] === "date") {
                oldjsondata["expirationdate"] = new Date(oldjsondata["expirationdate"]);
            }
            oRs.Close();
        }
        var result = generic_REST_PUT(this)(params, jsondata, the_key);
        _updateSubscriptions(result, jsondata, oldjsondata);
        return result;
    };

    this.REST_DELETE = generic_REST_DELETE(this, {});
}
%>