Skip to main content

automapper_validation/generated/fv2504/
ordchg_conditions_fv2504.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2504/ORDCHG_AHB_1_0a_20241001.xml
4// Generated: 2026-03-12T10:14:16Z
5// </auto-generated>
6
7// LLM-produced bodies aren't idiomatic Rust — silence stylistic lints at
8// file scope so `cargo clippy -D warnings` stays green. Correctness,
9// suspicious, and perf categories stay on so real bugs still surface.
10#![allow(clippy::style, clippy::complexity)]
11
12#[allow(unused_imports)]
13use crate::eval::format_validators::*;
14use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
15
16/// Generated condition evaluator for ORDCHG FV2504.
17pub struct OrdchgConditionEvaluatorFV2504 {
18    // External condition IDs that require runtime context.
19    external_conditions: std::collections::HashSet<u32>,
20}
21
22impl Default for OrdchgConditionEvaluatorFV2504 {
23    fn default() -> Self {
24        let mut external_conditions = std::collections::HashSet::new();
25        external_conditions.insert(1);
26        Self {
27            external_conditions,
28        }
29    }
30}
31
32impl ConditionEvaluator for OrdchgConditionEvaluatorFV2504 {
33    fn message_type(&self) -> &str {
34        "ORDCHG"
35    }
36
37    fn format_version(&self) -> &str {
38        "FV2504"
39    }
40
41    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
42        match condition {
43            1 => self.evaluate_1(ctx),
44            2 => self.evaluate_2(ctx),
45            3 => self.evaluate_3(ctx),
46            4 => self.evaluate_4(ctx),
47            5 => self.evaluate_5(ctx),
48            494 => self.evaluate_494(ctx),
49            500 => self.evaluate_500(ctx),
50            501 => self.evaluate_501(ctx),
51            502 => self.evaluate_502(ctx),
52            503 => self.evaluate_503(ctx),
53            931 => self.evaluate_931(ctx),
54            939 => self.evaluate_939(ctx),
55            940 => self.evaluate_940(ctx),
56            _ => ConditionResult::Unknown,
57        }
58    }
59
60    fn is_external(&self, condition: u32) -> bool {
61        self.external_conditions.contains(&condition)
62    }
63    fn is_known(&self, condition: u32) -> bool {
64        matches!(
65            condition,
66            1 | 2 | 3 | 4 | 5 | 494 | 500 | 501 | 502 | 503 | 931 | 939 | 940
67        )
68    }
69}
70
71impl OrdchgConditionEvaluatorFV2504 {
72    /// [1] MP-ID nur aus Sparte Strom
73    /// EXTERNAL: Requires context from outside the message.
74    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
75        ctx.external.evaluate("mp_id_only_strom")
76    }
77
78    /// [2] Wenn BGM+Z51 (Sperrung) vorhanden
79    fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
80        ctx.has_qualifier("BGM", 0, "Z51")
81    }
82
83    /// [3] Wenn BGM+Z52 (Entsperrung) vorhanden
84    fn evaluate_3(&self, ctx: &EvaluationContext) -> ConditionResult {
85        ctx.has_qualifier("BGM", 0, "Z52")
86    }
87
88    /// [4] wenn im DE3155 in demselben COM der Code EM vorhanden ist
89    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
90        let coms = ctx.find_segments("COM");
91        ConditionResult::from(coms.iter().any(|com| {
92            com.elements
93                .first()
94                .and_then(|e| e.get(1))
95                .is_some_and(|v| v == "EM")
96        }))
97    }
98
99    /// [5] wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
100    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
101        let coms = ctx.find_segments("COM");
102        ConditionResult::from(coms.iter().any(|com| {
103            com.elements
104                .first()
105                .and_then(|e| e.get(1))
106                .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
107        }))
108    }
109
110    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.
111    fn evaluate_494(&self, ctx: &EvaluationContext) -> ConditionResult {
112        // HAND-EDITED: subject is the current DTM's DE2380 (via ctx.resolved_value),
113        // compared with the message date (DTM+137). Lexicographic compare is valid
114        // for fixed-width CCYYMMDDHHMM+ZZ (format 303).
115        let current = match ctx.resolved_value {
116            Some(v) if !v.is_empty() => v,
117            _ => return ConditionResult::Unknown,
118        };
119        let threshold = match ctx
120            .find_segments_with_qualifier("DTM", 0, "137")
121            .first()
122            .and_then(|s| s.elements.first())
123            .and_then(|e| e.get(1))
124        {
125            Some(v) if !v.is_empty() => v.clone(),
126            _ => return ConditionResult::Unknown,
127        };
128        ConditionResult::from(current <= threshold.as_str())
129    }
130
131    /// [500] Hinweis: Dokumentennummer aus BGM DE1004 der ORDERS
132    fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
133        // Hinweis: Dokumentennummer aus BGM DE1004 der ORDERS — informational note, always applies
134        ConditionResult::True
135    }
136
137    /// [501] Hinweis: Wert aus BGM+Z33 DE1004 der IFTSTA mit der die Information über den Entsperrauftrag übermittelt wurde
138    fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
139        // Hinweis: Wert aus BGM+Z33 DE1004 der IFTSTA mit der die Information über den Entsperrauftrag übermittelt wurde — informational note, always applies
140        ConditionResult::True
141    }
142
143    /// [502] Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z33 mit der die Information über den Entsperrauftrag übermittelt wurde
144    fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
145        // Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z33 mit der die Information über den Entsperrauftrag übermittelt wurde — informational note, always applies
146        ConditionResult::True
147    }
148
149    /// [503] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
150    fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
151        // Hinweis: Es darf nur eine Information im DE3148 übermittelt werden — informational note, always applies
152        ConditionResult::True
153    }
154
155    /// [931] Format: ZZZ = +00
156    // REVIEW: Format constraint: ZZZ (timezone) must be '+00' (UTC). DTM elements[0][1] contains the datetime value including timezone suffix. Checks all DTM segments to ensure their datetime values end with '+00'. Returns Unknown when no DTM segments present, False if any DTM violates the constraint. (medium confidence)
157    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
158        let dtms = ctx.find_segments("DTM");
159        if dtms.is_empty() {
160            return ConditionResult::Unknown;
161        }
162        for dtm in &dtms {
163            if let Some(value) = dtm.elements.first().and_then(|e| e.get(1)) {
164                if !value.is_empty() && !value.ends_with("+00") {
165                    return ConditionResult::False;
166                }
167            }
168        }
169        ConditionResult::True
170    }
171
172    /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
173    // REVIEW: Format check: the email address string in COM DE3148 (elements[0][0]) when DE3155 (elements[0][1]) is 'EM' must contain both '@' and '.'. Returns Unknown if no EM-typed COM segment is found. (medium confidence)
174    fn evaluate_939(&self, ctx: &EvaluationContext) -> ConditionResult {
175        let coms = ctx.find_segments("COM");
176        for com in &coms {
177            let is_email = com
178                .elements
179                .first()
180                .and_then(|e| e.get(1))
181                .is_some_and(|v| v == "EM");
182            if is_email {
183                let value = com
184                    .elements
185                    .first()
186                    .and_then(|e| e.first())
187                    .cloned()
188                    .unwrap_or_default();
189                return ConditionResult::from(value.contains('@') && value.contains('.'));
190            }
191        }
192        ConditionResult::Unknown
193    }
194
195    /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
196    // REVIEW: Format check: the phone/fax number string in COM DE3148 (elements[0][0]) when DE3155 (elements[0][1]) is TE/FX/AJ/AL must start with '+' followed by digits only. Returns Unknown if no phone-typed COM segment is found. (medium confidence)
197    fn evaluate_940(&self, ctx: &EvaluationContext) -> ConditionResult {
198        let coms = ctx.find_segments("COM");
199        for com in &coms {
200            let is_phone = com
201                .elements
202                .first()
203                .and_then(|e| e.get(1))
204                .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"));
205            if is_phone {
206                let value = com
207                    .elements
208                    .first()
209                    .and_then(|e| e.first())
210                    .cloned()
211                    .unwrap_or_default();
212                let mut chars = value.chars();
213                let starts_with_plus = chars.next() == Some('+');
214                let rest_all_digits = chars.all(|c| c.is_ascii_digit());
215                return ConditionResult::from(starts_with_plus && rest_all_digits);
216            }
217        }
218        ConditionResult::Unknown
219    }
220}