1use crate::invoice::Invoice;
4use crate::report::Report;
5use crate::rules;
6
7pub fn validate(invoice: &Invoice) -> Report {
9 let core = rules::core_rules();
10 let extra = invoice.profile.extra_rules();
11 let mut report = Report {
12 profile_slug: invoice.profile.slug(),
13 rules_checked: core.len() + extra.len(),
14 ..Report::default()
15 };
16 for rule in core.iter().chain(extra) {
17 (rule.eval)(invoice, &mut report);
18 }
19 #[cfg(feature = "xrechnung")]
20 if crate::xrechnung::claimed(invoice) {
21 for rule in crate::xrechnung::RULES {
22 (rule.eval)(invoice, &mut report);
23 }
24 report.rules_checked += crate::xrechnung::RULES.len();
25 }
26 report.sort_stable();
27 report
28}
29
30#[cfg(all(test, not(feature = "xrechnung")))]
31mod tests {
32 use super::*;
33 use crate::invoice::{Invoice, Party};
34 use crate::profile::Profile;
35
36 #[test]
37 fn xrechnung_claim_without_feature_does_not_emit_br_de() {
38 let mut inv = Invoice::blank(
39 Profile::En16931,
40 "1",
41 "EUR",
42 Party::new("S", "DE"),
43 Party::new("B", "DE"),
44 );
45 inv.specification_id =
46 Some("urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0".into());
47 let report = validate(&inv);
48 assert!(
49 report
50 .findings
51 .iter()
52 .all(|f| !f.id.starts_with("BR-DE-") && f.id != "BR-TMP-2"),
53 "{report}"
54 );
55 }
56}