use super::super::{sanitize, Verdict};
use anyhow::{anyhow, Result};
const WEIGHTS: [u32; 7] = [8, 7, 6, 5, 4, 3, 2];
fn compute_check(body: &str) -> u32 {
let total: u32 = body
.chars()
.zip(WEIGHTS.iter())
.map(|(c, &w)| c.to_digit(10).unwrap() * w)
.sum();
((11 - total % 11) % 11) % 10
}
pub fn verify_me_vat(input: &str) -> Verdict {
let clean = match super::strip_vat_prefix(input, "ME") {
Ok(body) => body,
Err(v) => return v,
};
if clean.len() != 8 {
return Verdict::Invalid {
reason: format!("ME PIB: expected 8 digits, got {}", clean.len()),
};
}
if !clean.chars().all(|c| c.is_ascii_digit()) {
return Verdict::Invalid { reason: "non-digit input".into() };
}
let body = &clean[..7];
let check: u32 = clean.chars().nth(7).unwrap().to_digit(10).unwrap();
let expected = compute_check(body);
if expected == check {
Verdict::Valid {
formatted: format!("ME{}", clean),
detected: "Montenegrin PIB".into(),
comment: String::new(),
}
} else {
Verdict::Invalid {
reason: format!("ME PIB check mismatch: expected {}, got {}", expected, check),
}
}
}
pub fn create_me_vat(input: &str, _raw: bool) -> Result<String> {
let clean = sanitize(input, false);
if clean.len() != 7 {
return Err(anyhow!(
"ME PIB: expected 7 digits (body without check digit), got {}",
clean.len()
));
}
if !clean.chars().all(|c| c.is_ascii_digit()) {
return Err(anyhow!("non-digit input"));
}
let check = compute_check(&clean);
Ok(format!("ME{}{}", clean, check))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn me_vat_valid_02000989() {
match verify_me_vat("02000989") {
Verdict::Valid { formatted, detected, .. } => {
assert_eq!(formatted, "ME02000989");
assert_eq!(detected, "Montenegrin PIB");
}
v => panic!("{:?}", v),
}
}
#[test]
fn me_vat_valid_02005115() {
match verify_me_vat("02005115") {
Verdict::Valid { formatted, detected, .. } => {
assert_eq!(formatted, "ME02005115");
assert_eq!(detected, "Montenegrin PIB");
}
v => panic!("{:?}", v),
}
}
#[test]
fn me_vat_valid_02005328() {
match verify_me_vat("02005328") {
Verdict::Valid { formatted, detected, .. } => {
assert_eq!(formatted, "ME02005328");
assert_eq!(detected, "Montenegrin PIB");
}
v => panic!("{:?}", v),
}
}
#[test]
fn me_vat_rejects_wrong_length() {
match verify_me_vat("0335348") {
Verdict::Invalid { reason } => assert!(reason.contains("expected 8 digits")),
v => panic!("{:?}", v),
}
}
#[test]
fn me_vat_rejects_bad_check() {
match verify_me_vat("03353487") {
Verdict::Invalid { .. } => {}
v => panic!("{:?}", v),
}
}
#[test]
fn me_vat_round_trip() {
let body = "0200098";
let full = create_me_vat(body, false).unwrap();
assert_eq!(full, "ME02000989");
match verify_me_vat(&full) {
Verdict::Valid { .. } => {}
v => panic!("{:?}", v),
}
}
#[test]
fn me_vat_accepts_me_prefix() {
match verify_me_vat("ME02000989") {
Verdict::Valid { formatted, .. } => assert_eq!(formatted, "ME02000989"),
v => panic!("{:?}", v),
}
}
}