From 909badee565c8e5164890b71da6a03b9efe16b28 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 11 Aug 2019 17:45:28 -0400 Subject: refactor --- src/main.rs | 79 +++++++-------------------------------------- src/ynab.rs | 7 ++++ src/ynab/budget.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ src/ynab/client.rs | 31 ++++++++++++++++++ src/ynab/transaction.rs | 7 ++++ src/ynab/util.rs | 6 ++++ 6 files changed, 149 insertions(+), 67 deletions(-) create mode 100644 src/ynab.rs create mode 100644 src/ynab/budget.rs create mode 100644 src/ynab/client.rs create mode 100644 src/ynab/transaction.rs create mode 100644 src/ynab/util.rs diff --git a/src/main.rs b/src/main.rs index c3fa324..46f8042 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,76 +1,21 @@ -fn client(key: &str) -> ynab_api::apis::client::APIClient { - let mut ynab_config = ynab_api::apis::configuration::Configuration::new(); - ynab_config.api_key = Some(ynab_api::apis::configuration::ApiKey { - prefix: Some("Bearer".to_string()), - key: key.to_string(), - }); - ynab_api::apis::client::APIClient::new(ynab_config) -} - -fn format_amount(amount: i64) -> String { - let dollars = amount.abs() / 1000; - let cents = (amount.abs() % 1000) / 10; - let sign = if amount < 0 { "-" } else { "" }; - format!("{}{}.{:02}", sign, dollars, cents) -} +mod ynab; fn main() { let key = std::env::args().nth(1).unwrap(); - let client = client(&key); - - let budgets = client.budgets_api().get_budgets().unwrap().data.budgets; - let budget = budgets.iter().next().unwrap(); - println!("budget is {} ({})", budget.name, budget.id); - - let reimbursables_id = client - .categories_api() - .get_categories(&budget.id, 0) - .unwrap() - .data - .category_groups - .iter() - .map(|group| { - group - .categories - .iter() - .map(|c| (c.id.clone(), c.name.clone())) - }) - .flat_map(|cs| cs) - .find(|(_, name)| name == "Reimbursables") - .map(|(id, _)| id) - .unwrap(); - println!("found reimbursables category: {}", reimbursables_id); - - let full_budget = client - .budgets_api() - .get_budget_by_id(&budget.id, 0) - .unwrap() - .data - .budget; - println!("got full budget"); - - let transactions = full_budget.transactions.unwrap(); - let payees = full_budget.payees.unwrap(); - - for t in transactions { - if let Some(category_id) = t.category_id { - if category_id != reimbursables_id { - continue; - } - } else { - continue; - } + let client = ynab::Client::new(&key); + let budget = client.default_budget(); + println!("using budget {} ({})", budget.name(), budget.id()); - if t.flag_color.is_some() { + for t in budget.reimbursables() { + if t.reimbursed { continue; } - let payee = t - .payee_id - .map(|id| { - payees.iter().find(|p| p.id == id).unwrap().name.clone() - }) - .unwrap_or_else(|| "(none)".to_string()); - println!("{} | {} | {}", t.date, payee, format_amount(t.amount)) + println!( + "{} | {} | {}", + t.date, + t.payee, + ynab::format_amount(t.amount) + ) } } diff --git a/src/ynab.rs b/src/ynab.rs new file mode 100644 index 0000000..da80da0 --- /dev/null +++ b/src/ynab.rs @@ -0,0 +1,7 @@ +mod budget; +mod client; +mod transaction; +mod util; + +pub use client::Client; +pub use util::format_amount; diff --git a/src/ynab/budget.rs b/src/ynab/budget.rs new file mode 100644 index 0000000..85eab22 --- /dev/null +++ b/src/ynab/budget.rs @@ -0,0 +1,86 @@ +pub struct Budget<'a> { + api: &'a ynab_api::apis::client::APIClient, + budget: ynab_api::models::BudgetDetail, +} + +impl<'a> Budget<'a> { + pub fn new( + api: &'a ynab_api::apis::client::APIClient, + budget: ynab_api::models::BudgetDetail, + ) -> Self { + Self { api, budget } + } + + pub fn name(&self) -> String { + self.budget.name.clone() + } + + pub fn id(&self) -> String { + self.budget.id.clone() + } + + pub fn reimbursables(&self) -> Vec { + let reimbursables_id = self + .api + .categories_api() + .get_categories(&self.budget.id, 0) + .unwrap() + .data + .category_groups + .iter() + .map(|group| { + group + .categories + .iter() + .map(|c| (c.id.clone(), c.name.clone())) + }) + .flat_map(|cs| cs) + .find(|(_, name)| name == "Reimbursables") + .map(|(id, _)| id) + .unwrap(); + + let mut reimbursables = vec![]; + if let Some(transactions) = &self.budget.transactions { + if let Some(payees) = &self.budget.payees { + let mut payee_map = std::collections::HashMap::new(); + for p in payees { + payee_map.insert(p.id.clone(), p.name.clone()); + } + let payee_map = payee_map; + + for t in transactions { + if let Some(category_id) = &t.category_id { + if category_id != &reimbursables_id { + continue; + } + } else { + continue; + } + + let payee = t + .payee_id + .iter() + .flat_map(|payee_id| payee_map.get(payee_id).cloned()) + .next() + .unwrap_or_else(|| "(none)".to_string()); + let reimbursed = if let Some(color) = &t.flag_color { + color == "green" + } else { + false + }; + + reimbursables.push(super::transaction::Transaction { + date: t.date.clone(), + payee, + amount: t.amount, + reimbursed, + }) + } + } else { + panic!("no payees?"); + } + } + + reimbursables + } +} diff --git a/src/ynab/client.rs b/src/ynab/client.rs new file mode 100644 index 0000000..a2fbdb3 --- /dev/null +++ b/src/ynab/client.rs @@ -0,0 +1,31 @@ +pub struct Client { + api: ynab_api::apis::client::APIClient, +} + +impl Client { + pub fn new(key: &str) -> Self { + let mut ynab_config = + ynab_api::apis::configuration::Configuration::new(); + ynab_config.api_key = Some(ynab_api::apis::configuration::ApiKey { + prefix: Some("Bearer".to_string()), + key: key.to_string(), + }); + Self { + api: ynab_api::apis::client::APIClient::new(ynab_config), + } + } + + pub fn default_budget(&self) -> super::budget::Budget { + let budgets = + self.api.budgets_api().get_budgets().unwrap().data.budgets; + let budget = budgets.iter().next().unwrap(); + let full_budget = self + .api + .budgets_api() + .get_budget_by_id(&budget.id, 0) + .unwrap() + .data + .budget; + super::budget::Budget::new(&self.api, full_budget) + } +} diff --git a/src/ynab/transaction.rs b/src/ynab/transaction.rs new file mode 100644 index 0000000..79209b5 --- /dev/null +++ b/src/ynab/transaction.rs @@ -0,0 +1,7 @@ +#[derive(Clone, Debug)] +pub struct Transaction { + pub date: String, + pub payee: String, + pub amount: i64, + pub reimbursed: bool, +} diff --git a/src/ynab/util.rs b/src/ynab/util.rs new file mode 100644 index 0000000..6be9e6a --- /dev/null +++ b/src/ynab/util.rs @@ -0,0 +1,6 @@ +pub fn format_amount(amount: i64) -> String { + let dollars = amount.abs() / 1000; + let cents = (amount.abs() % 1000) / 10; + let sign = if amount < 0 { "-" } else { "" }; + format!("{}{}.{:02}", sign, dollars, cents) +} -- cgit v1.2.3-54-g00ecf