234 lines
7.1 KiB
Rust
234 lines
7.1 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use chrono::NaiveDate;
|
|
use chrono::NaiveDateTime;
|
|
use rocket::serde::{Deserialize, Serialize};
|
|
use sqlx::{FromRow, SqlitePool};
|
|
|
|
use super::log::Log;
|
|
use super::notification::Notification;
|
|
use super::role::Role;
|
|
use super::trailer::Trailer;
|
|
use super::user::User;
|
|
use crate::tera::trailerreservation::ReservationEditForm;
|
|
|
|
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
|
pub struct TrailerReservation {
|
|
pub id: i64,
|
|
pub trailer_id: i64,
|
|
pub start_date: NaiveDate,
|
|
pub end_date: NaiveDate,
|
|
pub time_desc: String,
|
|
pub usage: String,
|
|
pub user_id_applicant: i64,
|
|
pub user_id_confirmation: Option<i64>,
|
|
pub created_at: NaiveDateTime,
|
|
}
|
|
|
|
#[derive(FromRow, Debug, Serialize, Deserialize)]
|
|
pub struct TrailerReservationWithDetails {
|
|
#[serde(flatten)]
|
|
reservation: TrailerReservation,
|
|
trailer: Trailer,
|
|
user_applicant: User,
|
|
user_confirmation: Option<User>,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct TrailerReservationToAdd<'r> {
|
|
pub trailer: &'r Trailer,
|
|
pub start_date: NaiveDate,
|
|
pub end_date: NaiveDate,
|
|
pub time_desc: &'r str,
|
|
pub usage: &'r str,
|
|
pub user_applicant: &'r User,
|
|
}
|
|
|
|
impl TrailerReservation {
|
|
pub async fn find_by_id(db: &SqlitePool, id: i32) -> Option<Self> {
|
|
sqlx::query_as!(
|
|
Self,
|
|
"SELECT id, trailer_id, start_date, end_date, time_desc, usage, user_id_applicant, user_id_confirmation, created_at
|
|
FROM trailer_reservation
|
|
WHERE id like ?",
|
|
id
|
|
)
|
|
.fetch_one(db)
|
|
.await
|
|
.ok()
|
|
}
|
|
|
|
pub async fn all_future(db: &SqlitePool) -> Vec<TrailerReservationWithDetails> {
|
|
let trailerreservations = sqlx::query_as!(
|
|
Self,
|
|
"
|
|
SELECT id, trailer_id, start_date, end_date, time_desc, usage, user_id_applicant, user_id_confirmation, created_at
|
|
FROM trailer_reservation
|
|
WHERE end_date >= CURRENT_DATE ORDER BY end_date
|
|
"
|
|
)
|
|
.fetch_all(db)
|
|
.await
|
|
.unwrap(); //TODO: fixme
|
|
|
|
let mut res = Vec::new();
|
|
for reservation in trailerreservations {
|
|
let user_confirmation = match reservation.user_id_confirmation {
|
|
Some(id) => {
|
|
let user = User::find_by_id(db, id as i32).await;
|
|
Some(user.unwrap())
|
|
}
|
|
None => None,
|
|
};
|
|
let user_applicant = User::find_by_id(db, reservation.user_id_applicant as i32)
|
|
.await
|
|
.unwrap();
|
|
let trailer = Trailer::find_by_id(db, reservation.trailer_id as i32)
|
|
.await
|
|
.unwrap();
|
|
|
|
res.push(TrailerReservationWithDetails {
|
|
reservation,
|
|
trailer,
|
|
user_applicant,
|
|
user_confirmation,
|
|
});
|
|
}
|
|
res
|
|
}
|
|
pub async fn all_future_with_groups(
|
|
db: &SqlitePool,
|
|
) -> HashMap<String, Vec<TrailerReservationWithDetails>> {
|
|
let mut grouped_reservations: HashMap<String, Vec<TrailerReservationWithDetails>> =
|
|
HashMap::new();
|
|
|
|
let reservations = Self::all_future(db).await;
|
|
for reservation in reservations {
|
|
let key = format!(
|
|
"{}-{}-{}-{}-{}",
|
|
reservation.reservation.start_date,
|
|
reservation.reservation.end_date,
|
|
reservation.reservation.time_desc,
|
|
reservation.reservation.usage,
|
|
reservation.user_applicant.name
|
|
);
|
|
|
|
grouped_reservations
|
|
.entry(key)
|
|
.or_default()
|
|
.push(reservation);
|
|
}
|
|
|
|
grouped_reservations
|
|
}
|
|
|
|
pub async fn create(
|
|
db: &SqlitePool,
|
|
trailerreservation: TrailerReservationToAdd<'_>,
|
|
) -> Result<(), String> {
|
|
if Self::trailer_reserved_between_dates(
|
|
db,
|
|
trailerreservation.trailer,
|
|
&trailerreservation.start_date,
|
|
&trailerreservation.end_date,
|
|
)
|
|
.await
|
|
{
|
|
return Err("Hänger in diesem Zeitraum bereits reserviert.".into());
|
|
}
|
|
|
|
Log::create(
|
|
db,
|
|
format!("New trailer reservation: {trailerreservation:?}"),
|
|
)
|
|
.await;
|
|
|
|
sqlx::query!(
|
|
"INSERT INTO trailer_reservation(trailer_id, start_date, end_date, time_desc, usage, user_id_applicant) VALUES (?,?,?,?,?,?)",
|
|
trailerreservation.trailer.id,
|
|
trailerreservation.start_date,
|
|
trailerreservation.end_date,
|
|
trailerreservation.time_desc,
|
|
trailerreservation.usage,
|
|
trailerreservation.user_applicant.id,
|
|
)
|
|
.execute(db)
|
|
.await
|
|
.map_err(|e| e.to_string())?;
|
|
|
|
let board =
|
|
User::all_with_role(db, &Role::find_by_name(db, "Vorstand").await.unwrap()).await;
|
|
for user in board {
|
|
let date = if trailerreservation.start_date == trailerreservation.end_date {
|
|
format!("am {}", trailerreservation.start_date)
|
|
} else {
|
|
format!(
|
|
"von {} bis {}",
|
|
trailerreservation.start_date, trailerreservation.end_date
|
|
)
|
|
};
|
|
|
|
Notification::create(
|
|
db,
|
|
&user,
|
|
&format!(
|
|
"{} hat eine neue Hängerreservierung für Hänger '{}' {} angelegt. Zeit: {}; Zweck: {}",
|
|
trailerreservation.user_applicant.name,
|
|
trailerreservation.trailer.name,
|
|
date,
|
|
trailerreservation.time_desc,
|
|
trailerreservation.usage
|
|
),
|
|
"Neue Hängerreservierung",
|
|
None,None
|
|
)
|
|
.await;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn trailer_reserved_between_dates(
|
|
db: &SqlitePool,
|
|
trailer: &Trailer,
|
|
start_date: &NaiveDate,
|
|
end_date: &NaiveDate,
|
|
) -> bool {
|
|
sqlx::query!(
|
|
"SELECT COUNT(*) AS reservation_count
|
|
FROM trailer_reservation
|
|
WHERE trailer_id = ?
|
|
AND start_date <= ? AND end_date >= ?;",
|
|
trailer.id,
|
|
end_date,
|
|
start_date
|
|
)
|
|
.fetch_one(db)
|
|
.await
|
|
.unwrap()
|
|
.reservation_count
|
|
> 0
|
|
}
|
|
|
|
pub async fn update(&self, db: &SqlitePool, data: ReservationEditForm) {
|
|
let time_desc = data.time_desc.trim();
|
|
let usage = data.usage.trim();
|
|
sqlx::query!(
|
|
"UPDATE trailer_reservation SET time_desc = ?, usage = ? where id = ?",
|
|
time_desc,
|
|
usage,
|
|
self.id
|
|
)
|
|
.execute(db)
|
|
.await
|
|
.unwrap(); //Okay, because we can only create a User of a valid id
|
|
}
|
|
|
|
pub async fn delete(&self, db: &SqlitePool) {
|
|
sqlx::query!("DELETE FROM trailer_reservation WHERE id=?", self.id)
|
|
.execute(db)
|
|
.await
|
|
.unwrap(); //Okay, because we can only create a Boat of a valid id
|
|
}
|
|
}
|