Skip to main content

automapper_validation/generated/fv2504/
aperak_conditions_fv2504.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2504/APERAK_AHB_2_4a_Fehlerkorrektur_20250331.xml
4// Generated: 2026-03-12T10:19:40Z
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 APERAK FV2504.
17pub struct AperakConditionEvaluatorFV2504 {
18    // External condition IDs that require runtime context.
19    external_conditions: std::collections::HashSet<u32>,
20}
21
22impl Default for AperakConditionEvaluatorFV2504 {
23    fn default() -> Self {
24        let mut external_conditions = std::collections::HashSet::new();
25        external_conditions.insert(3);
26        external_conditions.insert(6);
27        Self {
28            external_conditions,
29        }
30    }
31}
32
33impl ConditionEvaluator for AperakConditionEvaluatorFV2504 {
34    fn message_type(&self) -> &str {
35        "APERAK"
36    }
37
38    fn format_version(&self) -> &str {
39        "FV2504"
40    }
41
42    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
43        match condition {
44            1 => self.evaluate_1(ctx),
45            2 => self.evaluate_2(ctx),
46            3 => self.evaluate_3(ctx),
47            4 => self.evaluate_4(ctx),
48            5 => self.evaluate_5(ctx),
49            6 => self.evaluate_6(ctx),
50            7 => self.evaluate_7(ctx),
51            8 => self.evaluate_8(ctx),
52            9 => self.evaluate_9(ctx),
53            10 => self.evaluate_10(ctx),
54            11 => self.evaluate_11(ctx),
55            12 => self.evaluate_12(ctx),
56            13 => self.evaluate_13(ctx),
57            14 => self.evaluate_14(ctx),
58            15 => self.evaluate_15(ctx),
59            16 => self.evaluate_16(ctx),
60            494 => self.evaluate_494(ctx),
61            500 => self.evaluate_500(ctx),
62            501 => self.evaluate_501(ctx),
63            502 => self.evaluate_502(ctx),
64            931 => self.evaluate_931(ctx),
65            939 => self.evaluate_939(ctx),
66            940 => self.evaluate_940(ctx),
67            _ => ConditionResult::Unknown,
68        }
69    }
70
71    fn is_external(&self, condition: u32) -> bool {
72        self.external_conditions.contains(&condition)
73    }
74    fn is_known(&self, condition: u32) -> bool {
75        matches!(
76            condition,
77            1 | 2
78                | 3
79                | 4
80                | 5
81                | 6
82                | 7
83                | 8
84                | 9
85                | 10
86                | 11
87                | 12
88                | 13
89                | 14
90                | 15
91                | 16
92                | 494
93                | 500
94                | 501
95                | 502
96                | 931
97                | 939
98                | 940
99        )
100    }
101}
102
103impl AperakConditionEvaluatorFV2504 {
104    /// [3] Wenn für weitere Fehlerangabe benötigt.
105    /// EXTERNAL: Requires context from outside the message.
106    fn evaluate_3(&self, ctx: &EvaluationContext) -> ConditionResult {
107        ctx.external.evaluate("additional_error_detail_needed")
108    }
109
110    /// [6] Wenn Fehler innerhalb der Vorgangsebene von IFTSTA, INSRPT, UTILMD oder UTILTS vorhanden.
111    /// EXTERNAL: Requires context from outside the message.
112    fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
113        ctx.external
114            .evaluate("transaction_level_error_in_referenced_message")
115    }
116
117    /// [1] Wenn SG3 CTA+IC vorhanden.
118    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
119        ctx.has_qualifier("CTA", 0, "IC")
120    }
121
122    /// [2] Wenn fehlerhafter Inhalt vorhanden.
123    // REVIEW: In APERAK messages, the ERC (Error Reason Code) segment is present when erroneous content is being reported. Checking for ERC existence is the best proxy for 'fehlerhafter Inhalt vorhanden'. An APERAK with no ERC segments is a pure positive acknowledgment with no errors. (medium confidence)
124    fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
125        // Wenn fehlerhafter Inhalt vorhanden — ERC segment indicates presence of erroneous content
126        ConditionResult::from(ctx.has_segment("ERC"))
127    }
128
129    /// [4] Wenn in dieser SG4, RFF+TN nicht vorhanden.
130    // REVIEW: Checks whether RFF+TN is absent within the current SG4 group's child SG5 groups. Uses parent-child navigation: for each SG4 instance, inspects all SG5 children for RFF with qualifier TN. Falls back to message-wide lacks_qualifier when no navigator is available. Medium confidence because the SG4/SG5 nesting in APERAK may differ from other message types. (medium confidence)
131    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
132        let nav = match ctx.navigator() {
133            Some(n) => n,
134            None => return ctx.lacks_qualifier("RFF", 0, "TN"),
135        };
136        let sg4_count = nav.group_instance_count(&["SG4"]);
137        for i in 0..sg4_count {
138            let sg5_count = nav.child_group_instance_count(&["SG4"], i, "SG5");
139            let has_tn = (0..sg5_count).any(|j| {
140                nav.find_segments_in_child_group("RFF", &["SG4"], i, "SG5", j)
141                    .iter()
142                    .any(|s| {
143                        s.elements
144                            .first()
145                            .and_then(|e| e.first())
146                            .is_some_and(|v| v == "TN")
147                    })
148            });
149            if !has_tn {
150                return ConditionResult::True;
151            }
152        }
153        ConditionResult::False
154    }
155
156    /// [5] Wenn SG4 ERC+Z29 vorhanden.
157    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
158        ctx.has_qualifier("ERC", 0, "Z29")
159    }
160
161    /// [7] Wenn SG4 ERC+Z21 vorhanden.
162    fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
163        ctx.has_qualifier("ERC", 0, "Z21")
164    }
165
166    /// [8] Wenn SG4 ERC+Z16 vorhanden.
167    fn evaluate_8(&self, ctx: &EvaluationContext) -> ConditionResult {
168        ctx.has_qualifier("ERC", 0, "Z16")
169    }
170
171    /// [9] Wenn SG4 ERC+Z35 vorhanden.
172    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
173        ctx.has_qualifier("ERC", 0, "Z35")
174    }
175
176    /// [10] Wenn SG4 ERC+Z38 vorhanden.
177    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
178        ctx.has_qualifier("ERC", 0, "Z38")
179    }
180
181    /// [11] Wenn SG4 ERC+Z39 vorhanden.
182    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
183        ctx.has_qualifier("ERC", 0, "Z39")
184    }
185
186    /// [12] Wenn SG4 ERC+Z41 vorhanden.
187    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
188        ctx.has_qualifier("ERC", 0, "Z41")
189    }
190
191    /// [13] Wenn SG4 ERC+Z40 vorhanden.
192    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
193        ctx.has_qualifier("ERC", 0, "Z40")
194    }
195
196    /// [14] Wenn im DE3155 in demselben COM der Code EM vorhanden ist
197    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
198        let coms = ctx.find_segments("COM");
199        ConditionResult::from(coms.iter().any(|com| {
200            com.elements
201                .first()
202                .and_then(|e| e.get(1))
203                .is_some_and(|v| v == "EM")
204        }))
205    }
206
207    /// [15] Wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
208    fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
209        let coms = ctx.find_segments("COM");
210        ConditionResult::from(coms.iter().any(|com| {
211            com.elements
212                .first()
213                .and_then(|e| e.get(1))
214                .map(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
215                .unwrap_or(false)
216        }))
217    }
218
219    /// [16] Wenn der referenzierte Nachrichtentyp IFTSTA, INSRPT, UTILMD oder UTILTS ist.
220    // REVIEW: APERAK references another message type. BGM and RFF segments in APERAK carry the referenced message type identifier. Checking all elements of BGM and RFF for the four message type names (IFTSTA, INSRPT, UTILMD, UTILTS) covers the likely encodings. (medium confidence)
221    fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
222        let bgm_segs = ctx.find_segments("BGM");
223        let in_bgm = bgm_segs.iter().any(|s| {
224            s.elements
225                .iter()
226                .flatten()
227                .any(|v| matches!(v.as_str(), "IFTSTA" | "INSRPT" | "UTILMD" | "UTILTS"))
228        });
229        if in_bgm {
230            return ConditionResult::True;
231        }
232        let rff_segs = ctx.find_segments("RFF");
233        ConditionResult::from(rff_segs.iter().any(|s| {
234            s.elements
235                .iter()
236                .flatten()
237                .any(|v| matches!(v.as_str(), "IFTSTA" | "INSRPT" | "UTILMD" | "UTILTS"))
238        }))
239    }
240
241    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
242    // REVIEW: This condition is a declarative constraint: the date in this field must be the document creation time or earlier. It is not a conditional predicate that selects when a field is used, but rather a validation rule that always applies. Without knowing the specific DTM qualifier pair to compare (which field this annotates vs. DTM+137), a full comparison is not implementable. Returning True reflects that the constraint is always in force. (medium confidence)
243    fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
244        // Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde,
245        // oder ein Zeitpunkt, der davor liegt.
246        // This is a declarative validation constraint on the field value itself — it always
247        // applies when the field is present. The AHB uses this condition to annotate the
248        // allowed date range; the constraint is unconditionally in effect.
249        ConditionResult::True
250    }
251
252    /// [500] Hinweis: Für Folgeprozesse.
253    fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
254        // Hinweis: Für Folgeprozesse — informational note, always applies
255        ConditionResult::True
256    }
257
258    /// [501] Hinweis: Für Initialprozesse.
259    fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
260        // Hinweis: Für Initialprozesse — informational note, always applies
261        ConditionResult::True
262    }
263
264    /// [502] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
265    fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
266        // Hinweis: Es darf nur eine Information im DE3148 übermittelt werden — informational note, always applies
267        ConditionResult::True
268    }
269
270    /// [931] Format: ZZZ = +00
271    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
272        ctx.format_check("DTM", 0, 1, validate_timezone_utc)
273    }
274
275    /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
276    fn evaluate_939(&self, ctx: &EvaluationContext) -> ConditionResult {
277        ctx.format_check("COM", 0, 0, validate_email)
278    }
279
280    /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
281    fn evaluate_940(&self, ctx: &EvaluationContext) -> ConditionResult {
282        ctx.format_check("COM", 0, 0, validate_phone)
283    }
284}