diff options
| author | Joe Carstairs <me@joeac.net> | 2024-11-25 13:05:35 +0000 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2024-11-25 13:05:35 +0000 |
| commit | e79fa9875d2122e607fb1150dafa99d703ed11b8 (patch) | |
| tree | 2417a8b6cfa9b0ea284859b9d9b70f082520375f /rust/actualbudget_to_schist_transformer/src/transform_state | |
| parent | 5bd223ee9c6853502d509627678f696c6ea5fcdc (diff) | |
Transform categories
Diffstat (limited to 'rust/actualbudget_to_schist_transformer/src/transform_state')
| -rw-r--r-- | rust/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs | 190 | ||||
| -rw-r--r-- | rust/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs | 25 |
2 files changed, 189 insertions, 26 deletions
diff --git a/rust/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs b/rust/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs index e0fc687..b78fd2b 100644 --- a/rust/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs +++ b/rust/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs @@ -1,38 +1,184 @@ -use actualbudget_models::ActualbudgetCategory; -use schist_models::{budget_period_unit::BudgetPeriodUnit, category::Category}; +use actualbudget_models::{ActualbudgetCategory, ActualbudgetZeroBudget}; +use schist_models::{budget_period_unit::BudgetPeriodUnit, category::Category, date_utc::DateUtc}; use super::transform_id; pub fn transform_categories( actualbudget_categories: &[ActualbudgetCategory], + actualbudget_zero_budgets: &[ActualbudgetZeroBudget], + before_first_transaction: &DateUtc, ) -> Vec<Category> { - let mut categories = Vec::<Category>::new(); - for actualbudget_category in actualbudget_categories { - categories.push(Category { - id: transform_id(&actualbudget_category.id.clone()), - name: actualbudget_category.name.clone(), - balance: 0, - balance_date: get_balance_date(), - budget_period: 1, - budget_period_unit: BudgetPeriodUnit::Month, - budget_quantity: get_budget_quantity(), - }) - } - categories + actualbudget_categories.iter().map(|actualbudget_category| Category { + id: transform_id(&actualbudget_category.id.clone()), + name: actualbudget_category.name.clone(), + balance: 0, + balance_date: before_first_transaction.clone(), + budget_period: 1, + budget_period_unit: BudgetPeriodUnit::Month, + budget_quantity: get_budget_quantity(actualbudget_category, actualbudget_zero_budgets), + }).collect() } -fn get_balance_date() -> schist_models::date_utc::DateUtc { - todo!() -} +fn get_budget_quantity( + actualbudget_category: &ActualbudgetCategory, + actualbudget_zero_budgets: &[ActualbudgetZeroBudget] +) -> i32 { + let latest_zero_budget_for_category = actualbudget_zero_budgets + .iter() + .filter(|zb| zb.category_id == actualbudget_category.id) + .max_by_key(|zb| zb.month.clone()); -fn get_budget_quantity() -> i32 { - todo!() + match latest_zero_budget_for_category { + Some(latest_zero_budget_for_category) => latest_zero_budget_for_category.amount, + None => 0, + } } #[cfg(test)] mod test { + use actualbudget_fakes::{actualbudget_category::make_fake_actualbudget_category_builder, actualbudget_zero_budget::make_fake_actualbudget_zero_budget_builder}; + use actualbudget_models::ActualbudgetDate; + use schist_models::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc}; + use schist_traits::nowlike::Nowlike; + + use crate::transform_state::transform_id::transform_id; + + use super::transform_categories; + + #[test] + fn when_one_category_one_zero_budget_then_transforms_category() { + let actualbudget_categories = [ + make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(), + ]; + let actualbudget_zero_budgets = [ + make_fake_actualbudget_zero_budget_builder("0").amount(100).build().unwrap(), + ]; + let before_first_transaction = DateUtc::now(); + + let categories = transform_categories( + &actualbudget_categories, + &actualbudget_zero_budgets, + &before_first_transaction, + ); + + assert_eq!(1, categories.len()); + let category = categories.get(0).unwrap(); + assert_eq!("Food", category.name); + assert_eq!(0, category.balance); + assert_eq!(before_first_transaction, category.balance_date); + assert_eq!(1, category.budget_period); + assert_eq!(BudgetPeriodUnit::Month, category.budget_period_unit); + assert_eq!(100, category.budget_quantity); + } + + #[test] + fn when_one_category_no_zero_budget_then_transforms_category() { + let actualbudget_categories = [ + make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(), + ]; + let actualbudget_zero_budgets = []; + let before_first_transaction = DateUtc::now(); + + let categories = transform_categories( + &actualbudget_categories, + &actualbudget_zero_budgets, + &before_first_transaction, + ); + + assert_eq!(1, categories.len()); + let category = categories.get(0).unwrap(); + assert_eq!("Food", category.name); + assert_eq!(0, category.balance); + assert_eq!(before_first_transaction, category.balance_date); + assert_eq!(1, category.budget_period); + assert_eq!(BudgetPeriodUnit::Month, category.budget_period_unit); + assert_eq!(0, category.budget_quantity); + } + #[test] - fn todo() { - todo!() + fn when_one_category_multiple_zero_budgets_then_transforms_category() { + let actualbudget_categories = [ + make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(), + ]; + let jan = ActualbudgetDate::from_i32(202401); + let feb = ActualbudgetDate::from_i32(202402); + let mar = ActualbudgetDate::from_i32(202403); + let actualbudget_zero_budgets = [ + make_fake_actualbudget_zero_budget_builder("0").amount(100).month(jan).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("1").amount(200).month(feb).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("2").amount(300).month(mar).build().unwrap(), + ]; + let before_first_transaction = DateUtc::now(); + + let categories = transform_categories( + &actualbudget_categories, + &actualbudget_zero_budgets, + &before_first_transaction, + ); + + assert_eq!(1, categories.len()); + let category = categories.get(0).unwrap(); + assert_eq!("Food", category.name); + assert_eq!(0, category.balance); + assert_eq!(before_first_transaction, category.balance_date); + assert_eq!(1, category.budget_period); + assert_eq!(BudgetPeriodUnit::Month, category.budget_period_unit); + assert_eq!(300, category.budget_quantity); + } + + #[test] + fn when_multiple_categories_multiple_zero_budgets_then_transforms_category() { + let actualbudget_categories = [ + make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(), + make_fake_actualbudget_category_builder("1").name(String::from("Clothes")).build().unwrap(), + make_fake_actualbudget_category_builder("2").name(String::from("Rent")).build().unwrap(), + ]; + let jan = ActualbudgetDate::from_i32(202401); + let feb = ActualbudgetDate::from_i32(202402); + let mar = ActualbudgetDate::from_i32(202403); + let actualbudget_zero_budgets = [ + make_fake_actualbudget_zero_budget_builder("0").amount(100).month(jan.clone()).category_id(String::from("0")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("1").amount(200).month(feb.clone()).category_id(String::from("0")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("2").amount(300).month(mar.clone()).category_id(String::from("0")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("3").amount(110).month(jan.clone()).category_id(String::from("1")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("4").amount(210).month(feb.clone()).category_id(String::from("1")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("5").amount(310).month(mar.clone()).category_id(String::from("1")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("6").amount(120).month(jan.clone()).category_id(String::from("2")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("7").amount(220).month(feb.clone()).category_id(String::from("2")).build().unwrap(), + make_fake_actualbudget_zero_budget_builder("8").amount(320).month(mar.clone()).category_id(String::from("2")).build().unwrap(), + ]; + let before_first_transaction = DateUtc::now(); + + let categories = transform_categories( + &actualbudget_categories, + &actualbudget_zero_budgets, + &before_first_transaction, + ); + + assert_eq!(3, categories.len()); + + let category_0 = categories.iter().filter(|c| c.id == transform_id("0")).last().unwrap(); + assert_eq!("Food", category_0.name); + assert_eq!(0, category_0.balance); + assert_eq!(before_first_transaction, category_0.balance_date); + assert_eq!(1, category_0.budget_period); + assert_eq!(BudgetPeriodUnit::Month, category_0.budget_period_unit); + assert_eq!(300, category_0.budget_quantity); + + let category_1 = categories.iter().filter(|c| c.id == transform_id("1")).last().unwrap(); + assert_eq!("Clothes", category_1.name); + assert_eq!(0, category_1.balance); + assert_eq!(before_first_transaction, category_1.balance_date); + assert_eq!(1, category_1.budget_period); + assert_eq!(BudgetPeriodUnit::Month, category_1.budget_period_unit); + assert_eq!(310, category_1.budget_quantity); + + let category_2 = categories.iter().filter(|c| c.id == transform_id("2")).last().unwrap(); + assert_eq!("Rent", category_2.name); + assert_eq!(0, category_2.balance); + assert_eq!(before_first_transaction, category_2.balance_date); + assert_eq!(1, category_2.budget_period); + assert_eq!(BudgetPeriodUnit::Month, category_2.budget_period_unit); + assert_eq!(320, category_2.budget_quantity); } } diff --git a/rust/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs b/rust/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs index 2285276..cc5dfe1 100644 --- a/rust/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs +++ b/rust/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs @@ -1,5 +1,5 @@ -use anyhow::Result; -use schist_models::{account::Account, category::Category, category_transfer::CategoryTransfer, transaction::Transaction, transaction_categorisation::TransactionCategorisation}; +use anyhow::{bail, Result}; +use schist_models::{account::Account, category::Category, category_transfer::CategoryTransfer, date_utc::DateUtc, datetime_utc::DatetimeUtc, transaction::Transaction, transaction_categorisation::TransactionCategorisation}; use crate::{actualbudget_state::ActualbudgetState, schist_state::SchistState}; @@ -8,11 +8,15 @@ use super::{transform_accounts, transform_budget_drips::transform_budget_drips, pub fn transform_state(actualbudget_state: ActualbudgetState) -> Result<SchistState> { let first_transaction_date = transform_date(&actualbudget_state.actualbudget_first_transaction_date)?; + let before_first_transaction_date = find_date_before(&first_transaction_date)?; let accounts: Vec<Account> = transform_accounts(&actualbudget_state.actualbudget_accounts, &first_transaction_date); let budget_drips = transform_budget_drips(&actualbudget_state.actualbudget_zero_budgets)?; - let categories: Vec<Category> = - transform_categories(&actualbudget_state.actualbudget_categories); + let categories: Vec<Category> = transform_categories( + &actualbudget_state.actualbudget_categories, + &actualbudget_state.actualbudget_zero_budgets, + &before_first_transaction_date, + ); let (transactions, transaction_categorisations): (Vec<Transaction>, Vec<TransactionCategorisation>) = transform_transactions( &actualbudget_state.actualbudget_transactions, @@ -33,3 +37,16 @@ pub fn transform_state(actualbudget_state: ActualbudgetState) -> Result<SchistSt category_transfers, }) } + +fn find_date_before(datetime: &DatetimeUtc) -> Result<DateUtc> { + let date: DateUtc = datetime.into(); + + for days_before in 0..31 { + let result = date.sub_days(days_before); + if result.is_ok() { + return result; + } + } + + bail!("failed to find a date before {}", date) +} |
