Get accounts and balances

This commit is contained in:
Pierre HUBERT 2025-04-21 12:08:12 +02:00
parent f5b0ae49ca
commit 6ee250d872
5 changed files with 72 additions and 5 deletions

View File

@ -1,8 +1,9 @@
use crate::controllers::HttpResult;
use crate::extractors::account_extractor::AccountInPath;
use crate::extractors::auth_extractor::AuthExtractor;
use crate::services::accounts_service;
use crate::models::accounts::Account;
use crate::services::accounts_service::UpdateAccountQuery;
use crate::services::{accounts_service, movements_service};
use actix_web::{HttpResponse, web};
/// Create a new account
@ -16,9 +17,38 @@ pub async fn create(auth: AuthExtractor, req: web::Json<UpdateAccountQuery>) ->
Ok(HttpResponse::Created().finish())
}
#[derive(serde::Deserialize)]
pub struct GetListQuery {
#[serde(default)]
include_balances: bool,
}
#[derive(serde::Serialize)]
struct AccountAndBalance {
#[serde(flatten)]
account: Account,
balance: f32,
}
/// Get the list of accounts of the user
pub async fn get_list(auth: AuthExtractor) -> HttpResult {
Ok(HttpResponse::Ok().json(accounts_service::get_list_user(auth.user_id()).await?))
pub async fn get_list(auth: AuthExtractor, query: web::Query<GetListQuery>) -> HttpResult {
let accounts = accounts_service::get_list_user(auth.user_id()).await?;
Ok(match query.include_balances {
false => HttpResponse::Ok().json(accounts),
true => {
let balances = movements_service::get_balances(auth.user_id()).await?;
let accounts = accounts
.into_iter()
.map(|account| AccountAndBalance {
balance: *balances.get(&account.id()).unwrap_or(&0.0),
account,
})
.collect::<Vec<_>>();
HttpResponse::Ok().json(accounts)
}
})
}
/// Get a single account

View File

@ -17,6 +17,11 @@ pub async fn create(auth: AuthExtractor, req: web::Json<UpdateMovementQuery>) ->
Ok(HttpResponse::Created().finish())
}
/// Get the balances of all the accounts of the user
pub async fn get_accounts_balances(auth: AuthExtractor) -> HttpResult {
Ok(HttpResponse::Ok().json(movements_service::get_balances(auth.user_id()).await?))
}
/// Get the list of movements of an account
pub async fn get_list_of_account(account_id: AccountInPath) -> HttpResult {
Ok(HttpResponse::Ok()

View File

@ -131,6 +131,10 @@ async fn main() -> std::io::Result<()> {
)
// Movement controller
.route("/api/movement", web::post().to(movement_controller::create))
.route(
"/api/accounts/balances",
web::get().to(movement_controller::get_accounts_balances),
)
.route(
"/api/account/{account_id}/movements",
web::get().to(movement_controller::get_list_of_account),

View File

@ -3,7 +3,9 @@ use crate::schema::*;
use diesel::prelude::*;
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[derive(
Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord,
)]
pub struct AccountID(pub i32);
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq)]

View File

@ -7,8 +7,9 @@ use crate::models::users::UserID;
use crate::schema::movements;
use crate::services::{accounts_service, files_service};
use crate::utils::time_utils::time;
use diesel::RunQueryDsl;
use diesel::prelude::*;
use diesel::{RunQueryDsl, sql_query};
use std::collections::HashMap;
#[derive(serde::Deserialize)]
pub struct UpdateMovementQuery {
@ -136,6 +137,31 @@ pub async fn get_list_account(account_id: AccountID) -> anyhow::Result<Vec<Movem
.get_results(&mut db()?)?)
}
table! {
accounts_balances (account_id) {
account_id -> Int4,
balance -> Float4,
}
}
#[derive(QueryableByName)]
#[diesel(table_name = accounts_balances)]
struct AccountBalance {
account_id: i32,
balance: f32,
}
/// Get the balances of all the accounts of the user
pub async fn get_balances(user_id: UserID) -> anyhow::Result<HashMap<AccountID, f32>> {
let result = sql_query(format!("select a.id as account_id, sum(m.amount) as balance from accounts a right join movements m on a.id = m.account_id where a.user_id = {} group by a.id", user_id.0))
.get_results::<AccountBalance>(&mut db()?)?;
Ok(result
.into_iter()
.map(|r| (AccountID(r.account_id), r.balance))
.collect())
}
/// Delete a movement
pub async fn delete(id: MovementID) -> anyhow::Result<()> {
diesel::delete(movements::dsl::movements.filter(movements::dsl::id.eq(id.0)))