use std::{
fmt::{self, Display},
ops::{Add, Div, Sub},
};
#[derive(Debug, PartialEq)]
pub struct Amount {
pub netto: Money,
pub bruto: Money,
pub tax: Money,
pub percentage: u8,
}
impl std::fmt::Display for Amount {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Netto: {}\nBruto: {}\nBtw bedrag: {}\nBtw percentage: {}",
self.netto, self.bruto, self.tax, self.percentage
)
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Money {
pub cents: f64,
}
impl Money {
pub fn new(cents: f64) -> Self {
Money {
cents: cents.round(),
}
}
}
impl From<f64> for Money {
fn from(fractional: f64) -> Self {
let cents = 100.0 * fractional;
Money {
cents: cents.round(),
}
}
}
#[allow(clippy::from_over_into)]
impl Into<f64> for Money {
fn into(self) -> f64 {
let cents = self.cents as f64;
cents / 100.0
}
}
impl Display for Money {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:.2}", (self.cents / 100.0))
}
}
impl Add for Money {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Money::new(self.cents + rhs.cents)
}
}
impl Sub for Money {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Money::new(self.cents - rhs.cents)
}
}
impl Div for Money {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Money::new((self.cents / rhs.cents).round())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn money_from_float() {
let float = 1.83;
let expected = Money { cents: 183.0 };
let actual = Money::from(float);
assert_eq!(expected, actual);
}
#[test]
fn money_to_float() {
let money = Money { cents: 183.0 };
let expected = 1.83;
let actual: f64 = money.into();
assert_eq!(expected, actual);
}
#[test]
fn money_float_trucated() {
let float = 13.3742;
let expected = Money { cents: 1337.0 };
let actual = Money::from(float);
assert_eq!(expected, actual);
}
#[test]
fn money_float_rounded() {
let float = 13.3750;
let expected = Money { cents: 1338.0 };
let actual = Money::from(float);
assert_eq!(expected, actual);
}
}