aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2019-08-11 17:45:28 -0400
committerJesse Luehrs <doy@tozt.net>2019-08-11 17:45:28 -0400
commit909badee565c8e5164890b71da6a03b9efe16b28 (patch)
tree5a98249940e8ec848bc6634d979391947a1503fc
parent53f34a6d47c43d96e5a3f5b368387776e9db7b02 (diff)
downloadynab-api-909badee565c8e5164890b71da6a03b9efe16b28.tar.gz
ynab-api-909badee565c8e5164890b71da6a03b9efe16b28.zip
refactor
-rw-r--r--src/main.rs79
-rw-r--r--src/ynab.rs7
-rw-r--r--src/ynab/budget.rs86
-rw-r--r--src/ynab/client.rs31
-rw-r--r--src/ynab/transaction.rs7
-rw-r--r--src/ynab/util.rs6
6 files changed, 149 insertions, 67 deletions
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<super::transaction::Transaction> {
+ 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)
+}