Skip to main content

automapper_validation/generated/fv2510/
orders_conditions_fv2510.rs

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