use crate::entities::{Bill, DateTime, Duration, Money, Result};
use derive_more::{Deref, DerefMut};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deref, DerefMut, Clone, Serialize, Deserialize)]
pub(crate) struct Invoice {
pub(crate) client: String,
pub(crate) subject: Option<String>,
#[deref]
#[deref_mut]
pub(crate) bills: Vec<Bill>,
pub(crate) date: DateTime,
pub(crate) deleted: bool,
}
impl Invoice {
pub(crate) fn hours(&self) -> f64 {
self.bills
.iter()
.map(|b| b.worked())
.sum::<Duration>()
.num_minutes() as f64
/ 60.0
}
pub(crate) fn worked(&self) -> Duration {
self.bills.iter().map(|b| b.worked()).sum()
}
pub(crate) fn revenue(&self) -> Result<Money> {
let revenues = self.revenues()?;
if let Some(first) = &revenues.first() {
let init = Money::zero(first.currency());
Ok(revenues.into_iter().try_fold(init, |acc, x| acc.add(x))?)
} else {
todo!("error: no revenues")
}
}
pub(crate) fn revenues(&self) -> Result<Vec<Money>> {
self.bills
.iter()
.map(|b| {
if b.scheme.rate.is_none() {
todo!("error: no payment rate in invoice")
}
b.revenue()
})
.collect::<Result<_>>()
}
pub(crate) fn tax(&self) -> Result<Money> {
let tax = Decimal::from_f64_retain(0.19).unwrap();
self.revenue()?.mul(tax)
}
pub(crate) fn revenue_taxed(&self) -> Result<Money> {
let taxed = Decimal::from_f64_retain(1.19).unwrap();
self.revenue()?.mul(taxed)
}
}