automapper_validation/generated/fv2504/orders_conditions_fv2504.rs
1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2504/ORDERS_AHB_1_0a_Fehlerkorrektur_20250623.xml
4// Generated: 2026-03-12T10:26:58Z
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 ORDERS FV2504.
17pub struct OrdersConditionEvaluatorFV2504 {
18 // External condition IDs that require runtime context.
19 external_conditions: std::collections::HashSet<u32>,
20}
21
22impl Default for OrdersConditionEvaluatorFV2504 {
23 fn default() -> Self {
24 let mut external_conditions = std::collections::HashSet::new();
25 external_conditions.insert(6);
26 external_conditions.insert(7);
27 external_conditions.insert(9);
28 external_conditions.insert(15);
29 external_conditions.insert(16);
30 external_conditions.insert(17);
31 external_conditions.insert(23);
32 external_conditions.insert(26);
33 external_conditions.insert(27);
34 external_conditions.insert(28);
35 external_conditions.insert(29);
36 external_conditions.insert(36);
37 external_conditions.insert(45);
38 external_conditions.insert(60);
39 external_conditions.insert(61);
40 external_conditions.insert(62);
41 external_conditions.insert(63);
42 external_conditions.insert(76);
43 external_conditions.insert(78);
44 external_conditions.insert(82);
45 external_conditions.insert(86);
46 external_conditions.insert(91);
47 external_conditions.insert(95);
48 external_conditions.insert(96);
49 external_conditions.insert(100);
50 external_conditions.insert(101);
51 external_conditions.insert(104);
52 external_conditions.insert(105);
53 external_conditions.insert(125);
54 external_conditions.insert(126);
55 external_conditions.insert(127);
56 external_conditions.insert(128);
57 external_conditions.insert(129);
58 external_conditions.insert(131);
59 external_conditions.insert(132);
60 external_conditions.insert(133);
61 external_conditions.insert(140);
62 external_conditions.insert(141);
63 external_conditions.insert(142);
64 external_conditions.insert(143);
65 external_conditions.insert(152);
66 external_conditions.insert(153);
67 external_conditions.insert(154);
68 external_conditions.insert(155);
69 external_conditions.insert(156);
70 external_conditions.insert(157);
71 external_conditions.insert(164);
72 external_conditions.insert(165);
73 external_conditions.insert(166);
74 external_conditions.insert(172);
75 external_conditions.insert(178);
76 external_conditions.insert(179);
77 external_conditions.insert(492);
78 external_conditions.insert(493);
79 external_conditions.insert(2001);
80 external_conditions.insert(2065);
81 Self {
82 external_conditions,
83 }
84 }
85}
86
87impl ConditionEvaluator for OrdersConditionEvaluatorFV2504 {
88 fn message_type(&self) -> &str {
89 "ORDERS"
90 }
91
92 fn format_version(&self) -> &str {
93 "FV2504"
94 }
95
96 fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
97 match condition {
98 1 => self.evaluate_1(ctx),
99 2 => self.evaluate_2(ctx),
100 6 => self.evaluate_6(ctx),
101 7 => self.evaluate_7(ctx),
102 9 => self.evaluate_9(ctx),
103 12 => self.evaluate_12(ctx),
104 13 => self.evaluate_13(ctx),
105 15 => self.evaluate_15(ctx),
106 16 => self.evaluate_16(ctx),
107 17 => self.evaluate_17(ctx),
108 18 => self.evaluate_18(ctx),
109 19 => self.evaluate_19(ctx),
110 21 => self.evaluate_21(ctx),
111 23 => self.evaluate_23(ctx),
112 24 => self.evaluate_24(ctx),
113 26 => self.evaluate_26(ctx),
114 27 => self.evaluate_27(ctx),
115 28 => self.evaluate_28(ctx),
116 29 => self.evaluate_29(ctx),
117 33 => self.evaluate_33(ctx),
118 34 => self.evaluate_34(ctx),
119 35 => self.evaluate_35(ctx),
120 36 => self.evaluate_36(ctx),
121 38 => self.evaluate_38(ctx),
122 45 => self.evaluate_45(ctx),
123 46 => self.evaluate_46(ctx),
124 47 => self.evaluate_47(ctx),
125 51 => self.evaluate_51(ctx),
126 54 => self.evaluate_54(ctx),
127 55 => self.evaluate_55(ctx),
128 56 => self.evaluate_56(ctx),
129 57 => self.evaluate_57(ctx),
130 60 => self.evaluate_60(ctx),
131 61 => self.evaluate_61(ctx),
132 62 => self.evaluate_62(ctx),
133 63 => self.evaluate_63(ctx),
134 64 => self.evaluate_64(ctx),
135 65 => self.evaluate_65(ctx),
136 67 => self.evaluate_67(ctx),
137 68 => self.evaluate_68(ctx),
138 69 => self.evaluate_69(ctx),
139 70 => self.evaluate_70(ctx),
140 76 => self.evaluate_76(ctx),
141 77 => self.evaluate_77(ctx),
142 78 => self.evaluate_78(ctx),
143 79 => self.evaluate_79(ctx),
144 80 => self.evaluate_80(ctx),
145 81 => self.evaluate_81(ctx),
146 82 => self.evaluate_82(ctx),
147 83 => self.evaluate_83(ctx),
148 84 => self.evaluate_84(ctx),
149 85 => self.evaluate_85(ctx),
150 86 => self.evaluate_86(ctx),
151 87 => self.evaluate_87(ctx),
152 91 => self.evaluate_91(ctx),
153 93 => self.evaluate_93(ctx),
154 94 => self.evaluate_94(ctx),
155 95 => self.evaluate_95(ctx),
156 96 => self.evaluate_96(ctx),
157 97 => self.evaluate_97(ctx),
158 99 => self.evaluate_99(ctx),
159 100 => self.evaluate_100(ctx),
160 101 => self.evaluate_101(ctx),
161 102 => self.evaluate_102(ctx),
162 103 => self.evaluate_103(ctx),
163 104 => self.evaluate_104(ctx),
164 105 => self.evaluate_105(ctx),
165 106 => self.evaluate_106(ctx),
166 107 => self.evaluate_107(ctx),
167 108 => self.evaluate_108(ctx),
168 109 => self.evaluate_109(ctx),
169 110 => self.evaluate_110(ctx),
170 112 => self.evaluate_112(ctx),
171 113 => self.evaluate_113(ctx),
172 114 => self.evaluate_114(ctx),
173 115 => self.evaluate_115(ctx),
174 117 => self.evaluate_117(ctx),
175 118 => self.evaluate_118(ctx),
176 119 => self.evaluate_119(ctx),
177 120 => self.evaluate_120(ctx),
178 121 => self.evaluate_121(ctx),
179 122 => self.evaluate_122(ctx),
180 123 => self.evaluate_123(ctx),
181 124 => self.evaluate_124(ctx),
182 125 => self.evaluate_125(ctx),
183 126 => self.evaluate_126(ctx),
184 127 => self.evaluate_127(ctx),
185 128 => self.evaluate_128(ctx),
186 129 => self.evaluate_129(ctx),
187 130 => self.evaluate_130(ctx),
188 131 => self.evaluate_131(ctx),
189 132 => self.evaluate_132(ctx),
190 133 => self.evaluate_133(ctx),
191 134 => self.evaluate_134(ctx),
192 135 => self.evaluate_135(ctx),
193 136 => self.evaluate_136(ctx),
194 137 => self.evaluate_137(ctx),
195 138 => self.evaluate_138(ctx),
196 139 => self.evaluate_139(ctx),
197 140 => self.evaluate_140(ctx),
198 141 => self.evaluate_141(ctx),
199 142 => self.evaluate_142(ctx),
200 143 => self.evaluate_143(ctx),
201 147 => self.evaluate_147(ctx),
202 148 => self.evaluate_148(ctx),
203 152 => self.evaluate_152(ctx),
204 153 => self.evaluate_153(ctx),
205 154 => self.evaluate_154(ctx),
206 155 => self.evaluate_155(ctx),
207 156 => self.evaluate_156(ctx),
208 157 => self.evaluate_157(ctx),
209 158 => self.evaluate_158(ctx),
210 159 => self.evaluate_159(ctx),
211 160 => self.evaluate_160(ctx),
212 161 => self.evaluate_161(ctx),
213 162 => self.evaluate_162(ctx),
214 163 => self.evaluate_163(ctx),
215 164 => self.evaluate_164(ctx),
216 165 => self.evaluate_165(ctx),
217 166 => self.evaluate_166(ctx),
218 167 => self.evaluate_167(ctx),
219 168 => self.evaluate_168(ctx),
220 169 => self.evaluate_169(ctx),
221 170 => self.evaluate_170(ctx),
222 171 => self.evaluate_171(ctx),
223 172 => self.evaluate_172(ctx),
224 173 => self.evaluate_173(ctx),
225 174 => self.evaluate_174(ctx),
226 175 => self.evaluate_175(ctx),
227 176 => self.evaluate_176(ctx),
228 177 => self.evaluate_177(ctx),
229 178 => self.evaluate_178(ctx),
230 179 => self.evaluate_179(ctx),
231 180 => self.evaluate_180(ctx),
232 490 => self.evaluate_490(ctx),
233 491 => self.evaluate_491(ctx),
234 492 => self.evaluate_492(ctx),
235 493 => self.evaluate_493(ctx),
236 494 => self.evaluate_494(ctx),
237 495 => self.evaluate_495(ctx),
238 500 => self.evaluate_500(ctx),
239 501 => self.evaluate_501(ctx),
240 503 => self.evaluate_503(ctx),
241 506 => self.evaluate_506(ctx),
242 507 => self.evaluate_507(ctx),
243 514 => self.evaluate_514(ctx),
244 515 => self.evaluate_515(ctx),
245 517 => self.evaluate_517(ctx),
246 518 => self.evaluate_518(ctx),
247 519 => self.evaluate_519(ctx),
248 521 => self.evaluate_521(ctx),
249 522 => self.evaluate_522(ctx),
250 523 => self.evaluate_523(ctx),
251 525 => self.evaluate_525(ctx),
252 527 => self.evaluate_527(ctx),
253 530 => self.evaluate_530(ctx),
254 531 => self.evaluate_531(ctx),
255 532 => self.evaluate_532(ctx),
256 533 => self.evaluate_533(ctx),
257 535 => self.evaluate_535(ctx),
258 536 => self.evaluate_536(ctx),
259 539 => self.evaluate_539(ctx),
260 540 => self.evaluate_540(ctx),
261 542 => self.evaluate_542(ctx),
262 543 => self.evaluate_543(ctx),
263 545 => self.evaluate_545(ctx),
264 547 => self.evaluate_547(ctx),
265 548 => self.evaluate_548(ctx),
266 549 => self.evaluate_549(ctx),
267 550 => self.evaluate_550(ctx),
268 551 => self.evaluate_551(ctx),
269 552 => self.evaluate_552(ctx),
270 553 => self.evaluate_553(ctx),
271 554 => self.evaluate_554(ctx),
272 555 => self.evaluate_555(ctx),
273 557 => self.evaluate_557(ctx),
274 558 => self.evaluate_558(ctx),
275 559 => self.evaluate_559(ctx),
276 560 => self.evaluate_560(ctx),
277 561 => self.evaluate_561(ctx),
278 562 => self.evaluate_562(ctx),
279 563 => self.evaluate_563(ctx),
280 564 => self.evaluate_564(ctx),
281 566 => self.evaluate_566(ctx),
282 567 => self.evaluate_567(ctx),
283 568 => self.evaluate_568(ctx),
284 569 => self.evaluate_569(ctx),
285 570 => self.evaluate_570(ctx),
286 571 => self.evaluate_571(ctx),
287 572 => self.evaluate_572(ctx),
288 573 => self.evaluate_573(ctx),
289 574 => self.evaluate_574(ctx),
290 575 => self.evaluate_575(ctx),
291 576 => self.evaluate_576(ctx),
292 903 => self.evaluate_903(ctx),
293 906 => self.evaluate_906(ctx),
294 911 => self.evaluate_911(ctx),
295 914 => self.evaluate_914(ctx),
296 922 => self.evaluate_922(ctx),
297 930 => self.evaluate_930(ctx),
298 931 => self.evaluate_931(ctx),
299 932 => self.evaluate_932(ctx),
300 933 => self.evaluate_933(ctx),
301 934 => self.evaluate_934(ctx),
302 935 => self.evaluate_935(ctx),
303 939 => self.evaluate_939(ctx),
304 940 => self.evaluate_940(ctx),
305 950 => self.evaluate_950(ctx),
306 951 => self.evaluate_951(ctx),
307 955 => self.evaluate_955(ctx),
308 960 => self.evaluate_960(ctx),
309 961 => self.evaluate_961(ctx),
310 962 => self.evaluate_962(ctx),
311 967 => self.evaluate_967(ctx),
312 2001 => self.evaluate_2001(ctx),
313 2002 => self.evaluate_2002(ctx),
314 2003 => self.evaluate_2003(ctx),
315 2004 => self.evaluate_2004(ctx),
316 2005 => self.evaluate_2005(ctx),
317 2006 => self.evaluate_2006(ctx),
318 2007 => self.evaluate_2007(ctx),
319 2044 => self.evaluate_2044(ctx),
320 2050 => self.evaluate_2050(ctx),
321 2060 => self.evaluate_2060(ctx),
322 2061 => self.evaluate_2061(ctx),
323 2062 => self.evaluate_2062(ctx),
324 2063 => self.evaluate_2063(ctx),
325 2064 => self.evaluate_2064(ctx),
326 2065 => self.evaluate_2065(ctx),
327 2066 => self.evaluate_2066(ctx),
328 2088 => self.evaluate_2088(ctx),
329 2089 => self.evaluate_2089(ctx),
330 2090 => self.evaluate_2090(ctx),
331 2092 => self.evaluate_2092(ctx),
332 2094 => self.evaluate_2094(ctx),
333 2095 => self.evaluate_2095(ctx),
334 2096 => self.evaluate_2096(ctx),
335 2097 => self.evaluate_2097(ctx),
336 2098 => self.evaluate_2098(ctx),
337 2099 => self.evaluate_2099(ctx),
338 _ => ConditionResult::Unknown,
339 }
340 }
341
342 fn is_external(&self, condition: u32) -> bool {
343 self.external_conditions.contains(&condition)
344 }
345 fn is_known(&self, condition: u32) -> bool {
346 matches!(
347 condition,
348 1 | 2
349 | 6
350 | 7
351 | 9
352 | 12
353 | 13
354 | 15
355 | 16
356 | 17
357 | 18
358 | 19
359 | 21
360 | 23
361 | 24
362 | 26
363 | 27
364 | 28
365 | 29
366 | 33
367 | 34
368 | 35
369 | 36
370 | 38
371 | 45
372 | 46
373 | 47
374 | 51
375 | 54
376 | 55
377 | 56
378 | 57
379 | 60
380 | 61
381 | 62
382 | 63
383 | 64
384 | 65
385 | 67
386 | 68
387 | 69
388 | 70
389 | 76
390 | 77
391 | 78
392 | 79
393 | 80
394 | 81
395 | 82
396 | 83
397 | 84
398 | 85
399 | 86
400 | 87
401 | 91
402 | 93
403 | 94
404 | 95
405 | 96
406 | 97
407 | 99
408 | 100
409 | 101
410 | 102
411 | 103
412 | 104
413 | 105
414 | 106
415 | 107
416 | 108
417 | 109
418 | 110
419 | 112
420 | 113
421 | 114
422 | 115
423 | 117
424 | 118
425 | 119
426 | 120
427 | 121
428 | 122
429 | 123
430 | 124
431 | 125
432 | 126
433 | 127
434 | 128
435 | 129
436 | 130
437 | 131
438 | 132
439 | 133
440 | 134
441 | 135
442 | 136
443 | 137
444 | 138
445 | 139
446 | 140
447 | 141
448 | 142
449 | 143
450 | 147
451 | 148
452 | 152
453 | 153
454 | 154
455 | 155
456 | 156
457 | 157
458 | 158
459 | 159
460 | 160
461 | 161
462 | 162
463 | 163
464 | 164
465 | 165
466 | 166
467 | 167
468 | 168
469 | 169
470 | 170
471 | 171
472 | 172
473 | 173
474 | 174
475 | 175
476 | 176
477 | 177
478 | 178
479 | 179
480 | 180
481 | 490
482 | 491
483 | 492
484 | 493
485 | 494
486 | 495
487 | 500
488 | 501
489 | 503
490 | 506
491 | 507
492 | 514
493 | 515
494 | 517
495 | 518
496 | 519
497 | 521
498 | 522
499 | 523
500 | 525
501 | 527
502 | 530
503 | 531
504 | 532
505 | 533
506 | 535
507 | 536
508 | 539
509 | 540
510 | 542
511 | 543
512 | 545
513 | 547
514 | 548
515 | 549
516 | 550
517 | 551
518 | 552
519 | 553
520 | 554
521 | 555
522 | 557
523 | 558
524 | 559
525 | 560
526 | 561
527 | 562
528 | 563
529 | 564
530 | 566
531 | 567
532 | 568
533 | 569
534 | 570
535 | 571
536 | 572
537 | 573
538 | 574
539 | 575
540 | 576
541 | 903
542 | 906
543 | 911
544 | 914
545 | 922
546 | 930
547 | 931
548 | 932
549 | 933
550 | 934
551 | 935
552 | 939
553 | 940
554 | 950
555 | 951
556 | 955
557 | 960
558 | 961
559 | 962
560 | 967
561 | 2001
562 | 2002
563 | 2003
564 | 2004
565 | 2005
566 | 2006
567 | 2007
568 | 2044
569 | 2050
570 | 2060
571 | 2061
572 | 2062
573 | 2063
574 | 2064
575 | 2065
576 | 2066
577 | 2088
578 | 2089
579 | 2090
580 | 2092
581 | 2094
582 | 2095
583 | 2096
584 | 2097
585 | 2098
586 | 2099
587 )
588 }
589}
590
591impl OrdersConditionEvaluatorFV2504 {
592 /// [16] Wenn eine untergeordnete SG vorhanden
593 /// EXTERNAL: Requires context from outside the message.
594 // REVIEW: Generic structural condition: 'if a subordinate SG is present'. Depends entirely on which child segment group is being checked in context — the condition number is reused across many segment rows with different child SGs. Cannot be resolved from the EDIFACT message content alone; requires the validation framework to supply structural position context. (medium confidence)
595 fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
596 ctx.external.evaluate("subordinate_sg_present")
597 }
598
599 /// [17] Wenn ein Segment innerhalb der SG vorhanden
600 /// EXTERNAL: Requires context from outside the message.
601 // REVIEW: Generic structural condition: 'if a segment within the SG is present'. Like [16], this condition number is reused across many rows and the specific segment being checked depends on the validation context. Cannot determine which segment to check without positional context supplied externally. (medium confidence)
602 fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
603 ctx.external.evaluate("segment_within_sg_present")
604 }
605
606 /// [78] Wenn in derselben SG29 mit Z55 in LIN DE1229 (Erforderliches Produkt der Netzlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen, Kapitel 2 „Codeliste der Standard-...
607 /// EXTERNAL: Requires context from outside the message.
608 // REVIEW: Requires checking PIA DE7140 against an external code list from 'Codeliste der Konfigurationen, Kapitel 2 – Codeliste der Standard-Messprodukt Strom für Werte nach Typ 1' filtered to those with the Werteigenschaft 'Blindarbeit'. The structural check (LIN Z55 + PIA+5 in same SG29) is possible via navigator, but the code list membership for 'Blindarbeit' products is an external reference that cannot be determined from the EDIFACT message alone. (medium confidence)
609 fn evaluate_78(&self, ctx: &EvaluationContext) -> ConditionResult {
610 ctx.external
611 .evaluate("pia_has_blindarbeit_product_netzlokation")
612 }
613
614 /// [82] Wenn eine andere SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation) mit PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen, Kapitel 2.1.1 „Standard-Messproduk...
615 /// EXTERNAL: Requires context from outside the message.
616 // REVIEW: Requires: (1) finding ANOTHER SG29 (not the current one) where LIN DE1229 = Z54, (2) that SG29 also has PIA+5, and (3) PIA DE7140 is from 'Codeliste der Konfigurationen, Kapitel 2.1.1 – Standard-Messprodukt der Marktlokation mit der Wahlmöglichkeit der Zuordnung einer Zählzeit'. The code list membership is external and cannot be determined from the EDIFACT message alone. (medium confidence)
617 fn evaluate_82(&self, ctx: &EvaluationContext) -> ConditionResult {
618 ctx.external
619 .evaluate("other_sg29_z54_with_zaehlzeit_product")
620 }
621
622 /// [83] Wenn keine andere SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation) mit PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.1.1 „Standard-Messproduk...
623 // REVIEW: Logical negation of condition [82]: 'wenn KEINE andere SG29 mit Z54 ... vorhanden ist'. Implemented by inverting the external result for [82]. Returns Unknown when the underlying external condition is Unknown (e.g., code list not available). (medium confidence)
624 fn evaluate_83(&self, ctx: &EvaluationContext) -> ConditionResult {
625 match ctx
626 .external
627 .evaluate("other_sg29_z54_with_zaehlzeit_product")
628 {
629 ConditionResult::True => ConditionResult::False,
630 ConditionResult::False => ConditionResult::True,
631 ConditionResult::Unknown => ConditionResult::Unknown,
632 }
633 }
634
635 /// [86] Wenn in derselben SG29 mit Z19 in LIN DE1229 (Erforderliches Produkt der Messlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.3.1 "Standard-Messprodukt d...
636 /// EXTERNAL: Requires context from outside the message.
637 fn evaluate_86(&self, ctx: &EvaluationContext) -> ConditionResult {
638 ctx.external
639 .evaluate("pia_z19_has_standard_messprodukt_with_zählzeit_wahlmöglichkeit")
640 }
641
642 /// [91] Wenn in diesem Datenelement kein anderes Paket zur Möglichkeit der Angabe von mindestens einem anderen Code führt.
643 /// EXTERNAL: Requires context from outside the message.
644 fn evaluate_91(&self, ctx: &EvaluationContext) -> ConditionResult {
645 ctx.external
646 .evaluate("no_other_package_enables_additional_code")
647 }
648
649 /// [126] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.2 „Konfigurationsprodukte Leistungskurvendefinition“ enthalten sind.
650 /// EXTERNAL: Requires context from outside the message.
651 fn evaluate_126(&self, ctx: &EvaluationContext) -> ConditionResult {
652 ctx.external
653 .evaluate("product_in_konfigurationsprodukte_leistungskurvendefinition")
654 }
655
656 /// [127] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.3 „Konfigurationsprodukte Ad-Hoc-Steuerkanal“ enthalten sind.
657 /// EXTERNAL: Requires context from outside the message.
658 fn evaluate_127(&self, ctx: &EvaluationContext) -> ConditionResult {
659 ctx.external
660 .evaluate("product_in_konfigurationsprodukte_ad_hoc_steuerkanal")
661 }
662
663 /// [128] 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.
664 /// EXTERNAL: Requires context from outside the message.
665 fn evaluate_128(&self, ctx: &EvaluationContext) -> ConditionResult {
666 ctx.external
667 .evaluate("product_in_messprodukte_typ2_backend_lf_nb")
668 }
669
670 /// [129] 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.
671 /// EXTERNAL: Requires context from outside the message.
672 fn evaluate_129(&self, ctx: &EvaluationContext) -> ConditionResult {
673 ctx.external
674 .evaluate("product_in_smgw_typ2_konfiguration_codeliste")
675 }
676
677 /// [141] 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.
678 /// EXTERNAL: Requires context from outside the message.
679 fn evaluate_141(&self, ctx: &EvaluationContext) -> ConditionResult {
680 ctx.external
681 .evaluate("messprodukt_position_code_in_typ2_art_codeliste")
682 }
683
684 /// [142] Wenn innerhalb derselben SG29 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...
685 /// EXTERNAL: Requires context from outside the message.
686 fn evaluate_142(&self, ctx: &EvaluationContext) -> ConditionResult {
687 ctx.external
688 .evaluate("smgw_product_triggers_on_threshold_crossing")
689 }
690
691 /// [143] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist
692 /// EXTERNAL: Requires context from outside the message.
693 fn evaluate_143(&self, ctx: &EvaluationContext) -> ConditionResult {
694 ctx.external.evaluate("meldepunkt_is_steuerbare_ressource")
695 }
696
697 /// [152] Wenn in SG29 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...
698 /// EXTERNAL: Requires context from outside the message.
699 fn evaluate_152(&self, ctx: &EvaluationContext) -> ConditionResult {
700 ctx.external
701 .evaluate("messlokation_product_is_weitere_energieflussrichtung")
702 }
703
704 /// [153] 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...
705 /// EXTERNAL: Requires context from outside the message.
706 fn evaluate_153(&self, ctx: &EvaluationContext) -> ConditionResult {
707 ctx.external.evaluate("product_code_level_messlokation")
708 }
709
710 /// [154] 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...
711 /// EXTERNAL: Requires context from outside the message.
712 fn evaluate_154(&self, ctx: &EvaluationContext) -> ConditionResult {
713 ctx.external.evaluate("product_code_level_netzlokation")
714 }
715
716 /// [155] 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...
717 /// EXTERNAL: Requires context from outside the message.
718 fn evaluate_155(&self, ctx: &EvaluationContext) -> ConditionResult {
719 ctx.external
720 .evaluate("product_code_level_steuerbare_ressource")
721 }
722
723 /// [156] 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ü...
724 /// EXTERNAL: Requires context from outside the message.
725 fn evaluate_156(&self, ctx: &EvaluationContext) -> ConditionResult {
726 ctx.external.evaluate("product_code_orderable_by_nb")
727 }
728
729 /// [157] 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ü...
730 /// EXTERNAL: Requires context from outside the message.
731 fn evaluate_157(&self, ctx: &EvaluationContext) -> ConditionResult {
732 ctx.external.evaluate("product_code_orderable_by_lf")
733 }
734
735 /// [158] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 6.2 "Produkte zur Bestellung einer Änderung von Abrechnungsdaten" genannt sind.
736 fn evaluate_158(&self, ctx: &EvaluationContext) -> ConditionResult {
737 // HAND-EDITED: Codeliste der Konfigurationen 1.3c, Kapitel 6.2 (embedded).
738 crate::eval::abrechnungsdaten::product_is_listed(
739 ctx,
740 crate::eval::abrechnungsdaten::Edition::V1_3c,
741 )
742 }
743
744 /// [159] Wenn in derselben SG29 LIN im PIA+5 (Erforderliches Produkt Abrechnungsdaten) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6.2 "Produkte zur Bestellung e...
745 fn evaluate_159(&self, ctx: &EvaluationContext) -> ConditionResult {
746 // HAND-EDITED: Codeliste der Konfigurationen 1.3c, Kapitel 6.2 (embedded).
747 crate::eval::abrechnungsdaten::has_property_codes(
748 ctx,
749 crate::eval::abrechnungsdaten::Edition::V1_3c,
750 )
751 }
752
753 /// [160] Es sind nur die Codes der Produkteigenschaft zu dem in derselben SG29 LIN im PIA+5 (Erforderliches Produkt Abrechnungsdaten) DE7140 erlaubt, die in der Codeliste der Konfigurationen im Kapitel 6.2 ...
754 fn evaluate_160(&self, ctx: &EvaluationContext) -> ConditionResult {
755 // HAND-EDITED: Codeliste der Konfigurationen 1.3c, Kapitel 6.2 (embedded).
756 crate::eval::abrechnungsdaten::property_code_allowed(
757 ctx,
758 crate::eval::abrechnungsdaten::Edition::V1_3c,
759 )
760 }
761
762 /// [162] Es ist nur der Wertebereich erlaubt, der zu dem in derselben SG29 LIN im PIA+5 (Erforderliches Produkt Abrechnungsdaten) DE7140 genannten Produkt, das in der Codeliste der Konfigurationen im Kapite...
763 fn evaluate_162(&self, ctx: &EvaluationContext) -> ConditionResult {
764 // HAND-EDITED: Codeliste der Konfigurationen 1.3c, Kapitel 6.2 (embedded).
765 crate::eval::abrechnungsdaten::wertedetails_value_fits(
766 ctx,
767 crate::eval::abrechnungsdaten::Edition::V1_3c,
768 )
769 }
770
771 /// [164] Wenn die Konfiguration der in SG34 RFF+Z20 DE1154 (Referenz auf ID der Tranche) genannte Tranche innerhalb derselben SG29 LIN++Z16 (Erforderliches Produkt der Tranche) unverändert bestehen bleibt.
772 /// EXTERNAL: Requires context from outside the message.
773 fn evaluate_164(&self, ctx: &EvaluationContext) -> ConditionResult {
774 ctx.external.evaluate("tranche_configuration_unchanged")
775 }
776
777 /// [165] Wenn die Konfiguration der in SG34 RFF+Z20 DE1154 (Referenz auf ID der Tranche) genannte Tranche innerhalb derselben SG29 LIN++Z16 (Erforderliches Produkt der Tranche) aufgrund einer Zuordnung eine...
778 /// EXTERNAL: Requires context from outside the message.
779 fn evaluate_165(&self, ctx: &EvaluationContext) -> ConditionResult {
780 ctx.external
781 .evaluate("tranche_reconfiguration_by_lf_assignment")
782 }
783
784 /// [166] Wenn es sich um die Einrichtung der Konfigurationen aufgrund einer Zuordnung eines LF zu einer Tranche handelt
785 /// EXTERNAL: Requires context from outside the message.
786 fn evaluate_166(&self, ctx: &EvaluationContext) -> ConditionResult {
787 ctx.external
788 .evaluate("configuration_setup_by_lf_tranche_assignment")
789 }
790
791 /// [172] Wenn es sich bei der in SG2 LOC+172 DE3225 genannten Lokation um die Integration in eine Kundenanlage oder Herauslösung aus einer Kundenanlage nach §20 Abs.1d EnWG handelt. Details siehe UTILMD A...
792 /// EXTERNAL: Requires context from outside the message.
793 fn evaluate_172(&self, ctx: &EvaluationContext) -> ConditionResult {
794 ctx.external
795 .evaluate("location_is_kundenanlage_integration_or_removal")
796 }
797
798 /// [178] Wenn vom NB eine Abtretungserklärung vom Kunden gewünscht ist.
799 /// EXTERNAL: Requires context from outside the message.
800 fn evaluate_178(&self, ctx: &EvaluationContext) -> ConditionResult {
801 ctx.external.evaluate("nb_requires_assignment_declaration")
802 }
803
804 /// [179] Wenn in derselben SG29 LIN im PIA+5 (Erforderliches Produkt Abrechnungsdaten) DE7140 das Produkt "Empfänger der Vergütung zur Einspeisung" aus der Codeliste der Konfigurationen im Kapitel 6.2 "Pr...
805 /// EXTERNAL: Requires context from outside the message — codelist chapter 6.2 "Produkte zur Bestellung …" defines the product codes.
806 fn evaluate_179(&self, ctx: &EvaluationContext) -> ConditionResult {
807 ctx.external
808 .evaluate("empfaenger_verguetung_einspeisung_and_lieferant")
809 }
810
811 /// [180] Wenn in derselben SG29 LIN im PIA+5 (Erforderliches Produkt Abrechnungsdaten) DE7140 ein Produkt-Code genannt ist der in der Codeliste der Konfigurationen im Kapitel 6.2 "Produkte zur Bestellung ei...
812 fn evaluate_180(&self, ctx: &EvaluationContext) -> ConditionResult {
813 // HAND-EDITED: Codeliste der Konfigurationen 1.3c, Kapitel 6.2 (embedded).
814 crate::eval::abrechnungsdaten::has_wertedetails(
815 ctx,
816 crate::eval::abrechnungsdaten::Edition::V1_3c,
817 )
818 }
819
820 /// [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...
821 fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
822 match ctx.resolved_value {
823 Some(val) => is_mesz_utc(val),
824 None => ConditionResult::False,
825 }
826 }
827
828 /// [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)...
829 fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
830 match ctx.resolved_value {
831 Some(val) => is_mez_utc(val),
832 None => ConditionResult::False,
833 }
834 }
835
836 /// [967] Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4
837 fn evaluate_967(&self, ctx: &EvaluationContext) -> ConditionResult {
838 // Structural check on the certificate body (base64 charset + plausible
839 // length). Cryptographic validation (signature, CA, BSI profile) is
840 // out of scope for static AHB validation.
841 match ctx.resolved_value {
842 Some(val) => validate_x509_cert_body(val),
843 None => ConditionResult::Unknown,
844 }
845 }
846
847 /// [2001] Die SG29 ist so oft zu wiederholen, wie ab dem DTM+203 (Ausführungsdatum) Tranchen zu der in der SG2 genannten Marktlokation vorhanden sind.
848 /// EXTERNAL: Requires context from outside the message.
849 fn evaluate_2001(&self, ctx: &EvaluationContext) -> ConditionResult {
850 ctx.external.evaluate("sg29_tranche_count_matches")
851 }
852
853 /// [2003] Die SG29 ist so oft zu wiederholen, wie ab dem DTM+203 (Ausführungsdatum) Messlokationen zu der in der SG2 genannten Marktlokation vorhanden sind und für jede dieser Messlokationen müssen alle M...
854 fn evaluate_2003(&self, _ctx: &EvaluationContext) -> ConditionResult {
855 // Hinweis: SG29 repetition cardinality rule — informational annotation documenting that
856 // SG29 must repeat once per Messlokation associated with the Marktlokation from DTM+203,
857 // and all Messprodukte for each Messlokation (including Tranchen) must be listed.
858 // This is a structural cardinality guidance note, always applies.
859 ConditionResult::True
860 }
861
862 /// [2065] Diese SG30 ist so oft zu wiederholen, wie zu den unterschiedlichen Messprodukt-Position-Codes zu dem innerhalb derselben SG29 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis fü...
863 /// EXTERNAL: Requires context from outside the message.
864 fn evaluate_2065(&self, ctx: &EvaluationContext) -> ConditionResult {
865 ctx.external
866 .evaluate("sg30_configuration_threshold_product_cardinality")
867 }
868
869 /// [1] Wenn IMD+Z03 vorhanden
870 fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
871 ctx.has_qualifier("IMD", 0, "Z03")
872 }
873
874 /// [2] Wenn BGM+7 vorhanden
875 fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
876 ctx.has_qualifier("BGM", 0, "7")
877 }
878
879 /// [6] Wenn MP-ID in SG2 NAD+MS mit Rolle LF vorhanden
880 /// EXTERNAL: Requires context from outside the message.
881 fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
882 ctx.external.evaluate("sender_is_lf")
883 }
884
885 /// [7] Wenn MP-ID in SG2 NAD+MS mit Rolle NB vorhanden
886 /// EXTERNAL: Requires context from outside the message.
887 fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
888 ctx.external.evaluate("sender_is_nb")
889 }
890
891 /// [9] Wenn bekannt
892 /// EXTERNAL: Requires context from outside the message.
893 // REVIEW: 'Wenn bekannt' (when known) depends on whether a value is known in the business context — cannot be derived from EDIFACT segments alone. (medium confidence)
894 fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
895 ctx.external.evaluate("information_is_known")
896 }
897
898 /// [12] Wenn vorhanden
899 // REVIEW: Condition 12 'Wenn vorhanden' is a generic self-referential meta-condition indicating that the attached validation rule applies whenever the field is populated. The validator framework handles actual presence detection; this evaluator simply returns True to indicate the rule is always applicable when invoked. (medium confidence)
900 fn evaluate_12(&self, _ctx: &EvaluationContext) -> ConditionResult {
901 // Wenn vorhanden — generic 'when present' meta-condition
902 // In AHB context this means: validation applies whenever the field is populated.
903 // Returning True here defers the presence check to the validator framework itself.
904 ConditionResult::True
905 }
906
907 /// [13] Wenn SG2 LOC+172 nicht vorhanden
908 fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
909 ctx.lacks_qualifier("LOC", 0, "172")
910 }
911
912 /// [15] Wenn MP-ID in SG2 NAD+MS mit Rolle MSB vorhanden
913 /// EXTERNAL: Requires context from outside the message.
914 fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
915 ctx.external.evaluate("sender_is_msb")
916 }
917
918 /// [18] Wenn IMD++Z11 vorhanden
919 fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
920 let imds = ctx.find_segments("IMD");
921 ConditionResult::from(imds.iter().any(|s| {
922 s.elements
923 .get(1)
924 .and_then(|e| e.first())
925 .is_some_and(|v| v == "Z11")
926 }))
927 }
928
929 /// [19] Wenn IMD++Z12 vorhanden
930 fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
931 let imds = ctx.find_segments("IMD");
932 ConditionResult::from(imds.iter().any(|s| {
933 s.elements
934 .get(1)
935 .and_then(|e| e.first())
936 .is_some_and(|v| v == "Z12")
937 }))
938 }
939
940 /// [21] Wenn BGM+Z28 vorhanden
941 fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
942 ctx.has_qualifier("BGM", 0, "Z28")
943 }
944
945 /// [23] Wenn MP-ID in SG2 NAD+MR mit Rolle NB vorhanden
946 /// EXTERNAL: Requires context from outside the message.
947 fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
948 ctx.external.evaluate("recipient_is_nb")
949 }
950
951 /// [24] Wenn IMD++Z35 vorhanden
952 fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
953 let imds = ctx.find_segments("IMD");
954 ConditionResult::from(imds.iter().any(|s| {
955 s.elements
956 .get(1)
957 .and_then(|e| e.first())
958 .is_some_and(|v| v == "Z35")
959 }))
960 }
961
962 /// [26] Wenn MP-ID in SG2 NAD+MS mit Rolle ÜNB vorhanden
963 /// EXTERNAL: Requires context from outside the message.
964 // REVIEW: Whether the NAD+MS market participant holds the role ÜNB (Übertragungsnetzbetreiber) cannot be determined from the EDIFACT message content alone. The role is a business context attribute of the MP-ID that requires an external master data lookup (e.g. Marktstammdatenregister or internal role registry). Marked external with name 'sender_is_uenb'. (medium confidence)
965 fn evaluate_26(&self, ctx: &EvaluationContext) -> ConditionResult {
966 ctx.external.evaluate("sender_is_uenb")
967 }
968
969 /// [27] Wenn MP-ID in SG2 NAD+MR mit Rolle MSB vorhanden
970 /// EXTERNAL: Requires context from outside the message.
971 // REVIEW: Whether the NAD+MR market participant holds the role MSB (Messstellenbetreiber) cannot be determined from the EDIFACT message content alone. The role is a business context attribute of the MP-ID requiring external master data. Marked external with name 'recipient_is_msb'. (medium confidence)
972 fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
973 ctx.external.evaluate("recipient_is_msb")
974 }
975
976 /// [28] Wenn MP-ID in SG2 NAD+MR aus Sparte Strom
977 /// EXTERNAL: Requires context from outside the message.
978 fn evaluate_28(&self, ctx: &EvaluationContext) -> ConditionResult {
979 ctx.external.evaluate("recipient_market_sector_is_strom")
980 }
981
982 /// [29] Wenn MP-ID in SG2 NAD+MR aus Sparte Gas
983 /// EXTERNAL: Requires context from outside the message.
984 fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
985 ctx.external.evaluate("recipient_market_sector_is_gas")
986 }
987
988 /// [33] Wenn IMD+Z01 vorhanden
989 fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
990 ctx.has_qualifier("IMD", 1, "Z01")
991 }
992
993 /// [34] Wenn IMD+Z02 vorhanden
994 fn evaluate_34(&self, ctx: &EvaluationContext) -> ConditionResult {
995 ctx.has_qualifier("IMD", 1, "Z02")
996 }
997
998 /// [35] IMD++Z14+Z06 vorhanden
999 fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
1000 let imds = ctx.find_segments("IMD");
1001 let found = imds.iter().any(|s| {
1002 let has_z14 = s
1003 .elements
1004 .get(1)
1005 .and_then(|e| e.first())
1006 .is_some_and(|v| v == "Z14");
1007 let has_z06 = s
1008 .elements
1009 .get(2)
1010 .and_then(|e| e.first())
1011 .is_some_and(|v| v == "Z06");
1012 has_z14 && has_z06
1013 });
1014 ConditionResult::from(found)
1015 }
1016
1017 /// [36] Wenn MP-ID in SG2 NAD+MR mit Rolle NB nicht vorhanden
1018 /// EXTERNAL: Requires context from outside the message.
1019 fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
1020 ctx.external.evaluate("recipient_role_is_not_nb")
1021 }
1022
1023 /// [38] Wenn FTX+Z04/Z05 vorhanden
1024 fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
1025 let found = ctx.find_segments("FTX").iter().any(|s| {
1026 s.elements
1027 .first()
1028 .and_then(|e| e.first())
1029 .is_some_and(|v| v == "Z04" || v == "Z05")
1030 });
1031 ConditionResult::from(found)
1032 }
1033
1034 /// [45] Wenn MP-ID in SG2 NAD+MS mit Rolle MSB nicht vorhanden
1035 /// EXTERNAL: Requires context from outside the message.
1036 fn evaluate_45(&self, ctx: &EvaluationContext) -> ConditionResult {
1037 ctx.external.evaluate("sender_role_is_not_msb")
1038 }
1039
1040 /// [46] Wenn SG29 IMD++Z46 vorhanden
1041 fn evaluate_46(&self, ctx: &EvaluationContext) -> ConditionResult {
1042 ctx.has_qualifier("IMD", 1, "Z46")
1043 }
1044
1045 /// [47] Wenn SG29 IMD++Z46 nicht vorhanden
1046 fn evaluate_47(&self, ctx: &EvaluationContext) -> ConditionResult {
1047 ctx.lacks_qualifier("IMD", 1, "Z46")
1048 }
1049
1050 /// [51] Wenn BGM+Z48 vorhanden
1051 fn evaluate_51(&self, ctx: &EvaluationContext) -> ConditionResult {
1052 ctx.has_qualifier("BGM", 0, "Z48")
1053 }
1054
1055 /// [54] Wenn FTX+Z06 vorhanden
1056 fn evaluate_54(&self, ctx: &EvaluationContext) -> ConditionResult {
1057 ctx.has_qualifier("FTX", 0, "Z06")
1058 }
1059
1060 /// [55] Wenn DTM+469 (Beginn zum nächstmöglichen Termin) nicht vorhanden
1061 fn evaluate_55(&self, ctx: &EvaluationContext) -> ConditionResult {
1062 ctx.lacks_qualifier("DTM", 0, "469")
1063 }
1064
1065 /// [56] Wenn DTM+203 (Ausführungsdatum) nicht vorhanden
1066 fn evaluate_56(&self, ctx: &EvaluationContext) -> ConditionResult {
1067 ctx.lacks_qualifier("DTM", 0, "203")
1068 }
1069
1070 /// [57] Wenn im selben SG2 NAD DE3124 nicht vorhanden
1071 // REVIEW: Checks if any NAD segment in the message lacks DE3124 (C058 at elements[2][0]). 'Im selben SG2' requires group context; falls back to message-wide check. DE3124 is the first component of C058 (Zeile für Name und Anschrift / Zusatzinfo). (medium confidence)
1072 fn evaluate_57(&self, ctx: &EvaluationContext) -> ConditionResult {
1073 let nads = ctx.find_segments("NAD");
1074 if nads.is_empty() {
1075 return ConditionResult::Unknown;
1076 }
1077 let any_without = nads.iter().any(|nad| {
1078 nad.elements
1079 .get(2)
1080 .and_then(|e| e.first())
1081 .map(|v| v.is_empty())
1082 .unwrap_or(true)
1083 });
1084 ConditionResult::from(any_without)
1085 }
1086
1087 /// [60] MP-ID nur aus Sparte Gas
1088 /// EXTERNAL: Requires context from outside the message.
1089 fn evaluate_60(&self, ctx: &EvaluationContext) -> ConditionResult {
1090 ctx.external.evaluate("market_location_is_gas")
1091 }
1092
1093 /// [61] MP-ID nur aus Sparte Strom
1094 /// EXTERNAL: Requires context from outside the message.
1095 fn evaluate_61(&self, ctx: &EvaluationContext) -> ConditionResult {
1096 ctx.external.evaluate("market_location_is_electricity")
1097 }
1098
1099 /// [62] MP-ID mit Rolle MSB
1100 /// EXTERNAL: Requires context from outside the message.
1101 fn evaluate_62(&self, ctx: &EvaluationContext) -> ConditionResult {
1102 ctx.external.evaluate("sender_is_msb")
1103 }
1104
1105 /// [63] MP-ID mit Rolle NB
1106 /// EXTERNAL: Requires context from outside the message.
1107 fn evaluate_63(&self, ctx: &EvaluationContext) -> ConditionResult {
1108 ctx.external.evaluate("sender_is_nb")
1109 }
1110
1111 /// [64] Wenn SG2 NAD+Z03 nicht vorhanden
1112 fn evaluate_64(&self, ctx: &EvaluationContext) -> ConditionResult {
1113 ctx.lacks_qualifier("NAD", 0, "Z03")
1114 }
1115
1116 /// [65] Wenn FTX+Z08 vorhanden
1117 fn evaluate_65(&self, ctx: &EvaluationContext) -> ConditionResult {
1118 ctx.has_qualifier("FTX", 0, "Z08")
1119 }
1120
1121 /// [67] Wenn DTM+163 nicht vorhanden
1122 fn evaluate_67(&self, ctx: &EvaluationContext) -> ConditionResult {
1123 ctx.lacks_qualifier("DTM", 0, "163")
1124 }
1125
1126 /// [68] Wenn DTM+7 nicht vorhanden
1127 fn evaluate_68(&self, ctx: &EvaluationContext) -> ConditionResult {
1128 ctx.lacks_qualifier("DTM", 0, "7")
1129 }
1130
1131 /// [69] Wenn NAD+Z23 nicht vorhanden
1132 fn evaluate_69(&self, ctx: &EvaluationContext) -> ConditionResult {
1133 ctx.lacks_qualifier("NAD", 0, "Z23")
1134 }
1135
1136 /// [70] Wenn NAD+Z03 nicht vorhanden
1137 fn evaluate_70(&self, ctx: &EvaluationContext) -> ConditionResult {
1138 ctx.lacks_qualifier("NAD", 0, "Z03")
1139 }
1140
1141 /// [76] Wenn in derselben SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.1.1 "Standard-Messprodukt ...
1142 /// EXTERNAL: Requires context from outside the message.
1143 fn evaluate_76(&self, ctx: &EvaluationContext) -> ConditionResult {
1144 ctx.external
1145 .evaluate("pia_product_in_standard_messprodukt_wahlmoeglichkeit_list")
1146 }
1147
1148 /// [77] Wenn im selben CCI im DE7059 der Code Z39 (Code der Zählzeitdefinition) vorhanden ist
1149 // REVIEW: Checks if a CCI segment in the same SG29 group has DE7059 == 'Z39' (Code der Zählzeitdefinition). DE7059 is the class/type code at elements[0][0] in CCI. Group-scoped to SG29 with message-wide fallback. (medium confidence)
1150 fn evaluate_77(&self, ctx: &EvaluationContext) -> ConditionResult {
1151 ctx.any_group_has_qualifier("CCI", 0, "Z39", &["SG29"])
1152 }
1153
1154 /// [79] Wenn eine andere SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation) mit PIA+5+9991000000078:Z11 (für Wirkarbeit Lastgang 1/4 stündlich) vorhanden ist
1155 // REVIEW: Checks if any SG29 instance contains both LIN with Z54 at elements[1][0] and PIA with product code 9991000000078 at elements[1][0]. The 'another SG29' nuance is approximated as 'any SG29' since we have no current-group context. (medium confidence)
1156 fn evaluate_79(&self, ctx: &EvaluationContext) -> ConditionResult {
1157 ctx.any_group_has_co_occurrence(
1158 "LIN",
1159 1,
1160 &["Z54"],
1161 "PIA",
1162 1,
1163 0,
1164 &["9991000000078"],
1165 &["SG29"],
1166 )
1167 }
1168
1169 /// [80] Wenn keine andere SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation) mit PIA+5+9991000000078:Z11 (Wirkarbeit Lastgang 1/4 stündlich) vorhanden ist
1170 // REVIEW: Negation of condition 79 — no SG29 with LIN+Z54 AND PIA product 9991000000078. (medium confidence)
1171 fn evaluate_80(&self, ctx: &EvaluationContext) -> ConditionResult {
1172 match ctx.any_group_has_co_occurrence(
1173 "LIN",
1174 1,
1175 &["Z54"],
1176 "PIA",
1177 1,
1178 0,
1179 &["9991000000078"],
1180 &["SG29"],
1181 ) {
1182 ConditionResult::True => ConditionResult::False,
1183 ConditionResult::False => ConditionResult::True,
1184 ConditionResult::Unknown => ConditionResult::Unknown,
1185 }
1186 }
1187
1188 /// [81] Wenn in derselben SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation), das PIA+5+9991000000078:Z11 (Wirkarbeit Lastgang 1/4 stündlich) vorhanden ist
1189 // REVIEW: Group-scoped co-occurrence in the same SG29: LIN with Z54 at elements[1][0] AND PIA with product code 9991000000078 at elements[1][0]. Functionally equivalent to condition 79 since the API checks within the same group instance. (medium confidence)
1190 fn evaluate_81(&self, ctx: &EvaluationContext) -> ConditionResult {
1191 // HAND-EDITED: "in derselben SG29 mit Z54 in LIN … PIA+5+9991000000078:Z11" — the enclosing SG29 only, when the scope
1192 // reaches one; the message as before otherwise.
1193 if let Some(scope) = ctx.enclosing_scope("SG29") {
1194 return ConditionResult::from(
1195 ctx.find_segments_at(scope, "LIN")
1196 .iter()
1197 .any(|s| s.get_element(1) == "Z54")
1198 && ctx.find_segments_at(scope, "PIA").iter().any(|s| {
1199 s.get_element(0) == "5"
1200 && s.get_component(1, 0) == "9991000000078"
1201 && s.get_component(1, 1) == "Z11"
1202 }),
1203 );
1204 }
1205 ctx.any_group_has_co_occurrence(
1206 "LIN",
1207 1,
1208 &["Z54"],
1209 "PIA",
1210 1,
1211 0,
1212 &["9991000000078"],
1213 &["SG29"],
1214 )
1215 }
1216
1217 /// [84] IMD++Z14+Z07 vorhanden
1218 // REVIEW: Checks for IMD segment where elements[1][0]='Z14' (item characteristic) and elements[2][0]='Z07' (item description code). IMD++Z14+Z07 maps directly to these positions. (medium confidence)
1219 fn evaluate_84(&self, ctx: &EvaluationContext) -> ConditionResult {
1220 {
1221 let segments = ctx.find_segments("IMD");
1222 ConditionResult::from(segments.iter().any(|s| {
1223 s.elements
1224 .get(1)
1225 .and_then(|e| e.first())
1226 .is_some_and(|v| v == "Z14")
1227 && s.elements
1228 .get(2)
1229 .and_then(|e| e.first())
1230 .is_some_and(|v| v == "Z07")
1231 }))
1232 }
1233 }
1234
1235 /// [85] Wenn in derselben SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation), das PIA+5+9991000000086:Z11 (Wirkarbeit höchste 1/4 Stunde im Monat) vorhanden ist
1236 // REVIEW: Group-scoped co-occurrence in SG29: LIN with Z54 at elements[1][0] AND PIA with product code 9991000000086 (Wirkarbeit höchste 1/4 Stunde im Monat) at elements[1][0]. (medium confidence)
1237 fn evaluate_85(&self, ctx: &EvaluationContext) -> ConditionResult {
1238 // HAND-EDITED: "in derselben SG29 mit Z54 in LIN … PIA+5+9991000000086:Z11" — the enclosing SG29 only, when the scope
1239 // reaches one; the message as before otherwise.
1240 if let Some(scope) = ctx.enclosing_scope("SG29") {
1241 return ConditionResult::from(
1242 ctx.find_segments_at(scope, "LIN")
1243 .iter()
1244 .any(|s| s.get_element(1) == "Z54")
1245 && ctx.find_segments_at(scope, "PIA").iter().any(|s| {
1246 s.get_element(0) == "5"
1247 && s.get_component(1, 0) == "9991000000086"
1248 && s.get_component(1, 1) == "Z11"
1249 }),
1250 );
1251 }
1252 ctx.any_group_has_co_occurrence(
1253 "LIN",
1254 1,
1255 &["Z54"],
1256 "PIA",
1257 1,
1258 0,
1259 &["9991000000086"],
1260 &["SG29"],
1261 )
1262 }
1263
1264 /// [87] Wenn FTX+Z09/Z10 vorhanden
1265 fn evaluate_87(&self, ctx: &EvaluationContext) -> ConditionResult {
1266 {
1267 let segs = ctx.find_segments("FTX");
1268 ConditionResult::from(segs.iter().any(|s| {
1269 s.elements
1270 .first()
1271 .and_then(|e| e.first())
1272 .is_some_and(|v| v == "Z09" || v == "Z10")
1273 }))
1274 }
1275 }
1276
1277 /// [93] Wenn in derselben Nachricht eine SG29 mit Z16 in LIN DE1229 (Erforderliches Produkt der Tranche) nicht vorhanden
1278 fn evaluate_93(&self, ctx: &EvaluationContext) -> ConditionResult {
1279 ctx.lacks_qualifier("LIN", 1, "Z16")
1280 }
1281
1282 /// [94] Wenn in derselben Nachricht eine SG29 mit Z54 in LIN DE1229 (Erforderliches Produkt der Marktlokation) nicht vorhanden
1283 fn evaluate_94(&self, ctx: &EvaluationContext) -> ConditionResult {
1284 ctx.lacks_qualifier("LIN", 1, "Z54")
1285 }
1286
1287 /// [95] Messprodukt-Code aus dem Kapitel 2.1 "Standard-Messprodukte der Marktlokation" der Codeliste der Konfigurationen
1288 /// EXTERNAL: Requires context from outside the message.
1289 fn evaluate_95(&self, ctx: &EvaluationContext) -> ConditionResult {
1290 ctx.external.evaluate("messprodukt_standard_marktlokation")
1291 }
1292
1293 /// [96] Messprodukt-Code aus dem Kapitel 2.2 "Standard-Messprodukte der Tranche" der Codeliste der Konfigurationen
1294 /// EXTERNAL: Requires context from outside the message.
1295 fn evaluate_96(&self, ctx: &EvaluationContext) -> ConditionResult {
1296 ctx.external.evaluate("messprodukt_standard_tranche")
1297 }
1298
1299 /// [97] Wenn FTX+Z10 vorhanden
1300 fn evaluate_97(&self, ctx: &EvaluationContext) -> ConditionResult {
1301 ctx.has_qualifier("FTX", 0, "Z10")
1302 }
1303
1304 /// [99] Wenn FTX+Z08/Z10 vorhanden
1305 fn evaluate_99(&self, ctx: &EvaluationContext) -> ConditionResult {
1306 ctx.any_group_has_any_qualifier("FTX", 0, &["Z08", "Z10"], &["SG29"])
1307 }
1308
1309 /// [100] Messprodukt-Code aus dem Kapitel 2.3 "Standard-Messprodukte der Messlokation" der Codeliste der Konfigurationen
1310 /// EXTERNAL: Requires context from outside the message.
1311 fn evaluate_100(&self, ctx: &EvaluationContext) -> ConditionResult {
1312 ctx.external.evaluate("messprodukt_standard_messlokation")
1313 }
1314
1315 /// [101] Wenn MP-ID in SG2 NAD+MR mit Rolle MSB in der Sparte Gas nicht vorhanden
1316 /// EXTERNAL: Requires context from outside the message.
1317 // REVIEW: Checking whether the NAD+MR recipient has role MSB in Sparte Gas requires external business context about market participant roles — not determinable from message content alone. (medium confidence)
1318 fn evaluate_101(&self, ctx: &EvaluationContext) -> ConditionResult {
1319 ctx.external.evaluate("recipient_is_msb_gas")
1320 }
1321
1322 /// [102] Wenn in derselben SG29 LIN das CCI+++Z25 (Geräteart Wandler) vorhanden
1323 fn evaluate_102(&self, ctx: &EvaluationContext) -> ConditionResult {
1324 // HAND-EDITED: "in dieser/derselben SG29" — scoped to the enclosing group.
1325 ctx.this_group_has_qualifier("CCI", 2, "Z25", &["SG29"])
1326 }
1327
1328 /// [103] Wenn in derselben SG29 LIN das CCI+++Z25 (Geräteart Wandler) nicht vorhanden
1329 fn evaluate_103(&self, ctx: &EvaluationContext) -> ConditionResult {
1330 // HAND-EDITED: "in dieser/derselben SG29" — scoped to the enclosing group.
1331 match ctx.this_group_has_qualifier("CCI", 2, "Z25", &["SG29"]) {
1332 ConditionResult::True => ConditionResult::False,
1333 ConditionResult::False => ConditionResult::True,
1334 ConditionResult::Unknown => ConditionResult::Unknown,
1335 }
1336 }
1337
1338 /// [104] Wenn MP-ID in SG2 NAD+VY mit Rolle LF vorhanden
1339 /// EXTERNAL: Requires context from outside the message.
1340 // REVIEW: Checking whether the NAD+VY party has role LF requires external market participant role context — cannot be determined from the EDIFACT message alone. (medium confidence)
1341 fn evaluate_104(&self, ctx: &EvaluationContext) -> ConditionResult {
1342 ctx.external.evaluate("nad_vy_is_lf")
1343 }
1344
1345 /// [105] Wenn die bisherige Konfiguration mit Zählzeiten des LF vom LF beendet werden soll
1346 /// EXTERNAL: Requires context from outside the message.
1347 fn evaluate_105(&self, ctx: &EvaluationContext) -> ConditionResult {
1348 ctx.external
1349 .evaluate("bisherige_konfiguration_zaehltzeiten_lf_beenden")
1350 }
1351
1352 /// [106] wenn IMD++Z60 (Abbestellung Messprodukt mit Zählzeitdefinition des LF) nicht vorhanden
1353 fn evaluate_106(&self, ctx: &EvaluationContext) -> ConditionResult {
1354 ctx.lacks_qualifier("IMD", 1, "Z60")
1355 }
1356
1357 /// [107] Wenn IMD++Z57 (Abbestellung Zählzeitdefinition) nicht vorhanden
1358 fn evaluate_107(&self, ctx: &EvaluationContext) -> ConditionResult {
1359 ctx.lacks_qualifier("IMD", 1, "Z57")
1360 }
1361
1362 /// [108] Wenn RFF+AGK (Konfigurations-ID) nicht vorhanden
1363 fn evaluate_108(&self, ctx: &EvaluationContext) -> ConditionResult {
1364 ctx.lacks_qualifier("RFF", 0, "AGK")
1365 }
1366
1367 /// [109] Wenn LOC+172 (Meldepunkt) nicht vorhanden
1368 fn evaluate_109(&self, ctx: &EvaluationContext) -> ConditionResult {
1369 ctx.lacks_qualifier("LOC", 0, "172")
1370 }
1371
1372 /// [110] wenn DTM+163 (Beginn Zeitraum für Wertanfrage) vorhanden
1373 fn evaluate_110(&self, ctx: &EvaluationContext) -> ConditionResult {
1374 ctx.has_qualifier("DTM", 0, "163")
1375 }
1376
1377 /// [112] Wenn in derselben SG29 LIN++Z54 (Erforderliches Produkt der Marktlokation), das PIA+5+9991000000078: Z11 (Wirkarbeit Lastgang 1/4 stündlich) vorhanden ist
1378 // REVIEW: In same SG29: LIN with elements[1][0]=Z54 (Erforderliches Produkt der Marktlokation) co-occurs with PIA where elements[1][0]=9991000000078 (Wirkarbeit Lastgang 1/4h, product code from C212.DE7140). Co-occurrence check scoped to SG29. (medium confidence)
1379 fn evaluate_112(&self, ctx: &EvaluationContext) -> ConditionResult {
1380 // HAND-EDITED: "in derselben SG29 LIN++Z54 … PIA+5+9991000000078:Z11" — the enclosing SG29 only, when the scope
1381 // reaches one; the message as before otherwise.
1382 if let Some(scope) = ctx.enclosing_scope("SG29") {
1383 return ConditionResult::from(
1384 ctx.find_segments_at(scope, "LIN")
1385 .iter()
1386 .any(|s| s.get_element(1) == "Z54")
1387 && ctx.find_segments_at(scope, "PIA").iter().any(|s| {
1388 s.get_element(0) == "5"
1389 && s.get_component(1, 0) == "9991000000078"
1390 && s.get_component(1, 1) == "Z11"
1391 }),
1392 );
1393 }
1394 ctx.any_group_has_co_occurrence(
1395 "LIN",
1396 1,
1397 &["Z54"],
1398 "PIA",
1399 1,
1400 0,
1401 &["9991000000078"],
1402 &["SG29"],
1403 )
1404 }
1405
1406 /// [113] Wenn LIN DE1229 mit Code Z42 (Zählzeitdefinition) vorhanden
1407 fn evaluate_113(&self, ctx: &EvaluationContext) -> ConditionResult {
1408 ctx.has_qualifier("LIN", 1, "Z42")
1409 }
1410
1411 /// [114] Wenn LIN DE1229 mit Code Z69 (Schaltzeitdefinition) vorhanden
1412 fn evaluate_114(&self, ctx: &EvaluationContext) -> ConditionResult {
1413 ctx.has_qualifier("LIN", 1, "Z69")
1414 }
1415
1416 /// [115] Wenn LIN DE1229 mit Code Z70 (Leistungskurvendefinition) vorhanden
1417 fn evaluate_115(&self, ctx: &EvaluationContext) -> ConditionResult {
1418 ctx.has_qualifier("LIN", 1, "Z70")
1419 }
1420
1421 /// [117] Wenn SG29 LIN++Z64 (Erforderliches Produkt Schaltzeitdefinitionen) vorhanden
1422 fn evaluate_117(&self, ctx: &EvaluationContext) -> ConditionResult {
1423 ctx.has_qualifier("LIN", 1, "Z64")
1424 }
1425
1426 /// [118] Wenn SG29 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) vorhanden
1427 fn evaluate_118(&self, ctx: &EvaluationContext) -> ConditionResult {
1428 ctx.has_qualifier("LIN", 1, "Z65")
1429 }
1430
1431 /// [119] Wenn SG29 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) vorhanden
1432 fn evaluate_119(&self, ctx: &EvaluationContext) -> ConditionResult {
1433 ctx.has_qualifier("LIN", 1, "Z66")
1434 }
1435
1436 /// [120] Wenn SG29 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) vorhanden
1437 fn evaluate_120(&self, ctx: &EvaluationContext) -> ConditionResult {
1438 ctx.has_qualifier("LIN", 1, "Z67")
1439 }
1440
1441 /// [121] Wenn SG29 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) vorhanden
1442 fn evaluate_121(&self, ctx: &EvaluationContext) -> ConditionResult {
1443 ctx.has_qualifier("LIN", 1, "Z68")
1444 }
1445
1446 /// [122] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) nicht vorhanden
1447 fn evaluate_122(&self, ctx: &EvaluationContext) -> ConditionResult {
1448 ctx.lacks_qualifier("RFF", 0, "Z41")
1449 }
1450
1451 /// [123] Wenn DTM+203 (Ausführungsdatum) nicht vorhanden
1452 fn evaluate_123(&self, ctx: &EvaluationContext) -> ConditionResult {
1453 ctx.lacks_qualifier("DTM", 0, "203")
1454 }
1455
1456 /// [124] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) vorhanden
1457 fn evaluate_124(&self, ctx: &EvaluationContext) -> ConditionResult {
1458 ctx.has_qualifier("RFF", 0, "Z41")
1459 }
1460
1461 /// [125] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.1 „Konfigurationsprodukte Schaltzeitdefinition“ enthalten sind.
1462 /// EXTERNAL: Requires context from outside the message.
1463 fn evaluate_125(&self, ctx: &EvaluationContext) -> ConditionResult {
1464 ctx.external
1465 .evaluate("konfigurationsprodukt_schaltzeitdefinition")
1466 }
1467
1468 /// [130] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist
1469 fn evaluate_130(&self, ctx: &EvaluationContext) -> ConditionResult {
1470 // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist
1471 // LOC Meldepunkt: elements[0][0]=="172", elements[1][0]==DE3225 (Identifikator)
1472 let locs = ctx.find_segments_with_qualifier("LOC", 0, "172");
1473 match locs
1474 .first()
1475 .and_then(|s| s.elements.get(1))
1476 .and_then(|e| e.first())
1477 {
1478 Some(val) if !val.is_empty() => validate_malo_id(val),
1479 Some(_) => ConditionResult::False,
1480 None => ConditionResult::False, // segment absent → condition not applicable
1481 }
1482 }
1483
1484 /// [131] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist
1485 /// EXTERNAL: Requires context from outside the message.
1486 fn evaluate_131(&self, ctx: &EvaluationContext) -> ConditionResult {
1487 ctx.external.evaluate("meldepunkt_is_messlokation_id")
1488 }
1489
1490 /// [132] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist
1491 /// EXTERNAL: Requires context from outside the message.
1492 fn evaluate_132(&self, ctx: &EvaluationContext) -> ConditionResult {
1493 ctx.external.evaluate("meldepunkt_is_netzlokation_id")
1494 }
1495
1496 /// [133] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist
1497 /// EXTERNAL: Requires context from outside the message.
1498 fn evaluate_133(&self, ctx: &EvaluationContext) -> ConditionResult {
1499 ctx.external
1500 .evaluate("meldepunkt_is_steuerbare_ressource_id")
1501 }
1502
1503 /// [134] Wenn die Position in der ursprünglichen Antwort auf die Bestellung aus SG1 RFF+Z42 vorhanden war und reklamiert werden soll
1504 // REVIEW: RFF+Z42 in SG1 (elements[0][0]=="Z42") references the original order response position. Presence of this segment in the current message indicates the reclaim scenario. The 'reklamiert werden soll' clause is implied by the reference existing. (medium confidence)
1505 fn evaluate_134(&self, ctx: &EvaluationContext) -> ConditionResult {
1506 ctx.has_qualifier("RFF", 0, "Z42")
1507 }
1508
1509 /// [135] Wenn SG29 LIN++Z64 (Erforderliches Produkt Schaltzeitdefinitionen) nicht vorhanden
1510 fn evaluate_135(&self, ctx: &EvaluationContext) -> ConditionResult {
1511 ctx.lacks_qualifier("LIN", 1, "Z64")
1512 }
1513
1514 /// [136] Wenn SG29 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) nicht vorhanden
1515 fn evaluate_136(&self, ctx: &EvaluationContext) -> ConditionResult {
1516 ctx.lacks_qualifier("LIN", 1, "Z65")
1517 }
1518
1519 /// [137] Wenn SG29 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) nicht vorhanden
1520 fn evaluate_137(&self, ctx: &EvaluationContext) -> ConditionResult {
1521 ctx.lacks_qualifier("LIN", 1, "Z66")
1522 }
1523
1524 /// [138] Wenn SG29 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) nicht vorhanden
1525 fn evaluate_138(&self, ctx: &EvaluationContext) -> ConditionResult {
1526 ctx.lacks_qualifier("LIN", 1, "Z67")
1527 }
1528
1529 /// [139] Wenn SG29 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) nicht vorhanden
1530 fn evaluate_139(&self, ctx: &EvaluationContext) -> ConditionResult {
1531 ctx.lacks_qualifier("LIN", 1, "Z68")
1532 }
1533
1534 /// [140] Messprodukt-Code aus dem Kapitel 2.4 "Standard-Messprodukte der Netzlokation" der Codeliste der Konfigurationen
1535 /// EXTERNAL: Requires context from outside the message.
1536 fn evaluate_140(&self, ctx: &EvaluationContext) -> ConditionResult {
1537 ctx.external
1538 .evaluate("is_standard_messprodukt_netzlokation_code")
1539 }
1540
1541 /// [147] wenn im DE3155 in demselben COM der Code EM vorhanden ist
1542 fn evaluate_147(&self, ctx: &EvaluationContext) -> ConditionResult {
1543 let com_segments = ctx.find_segments("COM");
1544 ConditionResult::from(com_segments.iter().any(|s| {
1545 s.elements
1546 .first()
1547 .and_then(|e| e.get(1))
1548 .is_some_and(|v| v == "EM")
1549 }))
1550 }
1551
1552 /// [148] wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
1553 fn evaluate_148(&self, ctx: &EvaluationContext) -> ConditionResult {
1554 let com_segments = ctx.find_segments("COM");
1555 ConditionResult::from(com_segments.iter().any(|s| {
1556 s.elements
1557 .first()
1558 .and_then(|e| e.get(1))
1559 .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
1560 }))
1561 }
1562
1563 /// [161] Wenn in derselben SG29 LIN (Erforderliches Produkt Abrechnungsdaten) das SG30 CAV+ZH9 (Code der Produkteigenschaft) nicht vorhanden ist.
1564 fn evaluate_161(&self, ctx: &EvaluationContext) -> ConditionResult {
1565 // HAND-EDITED: "in derselben SG29 LIN das SG30 CAV+ZH9 nicht vorhanden" — the enclosing SG29 only, when the scope
1566 // reaches one; the message as before otherwise.
1567 if let Some(scope) = ctx.enclosing_scope("SG29") {
1568 return ConditionResult::from(
1569 !ctx.find_segments_at(scope, "CAV")
1570 .iter()
1571 .any(|s| s.get_element(0) == "ZH9"),
1572 );
1573 }
1574 ctx.any_group_has_qualifier_without("PIA", 0, "5", "CAV", 0, "ZH9", &["SG4", "SG29"])
1575 }
1576
1577 /// [163] Wenn innerhalb der Nachricht eine SG30 CCI+++ZA9 (Messprodukt für Übertragungsnetzbetreiber relevant) vorhanden ist.
1578 fn evaluate_163(&self, ctx: &EvaluationContext) -> ConditionResult {
1579 ctx.has_qualifier("CCI", 2, "ZA9")
1580 }
1581
1582 /// [167] Wenn SG2 NAD+DP (Meldepunkt), SG3 RFF+Z20 (Referenz auf ID der Tranche) vorhanden
1583 fn evaluate_167(&self, ctx: &EvaluationContext) -> ConditionResult {
1584 match (
1585 ctx.has_qualifier("NAD", 0, "DP"),
1586 ctx.has_qualifier("RFF", 0, "Z20"),
1587 ) {
1588 (ConditionResult::True, ConditionResult::True) => ConditionResult::True,
1589 (ConditionResult::False, _) | (_, ConditionResult::False) => ConditionResult::False,
1590 _ => ConditionResult::Unknown,
1591 }
1592 }
1593
1594 /// [168] Wenn SG2 NAD+DP (Meldepunkt), SG3 RFF+Z20 (Referenz auf ID der Tranche) nicht vorhanden
1595 fn evaluate_168(&self, ctx: &EvaluationContext) -> ConditionResult {
1596 match ctx.has_qualifier("NAD", 0, "DP") {
1597 ConditionResult::True => ctx.lacks_qualifier("RFF", 0, "Z20"),
1598 other => other,
1599 }
1600 }
1601
1602 /// [169] Wenn in SG29 LIN++Z19 (Erforderliches Produkt der Messlokation) in SG30 CCI (Zugeordnete Zählzeitdefinition im DE7059 der Code Z39 (Code der Zählzeitdefinition) vorhanden ist
1603 fn evaluate_169(&self, ctx: &EvaluationContext) -> ConditionResult {
1604 ctx.any_group_has_co_occurrence("LIN", 1, &["Z19"], "CCI", 0, 0, &["Z39"], &["SG29"])
1605 }
1606
1607 /// [170] Wenn in derselben SG29 LIN die SG30 CCI+Z37++ZD1 (Basis zur Bildung der Tranchengröße) (Prozentual) vorhanden
1608 fn evaluate_170(&self, ctx: &EvaluationContext) -> ConditionResult {
1609 // HAND-EDITED: "in dieser/derselben SG29" — scoped to the enclosing group.
1610 ctx.this_group_has_qualified_value("CCI", 0, "Z37", 2, 0, &["ZD1"], &["SG29"])
1611 }
1612
1613 /// [171] Wenn in derselben SG29 LIN (Erforderliches Produkt der Tranche) das IMD+++Z64 (Leistungsbeschreibung Konfiguration) (Neukonfiguration) vorhanden ist
1614 fn evaluate_171(&self, ctx: &EvaluationContext) -> ConditionResult {
1615 // HAND-EDITED: "in dieser/derselben SG29" — scoped to the enclosing group.
1616 ctx.this_group_has_qualifier("IMD", 2, "Z64", &["SG29"])
1617 }
1618
1619 /// [173] Wenn IMD++Z66 (Beendigung Konfiguration aufgrund Überführung der Marktlokation zu ruhender Marktlokation) vorhanden
1620 fn evaluate_173(&self, ctx: &EvaluationContext) -> ConditionResult {
1621 ctx.has_qualifier("IMD", 1, "Z66")
1622 }
1623
1624 /// [174] Wenn IMD++Z67 (Aktivierung Konfiguration in der derzeit ruhenden Marktlokation) vorhanden
1625 fn evaluate_174(&self, ctx: &EvaluationContext) -> ConditionResult {
1626 ctx.has_qualifier("IMD", 1, "Z67")
1627 }
1628
1629 /// [175] Wenn SG2 NAD+DP (Meldepunkt), SG3 RFF+Z59 (Referenz auf die ID der Marktlokation der Kundenanlage) vorhanden
1630 fn evaluate_175(&self, ctx: &EvaluationContext) -> ConditionResult {
1631 match (
1632 ctx.has_qualifier("NAD", 0, "DP"),
1633 ctx.has_qualifier("RFF", 0, "Z59"),
1634 ) {
1635 (ConditionResult::True, ConditionResult::True) => ConditionResult::True,
1636 (ConditionResult::False, _) | (_, ConditionResult::False) => ConditionResult::False,
1637 _ => ConditionResult::Unknown,
1638 }
1639 }
1640
1641 /// [176] Wenn SG2 NAD+DP (Meldepunkt), SG3 RFF+Z59 (Referenz auf die ID der Marktlokation der Kundenanlage) nicht vorhanden
1642 fn evaluate_176(&self, ctx: &EvaluationContext) -> ConditionResult {
1643 match ctx.has_qualifier("NAD", 0, "DP") {
1644 ConditionResult::True => ctx.lacks_qualifier("RFF", 0, "Z59"),
1645 other => other,
1646 }
1647 }
1648
1649 /// [177] Wenn IMD++Z66 (Beendigung Konfiguration aufgrund Überführung der Marktlokation zu ruhender Marktlokation) nicht vorhanden
1650 fn evaluate_177(&self, ctx: &EvaluationContext) -> ConditionResult {
1651 ctx.lacks_qualifier("IMD", 1, "Z66")
1652 }
1653
1654 /// [492] wenn MP-ID in NAD+MR aus Sparte Strom
1655 /// EXTERNAL: Requires context from outside the message.
1656 // REVIEW: Whether the MP-ID in NAD+MR belongs to the Strom (electricity) sector cannot be determined from the EDIFACT message alone — it requires a market participant registry lookup. (medium confidence)
1657 fn evaluate_492(&self, ctx: &EvaluationContext) -> ConditionResult {
1658 ctx.external.evaluate("recipient_is_strom")
1659 }
1660
1661 /// [493] wenn MP-ID in NAD+MR aus Sparte Gas
1662 /// EXTERNAL: Requires context from outside the message.
1663 // REVIEW: Whether the MP-ID in NAD+MR belongs to the Gas sector cannot be determined from the EDIFACT message alone — it requires a market participant registry lookup. (medium confidence)
1664 fn evaluate_493(&self, ctx: &EvaluationContext) -> ConditionResult {
1665 ctx.external.evaluate("recipient_is_gas")
1666 }
1667
1668 /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.
1669 fn evaluate_494(&self, ctx: &EvaluationContext) -> ConditionResult {
1670 // HAND-EDITED: subject is the current DTM's DE2380 (via ctx.resolved_value),
1671 // not a guessed other qualifier (it compared DTM+203 with DTM+137 and failed
1672 // DTM+137 itself whenever DTM+203 was later). Lexicographic compare is valid
1673 // for fixed-width CCYYMMDDHHMM+ZZ (format 303).
1674 let current = match ctx.resolved_value {
1675 Some(v) if !v.is_empty() => v,
1676 _ => return ConditionResult::Unknown,
1677 };
1678 let threshold = match ctx
1679 .find_segments_with_qualifier("DTM", 0, "137")
1680 .first()
1681 .and_then(|s| s.elements.first())
1682 .and_then(|e| e.get(1))
1683 {
1684 Some(v) if !v.is_empty() => v.clone(),
1685 _ => return ConditionResult::Unknown,
1686 };
1687 ConditionResult::from(current <= threshold.as_str())
1688 }
1689
1690 /// [495] Der Zeitpunkt muss ≤ dem Wert im DE2380 des DTM+137 sein
1691 fn evaluate_495(&self, ctx: &EvaluationContext) -> ConditionResult {
1692 // HAND-EDITED: subject is the current DTM's DE2380 (via ctx.resolved_value),
1693 // not a guessed other qualifier (it compared DTM+203 with DTM+137 and failed
1694 // DTM+137 itself whenever DTM+203 was later). Lexicographic compare is valid
1695 // for fixed-width CCYYMMDDHHMM+ZZ (format 303).
1696 let current = match ctx.resolved_value {
1697 Some(v) if !v.is_empty() => v,
1698 _ => return ConditionResult::Unknown,
1699 };
1700 let threshold = match ctx
1701 .find_segments_with_qualifier("DTM", 0, "137")
1702 .first()
1703 .and_then(|s| s.elements.first())
1704 .and_then(|e| e.get(1))
1705 {
1706 Some(v) if !v.is_empty() => v.clone(),
1707 _ => return ConditionResult::Unknown,
1708 };
1709 ConditionResult::from(current <= threshold.as_str())
1710 }
1711
1712 /// [500] Hinweis: Zählpunkt der BAS
1713 fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
1714 ConditionResult::Unknown
1715 }
1716
1717 /// [501] Hinweis: Zählpunkt der DZR
1718 fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
1719 ConditionResult::Unknown
1720 }
1721
1722 /// [503] Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
1723 fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
1724 ConditionResult::Unknown
1725 }
1726
1727 /// [506] Hinweis: Datum, bis zu dem der MSBA zur Fortführung verpflichtet wird
1728 fn evaluate_506(&self, _ctx: &EvaluationContext) -> ConditionResult {
1729 ConditionResult::Unknown
1730 }
1731
1732 /// [507] Hinweis: Es müssen alle nach Durchführung der Messlokationsänderung eingesetzten/genutzten OBIS- Kennzahlen übermittelt werden (wird eine "Erweiterung" des Messumfangs beauftragt, sind auch die...
1733 fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
1734 ConditionResult::Unknown
1735 }
1736
1737 /// [514] Hinweis: Das Abonnement kann frühestens ab dem aktuellen Liefermonat beim Netzbetreiber gestartet werden.
1738 fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
1739 ConditionResult::Unknown
1740 }
1741
1742 /// [515] Hinweis: Das angegebene Betrachtungszeitintervall bestimmt beim Start Abo bzw. Ende Abo ab bzw. bis wann (einschließlich) das Abo laufen soll.
1743 fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
1744 ConditionResult::Unknown
1745 }
1746
1747 /// [517] Hinweis: Zählpunkt der LF-AASZR
1748 fn evaluate_517(&self, _ctx: &EvaluationContext) -> ConditionResult {
1749 ConditionResult::Unknown
1750 }
1751
1752 /// [518] Hinweis: Das angegebene Ausführungsdatum bestimmt beim Start Abo bzw. Ende Abo ab bzw. bis wann (einschließlich) das Abo laufen soll.
1753 fn evaluate_518(&self, _ctx: &EvaluationContext) -> ConditionResult {
1754 ConditionResult::Unknown
1755 }
1756
1757 /// [519] Hinweis: Bei Gas bezieht sich die Anforderung immer sowohl auf die vorläufigen Profilwerte als auch auf die endgültigen Profilwerte, falls diese bereits vorliegen.
1758 fn evaluate_519(&self, _ctx: &EvaluationContext) -> ConditionResult {
1759 ConditionResult::Unknown
1760 }
1761
1762 /// [521] Hinweis: Verwendung der ID der Marktlokation
1763 fn evaluate_521(&self, _ctx: &EvaluationContext) -> ConditionResult {
1764 // Hinweis: Verwendung der ID der Marktlokation — informational note, always applies
1765 ConditionResult::True
1766 }
1767
1768 /// [522] Hinweis: Verwendung der ID der Messlokation
1769 fn evaluate_522(&self, _ctx: &EvaluationContext) -> ConditionResult {
1770 // Hinweis: Verwendung der ID der Messlokation — informational note, always applies
1771 ConditionResult::True
1772 }
1773
1774 /// [523] Hinweis: Verwendung der ID der Tranche
1775 fn evaluate_523(&self, _ctx: &EvaluationContext) -> ConditionResult {
1776 // Hinweis: Verwendung der ID der Tranche — informational note, always applies
1777 ConditionResult::True
1778 }
1779
1780 /// [525] Hinweis: Wert aus BGM DE1004 der MSCONS
1781 fn evaluate_525(&self, _ctx: &EvaluationContext) -> ConditionResult {
1782 // Hinweis: Wert aus BGM DE1004 der MSCONS — informational note, always applies
1783 ConditionResult::True
1784 }
1785
1786 /// [527] Hinweis: Zählpunkt der BG-SZR (Kategorie B)
1787 fn evaluate_527(&self, _ctx: &EvaluationContext) -> ConditionResult {
1788 // Hinweis: Zählpunkt der BG-SZR (Kategorie B) — informational note, always applies
1789 ConditionResult::True
1790 }
1791
1792 /// [530] Hinweis: Wert aus BGM+310 DE1004 der QUOTES mit der das Angebot erfolgt ist.
1793 fn evaluate_530(&self, _ctx: &EvaluationContext) -> ConditionResult {
1794 // Hinweis: Wert aus BGM+310 DE1004 der QUOTES mit der das Angebot erfolgt ist — informational note, always applies
1795 ConditionResult::True
1796 }
1797
1798 /// [531] Hinweis: Wert aus LIN DE1082 der QUOTES, mit der das Angebot erfolgt ist
1799 fn evaluate_531(&self, _ctx: &EvaluationContext) -> ConditionResult {
1800 // Hinweis: Wert aus LIN DE1082 der QUOTES, mit der das Angebot erfolgt ist — informational note, always applies
1801 ConditionResult::True
1802 }
1803
1804 /// [532] Hinweis: Wert aus BGM+Z29 DE1004 der QUOTES, mit der das Angebot zur Abrechnung des Messstellenbetriebs erfolgt ist.
1805 fn evaluate_532(&self, _ctx: &EvaluationContext) -> ConditionResult {
1806 // Hinweis: Wert aus BGM+Z29 DE1004 der QUOTES, mit der das Angebot zur Abrechnung des Messstellenbetriebs erfolgt ist — informational note, always applies
1807 ConditionResult::True
1808 }
1809
1810 /// [533] Hinweis: Gerichtsvollzieher hat Termin vorgegeben
1811 fn evaluate_533(&self, _ctx: &EvaluationContext) -> ConditionResult {
1812 // Hinweis: Gerichtsvollzieher hat Termin vorgegeben — informational note, always applies
1813 ConditionResult::True
1814 }
1815
1816 /// [535] Hinweis: Verwendung der ID der Messlokation der Sparte Strom
1817 fn evaluate_535(&self, _ctx: &EvaluationContext) -> ConditionResult {
1818 // Hinweis: Verwendung der ID der Messlokation der Sparte Strom — informational note, always applies
1819 ConditionResult::True
1820 }
1821
1822 /// [536] Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z59
1823 fn evaluate_536(&self, _ctx: &EvaluationContext) -> ConditionResult {
1824 // Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z59 — informational note, always applies
1825 ConditionResult::True
1826 }
1827
1828 /// [539] Hinweis: Es sind nur Codes von Zählzeiten aus Liste des NB anzugeben
1829 fn evaluate_539(&self, _ctx: &EvaluationContext) -> ConditionResult {
1830 // Hinweis: Es sind nur Codes von Zählzeiten aus Liste des NB anzugeben — informational note, always applies
1831 ConditionResult::True
1832 }
1833
1834 /// [540] Hinweis: Es sind nur Codes von Zählzeiten aus Liste des LF anzugeben
1835 fn evaluate_540(&self, _ctx: &EvaluationContext) -> ConditionResult {
1836 // Hinweis: Es sind nur Codes von Zählzeiten aus Liste des LF anzugeben — informational note, always applies
1837 ConditionResult::True
1838 }
1839
1840 /// [542] Hinweis: Wert aus BGM+Z57 DE1004 der QUOTES mit der das Angebot erfolgt ist.
1841 fn evaluate_542(&self, _ctx: &EvaluationContext) -> ConditionResult {
1842 // Hinweis: Wert aus BGM+Z57 DE1004 der QUOTES mit der das Angebot erfolgt ist — informational note, always applies
1843 ConditionResult::True
1844 }
1845
1846 /// [543] Hinweis: Wert aus BGM+Z57 DE1004 der ORDERS mit der die Bestellung der Werte erfolgt ist.
1847 fn evaluate_543(&self, _ctx: &EvaluationContext) -> ConditionResult {
1848 // Hinweis: Wert aus BGM+Z57 DE1004 der ORDERS mit der die Bestellung der Werte erfolgt ist — informational note, always applies
1849 ConditionResult::True
1850 }
1851
1852 /// [545] Hinweis: Es werden nur die Messprodukte der Messlokationen angegeben, die für die in der SG2 genannte Marktlokation bzw. deren Tranchen erforderlich sind. Messprodukte an der Messlokation für wei...
1853 fn evaluate_545(&self, _ctx: &EvaluationContext) -> ConditionResult {
1854 // Hinweis: Es werden nur die Messprodukte der Messlokationen angegeben... — informational note, always applies
1855 ConditionResult::True
1856 }
1857
1858 /// [547] Hinweis: Dokumentennummer aus BGM+Z60 DE1004 der UTILTS
1859 fn evaluate_547(&self, _ctx: &EvaluationContext) -> ConditionResult {
1860 // Hinweis: Dokumentennummer aus BGM+Z60 DE1004 der UTILTS — informational note, always applies
1861 ConditionResult::True
1862 }
1863
1864 /// [548] Hinweis: Wenn die Änderung der Gerätekonfiguration mit einer Zählzeit übermittelt wird, ist hier die MP-ID des Eigentümers der Liste der Zählzeit einzutragen. Wenn anstatt der bisherigen Zäh...
1865 fn evaluate_548(&self, _ctx: &EvaluationContext) -> ConditionResult {
1866 // Hinweis: MP-ID des Eigentümers der Zählzeitliste — informational note, always applies
1867 ConditionResult::True
1868 }
1869
1870 /// [549] Hinweis: Findet bei der Reklamation von Zählerständen immer Anwendung. Einzige Ausnahme ist, wenn es sich um die Reklamation eines fehlenden Zählerstandes aufgrund einer Turnusablesung handelt, ...
1871 fn evaluate_549(&self, _ctx: &EvaluationContext) -> ConditionResult {
1872 // Hinweis: Reklamation von Zählerständen — Zeitpunktangabe vs. Zeitintervall — informational note, always applies
1873 ConditionResult::True
1874 }
1875
1876 /// [550] Hinweis: Findet nur dann Anwendung, wenn es sich um die Reklamation eines fehlenden Zählerstandes aufgrund einer Turnusablesung handelt, bei welcher der MSB am Objekt der Marktlokation die Informa...
1877 fn evaluate_550(&self, _ctx: &EvaluationContext) -> ConditionResult {
1878 // Hinweis: Reklamation fehlender Zählerstand bei Turnusablesung — informational note, always applies
1879 ConditionResult::True
1880 }
1881
1882 /// [551] Hinweis: Die SG29 ist so oft zu wiederholen, dass alle Messprodukte und Zählzeiten genannt werden, die ab dem in DTM+203 genannten Zeitpunkt auf der Messlokation durch den MSB konfiguriert werden ...
1883 fn evaluate_551(&self, _ctx: &EvaluationContext) -> ConditionResult {
1884 // Hinweis: SG29 Wiederholung für alle Messprodukte und Zählzeiten — informational note, always applies
1885 ConditionResult::True
1886 }
1887
1888 /// [552] Hinweis: Verwendung der ID der Netzlokation
1889 fn evaluate_552(&self, _ctx: &EvaluationContext) -> ConditionResult {
1890 // Hinweis: Verwendung der ID der Netzlokation — informational note, always applies
1891 ConditionResult::True
1892 }
1893
1894 /// [553] Hinweis: Verwendung der ID der Steuerbaren Ressource
1895 fn evaluate_553(&self, _ctx: &EvaluationContext) -> ConditionResult {
1896 // Hinweis: Verwendung der ID der Steuerbaren Ressource — informational note, always applies
1897 ConditionResult::True
1898 }
1899
1900 /// [554] Hinweis: Wert aus BGM+Z74 DE1004 der QUOTES mit der das Angebot erfolgt ist.
1901 fn evaluate_554(&self, _ctx: &EvaluationContext) -> ConditionResult {
1902 // Hinweis: Wert aus BGM+Z74 DE1004 der QUOTES — informational note about value origin, always applies
1903 ConditionResult::True
1904 }
1905
1906 /// [555] Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD mit BGM+E01 mit der die Anmeldung des MSB-Wechsels erfolgt ist.
1907 fn evaluate_555(&self, _ctx: &EvaluationContext) -> ConditionResult {
1908 // Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD — informational note about value origin, always applies
1909 ConditionResult::True
1910 }
1911
1912 /// [557] Hinweis: Es werden nur die Messprodukte der Messlokationen angegeben, die für die in der SG2 genannte Netzlokation erforderlich sind. Messprodukte an der Messlokation für weitere Netzlokationen o...
1913 fn evaluate_557(&self, _ctx: &EvaluationContext) -> ConditionResult {
1914 // Hinweis: Only Messprodukte for Messlokationen required for the named Netzlokation are specified — informational note, always applies
1915 ConditionResult::True
1916 }
1917
1918 /// [558] Hinweis: Dokumentennummer aus BGM+Z78 DE1004 der UTILTS
1919 fn evaluate_558(&self, _ctx: &EvaluationContext) -> ConditionResult {
1920 // Hinweis: Dokumentennummer aus BGM+Z78 DE1004 der UTILTS — informational note, always applies
1921 ConditionResult::True
1922 }
1923
1924 /// [559] Hinweis: Dokumentennummer aus BGM+Z79 DE1004 der UTILTS
1925 fn evaluate_559(&self, _ctx: &EvaluationContext) -> ConditionResult {
1926 // Hinweis: Dokumentennummer aus BGM+Z79 DE1004 der UTILTS — informational note, always applies
1927 ConditionResult::True
1928 }
1929
1930 /// [560] Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z80
1931 fn evaluate_560(&self, _ctx: &EvaluationContext) -> ConditionResult {
1932 // Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z80 — informational note, always applies
1933 ConditionResult::True
1934 }
1935
1936 /// [561] Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z81
1937 fn evaluate_561(&self, _ctx: &EvaluationContext) -> ConditionResult {
1938 // Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z81 — informational note, always applies
1939 ConditionResult::True
1940 }
1941
1942 /// [562] Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
1943 fn evaluate_562(&self, _ctx: &EvaluationContext) -> ConditionResult {
1944 // Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA — informational note, always applies
1945 ConditionResult::True
1946 }
1947
1948 /// [563] Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z73 mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
1949 fn evaluate_563(&self, _ctx: &EvaluationContext) -> ConditionResult {
1950 // Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z73 mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde — informational note, always applies
1951 ConditionResult::True
1952 }
1953
1954 /// [564] Hinweis: Für den Empfang der Werte nach Typ 2 aus dem SMGW.
1955 fn evaluate_564(&self, _ctx: &EvaluationContext) -> ConditionResult {
1956 // Hinweis: Für den Empfang der Werte nach Typ 2 aus dem SMGW — informational note, always applies
1957 ConditionResult::True
1958 }
1959
1960 /// [566] Hinweis: Verwendung der ID der Technischen Ressource
1961 fn evaluate_566(&self, _ctx: &EvaluationContext) -> ConditionResult {
1962 // Hinweis: Verwendung der ID der Technischen Ressource — informational note, always applies
1963 ConditionResult::True
1964 }
1965
1966 /// [567] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
1967 fn evaluate_567(&self, _ctx: &EvaluationContext) -> ConditionResult {
1968 // Hinweis: Es darf nur eine Information im DE3148 übermittelt werden — informational note, always applies
1969 ConditionResult::True
1970 }
1971
1972 /// [568] Hinweis: Wenn die Einrichtung der Konfiguration mit einer Zählzeit übermittelt wird, ist hier die MP-ID des NB als Eigentümer der Liste der Zählzeit einzutragen.
1973 fn evaluate_568(&self, _ctx: &EvaluationContext) -> ConditionResult {
1974 // Hinweis: Wenn die Einrichtung der Konfiguration mit einer Zählzeit übermittelt wird, ist hier die MP-ID des NB als Eigentümer der Liste der Zählzeit einzutragen — informational note, always applies
1975 ConditionResult::True
1976 }
1977
1978 /// [569] Hinweis: MaBiS-Zählpunkt der LF-SZR
1979 fn evaluate_569(&self, _ctx: &EvaluationContext) -> ConditionResult {
1980 // Hinweis: MaBiS-Zählpunkt der LF-SZR — informational note, always applies
1981 ConditionResult::True
1982 }
1983
1984 /// [570] Hinweis: zur Angabe von Kontaktdaten des Kunden des Lieferanten um die Änderung an der Technik zu vereinfachen.
1985 fn evaluate_570(&self, _ctx: &EvaluationContext) -> ConditionResult {
1986 // Hinweis: zur Angabe von Kontaktdaten des Kunden des Lieferanten um die Änderung an der Technik zu vereinfachen — informational note, always applies
1987 ConditionResult::True
1988 }
1989
1990 /// [571] Hinweis: MSB der Marktlokation, an den die Werte der weiteren Energieflussrichtung der Messlokation zu übermitteln sind.
1991 fn evaluate_571(&self, _ctx: &EvaluationContext) -> ConditionResult {
1992 // Hinweis: MSB der Marktlokation, an den die Werte der weiteren Energieflussrichtung der Messlokation zu übermitteln sind — informational note, always applies
1993 ConditionResult::True
1994 }
1995
1996 /// [572] Hinweis: MSB der Marktlokation der Kundenanlage, in der die betroffene Lokation integriert wird.
1997 fn evaluate_572(&self, _ctx: &EvaluationContext) -> ConditionResult {
1998 // Hinweis: MSB der Marktlokation der Kundenanlage, in der die betroffene Lokation integriert wird — informational note, always applies
1999 ConditionResult::True
2000 }
2001
2002 /// [573] Hinweis: Es ist eine URI IPv4 für die Bereitstellung der Werte anzugeben.
2003 fn evaluate_573(&self, _ctx: &EvaluationContext) -> ConditionResult {
2004 // Hinweis: Es ist eine URI IPv4 für die Bereitstellung der Werte anzugeben — informational note, always applies
2005 ConditionResult::True
2006 }
2007
2008 /// [574] Hinweis: Es ist eine URI IPv6 für die Bereitstellung der Werte anzugeben.
2009 fn evaluate_574(&self, _ctx: &EvaluationContext) -> ConditionResult {
2010 // Hinweis: Es ist eine URI IPv6 für die Bereitstellung der Werte anzugeben.
2011 ConditionResult::True
2012 }
2013
2014 /// [575] Hinweis: Wenn der gewünschte Änderungszeitpunkt ein fixer Zeitpunkt ist.
2015 fn evaluate_575(&self, _ctx: &EvaluationContext) -> ConditionResult {
2016 // Hinweis: Wenn der gewünschte Änderungszeitpunkt ein fixer Zeitpunkt ist.
2017 ConditionResult::True
2018 }
2019
2020 /// [576] Hinweis: Wenn der gewünschte Änderungszeitpunkt ein nächst möglicher Termin zum oder nach dem angegebenen Zeitpunkt ist.
2021 fn evaluate_576(&self, _ctx: &EvaluationContext) -> ConditionResult {
2022 // Hinweis: Wenn der gewünschte Änderungszeitpunkt ein nächst möglicher Termin zum oder nach dem angegebenen Zeitpunkt ist.
2023 ConditionResult::True
2024 }
2025
2026 /// [903] Format: Möglicher Wert: 1
2027 fn evaluate_903(&self, _ctx: &EvaluationContext) -> ConditionResult {
2028 ConditionResult::True
2029 }
2030
2031 /// [906] Format: max. 3 Nachkommastellen
2032 fn evaluate_906(&self, ctx: &EvaluationContext) -> ConditionResult {
2033 ctx.format_check("QTY", 0, 1, |val| validate_max_decimal_places(val, 3))
2034 }
2035
2036 /// [911] Format: Mögliche Werte: 1 bis n, je Nachricht oder Segmentgruppe bei 1 beginnend und fortlaufend aufsteigend
2037 fn evaluate_911(&self, _ctx: &EvaluationContext) -> ConditionResult {
2038 // Hinweis: Mögliche Werte: 1 bis n, je Nachricht oder Segmentgruppe bei 1 beginnend und fortlaufend aufsteigend
2039 // This is a cardinality/sequencing annotation — informational, always applies
2040 ConditionResult::True
2041 }
2042
2043 /// [914] Format: Möglicher Wert: >0
2044 fn evaluate_914(&self, ctx: &EvaluationContext) -> ConditionResult {
2045 ctx.format_check("QTY", 0, 1, |val| validate_numeric(val, ">", 0.0))
2046 }
2047
2048 /// [922] Format: TR-ID
2049 // REVIEW: TR-ID (Transaktionsreferenz-ID) format. In ORDERS the transaction reference ID appears in BGM C106. The exact segment context depends on the AHB field definition — implemented as max-length-35 check on BGM, consistent with EDIFACT AN..35 data element constraints. Medium confidence because the target segment may differ by AHB row. (medium confidence)
2050 fn evaluate_922(&self, ctx: &EvaluationContext) -> ConditionResult {
2051 // Format: TR-ID — Transaktionsreferenz-ID, max 35 alphanumeric characters
2052 // In ORDERS, TR-ID typically appears in BGM element 1 (C106 document identifier)
2053 let segs = ctx.find_segments("BGM");
2054 match segs
2055 .first()
2056 .and_then(|s| s.elements.get(1))
2057 .and_then(|e| e.first())
2058 {
2059 Some(val) if !val.is_empty() => validate_max_length(val, 35),
2060 Some(_) => ConditionResult::False,
2061 None => ConditionResult::False, // segment absent → condition not applicable
2062 }
2063 }
2064
2065 /// [930] Format: max. 2 Nachkommastellen
2066 fn evaluate_930(&self, ctx: &EvaluationContext) -> ConditionResult {
2067 ctx.format_check("QTY", 0, 1, |val| validate_max_decimal_places(val, 2))
2068 }
2069
2070 /// [931] Format: ZZZ = +00
2071 fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
2072 ctx.format_check("DTM", 0, 1, validate_timezone_utc)
2073 }
2074
2075 /// [932] Format: HHMM = 2200
2076 // REVIEW: HHMM = 2200 time constraint on DTM. In ORDERS FV2504, delivery period end (qualifier 163) must terminate at 22:00 UTC, matching the standard German grid day-end convention. Medium confidence because the target DTM qualifier may differ for the specific AHB row — 163 is the most likely candidate for an end-of-period constraint. (medium confidence)
2077 fn evaluate_932(&self, ctx: &EvaluationContext) -> ConditionResult {
2078 ctx.format_check_qualified("DTM", 0, "163", 0, 1, |val| {
2079 validate_hhmm_equals(val, "2200")
2080 })
2081 }
2082
2083 /// [933] Format: HHMM = 2300
2084 fn evaluate_933(&self, ctx: &EvaluationContext) -> ConditionResult {
2085 ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2300"))
2086 }
2087
2088 /// [934] Format: HHMM = 0400
2089 fn evaluate_934(&self, ctx: &EvaluationContext) -> ConditionResult {
2090 ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "0400"))
2091 }
2092
2093 /// [935] Format: HHMM = 0500
2094 fn evaluate_935(&self, ctx: &EvaluationContext) -> ConditionResult {
2095 ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "0500"))
2096 }
2097
2098 /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
2099 fn evaluate_939(&self, ctx: &EvaluationContext) -> ConditionResult {
2100 ctx.format_check("COM", 0, 0, validate_email)
2101 }
2102
2103 /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
2104 fn evaluate_940(&self, ctx: &EvaluationContext) -> ConditionResult {
2105 ctx.format_check("COM", 0, 0, validate_phone)
2106 }
2107
2108 /// [950] Format: Marktlokations-ID
2109 // HAND-EDITED (#373): the condition sits on LOC+172 and RFF C506 1154, not on
2110 // LOC+Z16; judge the value it is attached to.
2111 fn evaluate_950(&self, ctx: &EvaluationContext) -> ConditionResult {
2112 ctx.format_check_resolved(validate_malo_id)
2113 }
2114
2115 /// [951] Format: Zählpunktbezeichnung
2116 // HAND-EDITED (#373): the condition sits on LOC+172 and RFF C506 1154, not on
2117 // LOC+Z17; judge the value it is attached to.
2118 fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
2119 ctx.format_check_resolved(validate_zahlpunkt)
2120 }
2121
2122 /// [955] Format: Möglicher Wert: <100
2123 // REVIEW: Format: Möglicher Wert: <100 — numeric value must be less than 100. Most likely applies to a QTY quantity value (C186.D6060, elements[0][1]). validate_numeric with "<" and threshold 100.0 covers this. Medium confidence because the exact segment context (QTY vs PRI vs PCT) is not specified — QTY is the most common numeric value carrier in ORDERS. (medium confidence)
2124 fn evaluate_955(&self, ctx: &EvaluationContext) -> ConditionResult {
2125 ctx.format_check("QTY", 0, 1, |val| validate_numeric(val, "<", 100.0))
2126 }
2127
2128 /// [960] Format: Netzlokations-ID
2129 // HAND-EDITED: a Netzlokations-ID is "E" + ten alphanumerics (`E1688117482`),
2130 // not MaLo-shaped; `validate_malo_id` rejected every real one (#173).
2131 // HAND-EDITED (#373): the condition sits on LOC+172 and RFF C506 1154, not on
2132 // LOC+Z18; judge the value it is attached to.
2133 fn evaluate_960(&self, ctx: &EvaluationContext) -> ConditionResult {
2134 ctx.format_check_resolved(validate_nelo_id)
2135 }
2136
2137 /// [961] Format: SR-ID
2138 // HAND-EDITED: an SR-ID ("C" + 10 characters), not a MaLo-ID.
2139 // HAND-EDITED (#373): the condition sits on LOC+172 and RFF C506 1154, not on
2140 // LOC+Z19; judge the value it is attached to.
2141 fn evaluate_961(&self, ctx: &EvaluationContext) -> ConditionResult {
2142 ctx.format_check_resolved(validate_sr_id)
2143 }
2144
2145 /// [962] Format: max. 6 Vorkommastellen
2146 // REVIEW: Format: max 6 integer digits (Vorkommastellen). Applied to QTY element[0][1] as the most common numeric data field in ORDERS requiring integer-part validation. Uses validate_max_integer_digits helper. Confidence medium because the target segment is inferred from context rather than explicitly stated. (medium confidence)
2147 fn evaluate_962(&self, ctx: &EvaluationContext) -> ConditionResult {
2148 ctx.format_check("QTY", 0, 1, |val| validate_max_integer_digits(val, 6))
2149 }
2150
2151 /// [2002] Ist mindestens zwei Mal anzugeben
2152 // REVIEW: Must be specified at least twice. Counts DTM+203 (Ausführungsdatum, qualifier at elements[0][0]) occurrences as a proxy for SG29 group instance count since each SG29 contains exactly one DTM+203. Condition is True when count >= 2. (medium confidence)
2153 fn evaluate_2002(&self, ctx: &EvaluationContext) -> ConditionResult {
2154 // "Ist mindestens zwei Mal anzugeben" — SG29 must appear at least twice.
2155 // DTM+203 (Ausführungsdatum) occurs exactly once per SG29 instance,
2156 // so counting DTM+203 segments gives the SG29 repetition count.
2157 let count = ctx.find_segments_with_qualifier("DTM", 0, "203").len();
2158 ConditionResult::from(count >= 2)
2159 }
2160
2161 /// [2004] Die SG29 ist so oft zu wiederholen, dass alle Geräte der betroffenen Geräteart die im Rahmen des Gerätewechsels aufgrund MSB-Wechsel getauscht werden sollen genannt sind.
2162 fn evaluate_2004(&self, _ctx: &EvaluationContext) -> ConditionResult {
2163 // Hinweis: Die SG29 ist so oft zu wiederholen, dass alle Geräte der betroffenen Geräteart
2164 // die im Rahmen des Gerätewechsels aufgrund MSB-Wechsel getauscht werden sollen, genannt sind.
2165 // Informational cardinality note — always applies.
2166 ConditionResult::True
2167 }
2168
2169 /// [2005] Pro SG29 LIN ist die SG34 RFF+Z09 (Gerätenummer) genau einmal anzugeben
2170 // HAND-EDITED (#392, reported by mako-twin): "pro SG29 LIN" — the RFF+Z09
2171 // of this SG29, not of the message: two LINs with one Gerätenummer each
2172 // made [2005] false for both.
2173 fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
2174 ConditionResult::from(geraetenummern_in_this_lin(ctx) == 1)
2175 }
2176
2177 /// [2006] Pro SG29 LIN ist die SG34 RFF+Z09 (Gerätenummer) bis zu dreimal anzugeben
2178 // HAND-EDITED (#392, reported by mako-twin): "pro SG29 LIN" — the RFF+Z09
2179 // of this SG29, not of the message: two LINs with one Gerätenummer each
2180 // made [2005] false for both.
2181 fn evaluate_2006(&self, ctx: &EvaluationContext) -> ConditionResult {
2182 ConditionResult::from(geraetenummern_in_this_lin(ctx) <= 3)
2183 }
2184
2185 /// [2007] Die SG29 ist so oft zu wiederholen, wie ab dem DTM+203 (Ausführungsdatum) Messlokationen zu der in der SG2 genannten Netzlokation vorhanden sind und für jede dieser Messlokationen müssen alle Me...
2186 fn evaluate_2007(&self, _ctx: &EvaluationContext) -> ConditionResult {
2187 // Hinweis: Die SG29 ist so oft zu wiederholen, wie ab dem DTM+203 (Ausführungsdatum)
2188 // Messlokationen zu der in der SG2 genannten Netzlokation vorhanden sind und für jede
2189 // dieser Messlokationen müssen alle Messprodukte genannt sein, die ab dem DTM+203
2190 // (Ausführungsdatum) in der SG2 genannten Netzlokation vorhanden sind.
2191 // Informational cardinality note — always applies.
2192 ConditionResult::True
2193 }
2194
2195 /// [2044] Pro SG29 LIN ist die SG29 PIA genau einmal anzugeben
2196 // REVIEW: Per SG29 LIN, the SG29 PIA segment must appear exactly once. We count PIA segments in the message and check for exactly one occurrence. This is a structural cardinality check on the PIA segment. (medium confidence)
2197 fn evaluate_2044(&self, ctx: &EvaluationContext) -> ConditionResult {
2198 {
2199 let pias = ctx.find_segments("PIA");
2200 ConditionResult::from(pias.len() == 1)
2201 }
2202 }
2203
2204 /// [2050] Pro Nachricht ist die SG29 genau einmal anzugeben
2205 // REVIEW: Per message, SG29 (identified by its entry segment LIN) must appear exactly once. We count all LIN segments in the message and check for exactly one occurrence. (medium confidence)
2206 fn evaluate_2050(&self, ctx: &EvaluationContext) -> ConditionResult {
2207 {
2208 let lins = ctx.find_segments("LIN");
2209 ConditionResult::from(lins.len() == 1)
2210 }
2211 }
2212
2213 /// [2060] Pro Nachricht ist die SG29 LIN+Z64 (Erforderliches Produkt Schaltzeitdefinitionen) maximal einmal anzugeben
2214 fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
2215 {
2216 let lins = ctx.find_segments("LIN");
2217 let count = lins
2218 .iter()
2219 .filter(|s| {
2220 s.elements
2221 .get(1)
2222 .and_then(|e| e.first())
2223 .is_some_and(|v| v == "Z64")
2224 })
2225 .count();
2226 ConditionResult::from(count <= 1)
2227 }
2228 }
2229
2230 /// [2061] Pro Nachricht ist die SG29 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) maximal einmal anzugeben
2231 fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
2232 {
2233 let lins = ctx.find_segments("LIN");
2234 let count = lins
2235 .iter()
2236 .filter(|s| {
2237 s.elements
2238 .get(1)
2239 .and_then(|e| e.first())
2240 .is_some_and(|v| v == "Z65")
2241 })
2242 .count();
2243 ConditionResult::from(count <= 1)
2244 }
2245 }
2246
2247 /// [2062] Pro Nachricht ist die SG29 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) maximal einmal anzugeben
2248 // REVIEW: Count LIN segments where elements[1][0]=="Z66" (LIN++Z66, ad-hoc Steuerkanal). Condition is True when at most one such SG29 line item is present per message. (medium confidence)
2249 fn evaluate_2062(&self, ctx: &EvaluationContext) -> ConditionResult {
2250 let count = ctx
2251 .find_segments("LIN")
2252 .iter()
2253 .filter(|s| {
2254 s.elements
2255 .get(1)
2256 .and_then(|e| e.first())
2257 .is_some_and(|v| v == "Z66")
2258 })
2259 .count();
2260 ConditionResult::from(count <= 1)
2261 }
2262
2263 /// [2063] Pro Nachricht ist die SG29 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) maximal einmal anzugeben
2264 // REVIEW: Count LIN segments where elements[1][0]=="Z67" (LIN++Z67, Messprodukt Typ 2 Backend). Condition is True when at most one such SG29 line item is present per message. (medium confidence)
2265 fn evaluate_2063(&self, ctx: &EvaluationContext) -> ConditionResult {
2266 let count = ctx
2267 .find_segments("LIN")
2268 .iter()
2269 .filter(|s| {
2270 s.elements
2271 .get(1)
2272 .and_then(|e| e.first())
2273 .is_some_and(|v| v == "Z67")
2274 })
2275 .count();
2276 ConditionResult::from(count <= 1)
2277 }
2278
2279 /// [2064] Pro Nachricht ist die SG29 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) maximal einmal anzugeben
2280 // REVIEW: Count LIN segments where elements[1][0]=="Z68" (LIN++Z68, Konfigurationserlaubnis Typ 2 SMGW). Condition is True when at most one such SG29 line item is present per message. (medium confidence)
2281 fn evaluate_2064(&self, ctx: &EvaluationContext) -> ConditionResult {
2282 let count = ctx
2283 .find_segments("LIN")
2284 .iter()
2285 .filter(|s| {
2286 s.elements
2287 .get(1)
2288 .and_then(|e| e.first())
2289 .is_some_and(|v| v == "Z68")
2290 })
2291 .count();
2292 ConditionResult::from(count <= 1)
2293 }
2294
2295 /// [2066] Die SG3 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 (Meldepu...
2296 fn evaluate_2066(&self, _ctx: &EvaluationContext) -> ConditionResult {
2297 // Hinweis: Die SG3 RFF+Z37 ist so oft zu wiederholen, bis alle IDs der Technischen
2298 // Ressourcen angegeben sind, die der Steuerbaren Ressource in LOC+172 DE3225 (Meldepunkt)
2299 // mit diesem Vorgang zugeordnet werden sollen.
2300 // Informational cardinality note — always applies.
2301 ConditionResult::True
2302 }
2303
2304 /// [2088] Die SG29 ist so oft zu wiederholen, dass alle Messprodukte ab dem DTM+203 (Ausführungsdatum) zu der in der SG2 genannten Netzlokation genannt sind.
2305 fn evaluate_2088(&self, _ctx: &EvaluationContext) -> ConditionResult {
2306 // Hinweis: Die SG29 ist so oft zu wiederholen, dass alle Messprodukte ab dem DTM+203
2307 // (Ausführungsdatum) zu der in der SG2 genannten Netzlokation genannt sind.
2308 // Informational cardinality note — always applies.
2309 ConditionResult::True
2310 }
2311
2312 /// [2089] Die SG29 ist so oft zu wiederholen, dass alle Messprodukte ab dem DTM+203 (Ausführungsdatum) zu der in der SG2 genannten Marktlokation genannt sind.
2313 fn evaluate_2089(&self, _ctx: &EvaluationContext) -> ConditionResult {
2314 // Hinweis: Die SG29 ist so oft zu wiederholen, dass alle Messprodukte ab dem DTM+203
2315 // (Ausführungsdatum) zu der in der SG2 genannten Marktlokation genannt sind.
2316 // Informational cardinality note about SG29 repetition count — always applies.
2317 ConditionResult::True
2318 }
2319
2320 /// [2090] Für 33-stellige ID im SG2 LOC+172 (Meldepunkt) DE3225 mindestens einmal anzugeben
2321 fn evaluate_2090(&self, ctx: &EvaluationContext) -> ConditionResult {
2322 let locs = ctx.find_segments_with_qualifier("LOC", 0, "172");
2323 ConditionResult::from(locs.iter().any(|s| {
2324 s.elements
2325 .get(1)
2326 .and_then(|e| e.first())
2327 .is_some_and(|v| v.len() == 33)
2328 }))
2329 }
2330
2331 /// [2092] Pro Nachricht ist die SG29 maximal einmal anzugeben
2332 // REVIEW: SG29 is initiated by the LIN segment. Count all LIN segments in the message and verify there is at most one, making the condition True when the cardinality constraint is satisfied. (medium confidence)
2333 fn evaluate_2092(&self, ctx: &EvaluationContext) -> ConditionResult {
2334 ConditionResult::from(ctx.find_segments("LIN").len() <= 1)
2335 }
2336
2337 /// [2094] Pro Nachricht ist die SG29 LIN (Positionsdaten) so oft anzugeben, wie Positionen aus dem Angebot, welches in SG1 RFF+AAG (Referenz Nachrichtennummer), DE1154 angegeben ist, bestellt werden sollen.
2338 fn evaluate_2094(&self, _ctx: &EvaluationContext) -> ConditionResult {
2339 // Hinweis: Pro Nachricht ist die SG29 LIN (Positionsdaten) so oft anzugeben, wie
2340 // Positionen aus dem Angebot (referenziert in SG1 RFF+AAG DE1154) bestellt werden sollen.
2341 // Informational cardinality note — the required repetition count depends on an external
2342 // offer document that cannot be inspected from within this EDIFACT message.
2343 ConditionResult::True
2344 }
2345
2346 /// [2095] Diese SG29 ist so oft zu wiederholen, dass alle Produkte zur Lokation die ab dem DTM+203 (Ausführungsdatum) gewünscht sind und deren Kombination gemäß Codeliste der Konfigurationen Kapitel 7 "P...
2347 fn evaluate_2095(&self, _ctx: &EvaluationContext) -> ConditionResult {
2348 // Hinweis: Diese SG29 ist so oft zu wiederholen, dass alle Produkte zur Lokation
2349 // ab dem DTM+203 (Ausführungsdatum) genannt sind, deren Kombination gemäß
2350 // Codeliste der Konfigurationen Kapitel 7 möglich sind.
2351 // Informational cardinality note — valid combinations are defined by an external
2352 // code list (Kapitel 7) and cannot be validated from EDIFACT content alone.
2353 ConditionResult::True
2354 }
2355
2356 /// [2096] Die SG3 Referenz auf die ID der Tranche ist so oft zu wiederholen, wie ab dem DTM+203 (Ausführungsdatum) Tranchen zu der in der SG2 genannten Marktlokation vorhanden sind.
2357 fn evaluate_2096(&self, _ctx: &EvaluationContext) -> ConditionResult {
2358 // Hinweis: Die SG3 Referenz auf die ID der Tranche ist so oft zu wiederholen, wie
2359 // ab dem DTM+203 (Ausführungsdatum) Tranchen zu der in der SG2 genannten
2360 // Marktlokation vorhanden sind.
2361 // Informational cardinality note — the number of Tranchen for a Marktlokation is
2362 // business context that cannot be determined from the EDIFACT message alone.
2363 ConditionResult::True
2364 }
2365
2366 /// [2097] Die SG29 ist so oft zu wiederholen, dass für alle in SG3 Referenz auf ID der Tranche genannten Tranchen mindestens eine SG29 vorhanden ist.
2367 fn evaluate_2097(&self, _ctx: &EvaluationContext) -> ConditionResult {
2368 // Hinweis: Die SG29 ist so oft zu wiederholen, dass für alle in SG3 RFF+Z20
2369 // (Referenz auf ID der Tranche) genannten Tranchen mindestens eine SG29 vorhanden ist.
2370 // Informational completeness note — each Tranche referenced in SG3 must have
2371 // at least one corresponding SG29. Documents structural pairing requirements.
2372 ConditionResult::True
2373 }
2374
2375 /// [2098] Die SG2 Lieferant an der Lokation ist so oft zu wiederholen, dass für alle in SG3 Referenz auf ID der Tranche genannten Tranchen genau eine SG2 Lieferant der Lokation vorhanden ist.
2376 // REVIEW: Cardinality rule: SG2 repetition count must equal the number of SG3 tranche references. Implemented by comparing count_in_group for both groups within SG29. Medium confidence because exact group paths and SG3 RFF qualifier for 'Tranche ID' are not confirmed without the full MIG segment structure reference — the paths &["SG29", "SG2"] and &["SG29", "SG3"] are based on standard ORDERS tx_group conventions from project memory. (medium confidence)
2377 fn evaluate_2098(&self, ctx: &EvaluationContext) -> ConditionResult {
2378 // SG2 Lieferant an der Lokation must repeat once per SG3 tranche reference.
2379 // Count SG2 group instances (NAD as entry segment) and SG3 RFF tranche references.
2380 // Both counts must be equal and non-zero for the condition to be satisfied.
2381 let sg2_count = ctx.count_in_group("NAD", &["SG29", "SG2"]);
2382 let sg3_count = ctx.count_in_group("RFF", &["SG29", "SG3"]);
2383 if sg2_count == 0 || sg3_count == 0 {
2384 return ConditionResult::Unknown;
2385 }
2386 ConditionResult::from(sg2_count == sg3_count)
2387 }
2388
2389 /// [2099] Die SG2 Lieferant an der Lokation ist genau einmal anzugeben.
2390 // REVIEW: Simple cardinality check: SG2 must appear exactly once (genau einmal). Implemented using count_in_group on NAD (the entry segment of SG2) within SG29. Returns Unknown when no SG2 is found at all (not yet present), False when count > 1, True when exactly 1. Medium confidence due to unconfirmed group path without the full EDIFACT Segment Structure Reference for this PID. (medium confidence)
2391 fn evaluate_2099(&self, ctx: &EvaluationContext) -> ConditionResult {
2392 // SG2 Lieferant an der Lokation must appear exactly once.
2393 // Count NAD segments (entry segment of SG2) within the SG29 SG2 group path.
2394 let count = ctx.count_in_group("NAD", &["SG29", "SG2"]);
2395 if count == 0 {
2396 return ConditionResult::Unknown;
2397 }
2398 ConditionResult::from(count == 1)
2399 }
2400}
2401
2402/// The SG34 RFF+Z09 (Gerätenummer) of the SG29 LIN being validated; of the
2403/// message where no SG29 is resolved.
2404fn geraetenummern_in_this_lin(ctx: &EvaluationContext) -> usize {
2405 let is_z09 = |s: &mig_types::segment::OwnedSegment| {
2406 s.elements
2407 .first()
2408 .and_then(|e| e.first())
2409 .is_some_and(|q| q == "Z09")
2410 };
2411 match ctx.enclosing_scope("SG29") {
2412 Some(scope) => ctx
2413 .find_segments_at(scope, "RFF")
2414 .iter()
2415 .filter(|s| is_z09(s))
2416 .count(),
2417 None => ctx
2418 .find_segments("RFF")
2419 .into_iter()
2420 .filter(|s| is_z09(s))
2421 .count(),
2422 }
2423}