aboutsummaryrefslogtreecommitdiff
path: root/budget/src
diff options
context:
space:
mode:
Diffstat (limited to 'budget/src')
-rw-r--r--budget/src/lib.rs81
1 files changed, 47 insertions, 34 deletions
diff --git a/budget/src/lib.rs b/budget/src/lib.rs
index 5013a9f..e848035 100644
--- a/budget/src/lib.rs
+++ b/budget/src/lib.rs
@@ -30,12 +30,14 @@ pub struct Day {
pub struct Expense {
pub name: String,
pub price: f64,
- #[serde(default = "shared_qty_default")]
- pub qty: u32, // unused for now, might use it the future or remove it
- #[serde(default = "shared_qty_default")]
- pub shared: u32,
- #[serde(default = "recurring_default")]
- pub recurring: bool,
+ #[serde(default)]
+ /// Whom this expense is shared with (if anybody).
+ pub shared: Vec<String>,
+ #[serde(default)]
+ /// Whether this was something we paid for somebody else, and thus is owed
+ /// to us. If true, then shared is the list of person(s) that owe us this
+ /// expense, and should therefore contain at least one name.
+ pub owed: bool,
#[serde(default)]
pub category: Option<String>,
}
@@ -49,7 +51,8 @@ pub struct Calculated {
pub categories_subtotal: HashMap<String, f64>,
pub total: f64,
pub balance: f64,
- pub total_owed: HashMap<u32, f64>,
+ pub owed: HashMap<String, f64>,
+ pub total_owed: f64,
pub days_left: f64,
pub days_left_essential: f64,
pub last_day: NaiveDate,
@@ -61,14 +64,6 @@ pub enum ParseError {
DeserializerError(DeserializerError),
}
-fn shared_qty_default() -> u32 {
- 1
-}
-
-fn recurring_default() -> bool {
- false
-}
-
// Parse the dates from toml's Datetime to Chrono's NaiveDate
fn deserialize_date<'de, D>(deserializer: D) -> Result<NaiveDate, D::Error>
where
@@ -97,7 +92,7 @@ pub fn parse_account(path: &str) -> Result<Account, ParseError> {
}
}
-pub fn calculate(account: &Account) -> Option<Calculated> {
+pub fn calculate(account: &Account, consider_owed: bool) -> Option<Calculated> {
if account.days.is_empty() {
return None;
}
@@ -110,7 +105,8 @@ 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(),
+ owed: HashMap::<String, f64>::new(),
+ total_owed: 0.0,
days_left: 0.0,
days_left_essential: 0.0,
last_day: account.days.last().unwrap().date,
@@ -122,34 +118,51 @@ pub fn calculate(account: &Account) -> Option<Calculated> {
}
for expense in day.expenses.iter() {
- calculated.total += expense.price;
+ let mut actual_expense: f64 = 0.0;
+
+ if expense.shared.len() > 0 {
+ let owed_share = if expense.owed {
+ expense.price / expense.shared.len() as f64
+ } else {
+ actual_expense =
+ expense.price / (expense.shared.len() as f64 + 1.0);
+ actual_expense
+ };
+
+ for person in expense.shared.iter() {
+ calculated.total_owed += owed_share;
+
+ if let Some(owed_by_person) =
+ calculated.owed.get_mut(person)
+ {
+ *owed_by_person += owed_share;
+ } else {
+ calculated.owed.insert(person.clone(), owed_share);
+ }
+ }
+ }
+
+ if expense.shared.len() == 0 || consider_owed {
+ actual_expense = expense.price;
+ } else if expense.owed {
+ continue;
+ }
+
+ calculated.total += actual_expense;
if let Some(category) = &expense.category {
if let Some(category_subtotal) =
calculated.categories_subtotal.get_mut(category)
{
- *category_subtotal += expense.price;
+ *category_subtotal += actual_expense;
} else {
calculated
.categories_subtotal
- .insert(category.to_string(), expense.price);
+ .insert(category.to_string(), actual_expense);
}
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);
- }
+ calculated.essential_subtotal += actual_expense;
}
}
}