<% /* $Revision$ $Id$ File: model_reservations.inc Description: Reservering model. Parameters: Context: Notes: In het technisch datamodel heeft een reservering een koppeling naar een res_ruimte_opstel record (een geldige ruimte<->opstelling combinatie) In de API splitsen we dat in de meer natuurlijk aanvoelende res_ruimte_key en res_ruimte_opstel_key We ondersteunen nog niet het aanmaken van een tweede deelreservering onder een reservering. */ %> <% var sqlro = "SELECT rg.res_ruimte_nr || CASE WHEN res_ruimte_opstel_default = 1 THEN '' ELSE ' (' || ro.res_opstelling_omschrijving || ')' END CASE" + " FROM res_ruimte_opstelling rro" + " , res_opstelling ro" + " , res_v_alg_ruimte_gegevens rg" + " WHERE rro.res_opstelling_key = ro.res_opstelling_key" + " AND rro.res_ruimte_key = rg.res_ruimte_key" + " AND rro.res_ruimte_opstel_key = res_rsv_ruimte.res_ruimte_opstel_key"; function fndirtwarn(level) { if (level & res.dirtlevel.ruimte.notavailable) return L("lcl_res_dirtyroom"); return null; } function model_reservations(rsv_key, params) { this.module = "RES"; this.table = "res_rsv_ruimte"; this.primary = "res_rsv_ruimte_key"; this.records_name = "reservations"; this.record_name = "reservation"; this.fields = {"id" : { dbs: "res_rsv_ruimte_key", typ: "key", filter: "exact", label: L("lcl_reservation") }, "name" : { dbs: "res_reservering_id", sql: "res_reservering_key||'/'||res_rsv_ruimte_volgnr", typ: "varchar", label: L("lcl_reservation")}, "from" : { dbs: "res_rsv_ruimte_van", typ: "datetime", filter: "range", label: L("lcl_res_starttime"), track: true}, // TODO: Andere lcl voor catering "to" : { dbs: "res_rsv_ruimte_tot", typ: "datetime", filter: "range", label: L("lcl_res_endtime"), track: true}, "description" : { dbs: "res_rsv_ruimte_omschrijving", typ: "varchar", label: L("lcl_descr"), track: true }, "activity" : { dbs: "res_activiteit_key", typ: "key", filter: "exact", foreign: "res_activiteit", label: L("lcl_activity"), track: true }, "remark" : { dbs: "res_rsv_ruimte_opmerking", typ: "varchar", label: L("lcl_remark"), track: true}, "host" : { dbs: "res_rsv_ruimte_host_key", typ: "key", foreign: "prs_perslid", label: L("lcl_host"), track: true}, "contact" : { dbs: "res_rsv_ruimte_contact_key", typ: "key", foreign: "prs_perslid", label: L("lcl_name"), track: true}, "visitorscount" : { dbs: "res_rsv_ruimte_bezoekers", typ: "number", label: L("lcl_visitors"), track: true }, "status" : { dbs: "res_status_fo_key", typ: "key", foreign: res.getfostatustext }, "flag" : { dbs: "res_rsv_ruimte_flag", typ: "number", LOV: ""}, "resroom" : { dbs: "res_ruimte_opstelling.res_ruimte_key", typ: "key", filter: "exact", label: L("lcl_room"), foreign: "res_ruimte" }, "configuration" : { dbs: "res_ruimte_opstelling.res_opstelling_key", typ: "key", foreign: "res_opstelling" }, "approved" : { dbs: "res_rsv_ruimte_afgerond", typ: "number", label: L("lcl_res_resappr"), track: true }, "warning" : { dbs: "res_rsv_ruimte_dirtlevel", typ: "number", foreign: fndirtwarn, readonly: true }, "reservation" : { dbs: "res_reservering_key", typ: "key", label: L("lcl_reservation") }, "extern_id" : { dbs: "res_rsv_ruimte_externnr", typ: "varchar", label: L("lcl_extrn_nr") } }; // Mogelijke waarden voor res_rsv_ruimte_flag is afhankelijk van het aantal toegestane flags. if (S("res_reservering_flags") > 0) { flag_array = []; for (i=0; i 0) { var this_res = res.func_enabled(params.filter.id); user.auth_required_or_abort(this_res.canReadAny); } else // lijst { var scope = params.filter.scope || "fe"; var autfunction = { fe : "WEB_RESUSE", fo : "WEB_RESFOF", bo : "WEB_RESBOF", mi : "WEB_RESBAC" } [scope]; params.authparams = user.checkAutorisation(autfunction, null, null, true); // pessimistisch if (scope == "fe") { query.wheres.push(user_key + " IN (res_rsv_ruimte_host_key, res_rsv_ruimte_contact_key)"); query.wheres.push("res_rsv_ruimte_van BETWEEN SYSDATE - " + S("facilitiespast_res") + " AND SYSDATE + " + S("facilitiesfuture_res")); } else { if (!params.filter.start_from && !params.filter.end_from && !params.filter.start_to && !params.filter.end_to) query.wheres.push("res_rsv_ruimte_van >= TRUNC(SYSDATE)"); // reserveringen van vandaag en komende dagen! } } query.tables.push("res_ruimte_opstelling"); query.tables.push("res_ruimte rr"); query.tables.push("res_alg_ruimte ra"); query.tables.push("alg_v_ruimte_gegevens_all rg"); query.tables.push("alg_district di"); query.tables.push("prs_perslid p"); query.tables.push("prs_v_afdeling_boom boom"); query.wheres.push("res_rsv_ruimte.res_ruimte_opstel_key = res_ruimte_opstelling.res_ruimte_opstel_key(+)"); query.wheres.push("rr.res_ruimte_key(+) = ra.res_ruimte_key"); query.wheres.push("ra.res_ruimte_key(+) = res_ruimte_opstelling.res_ruimte_key"); query.wheres.push("rg.alg_ruimte_key = COALESCE(res_rsv_ruimte.alg_ruimte_key, ra.alg_ruimte_key)"); query.wheres.push("rg.alg_district_key = di.alg_district_key"); query.wheres.push("res_rsv_ruimte.res_rsv_ruimte_contact_key = p.prs_perslid_key"); query.wheres.push("boom.prs_afdeling_key = p.prs_afdeling_key"); var wheres = api2.sqlfilter(params, this); query.wheres = query.wheres.concat(wheres); query.wheres.push("res_rsv_ruimte_verwijder IS NULL"); var sql = "SELECT " + query.selects.join(", ") + " FROM " + query.tables.join(", ") + " WHERE " + query.wheres.join(" AND " ); if (!(params.filter.id > 0)) { // Over het resultaat moet nog de 3D rasp, altijd sql = discx3d (sql, "rr.res_discipline_key", "di.alg_regio_key", "rg.alg_district_key", "rg.alg_locatie_key", "rg.alg_gebouw_key", "rg.alg_verdieping_key", "rg.alg_ruimte_key", "boom.prs_bedrijf_key", "boom.prs_afdeling_key", autfunction, "", 2,null,3 ); } sql += " ORDER BY res_rsv_ruimte.res_rsv_ruimte_key"; // Order by nodig voor includes if (query.orderbys.length) sql += ", " + query.orderbys.join(", "); var json = api2.sql2json (params, sql, this ); return json; }; function _analyze_fields(dbfields, params, jsondata) /* analyseer inkomende data, common voor PUT en POST */ /* res_ruimte+config wordt bijvoorbeeld omgezet in res_ruimte_opstel_key */ { if ("resroom" in jsondata) { var res_ruimte_key = parseInt(jsondata.resroom); var res_opstel_key = -1; if ("configuration" in jsondata) // Pas op: opstelling 'Standaard' heeft soms key 0 res_opstel_key = parseInt(jsondata.configuration); // De default komt bovenaan var sql = "SELECT rro.res_ruimte_opstel_key" + " , COALESCE (rro.res_ruimte_opstel_default, 0)" + " , rr.res_discipline_key" + " FROM res_ruimte_opstelling rro" + " , res_opstelling ro" + " , res_ruimte rr" + " WHERE rro.res_opstelling_key = ro.res_opstelling_key" + " AND rr.res_ruimte_key = " + res_ruimte_key + " AND rro.res_ruimte_key = " + res_ruimte_key + (res_opstel_key>=0 ? " AND ro.res_opstelling_key = " + res_opstel_key: "") + " ORDER BY COALESCE (rro.res_ruimte_opstel_default, 0)" + " , res_opstelling_volgnr"; var oRs = Oracle.Execute(sql); var res_disc_key = oRs("res_discipline_key").value; var soort = 0; // reserveerbare ruimtes dbfields["configuration"] = { dbs: "res_ruimte_opstel_key", typ: "key", val: oRs("res_ruimte_opstel_key").Value }; dbfields["room"] = { dbs: "alg_ruimte_key", typ: "key", val: -1 }; dbfields["bostatus"] = { dbs: "res_status_bo_key", typ: "key", val: 2 }; // 'ingevoerd'. Altijd bij ruimte reserveringen oRs.Close(); } else // moet er een alg_ruimte zijn { // TODO api2.error(500, "Missing room in input"); // var res_disc_key = ... // var soort = 1; // algemene ruimtes } if ("activity" in jsondata) { // TODO: mag hij? Of controleren we dat in _validate_fields } else { if (params.isNew) { // Er is nog niet het concept 'default activiteit' dus pak gewoon de laagste sql = " SELECT MIN (ra.res_activiteit_key) res_activiteit_key " + " FROM res_activiteitdiscipline ad, " + " res_activiteit ra," + " res_srtactiviteit rs" + " WHERE ad.res_discipline_key = " + res_disc_key + " AND ra.res_activiteit_key = ad.res_activiteit_key" + " AND rs.res_srtactiviteit_key = ra.res_srtactiviteit_key" + " AND res_srtactiviteit_soort = " + soort; oRs = Oracle.Execute(sql); //jsondata.activity = oRs("res_activiteit_key").Value; dbfields["activity"] = { dbs: "res_activiteit_key", typ: "key", val: oRs("res_activiteit_key").Value }; oRs.Close() } } } function _validate_fields (dbfields, params, jsondata) /* valideer dbfields, alle constraints die niet door de database worden afgevangen */ { }; this.REST_PUT = function (params, jsondata, the_key) /* update reservation */ { var rsv_ruimte_key = the_key; var this_res = res.func_enabled(rsv_ruimte_key); user.auth_required_or_abort(this_res.canChange); var dbfields = api2.update_fields(params, this, jsondata); // Build updater _analyze_fields(dbfields, params, jsondata); _validate_fields(dbfields, params, jsondata); var wheres = [" res_rsv_ruimte_key = " + rsv_ruimte_key]; // ons eigen tijdstip/zaal is mogelijk gewijzigd waardoor andere *dirty* reserveringen // clean wordt. Even onze oude datum onthouden zodat we niet *alles* hoeven te controleren // Ook even noshow onthouden oRs = Oracle.Execute("SELECT res_reservering_key" + " , res_rsv_ruimte_van" + " , res_rsv_ruimte_tot" + " , res_rsv_ruimte_noshow" + " , res_rsv_ruimte_volgnr" + " FROM res_rsv_ruimte" + " WHERE res_rsv_ruimte_key = " + rsv_ruimte_key); var reservering_key = oRs("res_reservering_key").Value; var oldvan = new Date(oRs("res_rsv_ruimte_van").Value); var oldtot = new Date(oRs("res_rsv_ruimte_tot").Value); var oldnoshow = oRs("res_rsv_ruimte_noshow").Value == 1; var volgnr = oRs("res_rsv_ruimte_volgnr").Value; var resUpd = buildTrackingUpdate("res_rsv_ruimte", wheres.join(" AND " ), dbfields, { noValidateToken: true }); var check_fail_sql = " if res.dirty_level_all(" + rsv_ruimte_key + ") <> 0 then" + " raise_application_error (-20000, 'res_m999 " + L("lcl_res_fe_no_dirty") + "');" + " end if;" var sql = "BEGIN " + resUpd.sql + ";" + " res.set_ruimte_dirty (" + rsv_ruimte_key + "); " // Zelf dirty geworden? + " res.set_ruimtes_clean (" + oldvan.toSQL() + "); " // Anderen 'clean' geworden + " res.follow_artikel (" + rsv_ruimte_key + ", " + oldvan.toSQL(true) + ", " + oldtot.toSQL(true) + "); " // catering mee verplaatsen + " res.follow_deel (" + rsv_ruimte_key + ", " + oldvan.toSQL(true) + ", " + oldtot.toSQL(true) + "); " // objecten mee verplaatsen + " res.follow_afspraak (" + rsv_ruimte_key + ", " + S("res_copy_to_bez") + "); " // bezoekers mee verplaatsen + check_fail_sql + "END;"; var err = Oracle.Execute(sql, true); if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); var restrack = api2.process_includes(params, this, jsondata, the_key); // TODO: Tracking // TODO: Bezoekers // TODO: Flex var flextrack = []; //var result = saveBezoekers(afspr_key, -1, { urole: urole, loctimechanged: changed }); //if (result.beztrack && result.beztrack.length > 0) //bezUpd.trackarray.push(result.beztrack.join("\n")); res.trackreserveringupdate(rsv_ruimte_key, resUpd.trackarray.length || flextrack.length? L("lcl_res_is_resupdtrack").format(reservering_key + "/" + volgnr) + "\n" + resUpd.trackarray.concat(flextrack).join("\n") : null); return { key: rsv_ruimte_key }; }; this.REST_POST = function (params, jsondata) /* new reservation */ { params.isNew = true; var dbfields = api2.update_fields(params, this, jsondata); // Build updater _analyze_fields(dbfields, params, jsondata); _validate_fields(dbfields, params, jsondata); // Eerst een nieuw res_reservering record aanmaken var resfields = { "id": { dbs: "res_reservering_key", typ: "key", seq: "res_s_res_reservering_key" }, "create": { dbs: "res_reservering_aanmaak", typ: "datetime", val: new Date() } }; var resIns = buildInsert("res_reservering", resfields, { noValidateToken: true }); var reservering_key = resIns.sequences["res_reservering_key"]; var volgnr = 1; Oracle.Execute(resIns.sql); var host_key = user_key; var contact_key = user_key; if (user.has("WEB_RESFOF")) { if ("host" in jsondata) host_key = jsondata.host; if ("contact" in jsondata) contact_key = jsondata.contact; } // Nu aan de slag met een res_rsv_ruimte record dbfields["id"] = { dbs: "res_rsv_ruimte_key", typ: "key", seq: "res_s_res_rsv_ruimte_key" }; dbfields["reskey"] = { dbs: "res_reservering_key", typ: "key", val: reservering_key }; dbfields["sequence"] = { dbs: "res_rsv_ruimte_volgnr", typ: "number", val: volgnr }; dbfields["host"] = { dbs: "res_rsv_ruimte_host_key", typ: "key", val: host_key }; dbfields["contact"] = { dbs: "res_rsv_ruimte_contact_key", typ: "key", val: contact_key }; if (!jsondata.status) dbfields["status"] = { dbs: "res_status_fo_key", typ: "key", val: S("res_default_fe_status_key") }; var resIns = buildInsert("res_rsv_ruimte", dbfields, { noValidateToken: true }); var rsv_ruimte_key = resIns.sequences["res_rsv_ruimte_key"]; var check_fail_sql = " if res.dirty_level_all(" + rsv_ruimte_key + ") <> 0 then" + " raise_application_error (-20000, 'res_m999 " + L("lcl_res_fe_no_dirty") + "');" + " end if;" var sql = "BEGIN " + resIns.sql + ";" //+ deel_sql + " res.set_ruimte_dirty (" + rsv_ruimte_key + "); " // Zelf dirty geworden? // set_ruimtes_clean hoeft niet: wij zijn nieuw en kunnen daarmee nooit een ander clean maken + check_fail_sql + "END;"; var err = Oracle.Execute(sql, true); if (err.friendlyMsg) abort_with_warning(err.friendlyMsg); var restrack = api2.process_includes(params, this, jsondata, rsv_ruimte_key); shared.trackaction("RESNEW", rsv_ruimte_key); return { key: rsv_ruimte_key }; }; this.REST_DELETE = function (params, the_key) /* delete reservation */ { // Sterk afgekeken van res_delete_save.asp. Die moet op termijn deze functie gaan // gebruiken maar dan moet de auth_required_or_abort mogelijk weer iets 'zachter' var cost_recharge = false; // TODO? var rsv_ruimte_key = the_key; var this_res = res.func_enabled(rsv_ruimte_key); // Wat mag ik op deze deelreservering user.auth_required_or_abort(this_res.canDelete); DeleteResAfspraak(rsv_ruimte_key); // update ruimte // equipment en articles are deleted automatically if the RES_RSV_RUIMTE is deleted // Deze velden altijd opslaan var dbfields = [ { dbs: "res_rsv_ruimte_opmerking", typ: "varchar", frm: "opmerk" }, { dbs: "res_status_fo_key", typ: "key", val: (cost_recharge? 4 : 1) }, // status 1=optie, 4=vervallen { dbs: "res_rsv_ruimte_verwijder", typ: "sql", val: "SYSDATE" } ]; var sql = buildUpdate("res_rsv_ruimte", dbfields, { noValidateToken: true }) + " res_rsv_ruimte_key = " + rsv_ruimte_key; // ons eigen tijdstip/zaal is mogelijk gewijzigd waardoor andere *dirty* reserveringen // clean wordt. Even onze oude datum onthouden zodat we niet *alles* hoeven te controleren var oRs = Oracle.Execute("select res_rsv_ruimte_van," + " res_rsv_ruimte_tot" + " from res_rsv_ruimte" + " where res_rsv_ruimte_key = " + rsv_ruimte_key); var oldvan = new Date(oRs("res_rsv_ruimte_van").value); var oldtot = new Date(oRs("res_rsv_ruimte_tot").value); oRs.Close(); // Nu de echte update. // Daarbij ook diverse controles/ updates uitvoeren op 'andere zaken' sql = "BEGIN " + sql + ";" + " res.set_ruimte_dirty (" + rsv_ruimte_key + "); " // Zelf dirty geworden? + " res.set_ruimtes_clean (" + oldvan.toSQL() + "); " // Anderen 'clean' geworden + " res.follow_artikel (" + rsv_ruimte_key + ", " + oldvan.toSQL(true) + ", " + oldtot.toSQL(true) + "); " // catering mee verplaatsen + " res.follow_deel (" + rsv_ruimte_key + ", " + oldvan.toSQL(true) + ", " + oldtot.toSQL(true) + "); " // objecten mee verplaatsen + "END;"; Oracle.Execute( sql ); shared.trackaction("RESDEL", rsv_ruimte_key); // En tenslotte eventueel de reservering zelf nog sql = "UPDATE res_reservering " + " SET res_reservering_verwijder=SYSDATE" + " WHERE res_reservering_key="+this_res.res_reservering_key + " AND NOT EXISTS (SELECT *" + " FROM res_v_aanwezigrsv_ruimte" + " WHERE res_reservering_key=" + this_res.res_reservering_key + ")" Oracle.Execute( sql ); } if (rsv_key > 0) { params.filter = params.filter || {}; params.filter.id = rsv_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]; } } %>