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#[allow(unused_imports)]
8use crate::eval::format_validators::*;
9use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
10
11/// Generated condition evaluator for INSRPT FV2510.
12pub struct InsrptConditionEvaluatorFV2510 {
13    // External condition IDs that require runtime context.
14    external_conditions: std::collections::HashSet<u32>,
15}
16
17impl Default for InsrptConditionEvaluatorFV2510 {
18    fn default() -> Self {
19        let mut external_conditions = std::collections::HashSet::new();
20        external_conditions.insert(1);
21        external_conditions.insert(4);
22        external_conditions.insert(5);
23        external_conditions.insert(9);
24        external_conditions.insert(12);
25        external_conditions.insert(14);
26        Self {
27            external_conditions,
28        }
29    }
30}
31
32impl ConditionEvaluator for InsrptConditionEvaluatorFV2510 {
33    fn message_type(&self) -> &str {
34        "INSRPT"
35    }
36
37    fn format_version(&self) -> &str {
38        "FV2510"
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            6 => self.evaluate_6(ctx),
49            7 => self.evaluate_7(ctx),
50            8 => self.evaluate_8(ctx),
51            9 => self.evaluate_9(ctx),
52            10 => self.evaluate_10(ctx),
53            11 => self.evaluate_11(ctx),
54            12 => self.evaluate_12(ctx),
55            13 => self.evaluate_13(ctx),
56            14 => self.evaluate_14(ctx),
57            494 => self.evaluate_494(ctx),
58            495 => self.evaluate_495(ctx),
59            506 => self.evaluate_506(ctx),
60            507 => self.evaluate_507(ctx),
61            508 => self.evaluate_508(ctx),
62            509 => self.evaluate_509(ctx),
63            510 => self.evaluate_510(ctx),
64            511 => self.evaluate_511(ctx),
65            512 => self.evaluate_512(ctx),
66            513 => self.evaluate_513(ctx),
67            514 => self.evaluate_514(ctx),
68            515 => self.evaluate_515(ctx),
69            908 => self.evaluate_908(ctx),
70            931 => self.evaluate_931(ctx),
71            950 => self.evaluate_950(ctx),
72            951 => self.evaluate_951(ctx),
73            _ => ConditionResult::Unknown,
74        }
75    }
76
77    fn is_external(&self, condition: u32) -> bool {
78        self.external_conditions.contains(&condition)
79    }
80    fn is_known(&self, condition: u32) -> bool {
81        matches!(
82            condition,
83            1 | 2
84                | 3
85                | 4
86                | 5
87                | 6
88                | 7
89                | 8
90                | 9
91                | 10
92                | 11
93                | 12
94                | 13
95                | 14
96                | 494
97                | 495
98                | 506
99                | 507
100                | 508
101                | 509
102                | 510
103                | 511
104                | 512
105                | 513
106                | 514
107                | 515
108                | 908
109                | 931
110                | 950
111                | 951
112        )
113    }
114}
115
116impl InsrptConditionEvaluatorFV2510 {
117    /// [1] Wenn Nachrichtenabsender vom Kunden informiert wurde.
118    /// EXTERNAL: Requires context from outside the message.
119    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
120        ctx.external
121            .evaluate("nachrichtenabsender_vom_kunden_informiert")
122    }
123
124    /// [2] Wenn SG7 STS+Z06+Z10+ZC1 vorhanden.
125    fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
126        ctx.has_segment_matching("STS", &[(0, 0, "Z06"), (1, 0, "Z10"), (2, 0, "ZC1")])
127    }
128
129    /// [3] Wenn vorhanden.
130    fn evaluate_3(&self, _ctx: &EvaluationContext) -> ConditionResult {
131        // TODO: Condition [3] requires manual implementation
132        // Reason: "Wenn vorhanden" is too vague without knowing which specific segment, element, or group this condition is applied to. No structural reference to evaluate against.
133        ConditionResult::Unknown
134    }
135
136    /// [4] Wenn MP-ID in SG2 NAD+MR in der Rolle NB
137    /// EXTERNAL: Requires context from outside the message.
138    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
139        ctx.external.evaluate("recipient_is_nb")
140    }
141
142    /// [5] Wenn MP-ID in SG2 NAD+MR in der Rolle LF
143    /// EXTERNAL: Requires context from outside the message.
144    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
145        ctx.external.evaluate("recipient_is_lf")
146    }
147
148    /// [6] Wenn keine Störung festgestellt werden konnte.
149    // 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)
150    fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
151        // "Keine Störung festgestellt" — STS+Z06 (Gerätestatus) with status code Z09 (no fault)
152        ctx.has_segment_matching_in_group("STS", &[(0, 0, "Z06"), (1, 0, "Z09")], &["SG3", "SG7"])
153    }
154
155    /// [7] Wenn keine weitere SG7 mit demselben Meldepunkt und DTM+9 vorhanden
156    fn evaluate_7(&self, _ctx: &EvaluationContext) -> ConditionResult {
157        // TODO: Condition [7] requires manual implementation
158        // Reason: "Keine weitere SG7 mit demselben Meldepunkt und DTM+9" requires cross-SG7 comparison on a 'Meldepunkt' identifier. The provided schema for SG7 only shows DTM and STS segments — no LOC, NAD, DOC, or RFF segment carrying the Meldepunkt identifier is documented. Without knowing which segment and element position carries the Meldepunkt reference, a correct implementation cannot be written.
159        ConditionResult::Unknown
160    }
161
162    /// [8] Wenn in dieser SG7 STS+Z06+Z10 vorhanden
163    fn evaluate_8(&self, ctx: &EvaluationContext) -> ConditionResult {
164        // "Wenn in dieser SG7 STS+Z06+Z10 vorhanden" — STS with Statuskategorie Z06 and Status Z10
165        ctx.has_segment_matching_in_group("STS", &[(0, 0, "Z06"), (1, 0, "Z10")], &["SG3", "SG7"])
166    }
167
168    /// [9] Wenn eine Störung festgestellt wurde, die durch den MSB selbständig und unverschuldet nicht behoben werden konnte.
169    /// EXTERNAL: Requires context from outside the message.
170    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
171        ctx.external.evaluate("msb_unrepairable_fault")
172    }
173
174    /// [10] Wenn in diesem STS DE4405 = Z09
175    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
176        // "Wenn in diesem STS DE4405 = Z09" — Status code Z09 in STS elements[1][0]
177        ctx.any_group_has_qualifier("STS", 1, "Z09", &["SG3", "SG7"])
178    }
179
180    /// [11] Wenn in diesem STS DE4405 = Z10
181    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
182        ctx.has_segment_matching("STS", &[(1, 0, "Z10")])
183    }
184
185    /// [12] Wenn eine Störung festgestellt wurde, die durch den MSB behoben wurde.
186    /// EXTERNAL: Requires context from outside the message.
187    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
188        ctx.external.evaluate("fault_resolved_by_msb")
189    }
190
191    /// [13] Wenn DE2379 = 303
192    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
193        ctx.has_segment_matching("DTM", &[(0, 2, "303")])
194    }
195
196    /// [14] Nur MP-ID aus Sparte Strom
197    /// EXTERNAL: Requires context from outside the message.
198    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
199        ctx.external.evaluate("mp_id_is_strom")
200    }
201
202    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
203    // 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)
204    fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
205        // Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
206        // Informational constraint: the date in this field must be <= document creation time.
207        // Without knowing which specific DTM qualifier is being constrained at this AHB position,
208        // returning True is the safe approximation (consistent with ordrsp evaluate_494).
209        ConditionResult::True
210    }
211
212    /// [495] Der Zeitpunkt muss ≤ dem Wert im DE2380 des DTM+137 sein
213    // 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)
214    fn evaluate_495(&self, ctx: &EvaluationContext) -> ConditionResult {
215        // Der Zeitpunkt muss ≤ dem Wert im DE2380 des DTM+137 sein
216        // Get the document date from DTM+137, then check all SG7 DTMs are ≤ that value
217        let dtm_137_segs = ctx.find_segments_with_qualifier("DTM", 0, "137");
218        let threshold = match dtm_137_segs
219            .first()
220            .and_then(|s| s.elements.first())
221            .and_then(|e| e.get(1))
222        {
223            Some(v) if !v.is_empty() => v.clone(),
224            _ => return ConditionResult::Unknown,
225        };
226        // SG7 DTM qualifiers: 9 (status determined), 163 (start), 164 (end), 292 (state end)
227        let sg7_qualifiers = ["9", "163", "164", "292"];
228        let mut found_any = false;
229        for qual in &sg7_qualifiers {
230            let segs = ctx.find_segments_with_qualifier("DTM", 0, qual);
231            for seg in segs {
232                if let Some(val) = seg.elements.first().and_then(|e| e.get(1)) {
233                    if !val.is_empty() {
234                        found_any = true;
235                        if val.as_str() > threshold.as_str() {
236                            return ConditionResult::False;
237                        }
238                    }
239                }
240            }
241        }
242        if found_any {
243            ConditionResult::True
244        } else {
245            ConditionResult::Unknown
246        }
247    }
248
249    /// [506] Hinweis: Zu nutzen, wenn Behebung der Störung durch den MSB selbständig und unverschuldet nicht möglich ist.
250    fn evaluate_506(&self, _ctx: &EvaluationContext) -> ConditionResult {
251        // Hinweis: Zu nutzen, wenn Behebung der Störung durch den MSB selbständig und unverschuldet nicht möglich ist.
252        // Informational note about usage context — always applies
253        ConditionResult::True
254    }
255
256    /// [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.
257    fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
258        // 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.
259        // Informational note about what content to provide in FTX+AAO — always applies
260        ConditionResult::True
261    }
262
263    /// [508] Hinweis: Vorgangsnummer aus DOC DE1004.
264    fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
265        // Hinweis: Vorgangsnummer aus DOC DE1004.
266        // Informational note indicating the value origin (transaction number from DOC DE1004) — always applies
267        ConditionResult::True
268    }
269
270    /// [509] Hinweis: Verwendung der ID der Messlokation
271    fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
272        // Hinweis: Verwendung der ID der Messlokation — informational note, always applies
273        ConditionResult::True
274    }
275
276    /// [510] Hinweis: Verwendung der ID der Marktlokation
277    fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
278        // Hinweis: Verwendung der ID der Marktlokation — informational note, always applies
279        ConditionResult::True
280    }
281
282    /// [511] Hinweis: Die Nummerierung beginnt in jedem Dokument bei 1
283    fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
284        // Hinweis: Die Nummerierung beginnt in jedem Dokument bei 1 — informational note, always applies
285        ConditionResult::True
286    }
287
288    /// [512] Hinweis: Wurde eine Störung festgestellt und durch den MSB behoben, ist die Segmentgruppe mit demselben Meldepunkt zweimal anzugeben
289    fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
290        // Hinweis: Wurde eine Störung festgestellt und durch den MSB behoben, ist die Segmentgruppe mit demselben Meldepunkt zweimal anzugeben — informational note, always applies
291        ConditionResult::True
292    }
293
294    /// [513] Hinweis: Wurde keine Störung festgestellt, ist die Segmentgruppe genau einmal anzugeben
295    fn evaluate_513(&self, _ctx: &EvaluationContext) -> ConditionResult {
296        // Hinweis: Wurde keine Störung festgestellt, ist die Segmentgruppe genau einmal anzugeben — informational note, always applies
297        ConditionResult::True
298    }
299
300    /// [514] Hinweis: Wurde eine Störung festgestellt, die nicht durch den MSB behoben werden konnte, ist die Segmentgruppe genau einmal anzugeben
301    fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
302        // Hinweis: Wurde eine Störung festgestellt, die nicht durch den MSB behoben werden konnte, ist die Segmentgruppe genau einmal anzugeben
303        // Informational note — always applies
304        ConditionResult::True
305    }
306
307    /// [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.
308    fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
309        // 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.
310        // Informational note — always applies
311        ConditionResult::True
312    }
313
314    /// [908] Format: Mögliche Werte: 1 bis n
315    // 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)
316    fn evaluate_908(&self, ctx: &EvaluationContext) -> ConditionResult {
317        // Format: Mögliche Werte: 1 bis n — numeric value must be >= 1 (positive integer)
318        // Applies to a sequence/count element in INSRPT (e.g. SEQ DE1050)
319        let segs = ctx.find_segments("SEQ");
320        match segs
321            .first()
322            .and_then(|s| s.elements.get(1))
323            .and_then(|e| e.first())
324        {
325            Some(val) => validate_numeric(val, ">=", 1.0),
326            None => ConditionResult::False, // segment absent → condition not applicable
327        }
328    }
329
330    /// [931] Format: ZZZ = +00
331    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
332        // Format: ZZZ = +00 — DTM value must use UTC timezone offset +00
333        // Applies to DTM+137 (Dokumentendatum) in INSRPT
334        let dtm_segs = ctx.find_segments_with_qualifier("DTM", 0, "137");
335        match dtm_segs
336            .first()
337            .and_then(|s| s.elements.first())
338            .and_then(|e| e.get(1))
339        {
340            Some(val) => validate_timezone_utc(val),
341            None => ConditionResult::False, // segment absent → condition not applicable
342        }
343    }
344
345    /// [950] Format: Marktlokations-ID
346    fn evaluate_950(&self, ctx: &EvaluationContext) -> ConditionResult {
347        // Format: Marktlokations-ID — 11-digit ID with Luhn check digit
348        // Applies to LOC+Z16 segment (Marktlokation identifier)
349        let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z16");
350        match segs
351            .first()
352            .and_then(|s| s.elements.get(1))
353            .and_then(|e| e.first())
354        {
355            Some(val) => validate_malo_id(val),
356            None => ConditionResult::False, // segment absent → condition not applicable
357        }
358    }
359
360    /// [951] Format: Zählpunktbezeichnung
361    // 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)
362    fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
363        // Format: Zählpunktbezeichnung — 33 alphanumeric characters
364        // Zählpunktbezeichnung is stored in a LOC or reference segment in INSRPT
365        // Try LOC segments (common location for Zählpunkt identifiers)
366        let loc_segs = ctx.find_segments("LOC");
367        for seg in &loc_segs {
368            if let Some(val) = seg.elements.get(1).and_then(|e| e.first()) {
369                if !val.is_empty() {
370                    return validate_zahlpunkt(val);
371                }
372            }
373        }
374        // Fallback: check NAD segment identification (C082)
375        let nad_segs = ctx.find_segments("NAD");
376        for seg in &nad_segs {
377            if let Some(val) = seg.elements.get(1).and_then(|e| e.first()) {
378                if !val.is_empty() && val.len() == 33 {
379                    return validate_zahlpunkt(val);
380                }
381            }
382        }
383        ConditionResult::Unknown
384    }
385}