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 fn evaluate_950(&self, ctx: &EvaluationContext) -> ConditionResult {
326 ctx.format_check_qualified("LOC", 0, "Z16", 1, 0, validate_malo_id)
327 }
328
329 /// [951] Format: Zählpunktbezeichnung
330 // 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)
331 fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
332 // Format: Zählpunktbezeichnung — 33 alphanumeric characters
333 // Zählpunktbezeichnung is stored in a LOC or reference segment in INSRPT
334 // Try LOC segments (common location for Zählpunkt identifiers)
335 let loc_segs = ctx.find_segments("LOC");
336 for seg in &loc_segs {
337 if let Some(val) = seg.elements.get(1).and_then(|e| e.first()) {
338 if !val.is_empty() {
339 return validate_zahlpunkt(val);
340 }
341 }
342 }
343 // Fallback: check NAD segment identification (C082)
344 let nad_segs = ctx.find_segments("NAD");
345 for seg in &nad_segs {
346 if let Some(val) = seg.elements.get(1).and_then(|e| e.first()) {
347 if !val.is_empty() && val.len() == 33 {
348 return validate_zahlpunkt(val);
349 }
350 }
351 }
352 ConditionResult::Unknown
353 }
354}