Skip to main content

automapper_validation/generated/fv2604/
orders_conditions_fv2604.rs

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