use super::User; use crate::{ model::family::Family, BOAT_STORAGE, DUAL_MEMBERSHIP, EINSCHREIBGEBUEHR, FAMILY_THREE_OR_MORE, FAMILY_TWO, FOERDERND, REGULAR, RENNRUDERBEITRAG, SCHECKBUCH, STUDENT_OR_PUPIL, TRIAL_ROWING, TRIAL_ROWING_REDUCED, UNTERSTUETZEND, }; use serde::Serialize; use sqlx::SqlitePool; #[derive(Debug, Serialize)] pub struct Fee { pub sum_in_cents: i64, pub parts: Vec<(String, i64)>, pub name: String, pub user_ids: String, pub paid: bool, pub users: Vec, } impl Default for Fee { fn default() -> Self { Self::new() } } impl Fee { pub fn new() -> Self { Self { sum_in_cents: 0, name: "".into(), parts: Vec::new(), user_ids: "".into(), users: Vec::new(), paid: false, } } pub fn add(&mut self, desc: String, price_in_cents: i64) { self.sum_in_cents += price_in_cents; self.parts.push((desc, price_in_cents)); } pub fn add_person(&mut self, user: &User) { if !self.name.is_empty() { self.name.push_str(" + "); self.user_ids.push('&'); } self.name.push_str(&user.name); self.user_ids.push_str(&format!("user_ids[]={}", user.id)); self.users.push(user.clone()); } pub fn paid(&mut self) { self.paid = true; } pub fn merge(&mut self, fee: Fee) { for (desc, price_in_cents) in fee.parts { self.add(desc, price_in_cents); } } } impl User { pub async fn fee(&self, db: &SqlitePool) -> Option { if !self.has_role(db, "Donau Linz").await && !self.has_role(db, "Unterstützend").await && !self.has_role(db, "Förderndes Mitglied").await && !self.has_role(db, "schnupperant").await && !self.has_role(db, "scheckbuch").await { return None; } if self.deleted { return None; } let mut fee = Fee::new(); if let Some(family) = Family::find_by_opt_id(db, self.family_id).await { let mut einschreibgebuehr = false; let mut half_price = true; for member in family.members(db).await { fee.add_person(&member); if member.has_role(db, "paid").await { fee.paid(); } fee.merge(member.fee_without_families(db, true).await); if member.has_to_pay_einschreibgebuehr_this_year(db).await { einschreibgebuehr = true; } if !member.has_to_pay_only_half() { half_price = false; } } if family.amount_family_members(db).await > 2 { if half_price { fee.add( "Familie 3+ Personen (Halbpreis)".into(), FAMILY_THREE_OR_MORE / 2, ); } else { fee.add("Familie 3+ Personen".into(), FAMILY_THREE_OR_MORE); } } else { if half_price { fee.add("Familie 2 Personen (Halbpreis)".into(), FAMILY_TWO / 2); } else { fee.add("Familie 2 Personen".into(), FAMILY_TWO); } } if einschreibgebuehr { fee.add("Einschreibgebühr (Familie)".into(), EINSCHREIBGEBUEHR); } } else { fee.add_person(self); if self.has_role(db, "paid").await { fee.paid(); } fee.merge(self.fee_without_families(db, false).await); } Some(fee) } async fn fee_without_families(&self, db: &SqlitePool, entry_fee_paid_with_family: bool) -> Fee { let mut fee = Fee::new(); if !self.has_role(db, "Donau Linz").await && !self.has_role(db, "Unterstützend").await && !self.has_role(db, "Förderndes Mitglied").await && !self.has_role(db, "schnupperant").await && !self.has_role(db, "scheckbuch").await { return fee; } if self.has_role(db, "Rennrudern").await { if self.has_role(db, "half-rennrudern").await { fee.add("Rennruderbeitrag (1/2 Preis) ".into(), RENNRUDERBEITRAG / 2); } else if !self.has_role(db, "renntrainer").await { fee.add("Rennruderbeitrag".into(), RENNRUDERBEITRAG); } } let amount_boats = self.amount_boats(db).await; if amount_boats > 0 { if self.has_to_pay_only_half() { fee.add( format!("{}x Bootsplatz (Halbpreis)", amount_boats), amount_boats * BOAT_STORAGE / 2, ); } else { fee.add( format!("{}x Bootsplatz", amount_boats), amount_boats * BOAT_STORAGE, ); } } if self.has_to_pay_einschreibgebuehr_this_year(db).await && !entry_fee_paid_with_family { fee.add("Einschreibgebühr".into(), EINSCHREIBGEBUEHR); } let halfprice = self.has_to_pay_only_half(); if self.has_role(db, "schnupperant").await { if self.has_role(db, "Student").await || self.has_role(db, "Schüler").await { fee.add("Schnupperkurs (reduziert)".into(), TRIAL_ROWING_REDUCED); } else { fee.add("Schnupperkurs".into(), TRIAL_ROWING); } } else if self.has_role(db, "scheckbuch").await { fee.add("Scheckbuch".into(), SCHECKBUCH); } else if self.has_role(db, "Unterstützend").await { fee.add("Unterstützendes Mitglied".into(), UNTERSTUETZEND); } else if self.has_role(db, "Förderndes Mitglied").await { fee.add("Förderndes Mitglied".into(), FOERDERND); } else if Family::find_by_opt_id(db, self.family_id).await.is_none() { if self.has_role(db, "Student").await || self.has_role(db, "Schüler").await { if halfprice { fee.add("Schüler/Student (Halbpreis)".into(), STUDENT_OR_PUPIL / 2); } else { fee.add("Schüler/Student".into(), STUDENT_OR_PUPIL); } } else if self.has_role(db, "Ehrenmitglied").await { fee.add("Ehrenmitglied".into(), 0); } else if self.has_role(db, "dual_membership").await { if halfprice { fee.add( "Doppelmitgliedschaft mit anderem österr. Ruderverein (Halbpreis)".into(), DUAL_MEMBERSHIP / 2, ); } else { fee.add( "Doppelmitgliedschaft mit anderem österr. Ruderverein".into(), DUAL_MEMBERSHIP, ); } } else if halfprice { fee.add("Mitgliedsbeitrag (Halbpreis)".into(), REGULAR / 2); } else { fee.add("Mitgliedsbeitrag".into(), REGULAR); } } if !self.has_role(db, "schnupperant").await && self.has_role(db, "participated_schnupperkurs").await { if self.has_role(db, "Student").await || self.has_role(db, "Schüler").await { fee.add( "Anrechnung reduzierter Schnupperkurs".into(), -TRIAL_ROWING_REDUCED, ); } else { fee.add("Anrechnung Schnupperkurs".into(), -TRIAL_ROWING); } } fee } }