1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#![allow(dead_code)]
use std::fmt::Display;
use std::str::FromStr;

#[derive(Clone, PartialEq)]
pub struct Iban {
    pub iban: String,
}

impl FromStr for Iban {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self { iban: s.to_owned() })
    }
}

impl Display for Iban {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.iban)
    }
}

#[derive(Debug)]

pub enum IbanError {
    FalutyPrefix,
    FaultyAccount,
    FaultyBank,
    InvalidCheckSum,
    InvalidFormat,
}

impl Iban {
    pub fn new_cz(prefix: Option<&str>, account: &str, bank: &str) -> Result<Self, IbanError> {
        let country_code = "CZ"; //2 spaces
        let country_code_num = "1235"; // a->10, c->12, z->35
        let prefix = prefix.unwrap_or("000000");
        let full_account = format!("{prefix}{account}"); //16 spaces = 6 prefix + 10 account

        let checksum_prep =
            match format!("{}{}{}00", bank, full_account, country_code_num).parse::<u128>() {
                Ok(x) => x,
                _ => return Err(IbanError::InvalidFormat),
            };

        let modulo = checksum_prep % 97;
        let checksum = 98 - modulo;

        let iban = format!("{}{}{}{}", country_code, checksum, bank, full_account);

        Ok(Self { iban })
    }
}

#[test]
fn filips_account_is_calculated_correctly() {
    let iban = Iban::new_cz(Some("000019"), "0000123457", "0710").unwrap();

    assert_eq!(iban.to_string(), "CZ3507100000190000123457".to_owned())
}