aboutsummaryrefslogtreecommitdiff
path: root/src/controller
diff options
context:
space:
mode:
authorJoris Guyonvarch2026-04-18 11:04:47 +0200
committerJoris Guyonvarch2026-04-18 11:05:17 +0200
commit6d1300640051baa23360846197b54e1e69ae32e3 (patch)
tree46219dcf5b5c9e5da0920ffd966d49ba80947a9b /src/controller
parentb35589eb90f2e5ee5521964e64eb578e9eb99032 (diff)
Add balancing capabilities
If payment are too unbalanced, it’s easier to make a transfer.
Diffstat (limited to 'src/controller')
-rw-r--r--src/controller/balance.rs20
-rw-r--r--src/controller/balancing.rs189
-rw-r--r--src/controller/mod.rs1
3 files changed, 209 insertions, 1 deletions
diff --git a/src/controller/balance.rs b/src/controller/balance.rs
index 309f15c..6cb937b 100644
--- a/src/controller/balance.rs
+++ b/src/controller/balance.rs
@@ -7,6 +7,7 @@ use crate::controller::utils;
use crate::controller::wallet::Wallet;
use crate::db;
use crate::model::user::User;
+use crate::model::balancing::Balancing;
use crate::payer;
use crate::templates;
@@ -22,7 +23,10 @@ pub async fn get(wallet: &Wallet) -> Response<Full<Bytes>> {
get_template_user_incomes(&users, &user_incomes);
let total_income: i64 = user_incomes.values().sum();
- let user_payments = db::payments::repartition(&wallet.db_conn).await;
+ let user_payments = with_balancing(
+ db::payments::repartition(&wallet.db_conn).await,
+ db::balancing::list(&wallet.db_conn).await
+ );
let template_user_payments =
get_template_user_payments(&users, &user_payments);
let total_payments: i64 = user_payments.iter().map(|p| p.1).sum();
@@ -67,3 +71,17 @@ fn get_template_user_incomes(
user_incomes.sort_by_key(|i| i.1);
user_incomes
}
+
+fn with_balancing(
+ user_payments: HashMap<i64, i64>,
+ balancings: Vec<Balancing>
+) -> HashMap<i64, i64> {
+ let mut user_payments = user_payments;
+ for balancing in balancings {
+ let src = user_payments.entry(balancing.source).or_insert(0);
+ *src += balancing.amount;
+ let dest = user_payments.entry(balancing.destination).or_insert(0);
+ *dest -= balancing.amount;
+ }
+ user_payments
+}
diff --git a/src/controller/balancing.rs b/src/controller/balancing.rs
new file mode 100644
index 0000000..718358c
--- /dev/null
+++ b/src/controller/balancing.rs
@@ -0,0 +1,189 @@
+use http_body_util::Full;
+use hyper::Response;
+use hyper::body::Bytes;
+use std::collections::HashMap;
+
+use crate::controller::utils;
+use crate::controller::wallet::Wallet;
+use crate::db;
+use crate::queries;
+use crate::templates;
+use crate::validation;
+
+static PER_PAGE: i64 = 10;
+
+pub async fn table(
+ wallet: &Wallet,
+ query: queries::Balancing,
+) -> Response<Full<Bytes>> {
+ let page = query.page.unwrap_or(1);
+ let count = db::balancing::count(&wallet.db_conn).await;
+ let balancings = db::balancing::list_for_table(&wallet.db_conn, page, PER_PAGE).await;
+ let max_page = (count as f32 / PER_PAGE as f32).ceil() as i64;
+
+ let context = minijinja::context!(
+ header => templates::Header::Balancing,
+ connected_user => wallet.user,
+ balancings => balancings,
+ page => page,
+ max_page => max_page,
+ highlight => query.highlight
+ );
+
+ utils::template(
+ &wallet.assets,
+ &wallet.templates,
+ "balancing/table.html",
+ context,
+ )
+}
+
+pub async fn create_form(
+ wallet: &Wallet,
+ query: queries::Balancing,
+) -> Response<Full<Bytes>> {
+ create_form_feedback(wallet, query, HashMap::new(), None).await
+}
+
+async fn create_form_feedback(
+ wallet: &Wallet,
+ query: queries::Balancing,
+ form: HashMap<String, String>,
+ error: Option<String>,
+) -> Response<Full<Bytes>> {
+ let users = db::users::list(&wallet.db_conn).await;
+
+ let context = minijinja::context!(
+ header => templates::Header::Balancing,
+ connected_user => wallet.user,
+ users => users,
+ query => query,
+ form => form,
+ error => error,
+ );
+
+ utils::template(
+ &wallet.assets,
+ &wallet.templates,
+ "balancing/create.html",
+ context,
+ )
+}
+
+
+pub async fn create(
+ wallet: &Wallet,
+ query: queries::Balancing,
+ form: HashMap<String, String>,
+) -> Response<Full<Bytes>> {
+ let error = |e: &str| {
+ create_form_feedback(wallet, query, form.clone(), Some(e.to_string()))
+ };
+
+ match validation::balancing::create(&form) {
+ Some(balancing) => {
+ match db::balancing::create(&wallet.db_conn, balancing).await {
+ Some(id) => {
+ let row =
+ db::balancing::get_row(&wallet.db_conn, id).await;
+ let page = (row - 1) / PER_PAGE + 1;
+ utils::redirect(&format!(
+ "/balancings?page={}&highlight={}",
+ page, id
+ ))
+ }
+ None => error("Erreur serveur").await,
+ }
+ }
+ None => error("Erreur lors de la validation du formulaire.").await,
+ }
+}
+
+pub async fn update_form(
+ id: i64,
+ wallet: &Wallet,
+ query: queries::Balancing,
+) -> Response<Full<Bytes>> {
+ update_form_feedback(id, wallet, query, HashMap::new(), None).await
+}
+
+async fn update_form_feedback(
+ id: i64,
+ wallet: &Wallet,
+ query: queries::Balancing,
+ form: HashMap<String, String>,
+ error: Option<String>,
+) -> Response<Full<Bytes>> {
+ let users = db::users::list(&wallet.db_conn).await;
+ let balancing = db::balancing::get(&wallet.db_conn, id).await;
+
+ let context = minijinja::context!(
+ header => &templates::Header::Balancing,
+ connected_user => &wallet.user,
+ users => &users,
+ id => &id,
+ balancing => &balancing,
+ query => &query,
+ form => &form,
+ error => &error
+ );
+
+ utils::template(
+ &wallet.assets,
+ &wallet.templates,
+ "balancing/update.html",
+ context,
+ )
+}
+
+pub async fn update(
+ id: i64,
+ wallet: &Wallet,
+ query: queries::Balancing,
+ form: HashMap<String, String>,
+) -> Response<Full<Bytes>> {
+ let error = |e: &str| {
+ update_form_feedback(
+ id,
+ wallet,
+ query,
+ form.clone(),
+ Some(e.to_string()),
+ )
+ };
+
+ match validation::balancing::update(&form) {
+ Some(balancing) => {
+ if db::balancing::update(&wallet.db_conn, id, balancing).await {
+ let row = db::balancing::get_row(&wallet.db_conn, id).await;
+ let page = (row - 1) / PER_PAGE + 1;
+ utils::redirect(&format!(
+ "/balancings?page={}&highlight={}",
+ page, id
+ ))
+ } else {
+ error("Erreur serveur").await
+ }
+ }
+ None => error("Erreur lors de la validation du formulaire.").await,
+ }
+}
+
+pub async fn delete(
+ id: i64,
+ wallet: &Wallet,
+ query: queries::Balancing,
+) -> Response<Full<Bytes>> {
+ if db::balancing::delete(&wallet.db_conn, id).await {
+ utils::redirect(&format!("/balancings?page={}", query.page.unwrap_or(1)))
+ } else {
+ update_form_feedback(
+ id,
+ wallet,
+ query,
+ HashMap::new(),
+ Some("Erreur serveur".to_string()),
+ )
+ .await
+ }
+}
diff --git a/src/controller/mod.rs b/src/controller/mod.rs
index e2ef561..bbead68 100644
--- a/src/controller/mod.rs
+++ b/src/controller/mod.rs
@@ -1,4 +1,5 @@
pub mod balance;
+pub mod balancing;
pub mod categories;
pub mod error;
pub mod incomes;