summaryrefslogtreecommitdiff
path: root/rust/schist_actualbudget_importer/src/transformers.rs
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2024-11-21 22:35:57 +0000
committerJoe Carstairs <me@joeac.net>2024-11-21 22:35:57 +0000
commit6d441ca9318762a19d5e56002a6be6fe78d7262a (patch)
tree56100e914019d9fc32070d020defdda369b39fac /rust/schist_actualbudget_importer/src/transformers.rs
parent11cdd2ad3368e349d1cebe079629af61e8c45d78 (diff)
Refactors actualbudget importer
Diffstat (limited to 'rust/schist_actualbudget_importer/src/transformers.rs')
-rw-r--r--rust/schist_actualbudget_importer/src/transformers.rs257
1 files changed, 0 insertions, 257 deletions
diff --git a/rust/schist_actualbudget_importer/src/transformers.rs b/rust/schist_actualbudget_importer/src/transformers.rs
deleted file mode 100644
index 711904b..0000000
--- a/rust/schist_actualbudget_importer/src/transformers.rs
+++ /dev/null
@@ -1,257 +0,0 @@
-use actualbudget_models::{
- actualbudget_account::ActualbudgetAccount,
- actualbudget_category::ActualbudgetCategory,
- actualbudget_date::ActualbudgetDate,
- actualbudget_transaction::ActualbudgetTransaction,
- actualbudget_zero_budget::ActualbudgetZeroBudget,
-};
-use anyhow::Result;
-use schist_models::{
- account::Account,
- budget_update::BudgetUpdate,
- category::Category,
- category_transfer::CategoryTransfer,
- date_utc::DateUtc,
- datetime_utc::DatetimeUtc,
- transaction::Transaction,
- transaction_categorisation::TransactionCategorisation,
-};
-use core::panic;
-use std::hash::{DefaultHasher, Hash, Hasher};
-
-pub fn transform_date(actualbudget_date: &ActualbudgetDate) -> Result<DatetimeUtc> {
- actualbudget_date.to_iso().parse()
-}
-
-pub fn transform_accounts(
- actualbudget_accounts: &[ActualbudgetAccount],
- first_transaction_date: &DatetimeUtc,
-) -> Vec<Account> {
- let mut accounts = Vec::<Account>::new();
- for account in actualbudget_accounts {
- accounts.push(transform_account(account, first_transaction_date));
- }
- accounts
-}
-
-fn transform_account(
- actualbudget_account: &ActualbudgetAccount,
- opening_date: &DatetimeUtc,
-) -> Account {
- Account {
- id: transform_id(&actualbudget_account.id.clone()),
- name: actualbudget_account.name.clone(),
- opening_balance: 0,
- opening_date: opening_date.clone(),
- }
-}
-
-pub fn transform_categories(
- actualbudget_categories: &[ActualbudgetCategory],
-) -> 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(),
- })
- }
- categories
-}
-
-fn transform_id(actualbudget_id: &str) -> i32 {
- let mut hasher = DefaultHasher::new();
- actualbudget_id.hash(&mut hasher);
- (hasher.finish() % std::convert::TryInto::<u64>::try_into(i32::MAX).unwrap())
- .try_into()
- .unwrap()
-}
-
-pub fn transform_budget_updates(
- actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
-) -> Result<Vec<BudgetUpdate>> {
- let mut budget_updates = Vec::<BudgetUpdate>::new();
- for zero_budget in actualbudget_zero_budgets {
- let first_zero_budget_in_category = get_first_zero_budget_in_category(
- actualbudget_zero_budgets,
- &zero_budget.category_id.clone(),
- );
- if first_zero_budget_in_category.is_some_and(|zb| zb.id == zero_budget.id) {
- continue;
- }
- budget_updates.push(BudgetUpdate {
- id: transform_id(&zero_budget.id.clone()),
- category_id: transform_id(&zero_budget.category_id.clone()),
- date: DateUtc::from(transform_date(&zero_budget.month.clone())?),
- new_budget: zero_budget.amount.try_into().unwrap(),
- new_period: 30,
- })
- }
- Ok(budget_updates)
-}
-
-fn get_first_zero_budget_in_category(
- actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
- actualbudget_category_id: &str,
-) -> Option<ActualbudgetZeroBudget> {
- let mut category_zero_budgets = actualbudget_zero_budgets.to_vec();
- category_zero_budgets.retain(|zb| zb.category_id == actualbudget_category_id);
- category_zero_budgets
- .iter()
- .min_by_key(|zb| zb.month.clone())
- .cloned()
-}
-
-pub fn transform_transactions(
- actualbudget_transactions: &[ActualbudgetTransaction],
- actualbudget_category_transfers_account: &Option<ActualbudgetAccount>,
-) -> Result<(Vec<Transaction>, Vec<TransactionCategorisation>)> {
- let mut transactions = Vec::<Transaction>::new();
- let mut transaction_categorisations = Vec::<TransactionCategorisation>::new();
-
- let mut actualbudget_transactions = actualbudget_transactions.to_vec();
- actualbudget_transactions.retain(|transaction|
- is_not_category_transfer(transaction, actualbudget_category_transfers_account)
- );
- let mut parent_actualbudget_transactions = actualbudget_transactions.to_vec();
- parent_actualbudget_transactions.retain(|t| t.is_parent);
- let mut child_actualbudget_transactions = actualbudget_transactions.to_vec();
- child_actualbudget_transactions.retain(|t| t.is_child);
- let mut atomic_actualbudget_transactions = actualbudget_transactions.to_vec();
- atomic_actualbudget_transactions.retain(|t| !t.is_parent && !t.is_child);
-
- for atomic_actualbudget_transaction in atomic_actualbudget_transactions {
- let transaction_id = transform_id(&atomic_actualbudget_transaction.id);
-
- transactions.push(Transaction {
- id: transaction_id,
- description: atomic_actualbudget_transaction.notes.unwrap_or_else(String::new),
- payee: atomic_actualbudget_transaction.payee.unwrap_or_else(String::new),
- quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
- date: transform_date(&atomic_actualbudget_transaction.date)?,
- account_id: transform_id(&atomic_actualbudget_transaction.account_id),
- });
-
- let actualbudget_category_id = atomic_actualbudget_transaction
- .category_id
- .expect("actualbudget transaction should have been atomic, but in fact had no category ID");
-
- transaction_categorisations.push(TransactionCategorisation {
- id: transaction_id,
- description: String::new(),
- quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
- transaction_id,
- category_id: transform_id(&actualbudget_category_id),
- });
- }
-
- for parent_actualbudget_transaction in parent_actualbudget_transactions {
- let mut child_actualbudget_transactions = child_actualbudget_transactions.to_vec();
- child_actualbudget_transactions.retain(|t| {
- t.parent_id
- .clone()
- .is_some_and(|parent_id| parent_id == parent_actualbudget_transaction.id.clone())
- });
-
- let transaction_id = transform_id(&parent_actualbudget_transaction.id);
-
- transactions.push(Transaction {
- id: transaction_id,
- description: parent_actualbudget_transaction.notes.unwrap_or_else(String::new),
- payee: parent_actualbudget_transaction.payee.unwrap_or_else(String::new),
- quantity: parent_actualbudget_transaction.amount.try_into().unwrap(),
- date: transform_date(&parent_actualbudget_transaction.date)?,
- account_id: transform_id(&parent_actualbudget_transaction.account_id),
- });
-
- for child_actualbudget_transaction in child_actualbudget_transactions {
- let actualbudget_category_id = child_actualbudget_transaction
- .category_id
- .expect("actualbudget transaction should have been a child transaction, but in fact had no category ID");
-
- transaction_categorisations.push(TransactionCategorisation {
- id: transform_id(&child_actualbudget_transaction.id),
- description: child_actualbudget_transaction.notes.unwrap_or_else(String::new),
- quantity: child_actualbudget_transaction.amount.try_into().unwrap(),
- transaction_id,
- category_id: transform_id(&actualbudget_category_id),
- });
- }
- }
-
- Ok((transactions, transaction_categorisations))
-}
-
-pub fn transform_category_transfers(
- actualbudget_transactions: &[ActualbudgetTransaction],
- actualbudget_category_transfers_account: &Option<ActualbudgetAccount>,
-) -> Vec<CategoryTransfer> {
- let mut category_transfers = Vec::<CategoryTransfer>::new();
-
- let mut actualbudget_category_transfers = actualbudget_transactions.to_vec();
- actualbudget_category_transfers.retain(|transaction|
- is_category_transfer(transaction, actualbudget_category_transfers_account)
- );
- let mut actualbudget_parent_category_transfers = actualbudget_category_transfers.to_vec();
- actualbudget_parent_category_transfers.retain(|t| t.is_parent);
- let mut actualbudget_child_category_transfers = actualbudget_category_transfers.to_vec();
- actualbudget_child_category_transfers.retain(|t| t.is_child);
-
- for actualbudget_parent_category_transfer in actualbudget_parent_category_transfers {
- let mut actualbudget_child_category_transfers =
- actualbudget_child_category_transfers.to_vec();
- actualbudget_child_category_transfers.retain(|t| {
- t.parent_id
- .clone()
- .is_some_and(|parent_id| parent_id == actualbudget_parent_category_transfer.id)
- });
-
- if actualbudget_child_category_transfers.len() != 2 {
- panic!("Category transfers should always have exactly two children.");
- }
-
- let category_1 = actualbudget_child_category_transfers[0].clone();
- let category_2 = actualbudget_child_category_transfers[1].clone();
-
- // To avoid duplicates
- if category_1.amount >= 0 {
- continue;
- }
-
- if actualbudget_child_category_transfers[0].amount
- != -actualbudget_child_category_transfers[1].amount
- {
- panic!("Category transfer children should sum to zero.");
- }
-
- category_transfers.push(CategoryTransfer {
- id: transform_id(&actualbudget_parent_category_transfer.id),
- description: actualbudget_parent_category_transfer.notes.unwrap_or_else(String::new),
- quantity: actualbudget_child_category_transfers[0]
- .amount
- .try_into()
- .unwrap(),
- from_category_id: transform_id(&category_1.id),
- to_category_id: transform_id(&category_2.id),
- });
- }
-
- category_transfers
-}
-
-fn is_category_transfer(
- transaction: &ActualbudgetTransaction,
- actualbudget_category_transfers_account: &Option<ActualbudgetAccount>
-) -> bool {
- match actualbudget_category_transfers_account {
- None => false,
- Some(acc) => transaction.account_id.clone() == acc.id.clone(),
- }
-}
-
-fn is_not_category_transfer(
- transaction: &ActualbudgetTransaction,
- actualbudget_category_transfers_account: &Option<ActualbudgetAccount>
-) -> bool {
- !is_category_transfer(transaction, actualbudget_category_transfers_account)
-}