aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYaroslav de la Peña Smirnov <yps@yaroslavps.com>2020-10-09 23:51:37 +0300
committerYaroslav de la Peña Smirnov <yps@yaroslavps.com>2020-10-09 23:51:37 +0300
commitc1d4b0a43046b8aa4bad6ebf6ca3f74aba1bb54f (patch)
tree4cc9f11cdee92b9d50cb2ff240c8d64d475fbe32
parent742b9fa46d74762f58ae939afd980a532cc4636f (diff)
downloadfinbudg-c1d4b0a43046b8aa4bad6ebf6ca3f74aba1bb54f.tar.gz
finbudg-c1d4b0a43046b8aa4bad6ebf6ca3f74aba1bb54f.zip
take into account shared expenses
-rw-r--r--budget/src/lib.rs24
-rw-r--r--budget/tests/budget.rs14
-rw-r--r--budget/tests/test.toml3
-rw-r--r--src/main.rs16
4 files changed, 50 insertions, 7 deletions
diff --git a/budget/src/lib.rs b/budget/src/lib.rs
index 7d7c390..7d194c0 100644
--- a/budget/src/lib.rs
+++ b/budget/src/lib.rs
@@ -49,6 +49,7 @@ pub struct Calculated {
pub categories_subtotal: HashMap<String, f64>,
pub total: f64,
pub balance: f64,
+ pub total_owed: HashMap<u32, f64>,
pub days_left: f64,
pub days_left_essential: f64,
pub last_day: NaiveDate,
@@ -69,9 +70,6 @@ fn recurring_default() -> bool {
}
// Parse the dates from toml's Datetime to Chrono's NaiveDate
-// Probably unnecessary for now, but since I am planning on using the dates in
-// the future to more easily count the days, it would be better to have them in
-// a proper format
fn deserialize_date<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error>
where D: Deserializer<'de> {
toml::value::Datetime::deserialize(deserializer)
@@ -98,7 +96,7 @@ pub fn parse_account(path: &str) -> Result<Account, ParseError> {
}
pub fn calculate(account: &Account) -> Option<Calculated> {
- if account.days.len() < 1 {
+ if account.days.is_empty() {
return None;
}
@@ -110,6 +108,7 @@ pub fn calculate(account: &Account) -> Option<Calculated> {
categories_subtotal: HashMap::<String, f64>::new(),
total: 0.0,
balance: 0.0,
+ total_owed: HashMap::<u32, f64>::new(),
days_left: 0.0,
days_left_essential: 0.0,
last_day: account.days.last().unwrap().date,
@@ -137,6 +136,23 @@ pub fn calculate(account: &Account) -> Option<Calculated> {
if account.essential_categories.contains(category) {
calculated.essential_subtotal += expense.price;
}
+
+ if expense.shared > 1 {
+ let owed =
+ expense.price *
+ (expense.shared as f64 - 1.0) /
+ expense.shared as f64;
+
+ if let Some(total_owed_by) =
+ calculated.total_owed.get_mut(&expense.shared) {
+ *total_owed_by += owed;
+ } else {
+ calculated.total_owed.insert(
+ expense.shared,
+ owed,
+ );
+ }
+ }
}
}
}
diff --git a/budget/tests/budget.rs b/budget/tests/budget.rs
index feae240..6a9214d 100644
--- a/budget/tests/budget.rs
+++ b/budget/tests/budget.rs
@@ -31,7 +31,7 @@ fn can_parse_account() -> Result<(), ParseError>{
name: String::from("Bacon"),
price: 3.33,
qty: 1,
- shared: 2,
+ shared: 3,
recurring: false,
category: Some(String::from("products")),
},
@@ -39,7 +39,7 @@ fn can_parse_account() -> Result<(), ParseError>{
name: String::from("Yoghurt"),
price: 1.24,
qty: 2,
- shared: 1,
+ shared: 2,
recurring: false,
category: Some(String::from("products")),
},
@@ -106,6 +106,7 @@ fn can_calculate() -> Result<(), ParseError> {
categories_subtotal: HashMap::<String, f64>::new(),
total: 22.71,
balance: 397.29,
+ total_owed: HashMap::<u32, f64>::new(),
days_left: 69.9762219286658,
days_left_essential: 84.08253968253969,
last_day: NaiveDate::from_ymd(2020, 10, 04),
@@ -145,6 +146,15 @@ fn can_calculate() -> Result<(), ParseError> {
5.0,
);
+ should_be.total_owed.insert(
+ 2,
+ 1.7599999999999998,
+ );
+ should_be.total_owed.insert(
+ 3,
+ 2.22,
+ );
+
let account = budget::parse_account("tests/test.toml")?;
let actually_is = budget::calculate(&account).unwrap();
diff --git a/budget/tests/test.toml b/budget/tests/test.toml
index a29467e..ca2c1e5 100644
--- a/budget/tests/test.toml
+++ b/budget/tests/test.toml
@@ -19,13 +19,14 @@ date = 2020-10-01
name = "Bacon"
price = 3.33
category = "products"
- shared = 2
+ shared = 3
[[days.expenses]]
name = "Yoghurt"
price = 1.24
category = "products"
qty = 2
+ shared = 2
[[days.expenses]]
name = "Onion"
diff --git a/src/main.rs b/src/main.rs
index 5c64959..cd401e2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -181,6 +181,20 @@ fn output(account: Account, maybe_calculated: Option<Calculated>) {
println!();
+ for (n, owed) in calculated.total_owed.iter() {
+ println!(
+ "{} person(s) owe you in shared expenses: {:.2}",
+ n - 1,
+ owed,
+ );
+
+ if *n > 2 {
+ println!("Each owes you: {}", *owed / (*n as f64 - 1.0));
+ }
+
+ println!();
+ }
+
println!("Days until balance runs out:");
let days_left_output = format!(
@@ -192,6 +206,8 @@ fn output(account: Account, maybe_calculated: Option<Calculated>) {
calculated.days_left_essential,
);
+ // TODO: also show much money would be left by the end of the period
+
let mut all_are_healthy = true;
let mut essential_are_healthy = true;