use crate::models::{budget_update::BudgetUpdate, category::Category}; use super::{calculate_budgets_accrual, find_by_id_or}; pub fn calculate_category_balance( category: &Category, transaction_sums: &[(i32, Option)], category_transfer_from_sums: &[(i32, Option)], category_transfer_to_sums: &[(i32, Option)], budget_updates: &[BudgetUpdate], ) -> i64 { let transaction_sum = find_by_id_or(transaction_sums, category.id, 0); let category_transfer_from_sum = find_by_id_or(category_transfer_from_sums, category.id, 0); let category_transfer_to_sum = find_by_id_or(category_transfer_to_sums, category.id, 0); let budget_accruals_sum = calculate_budgets_accrual(category, budget_updates); transaction_sum + budget_accruals_sum + category_transfer_to_sum - category_transfer_from_sum } #[cfg(test)] mod test { use chrono::{Days, Utc}; use crate::{ models::{budget_update::BudgetUpdate, category::Category, date_time_utc::DateTimeUtc}, utils::calculate_category_balance, }; #[test] fn when_no_data_then_returns_zero() { let category = Category { id: 0, name: String::new(), }; let result = calculate_category_balance(&category, &[], &[], &[], &[]); assert_eq!(result, 0_i64); } #[test] fn when_data_only_for_another_category_then_returns_zero() { let category = Category { id: 0, name: String::new(), }; let transaction_sums = [(1, Some(100))]; let category_transfer_from_sums = [(1, Some(91))]; let category_transfer_to_sums = [(2, Some(79))]; let budget_updates = [BudgetUpdate { id: 0, category_id: 1, date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(120)).unwrap()), new_budget: 77, new_period: 1, }]; let result = calculate_category_balance( &category, &transaction_sums, &category_transfer_from_sums, &category_transfer_to_sums, &budget_updates, ); assert_eq!(result, 0_i64); } #[test] fn when_transaction_sum_is_none_then_returns_zero() { let category = Category { id: 0, name: String::new(), }; let transaction_sums = [(0, None)]; let category_transfer_from_sums = []; let category_transfer_to_sums = []; let budget_updates = []; let result = calculate_category_balance( &category, &transaction_sums, &category_transfer_from_sums, &category_transfer_to_sums, &budget_updates, ); assert_eq!(result, 0_i64); } #[test] fn when_category_transfers_are_none_then_returns_zero() { let category = Category { id: 0, name: String::new(), }; let transaction_sums = []; let category_transfer_from_sums = [(0, None)]; let category_transfer_to_sums = [(0, None)]; let budget_updates = []; let result = calculate_category_balance( &category, &transaction_sums, &category_transfer_from_sums, &category_transfer_to_sums, &budget_updates, ); assert_eq!(result, 0_i64); } #[test] fn when_some_data_then_calculates_as_expected() { let category = Category { id: 0, name: String::new(), }; let transaction_sums = [(0, Some(100))]; let category_transfer_from_sums = [(0, Some(91))]; let category_transfer_to_sums = [(0, Some(79))]; let budget_updates = [BudgetUpdate { id: 0, category_id: 0, date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(120)).unwrap()), new_budget: 77, new_period: 1, }]; let result = calculate_category_balance( &category, &transaction_sums, &category_transfer_from_sums, &category_transfer_to_sums, &budget_updates, ); let expected_result = 100 + (-91) + 79 + 77 * 120; assert_eq!(result, expected_result); } }