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