Skip to main content

automapper_validation/generated/fv2510/
insrpt_conditions_fv2510.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2510/INSRPT_AHB_1_1g_außerordentliche_20251211.xml
4// Generated: 2026-03-12T11:19:04Z
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 INSRPT FV2510.
17pub struct InsrptConditionEvaluatorFV2510 {
18    // External condition IDs that require runtime context.
19    external_conditions: std::collections::HashSet<u32>,
20}
21
22impl Default for InsrptConditionEvaluatorFV2510 {
23    fn default() -> Self {
24        let mut external_conditions = std::collections::HashSet::new();
25        external_conditions.insert(1);
26        external_conditions.insert(3);
27        external_conditions.insert(4);
28        external_conditions.insert(5);
29        external_conditions.insert(7);
30        external_conditions.insert(9);
31        external_conditions.insert(12);
32        external_conditions.insert(14);
33        Self {
34            external_conditions,
35        }
36    }
37}
38
39impl ConditionEvaluator for InsrptConditionEvaluatorFV2510 {
40    fn message_type(&self) -> &str {
41        "INSRPT"
42    }
43
44    fn format_version(&self) -> &str {
45        "FV2510"
46    }
47
48    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
49        match condition {
50            1 => self.evaluate_1(ctx),
51            2 => self.evaluate_2(ctx),
52            3 => self.evaluate_3(ctx),
53            4 => self.evaluate_4(ctx),
54            5 => self.evaluate_5(ctx),
55            6 => self.evaluate_6(ctx),
56            7 => self.evaluate_7(ctx),
57            8 => self.evaluate_8(ctx),
58            9 => self.evaluate_9(ctx),
59            10 => self.evaluate_10(ctx),
60            11 => self.evaluate_11(ctx),
61            12 => self.evaluate_12(ctx),
62            13 => self.evaluate_13(ctx),
63            14 => self.evaluate_14(ctx),
64            494 => self.evaluate_494(ctx),
65            495 => self.evaluate_495(ctx),
66            506 => self.evaluate_506(ctx),
67            507 => self.evaluate_507(ctx),
68            508 => self.evaluate_508(ctx),
69            509 => self.evaluate_509(ctx),
70            510 => self.evaluate_510(ctx),
71            511 => self.evaluate_511(ctx),
72            512 => self.evaluate_512(ctx),
73            513 => self.evaluate_513(ctx),
74            514 => self.evaluate_514(ctx),
75            515 => self.evaluate_515(ctx),
76            908 => self.evaluate_908(ctx),
77            931 => self.evaluate_931(ctx),
78            950 => self.evaluate_950(ctx),
79            951 => self.evaluate_951(ctx),
80            _ => ConditionResult::Unknown,
81        }
82    }
83
84    fn is_external(&self, condition: u32) -> bool {
85        self.external_conditions.contains(&condition)
86    }
87    fn is_known(&self, condition: u32) -> bool {
88        matches!(
89            condition,
90            1 | 2
91                | 3
92                | 4
93                | 5
94                | 6
95                | 7
96                | 8
97                | 9
98                | 10
99                | 11
100                | 12
101                | 13
102                | 14
103                | 494
104                | 495
105                | 506
106                | 507
107                | 508
108                | 509
109                | 510
110                | 511
111                | 512
112                | 513
113                | 514
114                | 515
115                | 908
116                | 931
117                | 950
118                | 951
119        )
120    }
121}
122
123impl InsrptConditionEvaluatorFV2510 {
124    /// [1] Wenn Nachrichtenabsender vom Kunden informiert wurde.
125    /// EXTERNAL: Requires context from outside the message.
126    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
127        ctx.external
128            .evaluate("nachrichtenabsender_vom_kunden_informiert")
129    }
130
131    /// [2] Wenn SG7 STS+Z06+Z10+ZC1 vorhanden.
132    fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
133        ctx.has_segment_matching("STS", &[(0, 0, "Z06"), (1, 0, "Z10"), (2, 0, "ZC1")])
134    }
135
136    /// [3] Wenn vorhanden.
137    /// EXTERNAL: The AHB text ("Wenn vorhanden.") is underspecified — no subject, no segment reference. Attached to DTM+9 (Bearbeitungs-/Verarbeitungsdatum) at `AHB_Status="Soll [3]"`, so the natural reading is "when a processing timestamp is available to include", which is a sender-side decision, not something the validator can derive from the message.
138    fn evaluate_3(&self, ctx: &EvaluationContext) -> ConditionResult {
139        ctx.external
140            .evaluate("insrpt_bearbeitungsdatum_available")
141    }
142
143    /// [4] Wenn MP-ID in SG2 NAD+MR in der Rolle NB
144    /// EXTERNAL: Requires context from outside the message.
145    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
146        ctx.external.evaluate("recipient_is_nb")
147    }
148
149    /// [5] Wenn MP-ID in SG2 NAD+MR in der Rolle LF
150    /// EXTERNAL: Requires context from outside the message.
151    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
152        ctx.external.evaluate("recipient_is_lf")
153    }
154
155    /// [6] Wenn keine Störung festgestellt werden konnte.
156    // REVIEW: "Keine Störung festgestellt" maps to STS Gerätestatus category Z06 with status Z09. Z09 appears in the STS schema as one of the valid DE4405 status codes, and condition [10] explicitly checks 'DE4405 = Z09', strongly suggesting Z09 encodes the no-fault result. Medium confidence because the semantic mapping of Z09 to 'no fault' is inferred from context rather than explicitly stated in the schema. (medium confidence)
157    fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
158        // "Keine Störung festgestellt" — STS+Z06 (Gerätestatus) with status code Z09 (no fault)
159        ctx.has_segment_matching_in_group("STS", &[(0, 0, "Z06"), (1, 0, "Z09")], &["SG3", "SG7"])
160    }
161
162    /// [7] Wenn keine weitere SG7 mit demselben Meldepunkt und DTM+9 vorhanden
163    /// EXTERNAL: The Meldepunkt identifier (LOC+172 DE3225) sits on the enclosing SG3, not on SG7 itself, so the check is a cross-SG3 correlation: "does any other SG3's SG7 carry the same LOC+172 AND the same DTM+9?". Per-field evaluation does not have the parent-SG3 anchor, and introducing `current_group_stack` was deferred (see cluster H notes). Delegated to the operator.
164    fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
165        ctx.external
166            .evaluate("insrpt_no_duplicate_sg7_same_meldepunkt_and_dtm9")
167    }
168
169    /// [8] Wenn in dieser SG7 STS+Z06+Z10 vorhanden
170    fn evaluate_8(&self, ctx: &EvaluationContext) -> ConditionResult {
171        // "Wenn in dieser SG7 STS+Z06+Z10 vorhanden" — STS with Statuskategorie Z06 and Status Z10
172        ctx.has_segment_matching_in_group("STS", &[(0, 0, "Z06"), (1, 0, "Z10")], &["SG3", "SG7"])
173    }
174
175    /// [9] Wenn eine Störung festgestellt wurde, die durch den MSB selbständig und unverschuldet nicht behoben werden konnte.
176    /// EXTERNAL: Requires context from outside the message.
177    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
178        ctx.external.evaluate("msb_unrepairable_fault")
179    }
180
181    /// [10] Wenn in diesem STS DE4405 = Z09
182    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
183        // "Wenn in diesem STS DE4405 = Z09" — Status code Z09 in STS elements[1][0]
184        ctx.any_group_has_qualifier("STS", 1, "Z09", &["SG3", "SG7"])
185    }
186
187    /// [11] Wenn in diesem STS DE4405 = Z10
188    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
189        ctx.has_segment_matching("STS", &[(1, 0, "Z10")])
190    }
191
192    /// [12] Wenn eine Störung festgestellt wurde, die durch den MSB behoben wurde.
193    /// EXTERNAL: Requires context from outside the message.
194    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
195        ctx.external.evaluate("fault_resolved_by_msb")
196    }
197
198    /// [13] Wenn DE2379 = 303
199    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
200        ctx.has_segment_matching("DTM", &[(0, 2, "303")])
201    }
202
203    /// [14] Nur MP-ID aus Sparte Strom
204    /// EXTERNAL: Requires context from outside the message.
205    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
206        ctx.external.evaluate("mp_id_is_strom")
207    }
208
209    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
210    // REVIEW: This condition constrains a specific date field to be at or before document creation time. Without knowing which DTM qualifier is being constrained at this AHB position in INSRPT, ConditionResult::True is the appropriate approximation — the constraint is unconditional when the field is present. (medium confidence)
211    fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
212        // Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
213        // Informational constraint: the date in this field must be <= document creation time.
214        // Without knowing which specific DTM qualifier is being constrained at this AHB position,
215        // returning True is the safe approximation (consistent with ordrsp evaluate_494).
216        ConditionResult::True
217    }
218
219    /// [495] Der Zeitpunkt muss ≤ dem Wert im DE2380 des DTM+137 sein
220    // REVIEW: DTM+137 is the document date. The condition requires all SG7 DTMs (qualifiers 9, 163, 164, 292) to be ≤ the document date value. String comparison is valid for EDIFACT format 303 (CCYYMMDDHHMM) timestamps. Medium confidence because the condition says 'Der Zeitpunkt' (singular) but applies to DTMs in SG7 — unclear which specific one without AHB context. (medium confidence)
221    fn evaluate_495(&self, ctx: &EvaluationContext) -> ConditionResult {
222        // Der Zeitpunkt muss ≤ dem Wert im DE2380 des DTM+137 sein
223        // Get the document date from DTM+137, then check all SG7 DTMs are ≤ that value
224        let dtm_137_segs = ctx.find_segments_with_qualifier("DTM", 0, "137");
225        let threshold = match dtm_137_segs
226            .first()
227            .and_then(|s| s.elements.first())
228            .and_then(|e| e.get(1))
229        {
230            Some(v) if !v.is_empty() => v.clone(),
231            _ => return ConditionResult::Unknown,
232        };
233        // SG7 DTM qualifiers: 9 (status determined), 163 (start), 164 (end), 292 (state end)
234        let sg7_qualifiers = ["9", "163", "164", "292"];
235        let mut found_any = false;
236        for qual in &sg7_qualifiers {
237            let segs = ctx.find_segments_with_qualifier("DTM", 0, qual);
238            for seg in segs {
239                if let Some(val) = seg.elements.first().and_then(|e| e.get(1)) {
240                    if !val.is_empty() {
241                        found_any = true;
242                        if val.as_str() > threshold.as_str() {
243                            return ConditionResult::False;
244                        }
245                    }
246                }
247            }
248        }
249        if found_any {
250            ConditionResult::True
251        } else {
252            ConditionResult::Unknown
253        }
254    }
255
256    /// [506] Hinweis: Zu nutzen, wenn Behebung der Störung durch den MSB selbständig und unverschuldet nicht möglich ist.
257    fn evaluate_506(&self, _ctx: &EvaluationContext) -> ConditionResult {
258        // Hinweis: Zu nutzen, wenn Behebung der Störung durch den MSB selbständig und unverschuldet nicht möglich ist.
259        // Informational note about usage context — always applies
260        ConditionResult::True
261    }
262
263    /// [507] Hinweis: In SG7 FTX+AAO ist anzugeben, was die übergeordnete Ursache ist, aufgrund derer der MSB nicht in der Lage ist die Störung zu beheben.
264    fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
265        // Hinweis: In SG7 FTX+AAO ist anzugeben, was die übergeordnete Ursache ist, aufgrund derer der MSB nicht in der Lage ist die Störung zu beheben.
266        // Informational note about what content to provide in FTX+AAO — always applies
267        ConditionResult::True
268    }
269
270    /// [508] Hinweis: Vorgangsnummer aus DOC DE1004.
271    fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
272        // Hinweis: Vorgangsnummer aus DOC DE1004.
273        // Informational note indicating the value origin (transaction number from DOC DE1004) — always applies
274        ConditionResult::True
275    }
276
277    /// [509] Hinweis: Verwendung der ID der Messlokation
278    fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
279        // Hinweis: Verwendung der ID der Messlokation — informational note, always applies
280        ConditionResult::True
281    }
282
283    /// [510] Hinweis: Verwendung der ID der Marktlokation
284    fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
285        // Hinweis: Verwendung der ID der Marktlokation — informational note, always applies
286        ConditionResult::True
287    }
288
289    /// [511] Hinweis: Die Nummerierung beginnt in jedem Dokument bei 1
290    fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
291        // Hinweis: Die Nummerierung beginnt in jedem Dokument bei 1 — informational note, always applies
292        ConditionResult::True
293    }
294
295    /// [512] Hinweis: Wurde eine Störung festgestellt und durch den MSB behoben, ist die Segmentgruppe mit demselben Meldepunkt zweimal anzugeben
296    fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
297        // Hinweis: Wurde eine Störung festgestellt und durch den MSB behoben, ist die Segmentgruppe mit demselben Meldepunkt zweimal anzugeben — informational note, always applies
298        ConditionResult::True
299    }
300
301    /// [513] Hinweis: Wurde keine Störung festgestellt, ist die Segmentgruppe genau einmal anzugeben
302    fn evaluate_513(&self, _ctx: &EvaluationContext) -> ConditionResult {
303        // Hinweis: Wurde keine Störung festgestellt, ist die Segmentgruppe genau einmal anzugeben — informational note, always applies
304        ConditionResult::True
305    }
306
307    /// [514] Hinweis: Wurde eine Störung festgestellt, die nicht durch den MSB behoben werden konnte, ist die Segmentgruppe genau einmal anzugeben
308    fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
309        // Hinweis: Wurde eine Störung festgestellt, die nicht durch den MSB behoben werden konnte, ist die Segmentgruppe genau einmal anzugeben
310        // Informational note — always applies
311        ConditionResult::True
312    }
313
314    /// [515] Hinweis: "≤ dem Wert im DE2380 des DTM+137" bedeutet, dass der dort genannte Tag ≥ dem in diesem DTM genannten Tag sein muss, wenn in DE2379 der Code 102 steht.
315    fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
316        // Hinweis: "≤ dem Wert im DE2380 des DTM+137" bedeutet, dass der dort genannte Tag ≥ dem in diesem DTM genannten Tag sein muss, wenn in DE2379 der Code 102 steht.
317        // Informational note — always applies
318        ConditionResult::True
319    }
320
321    /// [908] Format: Mögliche Werte: 1 bis n
322    // REVIEW: Format condition 'Mögliche Werte: 1 bis n' means the value must be a positive integer (>= 1). In INSRPT, the most likely target is a sequence number element (SEQ DE1050). Implemented using validate_numeric with '>=' 1.0. Medium confidence because the exact segment/element target is not specified in the provided structure reference. (medium confidence)
323    fn evaluate_908(&self, ctx: &EvaluationContext) -> ConditionResult {
324        ctx.format_check("SEQ", 1, 0, |val| validate_numeric(val, ">=", 1.0))
325    }
326
327    /// [931] Format: ZZZ = +00
328    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
329        ctx.format_check_qualified("DTM", 0, "137", 0, 1, validate_timezone_utc)
330    }
331
332    /// [950] Format: Marktlokations-ID
333    fn evaluate_950(&self, ctx: &EvaluationContext) -> ConditionResult {
334        ctx.format_check_qualified("LOC", 0, "Z16", 1, 0, validate_malo_id)
335    }
336
337    /// [951] Format: Zählpunktbezeichnung
338    // REVIEW: Format condition for Zählpunktbezeichnung (meter point designation) — 33 alphanumeric characters. Uses validate_zahlpunkt helper. Without the exact INSRPT segment structure reference, the implementation checks LOC segment element 1 (typical location for identifiers) with a fallback to NAD C082. Confidence is medium because the exact segment path for the Zählpunktbezeichnung in INSRPT is not confirmed without the MIG segment structure reference. (medium confidence)
339    fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
340        // Format: Zählpunktbezeichnung — 33 alphanumeric characters
341        // Zählpunktbezeichnung is stored in a LOC or reference segment in INSRPT
342        // Try LOC segments (common location for Zählpunkt identifiers)
343        let loc_segs = ctx.find_segments("LOC");
344        for seg in &loc_segs {
345            if let Some(val) = seg.elements.get(1).and_then(|e| e.first()) {
346                if !val.is_empty() {
347                    return validate_zahlpunkt(val);
348                }
349            }
350        }
351        // Fallback: check NAD segment identification (C082)
352        let nad_segs = ctx.find_segments("NAD");
353        for seg in &nad_segs {
354            if let Some(val) = seg.elements.get(1).and_then(|e| e.first()) {
355                if !val.is_empty() && val.len() == 33 {
356                    return validate_zahlpunkt(val);
357                }
358            }
359        }
360        ConditionResult::Unknown
361    }
362}