From f1b56bb5207b4211d09ab5c92e57610ed893fd50 Mon Sep 17 00:00:00 2001 From: Keanu D?lle Date: Mon, 25 Apr 2022 05:27:47 +0200 Subject: [PATCH] FEA: added event billing list --- resources/ajax_templates/eb_list_card.hbs | 51 ++++++ resources/js/eb_list.js | 146 ++++++++++++++++++ resources/js/em_eventlist.js | 29 +--- resources/js/global.js | 30 +++- resources/templates/module_eb_list.html.hbs | 98 ++++++++++++ resources/templates/sidebar.html.hbs | 2 + src/database/controller/events.rs | 13 +- src/main.rs | 1 + src/modules/api/events/read.rs | 22 ++- .../event_billing/event_billing_list.rs | 61 ++++++++ src/modules/event_billing/mod.rs | 3 +- 11 files changed, 418 insertions(+), 38 deletions(-) create mode 100644 resources/ajax_templates/eb_list_card.hbs create mode 100644 resources/js/eb_list.js create mode 100644 resources/templates/module_eb_list.html.hbs create mode 100644 src/modules/event_billing/event_billing_list.rs diff --git a/resources/ajax_templates/eb_list_card.hbs b/resources/ajax_templates/eb_list_card.hbs new file mode 100644 index 0000000..7816e3a --- /dev/null +++ b/resources/ajax_templates/eb_list_card.hbs @@ -0,0 +1,51 @@ +
+
{{timeframe}}: {{name}} {{#each cast_status.open_positions}}{{position_name}}{{/each}}
+
+
+
+
+
+
+
+
Veranstaltung
+

Name: {{name}}

+

Art: {{etype}}

+

Zeitraum: {{timeframe}}

+

Veranstaltungsort: {{site}}

+

Ansprechpartner vor Ort: {{contact_on_site_name}} ({{contact_on_site_phone}})

+
Intern
+

Ansprechpartner: {{member_responsible}}

+

Gruppe: {{related_group}}

+

Anmerkung: {{other}}

+
+
+
Veranstalter
+

Firma/Organisation: {{organiser.company}}

+

Name: {{organiser.firstname}} {{organiser.lastname}}

+ {{#if organiser.phone}}

Telefon: {{organiser.phone}}

{{/if}} + {{#if organiser.email}}

Email: {{organiser.email}}

{{/if}} + {{#if organiser.other}}

Sonstiges: {{organiser.other}}

{{/if}} +
Abrechnung
+

Status: {{state_name}}

+
+
+
+
+
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/resources/js/eb_list.js b/resources/js/eb_list.js new file mode 100644 index 0000000..d1c7f48 --- /dev/null +++ b/resources/js/eb_list.js @@ -0,0 +1,146 @@ +$(document).ready(async function () { + await EventBillingList.setup(); +}); + +EventBillingList = (function () { + let templates = {}; + let pending_requests = []; + let limit = 10; + + let setup = async function () { + await load_templates(); + await setup_pagination(); + await load_events(0); + $(".event_billing_list_load").off("click").on("click", load_events); + }; + let load_templates = function(){ + $.get("/templates/eb_list_card.hbs", function( res) { + templates.eb_list_card = Handlebars.compile(res); + }); + $.get("/templates/pagination.hbs", function( res) { + templates.pagination = Handlebars.compile(res); + }); + }; + let setup_pagination = function(){ + pag = new Pagination("eb_list_pagination", templates.pagination, ".billingpag", limit, load_events); + }; + let load_events = function(offset){ + if(offset === undefined || !Number.isInteger(offset)){ + offset = 0; + } + + let args = ""; + if($("#event_billing_list_start_datetime").val()){ + args += "&start="+$("#event_billing_list_start_datetime").val(); + } + if($("#event_billing_list_end_datetime").val()){ + args += "&end="+$("#event_billing_list_end_datetime").val(); + } + if($("#event_billing_list_groups_select").val()){ + args += "&groups="+$("#event_billing_list_groups_select").val(); + } + + //Add filter for event status to args + let event_states = ""; + if ($("#event_billing_list_status_unknown").prop("checked")){ + event_states += "0," + } + if ($("#event_billing_list_status_event_opened").prop("checked")){ + event_states += "2," + } + if ($("#event_billing_list_status_event_closed").prop("checked")){ + event_states += "4," + } + if ($("#event_billing_list_status_event_times_approved").prop("checked")){ + event_states += "6," + } + if ($("#event_billing_list_status_personnal_billing_done").prop("checked")){ + event_states += "7," + } + if ($("#event_billing_list_status_billing_approved").prop("checked")){ + event_states += "8," + } + if(event_states){ + args += "&states="+event_states.slice(0, event_states.length - 1); //Remove last comma + } + + //Load results + $.ajax({ + type: "GET", + url: "/api/events/?limit="+limit+"&offset="+offset+args, + contentType: 'application/json', + timeout: 3000, + error: function () { + alert("Verbindung zum Server unterbrochen!"); + }, + success: async function (data) { + if (is_ok(data)) { + $("#event_billing_list_accordion").html("").hide(); + + let event_loading_queue = []; + + $(data.events).each(function () { + event_loading_queue.push(load_event(this)) + }); + + async function load_event(event) { + if (event.member_responsible) { + let member = await get_member(event.member_responsible); + event.member_responsible = member.firstname + " " + member.lastname; + } + if (event.related_group) { + event.related_group = await get_related_group(event.related_group); + } + if (event.etype) { + event.etype = await get_event_type(event.etype); + } + if (event.organiser_id) { + event.organiser = await get_organiser(event.organiser_id); + } + + let date = new Date(event.start); + event.timeframe = ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear() + ' ' + ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ' - '; + let date2 = new Date(event.end); + if (date.getDate() === date2.getDate()) { + event.timeframe += ('0' + date2.getHours()).slice(-2) + ':' + ('0' + date2.getMinutes()).slice(-2) + } else { + event.timeframe += event.timeframe = ('0' + date2.getDate()).slice(-2) + '.' + ('0' + (date2.getMonth() + 1)).slice(-2) + '.' + date2.getFullYear() + ' ' + ('0' + date2.getHours()).slice(-2) + ':' + ('0' + date2.getMinutes()).slice(-2); + } + + event.cast_status = await load_event_cast_status(event.entity_id); + + if (event.state === 2) { + event.state_name = "Einsatz geöffnet"; + event.event_status_yellow = true; + } else if (event.state === 4) { + event.state_name = "Einsatz geschlossen"; + event.event_status_red = true; + } else if (event.state === 6) { + event.state_name = "Einsatzzeiten bestätigt"; + event.event_status_red = true; + } else if (event.state === 7) { + event.state_name = "Personalabrechnung abgeschlossen"; + event.event_status_red = true; + } else if (event.state === 8) { + event.state_name = "Abrechnung abgeschlossen"; + event.event_status_green = true; + }else{ + event.state_name = "unbekannt"; + } + return event; + } + + await Promise.all(event_loading_queue).then((values) => { + for(val of values){ + $("#event_billing_list_accordion").append(templates.eb_list_card(val)) + } + $("#event_billing_list_accordion").show(); + }) + } + } + }); + } + return{ + setup + } +}()); \ No newline at end of file diff --git a/resources/js/em_eventlist.js b/resources/js/em_eventlist.js index 1c64876..0761e6c 100644 --- a/resources/js/em_eventlist.js +++ b/resources/js/em_eventlist.js @@ -280,20 +280,6 @@ EventListModule = ( function() { alert("Du erfüllst nicht die nötigen Voraussetzungen für diese Position."); } } - let get_related_group = async function(entity_id){ - const res = await $.ajax({ - type: "GET", - url: "/api/groups/" + entity_id, - contentType: 'application/json', - timeout: 3000, - error: function () { - alert("Verbindung zum Server unterbrochen!"); - }, - }); - if (is_ok(res)) { - return res.name; - } - }; let check_edit_permission_callback = function(has_permission){ if(has_permission === true){ $(".eventlist_navtabs").each(function(){ @@ -301,20 +287,7 @@ EventListModule = ( function() { }); } }; - let load_event_cast_status = async function(event_id){ - const res = await $.ajax({ - type: "GET", - url: "/api/events/" + event_id+"/cast_status", - contentType: 'application/json', - timeout: 3000, - error: function () { - alert("Verbindung zum Server unterbrochen!"); - }, - }); - if (is_ok(res)) { - return res; - } - }; + return{ load_events: load_events, load_templates: load_templates, diff --git a/resources/js/global.js b/resources/js/global.js index 3b253d1..cc757b4 100644 --- a/resources/js/global.js +++ b/resources/js/global.js @@ -383,4 +383,32 @@ let combine_start_end_time = function (start, end) { } else { return start_date + " " + start_time + end_date + " " + end_time; } -} \ No newline at end of file +}; +let get_related_group = async function(entity_id){ + const res = await $.ajax({ + type: "GET", + url: "/api/groups/" + entity_id, + contentType: 'application/json', + timeout: 3000, + error: function () { + alert("Verbindung zum Server unterbrochen!"); + }, + }); + if (is_ok(res)) { + return res.name; + } +}; +let load_event_cast_status = async function(event_id){ + const res = await $.ajax({ + type: "GET", + url: "/api/events/" + event_id+"/cast_status", + contentType: 'application/json', + timeout: 3000, + error: function () { + alert("Verbindung zum Server unterbrochen!"); + }, + }); + if (is_ok(res)) { + return res; + } +}; \ No newline at end of file diff --git a/resources/templates/module_eb_list.html.hbs b/resources/templates/module_eb_list.html.hbs new file mode 100644 index 0000000..cfc7a42 --- /dev/null +++ b/resources/templates/module_eb_list.html.hbs @@ -0,0 +1,98 @@ +{{> header }} +
+
+
+ {{> sidebar }} + {{> searchbar}} +
+
+
+

Übersicht Einsatzabrechnung

+ +
+ +
+ +
+ +
+
+ +
+
+
+ Nach Abrechnungsstatus filtern: +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+
Einsätze
+
+ +
+
+
+
+ + +
+
+
+ +
+
+
+
+
+
+
+ {{> footer }} \ No newline at end of file diff --git a/resources/templates/sidebar.html.hbs b/resources/templates/sidebar.html.hbs index 6adf2a2..642605a 100644 --- a/resources/templates/sidebar.html.hbs +++ b/resources/templates/sidebar.html.hbs @@ -94,6 +94,7 @@
  • Vorlagen
  • Positionen
  • Anfragen
  • +
  • Abrechnung
  • {{/if}} @@ -171,6 +172,7 @@ Vorlagen Positionen Anfragen + Abrechnung {{/if}} {{#if sidebar.settings.active}} diff --git a/src/database/controller/events.rs b/src/database/controller/events.rs index 79164f9..d2b5e99 100644 --- a/src/database/controller/events.rs +++ b/src/database/controller/events.rs @@ -128,18 +128,19 @@ pub fn change_event(settings: &State, data: Event) -> Result, startdate: NaiveDateTime, enddate: NaiveDateTime, limit: i64, offset: i64, groups: Option>) -> Result, diesel::result::Error>{ +pub fn get_events(settings: &State, startdate: NaiveDateTime, enddate: NaiveDateTime, limit: i64, offset: i64, groups: Option>, states: Option>) -> Result, diesel::result::Error>{ use crate::schema::events::dsl::*; let connection = establish_connection(settings); let mut query = events.order(start.asc()).filter(start.ge(startdate)).filter(end.le(enddate)).limit(limit).offset(offset).into_boxed(); - match groups{ - Some(groups) => { - query = query.filter(related_group.eq(any(groups))); - } - None => {} + if let Some(groups) = groups { + query = query.filter(related_group.eq(any(groups))); + }; + + if let Some(states) = states{ + query = query.filter(state.eq(any(states))); }; match query.get_results(&connection){ diff --git a/src/main.rs b/src/main.rs index bee12c1..a4597da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -279,6 +279,7 @@ fn rocket() -> _ { modules::api::personnel_billing::delete::delete_position_instance, modules::api::personnel_billing::read::get_personnel_billing, modules::api::events::update::approve, + modules::event_billing::event_billing_list::event_billing_list, ], ) .mount("/css", FileServer::from("resources/css")) diff --git a/src/modules/api/events/read.rs b/src/modules/api/events/read.rs index a5da7a8..6686e3f 100644 --- a/src/modules/api/events/read.rs +++ b/src/modules/api/events/read.rs @@ -18,7 +18,7 @@ pub struct EventList { pub(crate) total_event_count: i64, } -#[get("/api/events?&&&&", format = "json")] +#[get("/api/events?&&&&&", format = "json")] pub fn read_events( settings: &State, cookie: SessionCookie, @@ -27,6 +27,7 @@ pub fn read_events( limit: Option, offset: Option, groups: Option, + states: Option, ) -> Result, Json> { let caller = parse_member_cookie(cookie.member)?; @@ -62,6 +63,23 @@ pub fn read_events( }; let limit = limit.unwrap_or(settings.api.default_pagination_limit); let offset = offset.unwrap_or(0); + let states = match states{ + Some(states) => { + let mut res: Vec = vec![]; + for state in states.split(","){ + let parsed_state : i16 = match state.parse(){ + Ok(state) => state, + Err(e) => { + error!("Couldn't parse transmitted event state: {}", e); + return Err(Json(ApiError::new(400, "Couldn't parse transmitted event states".to_string()).to_wrapper())) + } + }; + res.push(parsed_state) + } + Some(res) + }, + None => None + }; let groups = match groups{ Some(groups) => { @@ -74,7 +92,7 @@ pub fn read_events( None => None, }; - let events = match get_events(settings, start, end, limit, offset, groups.clone()){ + let events = match get_events(settings, start, end, limit, offset, groups.clone(), states){ Ok(events) => events, Err(e) => return Err(translate_diesel(e)), }; diff --git a/src/modules/event_billing/event_billing_list.rs b/src/modules/event_billing/event_billing_list.rs new file mode 100644 index 0000000..bcd2958 --- /dev/null +++ b/src/modules/event_billing/event_billing_list.rs @@ -0,0 +1,61 @@ +use rocket::http::Status; +use rocket::State; +use rocket_dyn_templates::Template; + +use crate::database::controller::groups::get_raw_groups; +use crate::helper::session_cookies::model::SessionCookie; +use crate::helper::sitebuilder::model::general::{Footer, Header, Script, Stylesheet}; +use crate::helper::sitebuilder::model::sidebar::Sidebar; +use crate::modules::event_billing::event::EventBilling; +use crate::modules::event_management::eventlist::EventList; +use crate::Settings; + +#[get("/portal/eb/list")] +pub fn event_billing_list(cookie: SessionCookie, settings: &State) -> Result { + let member = match cookie.member { + //Unwraps member from cookie or send user to login if no member specified (user skipped member selection) + Some(member) => member, + None => return Err(Status::Unauthorized), + }; + + if !member.has_permission( + crate::permissions::modules::event_billing::VIEW.to_string(), + ) { + return Err(Status::Forbidden); + } + + let header = Header { + html_language: "de".to_string(), + site_title: "Übersicht Einsatzabrechnung".to_string(), + stylesheets: vec![Stylesheet { + path: "/css/errms.css".to_string(), + }], + }; + let footer = Footer { + scripts: vec![Script { + path: "/js/eb_list.js".to_string(), + }, Script { + path: "/js/search2.js".to_string(), + },Script { + path: "/js/pagination.js".to_string(), + }], + + }; + let mut sidebar = Sidebar::new(member.clone()); + sidebar.event_management.active = true; + + let groups = match get_raw_groups(settings){ + Ok(groups) => groups, + Err(_e) => return Err(Status::InternalServerError) + }; + + let eventlist = EventList { + header, + footer, + sidebar, + caller: member.entity_id, + groups + }; + + Ok(Template::render("module_eb_list", eventlist)) +} diff --git a/src/modules/event_billing/mod.rs b/src/modules/event_billing/mod.rs index e201ba1..bf83190 100644 --- a/src/modules/event_billing/mod.rs +++ b/src/modules/event_billing/mod.rs @@ -3,4 +3,5 @@ pub mod close_event; pub mod edit_times; pub mod approve; pub mod edit_personnel_billing; -pub mod generate_billing_csv; \ No newline at end of file +pub mod generate_billing_csv; +pub mod event_billing_list; \ No newline at end of file