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.evaluate("insrpt_bearbeitungsdatum_available")
140    }
141
142    /// [4] Wenn MP-ID in SG2 NAD+MR in der Rolle NB
143    /// EXTERNAL: Requires context from outside the message.
144    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
145        ctx.external.evaluate("recipient_is_nb")
146    }
147
148    /// [5] Wenn MP-ID in SG2 NAD+MR in der Rolle LF
149    /// EXTERNAL: Requires context from outside the message.
150    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
151        ctx.external.evaluate("recipient_is_lf")
152    }
153
154    /// [6] Wenn keine Störung festgestellt werden konnte.
155    // 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)
156    fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
157        // "Keine Störung festgestellt" — STS+Z06 (Gerätestatus) with status code Z09 (no fault)
158        ctx.has_segment_matching_in_group("STS", &[(0, 0, "Z06"), (1, 0, "Z09")], &["SG3", "SG7"])
159    }
160
161    /// [7] Wenn keine weitere SG7 mit demselben Meldepunkt und DTM+9 vorhanden
162    /// 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.
163    fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
164        ctx.external
165            .evaluate("insrpt_no_duplicate_sg7_same_meldepunkt_and_dtm9")
166    }
167
168    /// [8] Wenn in dieser SG7 STS+Z06+Z10 vorhanden
169    fn evaluate_8(&self, ctx: &EvaluationContext) -> ConditionResult {
170        // HAND-EDITED: "in dieser SG7 STS+Z06+Z10" — the enclosing SG7 only, when the scope
171        // reaches one; the message as before otherwise.
172        if let Some(scope) = ctx.enclosing_scope("SG7") {
173            return ConditionResult::from(
174                ctx.find_segments_at(scope, "STS")
175                    .iter()
176                    .any(|s| s.get_element(0) == "Z06" && s.get_component(1, 0) == "Z10"),
177            );
178        }
179        // "Wenn in dieser SG7 STS+Z06+Z10 vorhanden" — STS with Statuskategorie Z06 and Status Z10
180        ctx.has_segment_matching_in_group("STS", &[(0, 0, "Z06"), (1, 0, "Z10")], &["SG3", "SG7"])
181    }
182
183    /// [9] Wenn eine Störung festgestellt wurde, die durch den MSB selbständig und unverschuldet nicht behoben werden konnte.
184    /// EXTERNAL: Requires context from outside the message.
185    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
186        ctx.external.evaluate("msb_unrepairable_fault")
187    }
188
189    /// [10] Wenn in diesem STS DE4405 = Z09
190    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
191        // "Wenn in diesem STS DE4405 = Z09" — Status code Z09 in STS elements[1][0]
192        ctx.any_group_has_qualifier("STS", 1, "Z09", &["SG3", "SG7"])
193    }
194
195    /// [11] Wenn in diesem STS DE4405 = Z10
196    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
197        ctx.has_segment_matching("STS", &[(1, 0, "Z10")])
198    }
199
200    /// [12] Wenn eine Störung festgestellt wurde, die durch den MSB behoben wurde.
201    /// EXTERNAL: Requires context from outside the message.
202    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
203        ctx.external.evaluate("fault_resolved_by_msb")
204    }
205
206    /// [13] Wenn DE2379 = 303
207    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
208        ctx.has_segment_matching("DTM", &[(0, 2, "303")])
209    }
210
211    /// [14] Nur MP-ID aus Sparte Strom
212    /// EXTERNAL: Requires context from outside the message.
213    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
214        ctx.external.evaluate("mp_id_is_strom")
215    }
216
217    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
218    // 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)
219    fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
220        // Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
221        // Informational constraint: the date in this field must be <= document creation time.
222        // Without knowing which specific DTM qualifier is being constrained at this AHB position,
223        // returning True is the safe approximation (consistent with ordrsp evaluate_494).
224        ConditionResult::True
225    }
226
227    /// [495] Der Zeitpunkt muss ≤ dem Wert im DE2380 des DTM+137 sein
228    fn evaluate_495(&self, ctx: &EvaluationContext) -> ConditionResult {
229        // HAND-EDITED: subject is the current DTM's DE2380 (via ctx.resolved_value),
230        // compared with the message date (DTM+137). Lexicographic compare is valid
231        // for fixed-width CCYYMMDDHHMM+ZZ (format 303).
232        let current = match ctx.resolved_value {
233            Some(v) if !v.is_empty() => v,
234            _ => return ConditionResult::Unknown,
235        };
236        let threshold = match ctx
237            .find_segments_with_qualifier("DTM", 0, "137")
238            .first()
239            .and_then(|s| s.elements.first())
240            .and_then(|e| e.get(1))
241        {
242            Some(v) if !v.is_empty() => v.clone(),
243            _ => return ConditionResult::Unknown,
244        };
245        ConditionResult::from(current <= threshold.as_str())
246    }
247
248    /// [506] Hinweis: Zu nutzen, wenn Behebung der Störung durch den MSB selbständig und unverschuldet nicht möglich ist.
249    fn evaluate_506(&self, _ctx: &EvaluationContext) -> ConditionResult {
250        // Hinweis: Zu nutzen, wenn Behebung der Störung durch den MSB selbständig und unverschuldet nicht möglich ist.
251        // Informational note about usage context — always applies
252        ConditionResult::True
253    }
254
255    /// [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.
256    fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
257        // 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.
258        // Informational note about what content to provide in FTX+AAO — always applies
259        ConditionResult::True
260    }
261
262    /// [508] Hinweis: Vorgangsnummer aus DOC DE1004.
263    fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
264        // Hinweis: Vorgangsnummer aus DOC DE1004.
265        // Informational note indicating the value origin (transaction number from DOC DE1004) — always applies
266        ConditionResult::True
267    }
268
269    /// [509] Hinweis: Verwendung der ID der Messlokation
270    fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
271        // Hinweis: Verwendung der ID der Messlokation — informational note, always applies
272        ConditionResult::True
273    }
274
275    /// [510] Hinweis: Verwendung der ID der Marktlokation
276    fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
277        // Hinweis: Verwendung der ID der Marktlokation — informational note, always applies
278        ConditionResult::True
279    }
280
281    /// [511] Hinweis: Die Nummerierung beginnt in jedem Dokument bei 1
282    fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
283        // Hinweis: Die Nummerierung beginnt in jedem Dokument bei 1 — informational note, always applies
284        ConditionResult::True
285    }
286
287    /// [512] Hinweis: Wurde eine Störung festgestellt und durch den MSB behoben, ist die Segmentgruppe mit demselben Meldepunkt zweimal anzugeben
288    fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
289        // Hinweis: Wurde eine Störung festgestellt und durch den MSB behoben, ist die Segmentgruppe mit demselben Meldepunkt zweimal anzugeben — informational note, always applies
290        ConditionResult::True
291    }
292
293    /// [513] Hinweis: Wurde keine Störung festgestellt, ist die Segmentgruppe genau einmal anzugeben
294    fn evaluate_513(&self, _ctx: &EvaluationContext) -> ConditionResult {
295        // Hinweis: Wurde keine Störung festgestellt, ist die Segmentgruppe genau einmal anzugeben — informational note, always applies
296        ConditionResult::True
297    }
298
299    /// [514] Hinweis: Wurde eine Störung festgestellt, die nicht durch den MSB behoben werden konnte, ist die Segmentgruppe genau einmal anzugeben
300    fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
301        // Hinweis: Wurde eine Störung festgestellt, die nicht durch den MSB behoben werden konnte, ist die Segmentgruppe genau einmal anzugeben
302        // Informational note — always applies
303        ConditionResult::True
304    }
305
306    /// [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.
307    fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
308        // 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.
309        // Informational note — always applies
310        ConditionResult::True
311    }
312
313    /// [908] Format: Mögliche Werte: 1 bis n
314    // 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)
315    fn evaluate_908(&self, ctx: &EvaluationContext) -> ConditionResult {
316        ctx.format_check("SEQ", 1, 0, |val| validate_numeric(val, ">=", 1.0))
317    }
318
319    /// [931] Format: ZZZ = +00
320    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
321        ctx.format_check_qualified("DTM", 0, "137", 0, 1, validate_timezone_utc)
322    }
323
324    /// [950] Format: Marktlokations-ID
325    // HAND-EDITED (#373): the condition sits on LOC+172 and RFF C506 1154, not on
326    // LOC+Z16; judge the value it is attached to.
327    fn evaluate_950(&self, ctx: &EvaluationContext) -> ConditionResult {
328        ctx.format_check_resolved(validate_malo_id)
329    }
330
331    /// [951] Format: Zählpunktbezeichnung
332    // HAND-EDITED (#392): the condition sits on SG8 RFF C506 1154 (ID einer
333    // Messlokation), but it read the first LOC instead: the LOC+172
334    // Marktlokations-ID, which is never 33 characters long. Judge the value it
335    // is attached to.
336    fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
337        ctx.format_check_resolved(validate_zahlpunkt)
338    }
339}