Skip to main content

server/command/report/
balance.rs

1use chrono::{DateTime, Utc};
2use sqlx::types::Uuid;
3use supp_macro::command;
4
5use crate::{config::ConfigError, user::User};
6
7use super::super::{CmdError, CmdResult, PeriodData, ReportData, ReportFilter, ReportMeta};
8use super::fetch::{
9    fetch_accounts, fetch_balance_splits_filtered_no_conversion,
10    fetch_balance_splits_filtered_with_conversion, fetch_balance_splits_no_conversion,
11    fetch_balance_splits_with_conversion, fetch_date_range_splits_filtered_no_conversion,
12    fetch_date_range_splits_filtered_with_conversion, fetch_date_range_splits_no_conversion,
13    fetch_date_range_splits_with_conversion, fetch_target_symbol,
14};
15use super::tree::{AccountAmounts, build_tree};
16
17async fn fetch_snapshot(
18    conn: &mut sqlx::PgConnection,
19    target_commodity_id: Option<Uuid>,
20    as_of: Option<DateTime<Utc>>,
21    report_filter: Option<&ReportFilter>,
22) -> Result<AccountAmounts, CmdError> {
23    match (target_commodity_id, report_filter) {
24        (Some(tid), Some(f)) => {
25            let sym = fetch_target_symbol(conn, tid).await?;
26            fetch_balance_splits_filtered_with_conversion(conn, tid, &sym, as_of, f).await
27        }
28        (Some(tid), None) => {
29            let sym = fetch_target_symbol(conn, tid).await?;
30            fetch_balance_splits_with_conversion(conn, tid, &sym, as_of).await
31        }
32        (None, Some(f)) => fetch_balance_splits_filtered_no_conversion(conn, as_of, f).await,
33        (None, None) => fetch_balance_splits_no_conversion(conn, as_of).await,
34    }
35}
36
37async fn fetch_range(
38    conn: &mut sqlx::PgConnection,
39    target_commodity_id: Option<Uuid>,
40    from: DateTime<Utc>,
41    to: DateTime<Utc>,
42    report_filter: Option<&ReportFilter>,
43) -> Result<AccountAmounts, CmdError> {
44    match (target_commodity_id, report_filter) {
45        (Some(tid), Some(f)) => {
46            let sym = fetch_target_symbol(conn, tid).await?;
47            fetch_date_range_splits_filtered_with_conversion(conn, tid, &sym, from, to, f).await
48        }
49        (Some(tid), None) => {
50            let sym = fetch_target_symbol(conn, tid).await?;
51            fetch_date_range_splits_with_conversion(conn, tid, &sym, from, to).await
52        }
53        (None, Some(f)) => fetch_date_range_splits_filtered_no_conversion(conn, from, to, f).await,
54        (None, None) => fetch_date_range_splits_no_conversion(conn, from, to).await,
55    }
56}
57
58command! {
59    BalanceReport {
60        #[required]
61        user_id: Uuid,
62        #[optional]
63        target_commodity_id: Uuid,
64        #[optional]
65        date_from: DateTime<Utc>,
66        #[optional]
67        as_of: DateTime<Utc>,
68        #[optional]
69        report_filter: ReportFilter,
70    } => {
71        super::filter::check_filter_size(
72            report_filter.as_ref().map_or(0, super::super::ReportFilter::leaves),
73        )?;
74
75        let user = User { id: user_id };
76        let mut conn = user.get_connection().await.map_err(|err| {
77            log::error!("{}", t!("Database error: %{err}", err = err : {:?}));
78            ConfigError::DB
79        })?;
80
81        let accounts = fetch_accounts(&mut conn).await?;
82
83        let amounts = match date_from {
84            Some(from) => {
85                let to = as_of.unwrap_or_else(Utc::now);
86                super::period::check_range(from, to)?;
87                fetch_range(&mut conn, target_commodity_id, from, to, report_filter.as_ref()).await?
88            }
89            None => fetch_snapshot(&mut conn, target_commodity_id, as_of, report_filter.as_ref()).await?,
90        };
91
92        let roots = build_tree(&accounts, &amounts);
93        let period = PeriodData { label: None, roots };
94
95        Ok(Some(CmdResult::Report(ReportData {
96            meta: ReportMeta {
97                date_from,
98                date_to: as_of,
99                target_commodity_id,
100            },
101            periods: vec![period],
102        })))
103    }
104}