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