billecta 1.14.0

Generated Billecta API
Documentation
use super::CurrencyCode;
use std::{cmp, fmt, ops};

#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, Default, PartialEq, Eq)]
pub struct Amount {
    #[serde(rename = "Value", default)]
    pub value: i64,

    #[serde(rename = "CurrencyCode")]
    #[serde(default)]
    pub currency_code: CurrencyCode,
}

impl Amount {
    pub fn fractions(n: i64) -> Self {
        Self {
            value: n,
            currency_code: CurrencyCode::Sek,
        }
    }

    pub fn with_currency(&self, cc: CurrencyCode) -> Self {
        Self {
            value: self.value,
            currency_code: cc,
        }
    }

    pub fn short(&self) -> ShortAmount<'_> {
        ShortAmount(self)
    }

    fn fmt_without_currency(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.value < 0 {
            f.write_str("-")?;
        }

        match (self.value / 100).abs() {
            n if n > 999_999_999_999_999_999 => write!(
                f,
                "{} {:03} {:03} {:03} {:03} {:03} {:03}",
                n / 1_000_000_000_000_000_000,
                (n / 1_000_000_000_000_000) % 1_000,
                (n / 1_000_000_000_000) % 1_000,
                (n / 1_000_000_000) % 1_000,
                (n / 1_000_000) % 1_000,
                (n / 1_000) % 1_000,
                n % 1_000
            ),

            n if n > 999_999_999_999_999 => write!(
                f,
                "{} {:03} {:03} {:03} {:03} {:03}",
                n / 1_000_000_000_000_000,
                (n / 1_000_000_000_000) % 1_000,
                (n / 1_000_000_000) % 1_000,
                (n / 1_000_000) % 1_000,
                (n / 1_000) % 1_000,
                n % 1_000
            ),

            n if n > 999_999_999_999 => write!(
                f,
                "{} {:03} {:03} {:03} {:03}",
                n / 1_000_000_000_000,
                (n / 1_000_000_000) % 1_000,
                (n / 1_000_000) % 1_000,
                (n / 1_000) % 1_000,
                n % 1_000
            ),

            n if n > 999_999_999 => write!(
                f,
                "{} {:03} {:03} {:03}",
                n / 1_000_000_000,
                (n / 1_000_000) % 1_000,
                (n / 1_000) % 1_000,
                n % 1_000
            ),

            n if n > 999_999 => write!(
                f,
                "{} {:03} {:03}",
                n / 1_000_000,
                (n / 1_000) % 1_000,
                n % 1_000
            ),

            n if n > 999 => write!(f, "{} {:03}", n / 1_000, n % 1_000,),

            n => write!(f, "{n}"),
        }?;

        write!(f, ",{:02}", (self.value % 100).abs())
    }
}

pub struct ShortAmount<'a>(&'a Amount);

impl fmt::Display for ShortAmount<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_without_currency(f)
    }
}

impl fmt::Debug for ShortAmount<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt_without_currency(f)
    }
}

impl fmt::Display for Amount {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.currency_code.as_str())?;
        f.write_str(" ")?;
        self.fmt_without_currency(f)
    }
}

impl<T> ops::Add<T> for Amount
where
    T: std::borrow::Borrow<Self>,
{
    type Output = Self;

    fn add(self, other: T) -> Self {
        let other = other.borrow();
        Self {
            value: self.value + other.value,
            currency_code: self.currency_code,
        }
    }
}

impl<T> ops::AddAssign<T> for Amount
where
    T: std::borrow::Borrow<Self>,
{
    fn add_assign(&mut self, other: T) {
        self.value += other.borrow().value;
    }
}

impl<T> ops::Sub<T> for Amount
where
    T: std::borrow::Borrow<Self>,
{
    type Output = Self;

    fn sub(self, other: T) -> Self {
        let other = other.borrow();
        Self {
            value: self.value - other.value,
            currency_code: self.currency_code,
        }
    }
}

// Multiplication
impl ops::Mul<i64> for Amount {
    type Output = Self;

    fn mul(self, other: i64) -> Self::Output {
        Amount::fractions(self.value * other)
    }
}

impl ops::Mul<i64> for &Amount {
    type Output = Amount;

    fn mul(self, other: i64) -> Self::Output {
        Amount::fractions(self.value * other)
    }
}

impl ops::Mul<i32> for Amount {
    type Output = Self;

    fn mul(self, other: i32) -> Self::Output {
        Amount::fractions(self.value * other as i64)
    }
}

impl ops::Mul<i32> for &Amount {
    type Output = Amount;

    fn mul(self, other: i32) -> Self::Output {
        Amount::fractions(self.value * other as i64)
    }
}

impl ops::Mul<u8> for Amount {
    type Output = Self;

    fn mul(self, other: u8) -> Self::Output {
        Amount::fractions(self.value * other as i64)
    }
}

impl ops::Mul<u8> for &Amount {
    type Output = Amount;

    fn mul(self, other: u8) -> Self::Output {
        Amount::fractions(self.value * other as i64)
    }
}

impl ops::Mul<f32> for Amount {
    type Output = Self;

    fn mul(self, other: f32) -> Self::Output {
        let fac = (other * 100.).round() as i64;
        Amount::fractions(self.value * fac / 100)
    }
}

impl ops::Mul<f32> for &Amount {
    type Output = Amount;

    fn mul(self, other: f32) -> Self::Output {
        let fac = (other * 100.).round() as i64;
        Amount::fractions(self.value * fac / 100)
    }
}

impl ops::Mul<f64> for Amount {
    type Output = Self;

    fn mul(self, other: f64) -> Self::Output {
        let fac = (other * 100.).round() as i64;
        Amount::fractions(self.value * fac / 100)
    }
}

impl ops::Mul<f64> for &Amount {
    type Output = Amount;

    fn mul(self, other: f64) -> Self::Output {
        let fac = (other * 100.).round() as i64;
        Amount::fractions(self.value * fac / 100)
    }
}

// Division

impl ops::Div<i64> for Amount {
    type Output = Amount;

    fn div(self, other: i64) -> Self::Output {
        Amount::fractions(self.value / other)
    }
}

impl ops::Div<i32> for Amount {
    type Output = Amount;

    fn div(self, other: i32) -> Self::Output {
        Amount::fractions(self.value / i64::from(other))
    }
}

impl ops::Div<u32> for &Amount {
    type Output = Amount;

    fn div(self, other: u32) -> Self::Output {
        Amount::fractions(self.value / other as i64)
    }
}

impl ops::Div<u8> for Amount {
    type Output = Amount;

    fn div(self, other: u8) -> Self::Output {
        Amount::fractions(self.value / other as i64)
    }
}

impl ops::Div<u8> for &Amount {
    type Output = Amount;

    fn div(self, other: u8) -> Self::Output {
        Amount::fractions(self.value / other as i64)
    }
}
impl<A> std::iter::Sum<A> for Amount
where
    A: std::borrow::Borrow<Self>,
{
    fn sum<I>(mut iter: I) -> Self
    where
        I: Iterator<Item = A>,
    {
        let first = if let Some(first) = iter.next() {
            first
        } else {
            return Amount::fractions(0);
        };

        let init = *first.borrow();

        iter.fold(init, |acc, e| acc + e.borrow())
    }
}

impl cmp::Ord for Amount {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.value.cmp(&other.value)
    }
}

impl cmp::PartialOrd for Amount {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

#[cfg(test)]
mod tests {

    #![allow(clippy::inconsistent_digit_grouping)]

    use super::*;

    #[test]
    fn test_float_mul() {
        assert_eq!(Amount::fractions(4000_00) * 0.9, Amount::fractions(3600_00));
    }

    #[test]
    fn test_formatting() {
        assert_eq!(Amount::fractions(123_456_00).to_string(), "SEK 123 456,00");
        assert_eq!(Amount::fractions(1_234_56).to_string(), "SEK 1 234,56");
        assert_eq!(Amount::fractions(1_456_00).to_string(), "SEK 1 456,00");
        assert_eq!(Amount::fractions(14_56).to_string(), "SEK 14,56");
        assert_eq!(Amount::fractions(156_00).to_string(), "SEK 156,00");
        assert_eq!(Amount::fractions(156).to_string(), "SEK 1,56");
        assert_eq!(Amount::fractions(999).to_string(), "SEK 9,99");
        assert_eq!(Amount::fractions(999_00).to_string(), "SEK 999,00");
        assert_eq!(Amount::fractions(10_01).to_string(), "SEK 10,01");
        assert_eq!(Amount::fractions(1_001_00).to_string(), "SEK 1 001,00");
        assert_eq!(Amount::fractions(-1_001_00).to_string(), "SEK -1 001,00");
        assert_eq!(Amount::fractions(-10_01).to_string(), "SEK -10,01");
        assert_eq!(Amount::fractions(9_123_00).to_string(), "SEK 9 123,00");
        assert_eq!(Amount::fractions(91_23).to_string(), "SEK 91,23");
        assert_eq!(Amount::fractions(92_568_07).to_string(), "SEK 92 568,07");
        assert_eq!(
            Amount::fractions(92_568_07_00).to_string(),
            "SEK 9 256 807,00"
        );
        assert_eq!(
            Amount::fractions(9_256_807_123_00).to_string(),
            "SEK 9 256 807 123,00"
        );
        assert_eq!(
            Amount::fractions(92_568_071_234_56).to_string(),
            "SEK 92 568 071 234,56"
        );
        assert_eq!(
            Amount::fractions(92_568_071_234_563_62).to_string(),
            "SEK 92 568 071 234 563,62"
        );
        assert_eq!(
            Amount::fractions(92_233_720_368_547_758_07).to_string(),
            "SEK 92 233 720 368 547 758,07"
        );
    }
}