diff --git a/src/model/role.rs b/src/model/role.rs index d37ca49..111b18b 100644 --- a/src/model/role.rs +++ b/src/model/role.rs @@ -3,8 +3,8 @@ use sqlx::{FromRow, SqlitePool}; #[derive(FromRow, Serialize, Clone)] pub struct Role { - id: i64, - name: String, + pub(crate) id: i64, + pub(crate) name: String, } impl Role { @@ -30,6 +30,21 @@ WHERE id like ? .ok() } + pub async fn find_by_name(db: &SqlitePool, name: &str) -> Option { + sqlx::query_as!( + Self, + " +SELECT id, name +FROM role +WHERE name like ? + ", + name + ) + .fetch_one(db) + .await + .ok() + } + pub async fn mails_from_role(&self, db: &SqlitePool) -> Vec { let query = format!( "SELECT u.mail diff --git a/src/model/user.rs b/src/model/user.rs index 3bbc351..e38b68b 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -14,7 +14,7 @@ use rocket::{ use serde::{Deserialize, Serialize}; use sqlx::{FromRow, Sqlite, SqlitePool, Transaction}; -use super::{family::Family, log::Log, tripdetails::TripDetails, Day}; +use super::{family::Family, log::Log, role::Role, tripdetails::TripDetails, Day}; use crate::tera::admin::user::UserEditForm; const RENNRUDERBEITRAG: i32 = 11000; @@ -105,6 +105,8 @@ pub(crate) struct Fee { pub(crate) sum_in_cents: i32, pub(crate) parts: Vec<(String, i32)>, pub(crate) name: String, + pub(crate) user_ids: String, + pub(crate) paid: bool, } impl Fee { @@ -113,6 +115,8 @@ impl Fee { sum_in_cents: 0, name: "".into(), parts: Vec::new(), + user_ids: "".into(), + paid: false, } } @@ -122,8 +126,18 @@ impl Fee { self.parts.push((desc, price_in_cents)); } - pub fn name(&mut self, name: String) { - self.name = name; + pub fn add_person(&mut self, user: &User) { + if !self.name.is_empty() { + self.name.push_str(" + "); + self.user_ids.push_str("&"); + } + self.name.push_str(&user.name); + + self.user_ids.push_str(&format!("user_ids[]={}", user.id)); + } + + pub fn paid(&mut self) { + self.paid = true; } pub fn merge(&mut self, fee: Fee) { @@ -144,20 +158,22 @@ impl User { if let Some(family) = Family::find_by_opt_id(db, self.family_id).await { let mut names = String::new(); for member in family.members(db).await { - if !names.is_empty() { - names.push_str(" + "); + fee.add_person(&member); + if member.has_role(db, "paid").await { + fee.paid(); } - names.push_str(&member.name); fee.merge(member.fee_without_families(db).await); } - fee.name(names); if family.amount_family_members(db).await > 2 { fee.add("Familie 3+ Personen".into(), FAMILY_THREE_OR_MORE); } else { fee.add("Familie 2 Personen".into(), FAMILY_TWO); } } else { - fee.name(self.name.clone()); + fee.add_person(&self); + if self.has_role(db, "paid").await { + fee.paid(); + } fee.merge(self.fee_without_families(db).await); } @@ -452,17 +468,38 @@ ORDER BY last_access DESC .unwrap(); for role_id in data.roles.into_keys() { - sqlx::query!( - "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)", - self.id, - role_id + self.add_role( + db, + &Role::find_by_id(db, role_id.parse::().unwrap()) + .await + .unwrap(), ) - .execute(db) - .await - .unwrap(); + .await; } } + pub async fn add_role(&self, db: &SqlitePool, role: &Role) { + sqlx::query!( + "INSERT INTO user_role(user_id, role_id) VALUES (?, ?)", + self.id, + role.id + ) + .execute(db) + .await + .unwrap(); + } + + pub async fn remove_role(&self, db: &SqlitePool, role: &Role) { + sqlx::query!( + "DELETE FROM user_role WHERE user_id = ? and role_id = ?", + self.id, + role.id + ) + .execute(db) + .await + .unwrap(); + } + pub async fn login(db: &SqlitePool, name: &str, pw: &str) -> Result { let name = name.trim(); // just to make sure... let Some(user) = User::find_by_name(db, name).await else { diff --git a/src/tera/admin/user.rs b/src/tera/admin/user.rs index e47df2c..c89ff00 100644 --- a/src/tera/admin/user.rs +++ b/src/tera/admin/user.rs @@ -77,6 +77,33 @@ async fn fees( Template::render("admin/user/fees", context.into_json()) } +#[get("/user/fees/paid?")] +async fn fees_paid( + db: &State, + admin: AdminUser, + user_ids: Vec, +) -> Flash { + let mut res = String::new(); + for user_id in user_ids { + let user = User::find_by_id(db, user_id).await.unwrap(); + res.push_str(&format!("{} + ", user.name)); + if user.has_role(db, "paid").await { + user.remove_role(db, &Role::find_by_name(db, "paid").await.unwrap()) + .await; + } else { + user.add_role(db, &Role::find_by_name(db, "paid").await.unwrap()) + .await; + } + } + + res.truncate(res.len() - 3); // remove ' + ' from the end + + Flash::success( + Redirect::to("/admin/user/fees"), + format!("Zahlungsstatus von {} erfolgreich geändert", res), + ) +} + #[get("/user//reset-pw")] async fn resetpw(db: &State, _admin: AdminUser, user: i32) -> Flash { let user = User::find_by_id(db, user).await; @@ -165,5 +192,5 @@ async fn create( } pub fn routes() -> Vec { - routes![index, resetpw, update, create, delete, fees] + routes![index, resetpw, update, create, delete, fees, fees_paid] } diff --git a/templates/admin/user/fees.html.tera b/templates/admin/user/fees.html.tera index ad06078..b277ce6 100644 --- a/templates/admin/user/fees.html.tera +++ b/templates/admin/user/fees.html.tera @@ -3,29 +3,45 @@ {% extends "base" %} {% block content %} -
+
+ {% if flash %} + {{ macros::alert(message=flash.1, type=flash.0, class="sm:col-span-2 lg:col-span-3") }} + {% endif %} - {% if flash %} - {{ macros::alert(message=flash.1, type=flash.0, class="my-3") }} - {% endif %} +

Gebühren

+ + +
+ + +
+ + +
+
-
- -
- -
-{% endblock content%} - +{% endblock content %}