automapper_validation/generated/fv2510/reqote_conditions_fv2510.rs
1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2510/REQOTE_AHB_1_1_20250401.xml
4// Generated: 2026-03-12T10:31:57Z
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 REQOTE FV2510.
17pub struct ReqoteConditionEvaluatorFV2510 {
18 // External condition IDs that require runtime context.
19 external_conditions: std::collections::HashSet<u32>,
20}
21
22impl Default for ReqoteConditionEvaluatorFV2510 {
23 fn default() -> Self {
24 let mut external_conditions = std::collections::HashSet::new();
25 external_conditions.insert(10);
26 external_conditions.insert(24);
27 external_conditions.insert(28);
28 external_conditions.insert(29);
29 external_conditions.insert(30);
30 external_conditions.insert(31);
31 external_conditions.insert(32);
32 external_conditions.insert(33);
33 external_conditions.insert(35);
34 external_conditions.insert(36);
35 external_conditions.insert(37);
36 external_conditions.insert(38);
37 external_conditions.insert(41);
38 external_conditions.insert(42);
39 external_conditions.insert(43);
40 external_conditions.insert(44);
41 external_conditions.insert(45);
42 external_conditions.insert(47);
43 external_conditions.insert(48);
44 external_conditions.insert(49);
45 external_conditions.insert(50);
46 external_conditions.insert(51);
47 external_conditions.insert(53);
48 external_conditions.insert(492);
49 external_conditions.insert(493);
50 external_conditions.insert(2065);
51 external_conditions.insert(2066);
52 Self {
53 external_conditions,
54 }
55 }
56}
57
58impl ConditionEvaluator for ReqoteConditionEvaluatorFV2510 {
59 fn message_type(&self) -> &str {
60 "REQOTE"
61 }
62
63 fn format_version(&self) -> &str {
64 "FV2510"
65 }
66
67 fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
68 match condition {
69 1 => self.evaluate_1(ctx),
70 2 => self.evaluate_2(ctx),
71 10 => self.evaluate_10(ctx),
72 15 => self.evaluate_15(ctx),
73 16 => self.evaluate_16(ctx),
74 17 => self.evaluate_17(ctx),
75 18 => self.evaluate_18(ctx),
76 19 => self.evaluate_19(ctx),
77 20 => self.evaluate_20(ctx),
78 21 => self.evaluate_21(ctx),
79 22 => self.evaluate_22(ctx),
80 23 => self.evaluate_23(ctx),
81 24 => self.evaluate_24(ctx),
82 25 => self.evaluate_25(ctx),
83 26 => self.evaluate_26(ctx),
84 27 => self.evaluate_27(ctx),
85 28 => self.evaluate_28(ctx),
86 29 => self.evaluate_29(ctx),
87 30 => self.evaluate_30(ctx),
88 31 => self.evaluate_31(ctx),
89 32 => self.evaluate_32(ctx),
90 33 => self.evaluate_33(ctx),
91 35 => self.evaluate_35(ctx),
92 36 => self.evaluate_36(ctx),
93 37 => self.evaluate_37(ctx),
94 38 => self.evaluate_38(ctx),
95 39 => self.evaluate_39(ctx),
96 40 => self.evaluate_40(ctx),
97 41 => self.evaluate_41(ctx),
98 42 => self.evaluate_42(ctx),
99 43 => self.evaluate_43(ctx),
100 44 => self.evaluate_44(ctx),
101 45 => self.evaluate_45(ctx),
102 47 => self.evaluate_47(ctx),
103 48 => self.evaluate_48(ctx),
104 49 => self.evaluate_49(ctx),
105 50 => self.evaluate_50(ctx),
106 51 => self.evaluate_51(ctx),
107 52 => self.evaluate_52(ctx),
108 53 => self.evaluate_53(ctx),
109 490 => self.evaluate_490(ctx),
110 491 => self.evaluate_491(ctx),
111 492 => self.evaluate_492(ctx),
112 493 => self.evaluate_493(ctx),
113 494 => self.evaluate_494(ctx),
114 500 => self.evaluate_500(ctx),
115 501 => self.evaluate_501(ctx),
116 502 => self.evaluate_502(ctx),
117 503 => self.evaluate_503(ctx),
118 504 => self.evaluate_504(ctx),
119 507 => self.evaluate_507(ctx),
120 508 => self.evaluate_508(ctx),
121 509 => self.evaluate_509(ctx),
122 510 => self.evaluate_510(ctx),
123 511 => self.evaluate_511(ctx),
124 512 => self.evaluate_512(ctx),
125 514 => self.evaluate_514(ctx),
126 515 => self.evaluate_515(ctx),
127 516 => self.evaluate_516(ctx),
128 517 => self.evaluate_517(ctx),
129 518 => self.evaluate_518(ctx),
130 520 => self.evaluate_520(ctx),
131 521 => self.evaluate_521(ctx),
132 903 => self.evaluate_903(ctx),
133 906 => self.evaluate_906(ctx),
134 911 => self.evaluate_911(ctx),
135 922 => self.evaluate_922(ctx),
136 931 => self.evaluate_931(ctx),
137 932 => self.evaluate_932(ctx),
138 933 => self.evaluate_933(ctx),
139 934 => self.evaluate_934(ctx),
140 935 => self.evaluate_935(ctx),
141 939 => self.evaluate_939(ctx),
142 940 => self.evaluate_940(ctx),
143 950 => self.evaluate_950(ctx),
144 951 => self.evaluate_951(ctx),
145 960 => self.evaluate_960(ctx),
146 961 => self.evaluate_961(ctx),
147 962 => self.evaluate_962(ctx),
148 967 => self.evaluate_967(ctx),
149 2005 => self.evaluate_2005(ctx),
150 2060 => self.evaluate_2060(ctx),
151 2061 => self.evaluate_2061(ctx),
152 2062 => self.evaluate_2062(ctx),
153 2063 => self.evaluate_2063(ctx),
154 2064 => self.evaluate_2064(ctx),
155 2065 => self.evaluate_2065(ctx),
156 2066 => self.evaluate_2066(ctx),
157 2067 => self.evaluate_2067(ctx),
158 2068 => self.evaluate_2068(ctx),
159 _ => ConditionResult::Unknown,
160 }
161 }
162
163 fn is_external(&self, condition: u32) -> bool {
164 self.external_conditions.contains(&condition)
165 }
166 fn is_known(&self, condition: u32) -> bool {
167 matches!(
168 condition,
169 1 | 2
170 | 10
171 | 15
172 | 16
173 | 17
174 | 18
175 | 19
176 | 20
177 | 21
178 | 22
179 | 23
180 | 24
181 | 25
182 | 26
183 | 27
184 | 28
185 | 29
186 | 30
187 | 31
188 | 32
189 | 33
190 | 35
191 | 36
192 | 37
193 | 38
194 | 39
195 | 40
196 | 41
197 | 42
198 | 43
199 | 44
200 | 45
201 | 47
202 | 48
203 | 49
204 | 50
205 | 51
206 | 52
207 | 53
208 | 490
209 | 491
210 | 492
211 | 493
212 | 494
213 | 500
214 | 501
215 | 502
216 | 503
217 | 504
218 | 507
219 | 508
220 | 509
221 | 510
222 | 511
223 | 512
224 | 514
225 | 515
226 | 516
227 | 517
228 | 518
229 | 520
230 | 521
231 | 903
232 | 906
233 | 911
234 | 922
235 | 931
236 | 932
237 | 933
238 | 934
239 | 935
240 | 939
241 | 940
242 | 950
243 | 951
244 | 960
245 | 961
246 | 962
247 | 967
248 | 2005
249 | 2060
250 | 2061
251 | 2062
252 | 2063
253 | 2064
254 | 2065
255 | 2066
256 | 2067
257 | 2068
258 )
259 }
260}
261
262impl ReqoteConditionEvaluatorFV2510 {
263 /// [33] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.4 „Messprodukte mit Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW“ enthalten sind.
264 /// EXTERNAL: Requires context from outside the message.
265 fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
266 ctx.external
267 .evaluate("messprodukt_in_konfigurationserlaubnis_smgw_list")
268 }
269
270 /// [37] Es sind nur die Messprodukt-Position-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.7 „Art der Werte für Messprodukte nach Typ 2“ enthalten sind.
271 /// EXTERNAL: Requires context from outside the message.
272 fn evaluate_37(&self, ctx: &EvaluationContext) -> ConditionResult {
273 ctx.external
274 .evaluate("messprodukt_position_in_kapitel_4_7_list")
275 }
276
277 /// [38] Wenn innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) ein Produkt angegeben ist, das in der Codeliste der Konfigurationen...
278 /// EXTERNAL: Requires context from outside the message.
279 fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
280 ctx.external.evaluate("pia_product_triggers_schwellwert")
281 }
282
283 /// [41] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.6.1 „Werte nach Typ 2 aus Backend“ enthalten sind.
284 /// EXTERNAL: Requires context from outside the message.
285 fn evaluate_41(&self, ctx: &EvaluationContext) -> ConditionResult {
286 ctx.external
287 .evaluate("messprodukt_in_kapitel_4_6_1_backend_list")
288 }
289
290 /// [42] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.6.2 „Werte nach Typ 2 aus SMGW“ enthalten sind.
291 /// EXTERNAL: Requires context from outside the message.
292 fn evaluate_42(&self, ctx: &EvaluationContext) -> ConditionResult {
293 ctx.external
294 .evaluate("messprodukt_in_kapitel_4_6_2_smgw_list")
295 }
296
297 /// [43] Wenn innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) ein Produkt angegeben ist, das in der Codeliste der Konfigurationen...
298 /// EXTERNAL: Requires context from outside the message.
299 fn evaluate_43(&self, ctx: &EvaluationContext) -> ConditionResult {
300 ctx.external.evaluate("pia_config_schwellwert_ausloeser")
301 }
302
303 /// [44] Wenn in SG27 LIN (Erforderliches Produkt der Messlokation) das PIA+5 DE7140 mit einem Produkt-Code vorhanden ist der in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer...
304 /// EXTERNAL: Requires context from outside the message.
305 fn evaluate_44(&self, ctx: &EvaluationContext) -> ConditionResult {
306 ctx.external
307 .evaluate("pia_messlokation_weitere_energieflussrichtung")
308 }
309
310 /// [45] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist.
311 /// EXTERNAL: Requires context from outside the message.
312 fn evaluate_45(&self, ctx: &EvaluationContext) -> ConditionResult {
313 ctx.external.evaluate("loc_172_is_steuerbare_ressource")
314 }
315
316 /// [47] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Ebene" mit dem Wert "Mess...
317 /// EXTERNAL: Requires context from outside the message.
318 fn evaluate_47(&self, ctx: &EvaluationContext) -> ConditionResult {
319 ctx.external.evaluate("pia_product_code_messlokation_ebene")
320 }
321
322 /// [48] Es sind weiterhin nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Produkt gegenü...
323 /// EXTERNAL: Requires context from outside the message.
324 fn evaluate_48(&self, ctx: &EvaluationContext) -> ConditionResult {
325 ctx.external.evaluate("pia_product_code_nb_bestellbar")
326 }
327
328 /// [49] Es sind weiterhin nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Produkt gegenü...
329 /// EXTERNAL: Requires context from outside the message.
330 fn evaluate_49(&self, ctx: &EvaluationContext) -> ConditionResult {
331 ctx.external.evaluate("product_code_allowed_for_lf")
332 }
333
334 /// [50] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Ebene" mit dem Wert "Netz...
335 /// EXTERNAL: Requires context from outside the message.
336 fn evaluate_50(&self, ctx: &EvaluationContext) -> ConditionResult {
337 ctx.external.evaluate("product_code_level_netzlokation")
338 }
339
340 /// [51] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Ebene" mit dem Wert "Steu...
341 /// EXTERNAL: Requires context from outside the message.
342 fn evaluate_51(&self, ctx: &EvaluationContext) -> ConditionResult {
343 ctx.external
344 .evaluate("product_code_level_steuerbare_ressource")
345 }
346
347 /// [52] wenn im DE3155 in demselben COM der Code TE / AL vorhanden ist
348 fn evaluate_52(&self, ctx: &EvaluationContext) -> ConditionResult {
349 // wenn im DE3155 in demselben COM der Code TE / AL vorhanden ist
350 // COM segment: elements[0][0] = D3148 (address), elements[0][1] = D3155 (channel qualifier)
351 let com_segs = ctx.find_segments("COM");
352 if com_segs.is_empty() {
353 return ConditionResult::Unknown;
354 }
355 for seg in &com_segs {
356 if let Some(code) = seg.elements.first().and_then(|e| e.get(1)) {
357 if code == "TE" || code == "AL" {
358 return ConditionResult::True;
359 }
360 }
361 }
362 ConditionResult::False
363 }
364
365 /// [53] wenn der LF der Marktlokation der genannten Lokation im gewünschten Umsetzungszeitraum nicht zugeordnet ist.
366 /// EXTERNAL: Requires context from outside the message.
367 fn evaluate_53(&self, ctx: &EvaluationContext) -> ConditionResult {
368 ctx.external
369 .evaluate("lf_not_assigned_to_lokation_in_umsetzungszeitraum")
370 }
371
372 /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.
373 fn evaluate_494(&self, ctx: &EvaluationContext) -> ConditionResult {
374 // The date in this DE must be ≤ DTM+137 (Nachrichtendatum).
375 // Prefer the tree-resolved value; fall back to scanning for a
376 // non-137 DTM when unavailable.
377 let creation = match ctx
378 .find_segments_with_qualifier("DTM", 0, "137")
379 .first()
380 .and_then(|s| s.elements.first())
381 .and_then(|e| e.get(1))
382 {
383 Some(v) if !v.is_empty() => v.clone(),
384 _ => return ConditionResult::Unknown,
385 };
386 if let Some(val) = ctx.resolved_value {
387 if !val.is_empty() {
388 return ConditionResult::from(val <= creation.as_str());
389 }
390 }
391 // Fallback for non-tree callers: first non-137 DTM value.
392 for dtm in ctx.find_segments("DTM") {
393 let qual = dtm
394 .elements
395 .first()
396 .and_then(|e| e.first())
397 .map(|s| s.as_str());
398 if qual != Some("137") {
399 if let Some(val) = dtm.elements.first().and_then(|e| e.get(1)) {
400 if !val.is_empty() {
401 return ConditionResult::from(val.as_str() <= creation.as_str());
402 }
403 }
404 }
405 }
406 ConditionResult::Unknown
407 }
408
409 /// [517] Hinweis: Verwendung der ID der Technischen Ressource
410 fn evaluate_517(&self, _ctx: &EvaluationContext) -> ConditionResult {
411 // Hinweis: Verwendung der ID der Technischen Ressource — informational note, always applies
412 ConditionResult::True
413 }
414
415 /// [518] Hinweis: zur Angabe von Kontaktdaten des Kunden des Lieferanten um die Änderung an der Technik zu vereinfachen.
416 fn evaluate_518(&self, _ctx: &EvaluationContext) -> ConditionResult {
417 // Hinweis: Angabe von Kontaktdaten des Kunden des Lieferanten — informational note, always applies
418 ConditionResult::True
419 }
420
421 /// [520] Hinweis: Angabe des Beginnzeitpunkts des gewünschten Umsetzungstermins aus Sicht des Anfragenden.
422 fn evaluate_520(&self, _ctx: &EvaluationContext) -> ConditionResult {
423 // Hinweis: Angabe des Beginnzeitpunkts des gewünschten Umsetzungstermins — informational note, always applies
424 ConditionResult::True
425 }
426
427 /// [521] Hinweis: Angabe des Endezeitpunkts des gewünschten Umsetzungstermins aus Sicht des Anfragenden.
428 fn evaluate_521(&self, _ctx: &EvaluationContext) -> ConditionResult {
429 // Hinweis: Angabe des Endezeitpunkts des gewünschten Umsetzungstermins — informational note, always applies
430 ConditionResult::True
431 }
432
433 /// [911] Format: Mögliche Werte: 1 bis n, je Nachricht oder Segmentgruppe bei 1 beginnend und fortlaufend aufsteigend
434 // REVIEW: Per-field check of the value carried in the current DE (typically LIN DE1082 Positionsnummer). Verifies it parses as a positive integer (>= 1). The structural "1..n without gaps, fortlaufend" aspect is a cross-field sequence invariant that cannot be verified within the per-field `ConditionResult` model without an evaluator-level pass — documented as a known limitation; fail reports for sequence gaps would need to come from a separate structural check.
435 fn evaluate_911(&self, ctx: &EvaluationContext) -> ConditionResult {
436 let value = match ctx.resolved_value {
437 Some(v) if !v.is_empty() => v,
438 _ => return ConditionResult::Unknown,
439 };
440 // Reject leading '+', '-', decimals, leading zeros → must be a plain
441 // positive integer literal.
442 if !value.chars().all(|c| c.is_ascii_digit()) {
443 return ConditionResult::False;
444 }
445 if value.starts_with('0') {
446 // "01" and "001" are also not in "1..n" form.
447 return ConditionResult::False;
448 }
449 validate_numeric(value, ">=", 1.0)
450 }
451
452 /// [922] Format: TR-ID
453 fn evaluate_922(&self, ctx: &EvaluationContext) -> ConditionResult {
454 // Validate the resolved field as a Transaktionsreferenz-ID
455 // (1–35 alphanumeric characters).
456 match ctx.resolved_value {
457 Some(val) => validate_tr_id(val),
458 None => ConditionResult::Unknown,
459 }
460 }
461
462 /// [967] Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4
463 fn evaluate_967(&self, ctx: &EvaluationContext) -> ConditionResult {
464 // Structural check on the certificate body (base64 charset + plausible
465 // length). Cryptographic validation (signature, CA, BSI profile) is
466 // out of scope for static AHB validation.
467 match ctx.resolved_value {
468 Some(val) => validate_x509_cert_body(val),
469 None => ConditionResult::Unknown,
470 }
471 }
472
473 /// [2065] Diese SG28 ist so oft zu wiederholen, wie zu den unterschiedlichen Messprodukt-Position-Codes zu dem innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis fü...
474 /// EXTERNAL: Requires context from outside the message.
475 fn evaluate_2065(&self, ctx: &EvaluationContext) -> ConditionResult {
476 ctx.external
477 .evaluate("sg28_repetition_schwellwert_konfigurationserlaubnis_smgw")
478 }
479
480 /// [2066] Diese SG28 ist so oft zu wiederholen, wie zu den unterschiedlichen Messprodukt-Position-Codes zu dem innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis fü...
481 /// EXTERNAL: Requires context from outside the message.
482 fn evaluate_2066(&self, ctx: &EvaluationContext) -> ConditionResult {
483 ctx.external
484 .evaluate("sg28_repetition_schwellwert_werte_typ2_smgw")
485 }
486
487 /// [2067] Die SG12 RFF+Z37 Referenz auf ID der Technischen Ressource ist so oft zu wiederholen, bis alle IDs der Technischen Ressourcen angegeben sind, die der Steuerbaren Ressource in LOC+172 DE3225 (Meldep...
488 fn evaluate_2067(&self, _ctx: &EvaluationContext) -> ConditionResult {
489 // Hinweis: SG12 RFF+Z37 (Referenz auf ID der Technischen Ressource) ist so oft zu wiederholen,
490 // bis alle IDs der Technischen Ressourcen angegeben sind, die der Steuerbaren Ressource in
491 // LOC+172 DE3225 (Meldepunkt) zugeordnet werden sollen — informational repetition cardinality note.
492 ConditionResult::True
493 }
494
495 /// [2068] Diese SG27 ist so oft zu wiederholen, dass alle Produkte zur Lokation die innerhalb des gewünschten Umsetzungstermins (Zeitintervall aus DTM+469 (Startdatum oder Zeitpunkt) und DTM+472 (Endedatum...
496 fn evaluate_2068(&self, _ctx: &EvaluationContext) -> ConditionResult {
497 // Hinweis: SG27 ist so oft zu wiederholen, dass alle gewünschten Produkte zur Lokation
498 // innerhalb des Umsetzungstermins (DTM+469 bis DTM+472) genannt sind, deren Kombination
499 // gemäß Codeliste Kapitel 7 möglich ist — informational repetition cardinality note.
500 ConditionResult::True
501 }
502
503 /// [1] Wenn DTM+203 (Ausführungsdatum) nicht vorhanden
504 fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
505 ctx.lacks_qualifier("DTM", 0, "203")
506 }
507
508 /// [2] Wenn DTM+469 (Beginn zum (nächstmöglichen Termin)) nicht vorhanden
509 fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
510 ctx.lacks_qualifier("DTM", 0, "469")
511 }
512
513 /// [10] MP-ID nur aus Sparte Strom
514 /// EXTERNAL: Requires context from outside the message.
515 fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
516 ctx.external.evaluate("mp_id_strom_only")
517 }
518
519 /// [15] Wenn DTM+76 (Datum zum geplanten Leistungsbeginn) nicht vorhanden
520 fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
521 ctx.lacks_qualifier("DTM", 0, "76")
522 }
523
524 /// [16] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) nicht vorhanden
525 fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
526 ctx.lacks_qualifier("RFF", 0, "Z41")
527 }
528
529 /// [17] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) vorhanden
530 fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
531 ctx.has_qualifier("RFF", 0, "Z41")
532 }
533
534 /// [18] Wenn IMD++Z55 (Änderung Konfiguration) vorhanden
535 fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
536 ctx.has_qualifier("IMD", 1, "Z55")
537 }
538
539 /// [19] Wenn SG27 LIN++Z64 (Erforderliches Produkt Schaltzeitdefinitionen) vorhanden
540 fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
541 ctx.has_qualifier("LIN", 1, "Z64")
542 }
543
544 /// [20] Wenn SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) vorhanden
545 fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
546 ctx.has_qualifier("LIN", 1, "Z65")
547 }
548
549 /// [21] Wenn SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) vorhanden
550 fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
551 ctx.has_qualifier("LIN", 1, "Z66")
552 }
553
554 /// [22] Wenn SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) vorhanden
555 fn evaluate_22(&self, ctx: &EvaluationContext) -> ConditionResult {
556 ctx.has_qualifier("LIN", 1, "Z67")
557 }
558
559 /// [23] Wenn SG27 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) vorhanden
560 fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
561 ctx.has_qualifier("LIN", 1, "Z68")
562 }
563
564 /// [24] Wenn Produkt bestellt werden soll
565 /// EXTERNAL: Requires context from outside the message.
566 // REVIEW: Whether a product should be ordered is a business-intent condition. In a REQOTE context this could theoretically be signalled by presence of PIA+5, but the AHB phrasing 'soll bestellt werden' indicates a business decision or workflow state that cannot be reliably inferred from message structure alone. (medium confidence)
567 fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
568 ctx.external.evaluate("product_to_be_ordered")
569 }
570
571 /// [25] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist.
572 fn evaluate_25(&self, ctx: &EvaluationContext) -> ConditionResult {
573 // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist.
574 // LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
575 // Marktlokation ID: 11 digits with Luhn check digit
576 let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
577 match segs
578 .first()
579 .and_then(|s| s.elements.get(1))
580 .and_then(|e| e.first())
581 {
582 Some(val) if !val.is_empty() => validate_malo_id(val),
583 _ => ConditionResult::Unknown,
584 }
585 }
586
587 /// [26] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist.
588 fn evaluate_26(&self, ctx: &EvaluationContext) -> ConditionResult {
589 // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist.
590 // LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
591 // Messlokation ID: 33 alphanumeric characters (Zählpunkt format)
592 let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
593 match segs
594 .first()
595 .and_then(|s| s.elements.get(1))
596 .and_then(|e| e.first())
597 {
598 Some(val) if !val.is_empty() => validate_zahlpunkt(val),
599 _ => ConditionResult::Unknown,
600 }
601 }
602
603 /// [27] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist.
604 // REVIEW: Checks LOC+172 DE3225 value as a Netzlokation ID by exclusion: it is present but does not match Marktlokation format (11-digit Luhn) nor Messlokation format (33 alphanumeric). Medium confidence because there is no dedicated Netzlokation validator — the logic relies on the three location types being mutually exclusive and exhaustive for this qualifier. (medium confidence)
605 fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
606 // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist.
607 // LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
608 // Netzlokation ID: neither MaLo (11 digits Luhn) nor MeLo (33 alphanumeric)
609 let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
610 match segs
611 .first()
612 .and_then(|s| s.elements.get(1))
613 .and_then(|e| e.first())
614 {
615 Some(val) if !val.is_empty() => {
616 let is_malo = matches!(validate_malo_id(val), ConditionResult::True);
617 let is_melo = matches!(validate_zahlpunkt(val), ConditionResult::True);
618 ConditionResult::from(!is_malo && !is_melo)
619 }
620 _ => ConditionResult::Unknown,
621 }
622 }
623
624 /// [28] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist.
625 /// EXTERNAL: Requires context from outside the message.
626 fn evaluate_28(&self, ctx: &EvaluationContext) -> ConditionResult {
627 ctx.external.evaluate("loc_172_is_steuerbare_ressource")
628 }
629
630 /// [29] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.1 „Konfigurationsprodukte Schaltzeitdefinition“ enthalten sind.
631 /// EXTERNAL: Requires context from outside the message.
632 fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
633 ctx.external
634 .evaluate("product_in_konfiguration_schaltzeitdefinition")
635 }
636
637 /// [30] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.2 „Konfigurationsprodukte Leistungskurvendefinition“ enthalten sind.
638 /// EXTERNAL: Requires context from outside the message.
639 fn evaluate_30(&self, ctx: &EvaluationContext) -> ConditionResult {
640 ctx.external
641 .evaluate("product_in_konfiguration_leistungskurvendefinition")
642 }
643
644 /// [31] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.3 „Konfigurationsprodukte Ad-Hoc-Steuerkanal“ enthalten sind.
645 /// EXTERNAL: Requires context from outside the message.
646 fn evaluate_31(&self, ctx: &EvaluationContext) -> ConditionResult {
647 ctx.external
648 .evaluate("product_in_konfiguration_adhoc_steuerkanal")
649 }
650
651 /// [32] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.5 „Messprodukte für Werte nach Typ 2 aus Backend für LF und NB“ enthalten sind.
652 /// EXTERNAL: Requires context from outside the message.
653 fn evaluate_32(&self, ctx: &EvaluationContext) -> ConditionResult {
654 ctx.external.evaluate("product_in_messprodukte_typ2_lf_nb")
655 }
656
657 /// [35] Wenn MP-ID in SG11 NAD+MS mit Rolle LF vorhanden
658 /// EXTERNAL: Requires context from outside the message.
659 // REVIEW: NAD+MS identifies the sender by MP-ID (elements[0]=MS), but the market role 'LF' (Lieferant) cannot be determined from the NAD segment alone — it requires an external participant role registry lookup. The segment only carries the ID, not the role. (medium confidence)
660 fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
661 ctx.external.evaluate("sender_is_lf")
662 }
663
664 /// [36] Wenn MP-ID in SG11 NAD+MS mit Rolle NB vorhanden
665 /// EXTERNAL: Requires context from outside the message.
666 // REVIEW: Same pattern as condition 35: NAD+MS carries the sender MP-ID but the market role 'NB' (Netzbetreiber) cannot be inferred from the EDIFACT segment alone — requires external role registry. (medium confidence)
667 fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
668 ctx.external.evaluate("sender_is_nb")
669 }
670
671 /// [39] wenn im DE3155 in demselben COM der Code EM vorhanden ist
672 fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
673 // COM segment: C076 composite — elements[0][0]=DE3148 (address), elements[0][1]=DE3155 (qualifier)
674 let coms = ctx.find_segments("COM");
675 if coms.is_empty() {
676 return ConditionResult::False;
677 }
678 ConditionResult::from(coms.iter().any(|s| {
679 s.elements
680 .first()
681 .and_then(|e| e.get(1))
682 .is_some_and(|v| v == "EM")
683 }))
684 }
685
686 /// [40] wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
687 fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
688 // COM segment: C076 composite — elements[0][0]=DE3148 (address), elements[0][1]=DE3155 (qualifier)
689 // TE=Telephone, FX=Fax, AJ=Unknown, AL=Unknown (telephony-related codes)
690 let coms = ctx.find_segments("COM");
691 if coms.is_empty() {
692 return ConditionResult::False;
693 }
694 ConditionResult::from(coms.iter().any(|s| {
695 s.elements
696 .first()
697 .and_then(|e| e.get(1))
698 .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
699 }))
700 }
701
702 /// [490] wenn Wert in diesem DE, an der Stelle CCYYMMDDHHMM ein Zeitpunkt aus dem angegeben Zeitraum der Tabelle Kapitel 3.5 „Übersicht gesetzliche deutsche Sommerzeit (MESZ)“ der Spalten: „Sommerzei...
703 fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
704 match ctx.resolved_value {
705 Some(val) => is_mesz_utc(val),
706 None => ConditionResult::False,
707 }
708 }
709
710 /// [491] wenn Wert in diesem DE, an der Stelle CCYYMMDDHHMM ein Zeitpunkt aus dem angegeben Zeitraum der Tabelle Kapitel 3.6 „Übersicht gesetzliche deutsche Zeit (MEZ)“ der Spalten: „Winterzeit (MEZ)...
711 fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
712 match ctx.resolved_value {
713 Some(val) => is_mez_utc(val),
714 None => ConditionResult::False,
715 }
716 }
717
718 /// [492] wenn MP-ID in NAD+MR aus Sparte Strom
719 /// EXTERNAL: Requires context from outside the message.
720 // REVIEW: Checks whether the MP-ID in NAD+MR belongs to the electricity sector (Sparte Strom). The sector of a market participant cannot be derived from the EDIFACT message structure — it requires external market participant registry lookup. Delegated to external provider. (medium confidence)
721 fn evaluate_492(&self, ctx: &EvaluationContext) -> ConditionResult {
722 ctx.external.evaluate("recipient_is_electricity_sector")
723 }
724
725 /// [493] wenn MP-ID in NAD+MR aus Sparte Gas
726 /// EXTERNAL: Requires context from outside the message.
727 // REVIEW: Checks whether the MP-ID in NAD+MR belongs to the gas sector (Sparte Gas). Same reasoning as condition 492 — sector membership requires external registry lookup. (medium confidence)
728 fn evaluate_493(&self, ctx: &EvaluationContext) -> ConditionResult {
729 ctx.external.evaluate("recipient_is_gas_sector")
730 }
731
732 /// [500] Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
733 fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
734 // Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
735 // Informational note — always applies
736 ConditionResult::True
737 }
738
739 /// [501] Hinweis: Angabe eines Ansprechpartners für die Rechnungsabwicklung
740 fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
741 // Hinweis: Angabe eines Ansprechpartners für die Rechnungsabwicklung
742 // Informational note — always applies
743 ConditionResult::True
744 }
745
746 /// [502] Hinweis: Verwendung der ID der Marktlokation
747 fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
748 // Hinweis: Verwendung der ID der Marktlokation
749 // Informational note — always applies
750 ConditionResult::True
751 }
752
753 /// [503] Hinweis: Verwendung der ID der Messlokation
754 fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
755 // Hinweis: Verwendung der ID der Messlokation
756 // Informational note — always applies
757 ConditionResult::True
758 }
759
760 /// [504] Hinweis: Verwendung der ID der Tranche
761 fn evaluate_504(&self, _ctx: &EvaluationContext) -> ConditionResult {
762 // Hinweis: Verwendung der ID der Tranche — informational note, always applies
763 ConditionResult::True
764 }
765
766 /// [507] Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD mit BGM+E01 mit der die Anmeldung des MSB-Wechsels erfolgt ist.
767 fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
768 // Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD — informational note, always applies
769 ConditionResult::True
770 }
771
772 /// [508] Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
773 fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
774 // Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA — informational note, always applies
775 ConditionResult::True
776 }
777
778 /// [509] Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z73 mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
779 fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
780 // Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA — informational note, always applies
781 ConditionResult::True
782 }
783
784 /// [510] Hinweis: Verwendung der ID der Netzlokation
785 fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
786 // Hinweis: Verwendung der ID der Netzlokation — informational note, always applies
787 ConditionResult::True
788 }
789
790 /// [511] Hinweis: Verwendung der ID der Steuerbaren Ressource
791 fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
792 ConditionResult::True
793 }
794
795 /// [512] Hinweis: Für den Empfang der Werte nach Typ 2 aus dem SMGW.
796 fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
797 ConditionResult::True
798 }
799
800 /// [514] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
801 fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
802 ConditionResult::True
803 }
804
805 /// [515] Hinweis: Es ist eine URI IPv4 für die Bereitstellung der Werte anzugeben.
806 fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
807 ConditionResult::True
808 }
809
810 /// [516] Hinweis: Es ist eine URI IPv6 für die Bereitstellung der Werte anzugeben.
811 fn evaluate_516(&self, _ctx: &EvaluationContext) -> ConditionResult {
812 ConditionResult::True
813 }
814
815 /// [903] Format: Möglicher Wert: 1
816 fn evaluate_903(&self, _ctx: &EvaluationContext) -> ConditionResult {
817 ConditionResult::True
818 }
819
820 /// [906] Format: max. 3 Nachkommastellen
821 fn evaluate_906(&self, _ctx: &EvaluationContext) -> ConditionResult {
822 ConditionResult::True
823 }
824
825 /// [931] Format: ZZZ = +00
826 fn evaluate_931(&self, _ctx: &EvaluationContext) -> ConditionResult {
827 ConditionResult::True
828 }
829
830 /// [932] Format: HHMM = 2200
831 fn evaluate_932(&self, _ctx: &EvaluationContext) -> ConditionResult {
832 ConditionResult::True
833 }
834
835 /// [933] Format: HHMM = 2300
836 fn evaluate_933(&self, _ctx: &EvaluationContext) -> ConditionResult {
837 ConditionResult::True
838 }
839
840 /// [934] Format: HHMM = 0400
841 fn evaluate_934(&self, _ctx: &EvaluationContext) -> ConditionResult {
842 ConditionResult::True
843 }
844
845 /// [935] Format: HHMM = 0500
846 fn evaluate_935(&self, _ctx: &EvaluationContext) -> ConditionResult {
847 ConditionResult::True
848 }
849
850 /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
851 fn evaluate_939(&self, _ctx: &EvaluationContext) -> ConditionResult {
852 ConditionResult::True
853 }
854
855 /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
856 fn evaluate_940(&self, _ctx: &EvaluationContext) -> ConditionResult {
857 ConditionResult::True
858 }
859
860 /// [950] Format: Marktlokations-ID
861 fn evaluate_950(&self, _ctx: &EvaluationContext) -> ConditionResult {
862 ConditionResult::True
863 }
864
865 /// [951] Format: Zählpunktbezeichnung
866 fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
867 ctx.format_check_qualified("LOC", 0, "Z17", 1, 0, validate_zahlpunkt)
868 }
869
870 /// [960] Format: Netzlokations-ID
871 // HAND-EDITED: a Netzlokations-ID is "E" + ten alphanumerics (`E1688117482`),
872 // not MaLo-shaped; `validate_malo_id` rejected every real one (#173).
873 fn evaluate_960(&self, ctx: &EvaluationContext) -> ConditionResult {
874 ctx.format_check_qualified("LOC", 0, "Z18", 1, 0, validate_nelo_id)
875 }
876
877 /// [961] Format: SR-ID
878 // REVIEW: SR-ID (SteuerbareRessource-ID) uses the same 11-digit Luhn check digit format as MaLo-ID. LOC+Z19 is the standard qualifier for SteuerbareRessource. (medium confidence)
879 fn evaluate_961(&self, ctx: &EvaluationContext) -> ConditionResult {
880 ctx.format_check_qualified("LOC", 0, "Z19", 1, 0, validate_malo_id)
881 }
882
883 /// [962] Format: max. 6 Vorkommastellen
884 fn evaluate_962(&self, ctx: &EvaluationContext) -> ConditionResult {
885 ctx.format_check("QTY", 0, 1, |val| validate_max_integer_digits(val, 6))
886 }
887
888 /// [2005] Pro Nachricht ist die SG27 genau einmal anzugeben
889 // REVIEW: SG27 must appear exactly once per message. LIN is the entry segment for SG27. Counting all LIN segments gives the SG27 instance count. Returns True when exactly one LIN exists. (medium confidence)
890 fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
891 let lin_count = ctx.find_segments("LIN").len();
892 ConditionResult::from(lin_count == 1)
893 }
894
895 /// [2060] Pro Nachricht ist die SG27 LIN+Z64 (Erforderliches Produkt Schaltzeitdefinitionen) maximal einmal anzugeben
896 // REVIEW: LIN with DE1229=Z64 (Erforderliches Produkt Schaltzeitdefinitionen) must appear at most once. Per segment structure reference, DE1229 (Handlung, Code) is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
897 fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
898 let lins = ctx.find_segments("LIN");
899 let count = lins
900 .iter()
901 .filter(|s| {
902 s.elements
903 .get(1)
904 .and_then(|e| e.first())
905 .is_some_and(|v| v == "Z64")
906 })
907 .count();
908 ConditionResult::from(count <= 1)
909 }
910
911 /// [2061] Pro Nachricht ist die SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) maximal einmal anzugeben
912 // REVIEW: LIN with DE1229=Z65 (Erforderliches Produkt Leistungskurvendefinitionen) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
913 fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
914 let lins = ctx.find_segments("LIN");
915 let count = lins
916 .iter()
917 .filter(|s| {
918 s.elements
919 .get(1)
920 .and_then(|e| e.first())
921 .is_some_and(|v| v == "Z65")
922 })
923 .count();
924 ConditionResult::from(count <= 1)
925 }
926
927 /// [2062] Pro Nachricht ist die SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) maximal einmal anzugeben
928 // REVIEW: LIN with DE1229=Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
929 fn evaluate_2062(&self, ctx: &EvaluationContext) -> ConditionResult {
930 let lins = ctx.find_segments("LIN");
931 let count = lins
932 .iter()
933 .filter(|s| {
934 s.elements
935 .get(1)
936 .and_then(|e| e.first())
937 .is_some_and(|v| v == "Z66")
938 })
939 .count();
940 ConditionResult::from(count <= 1)
941 }
942
943 /// [2063] Pro Nachricht ist die SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) maximal einmal anzugeben
944 // REVIEW: LIN with DE1229=Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
945 fn evaluate_2063(&self, ctx: &EvaluationContext) -> ConditionResult {
946 let lins = ctx.find_segments("LIN");
947 let count = lins
948 .iter()
949 .filter(|s| {
950 s.elements
951 .get(1)
952 .and_then(|e| e.first())
953 .is_some_and(|v| v == "Z67")
954 })
955 .count();
956 ConditionResult::from(count <= 1)
957 }
958
959 /// [2064] Pro Nachricht ist die SG27 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) maximal einmal anzugeben
960 // REVIEW: LIN with DE1229=Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
961 fn evaluate_2064(&self, ctx: &EvaluationContext) -> ConditionResult {
962 let lins = ctx.find_segments("LIN");
963 let count = lins
964 .iter()
965 .filter(|s| {
966 s.elements
967 .get(1)
968 .and_then(|e| e.first())
969 .is_some_and(|v| v == "Z68")
970 })
971 .count();
972 ConditionResult::from(count <= 1)
973 }
974}