1
use chrono::{DateTime, Utc};
2
use sqlx::types::Uuid;
3
use supp_macro::command;
4

            
5
use crate::{config::ConfigError, user::User};
6

            
7
use super::super::{CmdError, CmdResult, PeriodData, ReportData, ReportFilter, ReportMeta};
8
use 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
};
15
use super::tree::{AccountAmounts, build_tree};
16

            
17
10
async fn fetch_snapshot(
18
10
    conn: &mut sqlx::PgConnection,
19
10
    target_commodity_id: Option<Uuid>,
20
10
    as_of: Option<DateTime<Utc>>,
21
10
    report_filter: Option<&ReportFilter>,
22
10
) -> Result<AccountAmounts, CmdError> {
23
10
    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
5
        (Some(tid), None) => {
29
5
            let sym = fetch_target_symbol(conn, tid).await?;
30
5
            fetch_balance_splits_with_conversion(conn, tid, &sym, as_of).await
31
        }
32
1
        (None, Some(f)) => fetch_balance_splits_filtered_no_conversion(conn, as_of, f).await,
33
4
        (None, None) => fetch_balance_splits_no_conversion(conn, as_of).await,
34
    }
35
10
}
36

            
37
3
async fn fetch_range(
38
3
    conn: &mut sqlx::PgConnection,
39
3
    target_commodity_id: Option<Uuid>,
40
3
    from: DateTime<Utc>,
41
3
    to: DateTime<Utc>,
42
3
    report_filter: Option<&ReportFilter>,
43
3
) -> Result<AccountAmounts, CmdError> {
44
3
    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
1
        (Some(tid), None) => {
50
1
            let sym = fetch_target_symbol(conn, tid).await?;
51
1
            fetch_date_range_splits_with_conversion(conn, tid, &sym, from, to).await
52
        }
53
1
        (None, Some(f)) => fetch_date_range_splits_filtered_no_conversion(conn, from, to, f).await,
54
1
        (None, None) => fetch_date_range_splits_no_conversion(conn, from, to).await,
55
    }
56
3
}
57

            
58
command! {
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
        let user = User { id: user_id };
72
        let mut conn = user.get_connection().await.map_err(|err| {
73
            log::error!("{}", t!("Database error: %{err}", err = err : {:?}));
74
            ConfigError::DB
75
        })?;
76

            
77
        let accounts = fetch_accounts(&mut conn).await?;
78

            
79
        let amounts = match date_from {
80
            Some(from) => {
81
                let to = as_of.unwrap_or_else(Utc::now);
82
                fetch_range(&mut conn, target_commodity_id, from, to, report_filter.as_ref()).await?
83
            }
84
            None => fetch_snapshot(&mut conn, target_commodity_id, as_of, report_filter.as_ref()).await?,
85
        };
86

            
87
        let roots = build_tree(&accounts, &amounts);
88
        let period = PeriodData { label: None, roots };
89

            
90
        Ok(Some(CmdResult::Report(ReportData {
91
            meta: ReportMeta {
92
                date_from,
93
                date_to: as_of,
94
                target_commodity_id,
95
            },
96
            periods: vec![period],
97
        })))
98
    }
99
54
}