use std::{
fs::read_to_string,
path::PathBuf,
time::{Duration, SystemTime},
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::{bank::Bank, envelopes_folder, euro::Euros, target::SavingGoal, EnvelopeId};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Transaction {
pub time: Duration,
pub amount: Euros,
pub envelope: EnvelopeId,
}
impl Transaction {
pub fn new(amount: impl Into<Euros>, id: EnvelopeId) -> Self {
let amount = amount.into();
let time = current_time();
Self {
amount,
time,
envelope: id,
}
}
}
pub fn current_time() -> Duration {
system_time_as_unix_time(SystemTime::now())
}
pub fn system_time_as_unix_time(time: SystemTime) -> Duration {
time.duration_since(SystemTime::UNIX_EPOCH)
.expect("Time went backwards")
}
pub fn euros_on_track(now: Duration, start: Duration, end: Duration, end_euros: Euros) -> Euros {
let percentage = percentage_between(now, start, end);
let current_track: Euros = ((f32::from(end_euros)) * percentage).into();
current_track
}
pub fn percentage_between(now: Duration, start: Duration, end: Duration) -> f32 {
let interval = end - start;
let time_passed = now - start;
time_passed.as_secs_f32() / interval.as_secs_f32()
}
#[derive(Clone, Serialize, Deserialize, Default, Debug)]
pub struct Envelope {
pub name: String,
#[serde(default)]
pub goal: SavingGoal,
id: EnvelopeId,
}
impl Envelope {
pub fn id(&self) -> EnvelopeId {
self.id
}
pub fn assigned(&self, bank: &Bank) -> Euros {
bank.assigned(self.id())
}
pub fn fetch_all() -> Vec<Self> {
let mut envelopes = vec![];
let envelope_folder = envelopes_folder();
for entry in std::fs::read_dir(envelope_folder.as_path()).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("toml") {
let content = read_to_string(path).expect("Could not read the TOML file");
let envelope: Envelope = serde_json::from_str(&content).unwrap();
envelopes.push(envelope);
}
}
envelopes
}
pub fn as_path(&self) -> PathBuf {
let mut file_path = envelopes_folder().join(self.id.to_string());
file_path.set_extension("toml");
file_path
}
pub fn delete(self) {
let path = self.as_path();
std::fs::remove_file(path).unwrap();
}
pub fn persist(&self) {
let mut file_path = envelopes_folder().join(self.id.to_string());
file_path.set_extension("toml");
let s = serde_json::to_string_pretty(self).unwrap();
std::fs::write(file_path, s).unwrap();
}
pub fn new_empty(name: &str) -> Self {
let name = name.to_owned();
let id = Uuid::new_v4();
Self {
name,
id,
goal: SavingGoal::None,
}
}
}
#[cfg(test)]
mod tests {
use crate::cycle::{beginning_of_month, beginning_of_week, end_of_month};
use super::*;
#[test]
fn testing() {
let now = current_time();
dbg!(beginning_of_month(now));
dbg!(end_of_month(now));
dbg!(beginning_of_week(now));
}
}