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}