Skip to main content

automapper_validation/generated/fv2510/
ordrsp_conditions_fv2510.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2510/ORDRSP_AHB_1_1_Fehlerkorrektur_20250417.xml
4// Generated: 2026-03-12T10:41:52Z
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::{Cluster, ConditionEvaluator, ConditionResult, EvaluationContext};
15use mig_types::segment::OwnedSegment;
16// HAND-EDITED: shared cluster helpers for conditions [17]/[18].
17// Preserve across regeneration — see CLAUDE.md "Codelist Providers".
18use crate::eval::ebd_cluster::resolved_sts_code_in_cluster;
19
20/// Generated condition evaluator for ORDRSP FV2510.
21pub struct OrdrspConditionEvaluatorFV2510 {
22    // External condition IDs that require runtime context.
23    external_conditions: std::collections::HashSet<u32>,
24}
25
26impl Default for OrdrspConditionEvaluatorFV2510 {
27    fn default() -> Self {
28        let mut external_conditions = std::collections::HashSet::new();
29        external_conditions.insert(3);
30        external_conditions.insert(4);
31        external_conditions.insert(5);
32        external_conditions.insert(7);
33        external_conditions.insert(9);
34        external_conditions.insert(10);
35        external_conditions.insert(12);
36        external_conditions.insert(13);
37        external_conditions.insert(14);
38        external_conditions.insert(15);
39        external_conditions.insert(16);
40        // HAND-EDITED: [17]/[18] are no longer external — they now read
41        // the EBD cluster lookup directly. See FV2504 counterpart.
42        // external_conditions.insert(17);
43        // external_conditions.insert(18);
44        external_conditions.insert(29);
45        external_conditions.insert(30);
46        external_conditions.insert(31);
47        external_conditions.insert(32);
48        external_conditions.insert(40);
49        external_conditions.insert(49);
50        external_conditions.insert(52);
51        external_conditions.insert(60);
52        external_conditions.insert(70);
53        external_conditions.insert(71);
54        external_conditions.insert(75);
55        external_conditions.insert(492);
56        external_conditions.insert(493);
57        Self {
58            external_conditions,
59        }
60    }
61}
62
63impl ConditionEvaluator for OrdrspConditionEvaluatorFV2510 {
64    fn message_type(&self) -> &str {
65        "ORDRSP"
66    }
67
68    fn format_version(&self) -> &str {
69        "FV2510"
70    }
71
72    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
73        match condition {
74            1 => self.evaluate_1(ctx),
75            3 => self.evaluate_3(ctx),
76            4 => self.evaluate_4(ctx),
77            5 => self.evaluate_5(ctx),
78            7 => self.evaluate_7(ctx),
79            9 => self.evaluate_9(ctx),
80            10 => self.evaluate_10(ctx),
81            11 => self.evaluate_11(ctx),
82            12 => self.evaluate_12(ctx),
83            13 => self.evaluate_13(ctx),
84            14 => self.evaluate_14(ctx),
85            15 => self.evaluate_15(ctx),
86            16 => self.evaluate_16(ctx),
87            17 => self.evaluate_17(ctx),
88            18 => self.evaluate_18(ctx),
89            21 => self.evaluate_21(ctx),
90            22 => self.evaluate_22(ctx),
91            23 => self.evaluate_23(ctx),
92            24 => self.evaluate_24(ctx),
93            25 => self.evaluate_25(ctx),
94            27 => self.evaluate_27(ctx),
95            28 => self.evaluate_28(ctx),
96            29 => self.evaluate_29(ctx),
97            30 => self.evaluate_30(ctx),
98            31 => self.evaluate_31(ctx),
99            32 => self.evaluate_32(ctx),
100            33 => self.evaluate_33(ctx),
101            34 => self.evaluate_34(ctx),
102            37 => self.evaluate_37(ctx),
103            38 => self.evaluate_38(ctx),
104            39 => self.evaluate_39(ctx),
105            40 => self.evaluate_40(ctx),
106            41 => self.evaluate_41(ctx),
107            42 => self.evaluate_42(ctx),
108            43 => self.evaluate_43(ctx),
109            44 => self.evaluate_44(ctx),
110            45 => self.evaluate_45(ctx),
111            46 => self.evaluate_46(ctx),
112            47 => self.evaluate_47(ctx),
113            48 => self.evaluate_48(ctx),
114            49 => self.evaluate_49(ctx),
115            50 => self.evaluate_50(ctx),
116            51 => self.evaluate_51(ctx),
117            52 => self.evaluate_52(ctx),
118            53 => self.evaluate_53(ctx),
119            54 => self.evaluate_54(ctx),
120            55 => self.evaluate_55(ctx),
121            56 => self.evaluate_56(ctx),
122            57 => self.evaluate_57(ctx),
123            58 => self.evaluate_58(ctx),
124            59 => self.evaluate_59(ctx),
125            60 => self.evaluate_60(ctx),
126            61 => self.evaluate_61(ctx),
127            62 => self.evaluate_62(ctx),
128            63 => self.evaluate_63(ctx),
129            64 => self.evaluate_64(ctx),
130            65 => self.evaluate_65(ctx),
131            66 => self.evaluate_66(ctx),
132            67 => self.evaluate_67(ctx),
133            68 => self.evaluate_68(ctx),
134            69 => self.evaluate_69(ctx),
135            70 => self.evaluate_70(ctx),
136            71 => self.evaluate_71(ctx),
137            72 => self.evaluate_72(ctx),
138            73 => self.evaluate_73(ctx),
139            74 => self.evaluate_74(ctx),
140            75 => self.evaluate_75(ctx),
141            76 => self.evaluate_76(ctx),
142            77 => self.evaluate_77(ctx),
143            78 => self.evaluate_78(ctx),
144            79 => self.evaluate_79(ctx),
145            80 => self.evaluate_80(ctx),
146            81 => self.evaluate_81(ctx),
147            82 => self.evaluate_82(ctx),
148            83 => self.evaluate_83(ctx),
149            490 => self.evaluate_490(ctx),
150            491 => self.evaluate_491(ctx),
151            492 => self.evaluate_492(ctx),
152            493 => self.evaluate_493(ctx),
153            494 => self.evaluate_494(ctx),
154            500 => self.evaluate_500(ctx),
155            503 => self.evaluate_503(ctx),
156            504 => self.evaluate_504(ctx),
157            513 => self.evaluate_513(ctx),
158            518 => self.evaluate_518(ctx),
159            519 => self.evaluate_519(ctx),
160            520 => self.evaluate_520(ctx),
161            521 => self.evaluate_521(ctx),
162            522 => self.evaluate_522(ctx),
163            523 => self.evaluate_523(ctx),
164            524 => self.evaluate_524(ctx),
165            525 => self.evaluate_525(ctx),
166            526 => self.evaluate_526(ctx),
167            527 => self.evaluate_527(ctx),
168            529 => self.evaluate_529(ctx),
169            530 => self.evaluate_530(ctx),
170            533 => self.evaluate_533(ctx),
171            534 => self.evaluate_534(ctx),
172            535 => self.evaluate_535(ctx),
173            536 => self.evaluate_536(ctx),
174            537 => self.evaluate_537(ctx),
175            538 => self.evaluate_538(ctx),
176            539 => self.evaluate_539(ctx),
177            540 => self.evaluate_540(ctx),
178            542 => self.evaluate_542(ctx),
179            543 => self.evaluate_543(ctx),
180            544 => self.evaluate_544(ctx),
181            545 => self.evaluate_545(ctx),
182            546 => self.evaluate_546(ctx),
183            547 => self.evaluate_547(ctx),
184            548 => self.evaluate_548(ctx),
185            902 => self.evaluate_902(ctx),
186            903 => self.evaluate_903(ctx),
187            930 => self.evaluate_930(ctx),
188            931 => self.evaluate_931(ctx),
189            932 => self.evaluate_932(ctx),
190            933 => self.evaluate_933(ctx),
191            934 => self.evaluate_934(ctx),
192            935 => self.evaluate_935(ctx),
193            939 => self.evaluate_939(ctx),
194            940 => self.evaluate_940(ctx),
195            2036 => self.evaluate_2036(ctx),
196            _ => ConditionResult::Unknown,
197        }
198    }
199
200    fn is_external(&self, condition: u32) -> bool {
201        self.external_conditions.contains(&condition)
202    }
203    fn is_known(&self, condition: u32) -> bool {
204        matches!(
205            condition,
206            1 | 3
207                | 4
208                | 5
209                | 7
210                | 9
211                | 10
212                | 11
213                | 12
214                | 13
215                | 14
216                | 15
217                | 16
218                | 17
219                | 18
220                | 21
221                | 22
222                | 23
223                | 24
224                | 25
225                | 27
226                | 28
227                | 29
228                | 30
229                | 31
230                | 32
231                | 33
232                | 34
233                | 37
234                | 38
235                | 39
236                | 40
237                | 41
238                | 42
239                | 43
240                | 44
241                | 45
242                | 46
243                | 47
244                | 48
245                | 49
246                | 50
247                | 51
248                | 52
249                | 53
250                | 54
251                | 55
252                | 56
253                | 57
254                | 58
255                | 59
256                | 60
257                | 61
258                | 62
259                | 63
260                | 64
261                | 65
262                | 66
263                | 67
264                | 68
265                | 69
266                | 70
267                | 71
268                | 72
269                | 73
270                | 74
271                | 75
272                | 76
273                | 77
274                | 78
275                | 79
276                | 80
277                | 81
278                | 82
279                | 83
280                | 490
281                | 491
282                | 492
283                | 493
284                | 494
285                | 500
286                | 503
287                | 504
288                | 513
289                | 518
290                | 519
291                | 520
292                | 521
293                | 522
294                | 523
295                | 524
296                | 525
297                | 526
298                | 527
299                | 529
300                | 530
301                | 533
302                | 534
303                | 535
304                | 536
305                | 537
306                | 538
307                | 539
308                | 540
309                | 542
310                | 543
311                | 544
312                | 545
313                | 546
314                | 547
315                | 548
316                | 902
317                | 903
318                | 930
319                | 931
320                | 932
321                | 933
322                | 934
323                | 935
324                | 939
325                | 940
326                | 2036
327        )
328    }
329}
330
331impl OrdrspConditionEvaluatorFV2510 {
332    /// [7] Wenn MP-ID in SG3 NAD+MR aus Sparte Strom
333    /// EXTERNAL: Requires context from outside the message.
334    fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
335        ctx.external.evaluate("recipient_is_strom")
336    }
337
338    /// [13] Wenn MP-ID in SG3 NAD+MR aus Sparte Gas
339    /// EXTERNAL: Requires context from outside the message.
340    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
341        ctx.external.evaluate("recipient_is_gas")
342    }
343
344    /// [52] wenn es sich bei der Reklamation um die Reklamation der ausgerollten Leistungskurvendefinitionen handelte
345    /// EXTERNAL: Requires context from outside the message.
346    fn evaluate_52(&self, ctx: &EvaluationContext) -> ConditionResult {
347        ctx.external
348            .evaluate("reklamation_ausgerollte_leistungskurvendefinitionen")
349    }
350
351    /// [60] wenn es sich bei der Reklamation um die Reklamation der Übersicht der Zählzeitdefinitionen handelte
352    /// EXTERNAL: Requires context from outside the message.
353    fn evaluate_60(&self, ctx: &EvaluationContext) -> ConditionResult {
354        ctx.external
355            .evaluate("reklamation_uebersicht_zaehlzeitdefinitionen")
356    }
357
358    /// [70] wenn es sich bei der Reklamation um die Reklamation der ausgerollten Zählzeitdefinitionen handelte
359    /// EXTERNAL: Requires context from outside the message.
360    fn evaluate_70(&self, ctx: &EvaluationContext) -> ConditionResult {
361        ctx.external
362            .evaluate("reklamation_ausgerollte_zaehlzeitdefinitionen")
363    }
364
365    /// [71] wenn es sich bei der Reklamation um die Reklamation der ausgerollten Schaltzeitdefinitionen handelte
366    /// EXTERNAL: Requires context from outside the message.
367    fn evaluate_71(&self, ctx: &EvaluationContext) -> ConditionResult {
368        ctx.external
369            .evaluate("complaint_is_about_rolled_out_switch_time_definitions")
370    }
371
372    /// [75] Wenn es sich um die Antwort auf eine Bestellung handelt in der ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.6.2 „Werte nach Typ 2 aus SMGW“ bestellt wurde.
373    /// EXTERNAL: Requires context from outside the message.
374    fn evaluate_75(&self, ctx: &EvaluationContext) -> ConditionResult {
375        ctx.external
376            .evaluate("order_contains_smgw_type2_messprodukt")
377    }
378
379    /// [78] Wenn AJT+A04+E_0279 vorhanden
380    fn evaluate_78(&self, ctx: &EvaluationContext) -> ConditionResult {
381        ctx.has_segment_matching("AJT", &[(0, 0, "A04"), (1, 0, "E_0279")])
382    }
383
384    /// [79] Wenn AJT+A04+E_0283 vorhanden
385    fn evaluate_79(&self, ctx: &EvaluationContext) -> ConditionResult {
386        ctx.has_segment_matching("AJT", &[(0, 0, "A04"), (1, 0, "E_0283")])
387    }
388
389    /// [80] Wenn AJT+A05+E_0279 vorhanden
390    fn evaluate_80(&self, ctx: &EvaluationContext) -> ConditionResult {
391        ctx.has_segment_matching("AJT", &[(0, 0, "A05"), (1, 0, "E_0279")])
392    }
393
394    /// [81] Wenn AJT+A05+E_0283 vorhanden
395    fn evaluate_81(&self, ctx: &EvaluationContext) -> ConditionResult {
396        ctx.has_segment_matching("AJT", &[(0, 0, "A05"), (1, 0, "E_0283")])
397    }
398
399    /// [82] Wenn BGM+Z93 (Bestellung eines Angebots Änderung der Technik der Lokation) vorhanden
400    fn evaluate_82(&self, ctx: &EvaluationContext) -> ConditionResult {
401        ctx.has_qualifier("BGM", 0, "Z93")
402    }
403
404    /// [83] Wenn BGM+Z12 (Änderung der Technik der Lokation) vorhanden
405    fn evaluate_83(&self, ctx: &EvaluationContext) -> ConditionResult {
406        ctx.has_qualifier("BGM", 0, "Z12")
407    }
408
409    /// [513] Hinweis: Wert aus BGM+Z12 (Änderung der Technik der Lokation) DE1004 der ORDERS, mit der die Bestellung erfolgt ist.
410    fn evaluate_513(&self, _ctx: &EvaluationContext) -> ConditionResult {
411        // Hinweis: Wert aus BGM+Z12 (Änderung der Technik der Lokation) DE1004 der ORDERS — informational note, always applies
412        ConditionResult::True
413    }
414
415    /// [543] Hinweis: Wert aus BGM+Z93 (Bestellung eines Angebots Änderung der Technik der Lokation) DE1004 der ORDERS, mit der die Bestellung erfolgt ist.
416    fn evaluate_543(&self, _ctx: &EvaluationContext) -> ConditionResult {
417        // Hinweis: Wert aus BGM+Z93 (Bestellung eines Angebots Änderung der Technik der Lokation) DE1004 der ORDERS — informational note, always applies
418        ConditionResult::True
419    }
420
421    /// [544] Hinweis: Wert aus BGM DE1004 der PRICAT mit der das Preisblatt B des MSB, auf die aus Sicht des MSB das Angebot basiert, übermittelt wurde.
422    fn evaluate_544(&self, _ctx: &EvaluationContext) -> ConditionResult {
423        // Hinweis: Wert aus BGM DE1004 der PRICAT mit der das Preisblatt B des MSB — informational note, always applies
424        ConditionResult::True
425    }
426
427    /// [545] Hinweis: Angabe des Beginnzeitpunkts des realistisch möglichen Umsetzungstermins der zum Zeitpunkt der Ablehnung ermittelt werden kann.
428    fn evaluate_545(&self, _ctx: &EvaluationContext) -> ConditionResult {
429        // Hinweis: Angabe des Beginnzeitpunkts des realistisch möglichen Umsetzungstermins — informational note, always applies
430        ConditionResult::True
431    }
432
433    /// [546] Hinweis: Angabe des Endezeitpunkts des realistisch möglichen Umsetzungstermins der zum Zeitpunkt der Ablehnung ermittelt werden kann.
434    fn evaluate_546(&self, _ctx: &EvaluationContext) -> ConditionResult {
435        // Hinweis: Angabe des Endezeitpunkts des realistisch möglichen Umsetzungstermins — informational note, always applies
436        ConditionResult::True
437    }
438
439    /// [547] Hinweis: Wenn es sich um die Bestellung eines vorherigen Angebots im Rahmen der BDEW Anwendungshilfe "Prozesse zur Änderung der Technik an Lokationen" handelt.
440    fn evaluate_547(&self, _ctx: &EvaluationContext) -> ConditionResult {
441        // Hinweis: Bestellung eines vorherigen Angebots im Rahmen der BDEW Anwendungshilfe 'Prozesse zur Änderung der Technik an Lokationen' — informational note, always applies
442        ConditionResult::True
443    }
444
445    /// [548] Hinweis: Hinweis: wenn es sich um die Beauftragung einer Änderung gemäß WiM Teil1 UC "Messlokationsänderung" handelt.
446    fn evaluate_548(&self, _ctx: &EvaluationContext) -> ConditionResult {
447        // Hinweis: Beauftragung einer Änderung gemäß WiM Teil1 UC 'Messlokationsänderung' — informational note, always applies
448        ConditionResult::True
449    }
450
451    /// [1] Wenn BGM+7 vorhanden
452    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
453        ctx.has_qualifier("BGM", 0, "7")
454    }
455
456    /// [3] Wenn MP-ID in SG3 NAD+MS mit Rolle NB vorhanden
457    /// EXTERNAL: Requires context from outside the message.
458    fn evaluate_3(&self, ctx: &EvaluationContext) -> ConditionResult {
459        ctx.external.evaluate("sender_is_nb")
460    }
461
462    /// [4] Wenn MP-ID in SG3 NAD+MR mit Rolle LF vorhanden
463    /// EXTERNAL: Requires context from outside the message.
464    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
465        ctx.external.evaluate("recipient_is_lf")
466    }
467
468    /// [5] Wenn MP-ID in SG3 NAD+MS mit Rolle LF vorhanden
469    /// EXTERNAL: Requires context from outside the message.
470    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
471        ctx.external.evaluate("sender_is_lf")
472    }
473
474    /// [9] Wenn MP-ID in SG3 NAD+MS mit Rolle LF vorhanden
475    /// EXTERNAL: Requires context from outside the message.
476    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
477        ctx.external.evaluate("sender_is_lf")
478    }
479
480    /// [10] Wenn MP-ID in SG3 NAD+MS mit Rolle MSB vorhanden
481    /// EXTERNAL: Requires context from outside the message.
482    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
483        ctx.external.evaluate("sender_is_msb")
484    }
485
486    /// [11] Wenn AJT+A09+E_0470 vorhanden
487    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
488        ctx.has_qualified_value("AJT", 0, "A09", 1, 0, &["E_0470"])
489    }
490
491    /// [12] Wenn der NB eine unverbindliche Preisinformation angeben kann
492    /// EXTERNAL: Requires context from outside the message.
493    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
494        ctx.external.evaluate("nb_can_provide_price_info")
495    }
496
497    /// [14] Wenn MP-ID in SG3 NAD+MR mit Rolle MSB vorhanden
498    /// EXTERNAL: Requires context from outside the message.
499    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
500        ctx.external.evaluate("recipient_is_msb")
501    }
502
503    /// [15] Wenn MP-ID in SG3 NAD+MR mit Rolle NB vorhanden
504    /// EXTERNAL: Requires context from outside the message.
505    fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
506        ctx.external.evaluate("recipient_is_nb")
507    }
508
509    /// [16] Wenn MP-ID in SG3 NAD+MR mit Rolle ÜNB vorhanden
510    /// EXTERNAL: Requires context from outside the message.
511    fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
512        ctx.external.evaluate("recipient_is_uenb")
513    }
514
515    /// [17] Der hier angegebene Code des Prüfschritts muss im EBD dem Cluster Zustimmung zugeordnet sein
516    // HAND-EDITED: driven by per-EBD cluster data (mako_prozesse).
517    fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
518        resolved_sts_code_in_cluster(ctx, Cluster::is_zustimmung)
519    }
520
521    /// [18] Der hier angegebene Code des Prüfschritts muss im EBD dem Cluster Ablehnung zugeordnet sein
522    // HAND-EDITED: driven by per-EBD cluster data (mako_prozesse).
523    fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
524        resolved_sts_code_in_cluster(ctx, Cluster::is_ablehnung)
525    }
526
527    /// [21] Wenn IMD++Z01 vorhanden
528    fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
529        ctx.has_qualifier("IMD", 1, "Z01")
530    }
531
532    /// [22] Wenn IMD++Z02 vorhanden
533    fn evaluate_22(&self, ctx: &EvaluationContext) -> ConditionResult {
534        ctx.has_qualifier("IMD", 1, "Z02")
535    }
536
537    /// [23] Wenn IMD++Z03 vorhanden
538    fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
539        let segments = ctx.find_segments("IMD");
540        ConditionResult::from(segments.iter().any(|s| {
541            s.elements
542                .get(1)
543                .and_then(|e| e.first())
544                .is_some_and(|v| v == "Z03")
545        }))
546    }
547
548    /// [24] Wenn BGM+Z51 vorhanden
549    fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
550        ctx.has_qualifier("BGM", 0, "Z51")
551    }
552
553    /// [25] Wenn BGM+Z52 vorhanden
554    fn evaluate_25(&self, ctx: &EvaluationContext) -> ConditionResult {
555        ctx.has_qualifier("BGM", 0, "Z52")
556    }
557
558    /// [27] Wenn AJT+A05+E_0470 vorhanden
559    fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
560        sg2_ajt(ctx, &["A05"], &["E_0470"])
561    }
562
563    /// [28] Wenn AJT+A99 vorhanden
564    fn evaluate_28(&self, ctx: &EvaluationContext) -> ConditionResult {
565        sg2_ajt(ctx, &["A99"], &[])
566    }
567
568    /// [29] MP-ID nur aus Sparte Gas
569    /// EXTERNAL: Requires context from outside the message.
570    fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
571        ctx.external.evaluate("mp_id_is_gas")
572    }
573
574    /// [30] MP-ID nur aus Sparte Strom
575    /// EXTERNAL: Requires context from outside the message.
576    fn evaluate_30(&self, ctx: &EvaluationContext) -> ConditionResult {
577        ctx.external.evaluate("mp_id_is_strom")
578    }
579
580    /// [31] MP-ID mit Rolle MSB
581    /// EXTERNAL: Requires context from outside the message.
582    fn evaluate_31(&self, ctx: &EvaluationContext) -> ConditionResult {
583        ctx.external.evaluate("mp_id_role_is_msb")
584    }
585
586    /// [32] MP-ID mit Rolle NB
587    /// EXTERNAL: Requires context from outside the message.
588    fn evaluate_32(&self, ctx: &EvaluationContext) -> ConditionResult {
589        ctx.external.evaluate("mp_id_role_is_nb")
590    }
591
592    /// [33] Wenn AJT+A02/A03+E_0488 vorhanden
593    fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
594        sg2_ajt(ctx, &["A02", "A03"], &["E_0488"])
595    }
596
597    /// [34] wenn vorhanden
598    // REVIEW: 'wenn vorhanden' is a generic conditional-use annotation meaning the element should be included whenever the relevant data is available. As a standalone condition without a specific segment target, it functions as a Hinweis-like unconditional True. (medium confidence)
599    fn evaluate_34(&self, _ctx: &EvaluationContext) -> ConditionResult {
600        // 'wenn vorhanden' — generic availability condition: element is conditional on presence of the data
601        // Without a specific segment reference this acts as an unconditional note
602        ConditionResult::True
603    }
604
605    /// [37] Wenn in dieser Nachricht das SG8 CUX+2 vorhanden
606    fn evaluate_37(&self, ctx: &EvaluationContext) -> ConditionResult {
607        ctx.has_qualifier("CUX", 0, "2")
608    }
609
610    /// [38] Möglicher Wert: ZB4 oder ZB5
611    fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
612        // HAND-EDITED: the condition names the only values the element may
613        // carry, so it holds for them alone — not a note that always holds.
614        match ctx.resolved_value {
615            Some(v) if !v.is_empty() => ConditionResult::from(matches!(v, "ZB4" | "ZB5")),
616            _ => ConditionResult::Unknown,
617        }
618    }
619
620    /// [39] Möglicher Wert: E17 oder Z07
621    fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
622        // HAND-EDITED: the condition names the only values the element may
623        // carry, so it holds for them alone — not a note that always holds.
624        match ctx.resolved_value {
625            Some(v) if !v.is_empty() => ConditionResult::from(matches!(v, "E17" | "Z07")),
626            _ => ConditionResult::Unknown,
627        }
628    }
629
630    /// [40] Wenn der Code im DE3207 in der "EDI@Energy Codeliste der europäischen Ländercodes" in der Spalte "PLZ vorhanden" ein "X" enthält
631    /// EXTERNAL: Requires context from outside the message.
632    fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
633        ctx.external.evaluate("country_has_postal_code")
634    }
635
636    /// [41] wenn SG2 AJT (Einzelheiten zu einer Anpassung/Änderung) DE4465 mit Wert ZB5 vorhanden
637    fn evaluate_41(&self, ctx: &EvaluationContext) -> ConditionResult {
638        ctx.has_qualifier("AJT", 0, "ZB5")
639    }
640
641    /// [42] Wenn SG2 AJT+Z07 (Antwortkategorie: Ablehnung (Keine Berechtigung)) vorhanden
642    fn evaluate_42(&self, ctx: &EvaluationContext) -> ConditionResult {
643        ctx.has_qualifier("AJT", 0, "Z07")
644    }
645
646    /// [43] Wenn AJT+A02/A03+E_1001 vorhanden
647    fn evaluate_43(&self, ctx: &EvaluationContext) -> ConditionResult {
648        sg2_ajt(ctx, &["A02", "A03"], &["E_1001"])
649    }
650
651    /// [44] Wenn AJT+A05+E_1000 vorhanden
652    fn evaluate_44(&self, ctx: &EvaluationContext) -> ConditionResult {
653        sg2_ajt(ctx, &["A05"], &["E_1000"])
654    }
655
656    /// [45] Wenn AJT+A09+E_1000 vorhanden
657    fn evaluate_45(&self, ctx: &EvaluationContext) -> ConditionResult {
658        let ajts = ctx.find_segments("AJT");
659        let found = ajts.iter().any(|s| {
660            let code = s
661                .elements
662                .first()
663                .and_then(|e| e.first())
664                .map(|v| v.as_str());
665            let pos = s
666                .elements
667                .get(1)
668                .and_then(|e| e.first())
669                .map(|v| v.as_str());
670            matches!(code, Some("A09")) && matches!(pos, Some("E_1000"))
671        });
672        ConditionResult::from(found)
673    }
674
675    /// [46] Wenn AJT+A06+E_0552 vorhanden
676    fn evaluate_46(&self, ctx: &EvaluationContext) -> ConditionResult {
677        let ajts = ctx.find_segments("AJT");
678        let found = ajts.iter().any(|s| {
679            let code = s
680                .elements
681                .first()
682                .and_then(|e| e.first())
683                .map(|v| v.as_str());
684            let pos = s
685                .elements
686                .get(1)
687                .and_then(|e| e.first())
688                .map(|v| v.as_str());
689            matches!(code, Some("A06")) && matches!(pos, Some("E_0552"))
690        });
691        ConditionResult::from(found)
692    }
693
694    /// [47] Wenn AJT+A06+E_0553 vorhanden
695    fn evaluate_47(&self, ctx: &EvaluationContext) -> ConditionResult {
696        let ajts = ctx.find_segments("AJT");
697        let found = ajts.iter().any(|s| {
698            let code = s
699                .elements
700                .first()
701                .and_then(|e| e.first())
702                .map(|v| v.as_str());
703            let pos = s
704                .elements
705                .get(1)
706                .and_then(|e| e.first())
707                .map(|v| v.as_str());
708            matches!(code, Some("A06")) && matches!(pos, Some("E_0553"))
709        });
710        ConditionResult::from(found)
711    }
712
713    /// [48] Wenn AJT+A06+E_0554 vorhanden
714    fn evaluate_48(&self, ctx: &EvaluationContext) -> ConditionResult {
715        let ajts = ctx.find_segments("AJT");
716        let found = ajts.iter().any(|s| {
717            let code = s
718                .elements
719                .first()
720                .and_then(|e| e.first())
721                .map(|v| v.as_str());
722            let pos = s
723                .elements
724                .get(1)
725                .and_then(|e| e.first())
726                .map(|v| v.as_str());
727            matches!(code, Some("A06")) && matches!(pos, Some("E_0554"))
728        });
729        ConditionResult::from(found)
730    }
731
732    /// [49] nur, wenn in ursprünglicher Nachricht IMD++Z60 (Abbestellung Messprodukt mit Zählzeitdefinition des LF) vorhanden war
733    /// EXTERNAL: Requires context from outside the message.
734    fn evaluate_49(&self, ctx: &EvaluationContext) -> ConditionResult {
735        ctx.external.evaluate("original_order_had_imd_z60")
736    }
737
738    /// [50] wenn im DE3155 in demselben COM der Code EM vorhanden ist
739    fn evaluate_50(&self, ctx: &EvaluationContext) -> ConditionResult {
740        let coms = ctx.find_segments("COM");
741        ConditionResult::from(coms.iter().any(|s| {
742            s.elements
743                .first()
744                .and_then(|e| e.get(1))
745                .map(|v| v == "EM")
746                .unwrap_or(false)
747        }))
748    }
749
750    /// [51] wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
751    fn evaluate_51(&self, ctx: &EvaluationContext) -> ConditionResult {
752        let coms = ctx.find_segments("COM");
753        ConditionResult::from(coms.iter().any(|s| {
754            matches!(
755                s.elements
756                    .first()
757                    .and_then(|e| e.get(1))
758                    .map(|v| v.as_str()),
759                Some("TE") | Some("FX") | Some("AJ") | Some("AL")
760            )
761        }))
762    }
763
764    /// [53] Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z59
765    fn evaluate_53(&self, _ctx: &EvaluationContext) -> ConditionResult {
766        // Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z59 — informational note about value origin, always applies
767        ConditionResult::True
768    }
769
770    /// [54] Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z80
771    fn evaluate_54(&self, _ctx: &EvaluationContext) -> ConditionResult {
772        // Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z80 — informational note about value origin, always applies
773        ConditionResult::True
774    }
775
776    /// [55] Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z81
777    fn evaluate_55(&self, _ctx: &EvaluationContext) -> ConditionResult {
778        // Hinweis: Vorgangsnummer aus IDE DE7402 der UTILTS mit BGM+Z81 — informational note about value origin, always applies
779        ConditionResult::True
780    }
781
782    /// [56] wenn SG2 AJT+A02/A03/A06/A07/A10/A11+E_0548 vorhanden
783    fn evaluate_56(&self, ctx: &EvaluationContext) -> ConditionResult {
784        let ajts = ctx.find_segments("AJT");
785        ConditionResult::from(ajts.iter().any(|s| {
786            let de4465 = s
787                .elements
788                .first()
789                .and_then(|e| e.first())
790                .map(|s| s.as_str());
791            let de1082 = s
792                .elements
793                .get(1)
794                .and_then(|e| e.first())
795                .map(|s| s.as_str());
796            matches!(
797                de4465,
798                Some("A02") | Some("A03") | Some("A06") | Some("A07") | Some("A10") | Some("A11")
799            ) && de1082 == Some("E_0548")
800        }))
801    }
802
803    /// [57] wenn SG2 AJT+A02/A03/A06/A07/A10/A11+E_0549 vorhanden
804    fn evaluate_57(&self, ctx: &EvaluationContext) -> ConditionResult {
805        let ajts = ctx.find_segments("AJT");
806        ConditionResult::from(ajts.iter().any(|s| {
807            let de4465 = s
808                .elements
809                .first()
810                .and_then(|e| e.first())
811                .map(|s| s.as_str());
812            let de1082 = s
813                .elements
814                .get(1)
815                .and_then(|e| e.first())
816                .map(|s| s.as_str());
817            matches!(
818                de4465,
819                Some("A02") | Some("A03") | Some("A06") | Some("A07") | Some("A10") | Some("A11")
820            ) && de1082 == Some("E_0549")
821        }))
822    }
823
824    /// [58] wenn SG2 AJT+A02/A03/A06/A07+E_0550 vorhanden
825    fn evaluate_58(&self, ctx: &EvaluationContext) -> ConditionResult {
826        let ajts = ctx.find_segments("AJT");
827        ConditionResult::from(ajts.iter().any(|s| {
828            let de4465 = s
829                .elements
830                .first()
831                .and_then(|e| e.first())
832                .map(|s| s.as_str());
833            let de1082 = s
834                .elements
835                .get(1)
836                .and_then(|e| e.first())
837                .map(|s| s.as_str());
838            matches!(
839                de4465,
840                Some("A02") | Some("A03") | Some("A06") | Some("A07")
841            ) && de1082 == Some("E_0550")
842        }))
843    }
844
845    /// [59] wenn SG2 AJT+A02/A03/A06/A07/A10/A11+E_0551 vorhanden
846    fn evaluate_59(&self, ctx: &EvaluationContext) -> ConditionResult {
847        let ajts = ctx.find_segments("AJT");
848        ConditionResult::from(ajts.iter().any(|s| {
849            let de4465 = s
850                .elements
851                .first()
852                .and_then(|e| e.first())
853                .map(|s| s.as_str());
854            let de1082 = s
855                .elements
856                .get(1)
857                .and_then(|e| e.first())
858                .map(|s| s.as_str());
859            matches!(
860                de4465,
861                Some("A02") | Some("A03") | Some("A06") | Some("A07") | Some("A10") | Some("A11")
862            ) && de1082 == Some("E_0551")
863        }))
864    }
865
866    /// [61] wenn es sich bei der Reklamation um die Reklamation der Übersicht der Schaltzeitdefinitionen handelte
867    // REVIEW: The condition checks whether the complaint concerned the overview of switching time definitions (Schaltzeitdefinitionen). Condition 63 establishes that BGM+Z60 is the code for Schaltzeitdefinitionen in UTILTS, and the ORDRSP BGM code mirrors this type. Checking BGM elements[0][0] == 'Z60' identifies this complaint type. (medium confidence)
868    fn evaluate_61(&self, ctx: &EvaluationContext) -> ConditionResult {
869        // Reklamation der Übersicht der Schaltzeitdefinitionen → ORDRSP with BGM+Z60
870        ctx.has_qualifier("BGM", 0, "Z60")
871    }
872
873    /// [62] wenn es sich bei der Reklamation um die Reklamation der Übersicht der Leistungskurvendefinitionen handelte
874    // REVIEW: The condition checks whether the complaint concerned the overview of load curve definitions (Leistungskurvendefinitionen). Conditions 64 and 65 establish BGM+Z78 and BGM+Z79 as the two related UTILTS codes for Leistungskurven types, so both are checked. (medium confidence)
875    fn evaluate_62(&self, ctx: &EvaluationContext) -> ConditionResult {
876        // Reklamation der Übersicht der Leistungskurvendefinitionen → BGM+Z78 or BGM+Z79
877        let bgm_segs = ctx.find_segments("BGM");
878        match bgm_segs.first() {
879            Some(s) => {
880                let code = s
881                    .elements
882                    .first()
883                    .and_then(|e| e.first())
884                    .map(|v| v.as_str());
885                ConditionResult::from(matches!(code, Some("Z78") | Some("Z79")))
886            }
887            None => ConditionResult::False, // segment absent → condition not applicable
888        }
889    }
890
891    /// [63] Dokumentennummer aus BGM+Z60 DE1004 der UTILTS
892    fn evaluate_63(&self, _ctx: &EvaluationContext) -> ConditionResult {
893        // Hinweis: Dokumentennummer aus BGM+Z60 DE1004 der UTILTS — informational note, always applies
894        ConditionResult::True
895    }
896
897    /// [64] Dokumentennummer aus BGM+Z78 DE1004 der UTILTS
898    fn evaluate_64(&self, _ctx: &EvaluationContext) -> ConditionResult {
899        // Hinweis: Dokumentennummer aus BGM+Z78 DE1004 der UTILTS — informational note, always applies
900        ConditionResult::True
901    }
902
903    /// [65] Dokumentennummer aus BGM+Z79 DE1004 der UTILTS
904    fn evaluate_65(&self, _ctx: &EvaluationContext) -> ConditionResult {
905        // Hinweis: Dokumentennummer aus BGM+Z79 DE1004 der UTILTS — informational note, always applies
906        ConditionResult::True
907    }
908
909    /// [66] wenn SG2 AJT+A01/A02/A03+E_0544 vorhanden
910    fn evaluate_66(&self, ctx: &EvaluationContext) -> ConditionResult {
911        let ajts = ctx.find_segments("AJT");
912        ConditionResult::from(ajts.iter().any(|s| {
913            let de4465 = s
914                .elements
915                .first()
916                .and_then(|e| e.first())
917                .map(|s| s.as_str());
918            let de1082 = s
919                .elements
920                .get(1)
921                .and_then(|e| e.first())
922                .map(|s| s.as_str());
923            matches!(de4465, Some("A01") | Some("A02") | Some("A03")) && de1082 == Some("E_0544")
924        }))
925    }
926
927    /// [67] wenn SG2 AJT+A01/A02/A03+E_0545 vorhanden
928    fn evaluate_67(&self, ctx: &EvaluationContext) -> ConditionResult {
929        let ajts = ctx.find_segments("AJT");
930        ConditionResult::from(ajts.iter().any(|s| {
931            let de4465 = s
932                .elements
933                .first()
934                .and_then(|e| e.first())
935                .map(|s| s.as_str());
936            let de1082 = s
937                .elements
938                .get(1)
939                .and_then(|e| e.first())
940                .map(|s| s.as_str());
941            matches!(de4465, Some("A01") | Some("A02") | Some("A03")) && de1082 == Some("E_0545")
942        }))
943    }
944
945    /// [68] wenn SG2 AJT+A02/A03+E_0546 vorhanden
946    fn evaluate_68(&self, ctx: &EvaluationContext) -> ConditionResult {
947        let ajts = ctx.find_segments("AJT");
948        ConditionResult::from(ajts.iter().any(|s| {
949            let de4465 = s
950                .elements
951                .first()
952                .and_then(|e| e.first())
953                .map(|s| s.as_str());
954            let de1082 = s
955                .elements
956                .get(1)
957                .and_then(|e| e.first())
958                .map(|s| s.as_str());
959            matches!(de4465, Some("A02") | Some("A03")) && de1082 == Some("E_0546")
960        }))
961    }
962
963    /// [69] wenn SG2 AJT+A01/A02/A03+E_0547 vorhanden
964    fn evaluate_69(&self, ctx: &EvaluationContext) -> ConditionResult {
965        let ajts = ctx.find_segments("AJT");
966        ConditionResult::from(ajts.iter().any(|s| {
967            let de4465 = s
968                .elements
969                .first()
970                .and_then(|e| e.first())
971                .map(|s| s.as_str());
972            let de1082 = s
973                .elements
974                .get(1)
975                .and_then(|e| e.first())
976                .map(|s| s.as_str());
977            matches!(de4465, Some("A01") | Some("A02") | Some("A03")) && de1082 == Some("E_0547")
978        }))
979    }
980
981    /// [72] wenn AJT+A04+E_0552 vorhanden
982    fn evaluate_72(&self, ctx: &EvaluationContext) -> ConditionResult {
983        sg2_ajt(ctx, &["A04"], &["E_0552"])
984    }
985
986    /// [73] wenn AJT+A04+E_0553 vorhanden
987    fn evaluate_73(&self, ctx: &EvaluationContext) -> ConditionResult {
988        sg2_ajt(ctx, &["A04"], &["E_0553"])
989    }
990
991    /// [74] wenn AJT+A04+E_0554 vorhanden
992    fn evaluate_74(&self, ctx: &EvaluationContext) -> ConditionResult {
993        sg2_ajt(ctx, &["A04"], &["E_0554"])
994    }
995
996    /// [76] Wenn FTX+Z27 (IP-Adresse des Absenders) nicht vorhanden
997    fn evaluate_76(&self, ctx: &EvaluationContext) -> ConditionResult {
998        ctx.lacks_qualifier("FTX", 0, "Z27")
999    }
1000
1001    /// [77] Wenn FTX+Z28 (IP-Range des Absenders) nicht vorhanden
1002    fn evaluate_77(&self, ctx: &EvaluationContext) -> ConditionResult {
1003        ctx.lacks_qualifier("FTX", 0, "Z28")
1004    }
1005
1006    /// [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...
1007    fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
1008        match ctx.resolved_value {
1009            Some(val) => is_mesz_utc(val),
1010            None => ConditionResult::False,
1011        }
1012    }
1013
1014    /// [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)...
1015    fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
1016        match ctx.resolved_value {
1017            Some(val) => is_mez_utc(val),
1018            None => ConditionResult::False,
1019        }
1020    }
1021
1022    /// [492] wenn MP-ID in NAD+MR aus Sparte Strom
1023    /// EXTERNAL: Requires context from outside the message.
1024    fn evaluate_492(&self, ctx: &EvaluationContext) -> ConditionResult {
1025        ctx.external.evaluate("recipient_is_strom")
1026    }
1027
1028    /// [493] wenn MP-ID in NAD+MR aus Sparte Gas
1029    /// EXTERNAL: Requires context from outside the message.
1030    fn evaluate_493(&self, ctx: &EvaluationContext) -> ConditionResult {
1031        ctx.external.evaluate("recipient_is_gas")
1032    }
1033
1034    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.
1035    // REVIEW: 'Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.' This is a constraint description stating the date must be the document creation time or earlier. It functions as an unconditional validation rule (always applies) rather than a conditional trigger. Without knowing which specific DTM qualifier 'here' refers to in the calling context, and since the constraint itself is always applicable, returning True is appropriate. (medium confidence)
1036    fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
1037        ConditionResult::True
1038    }
1039
1040    /// [500] Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
1041    fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
1042        ConditionResult::True
1043    }
1044
1045    /// [503] Hinweis: Datum, bis zu dem der MSBA zur Fortführung verpflichtet wurde
1046    fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
1047        ConditionResult::True
1048    }
1049
1050    /// [504] Hinweis: Ggf. korrigiert bei einer Zeitangabe in der ORDERS, die außerhalb des max. möglichen Weiterverpflichtungszeitraums ist. Als Antwort wird dann in SG2 AJT Zustimmung mit Terminänderung an...
1051    fn evaluate_504(&self, _ctx: &EvaluationContext) -> ConditionResult {
1052        // Hinweis: Ggf. korrigiert bei einer Zeitangabe in der ORDERS, die außerhalb des max. möglichen Weiterverpflichtungszeitraums ist. Als Antwort wird dann in SG2 AJT Zustimmung mit Terminänderung angegeben.
1053        ConditionResult::True
1054    }
1055
1056    /// [518] Hinweis: Wert aus BGM+Z10 DE1004 der ORDERS, mit der die Bestellung erfolgt ist
1057    fn evaluate_518(&self, _ctx: &EvaluationContext) -> ConditionResult {
1058        // Hinweis: Wert aus BGM+Z10 DE1004 der ORDERS, mit der die Bestellung erfolgt ist.
1059        ConditionResult::True
1060    }
1061
1062    /// [519] Hinweis: Wert aus BGM+7 DE1004 der ORDERS, mit der die Bestellung erfolgt ist.
1063    fn evaluate_519(&self, _ctx: &EvaluationContext) -> ConditionResult {
1064        // Hinweis: Wert aus BGM+7 DE1004 der ORDERS, mit der die Bestellung erfolgt ist.
1065        ConditionResult::True
1066    }
1067
1068    /// [520] Hinweis: Wert aus BGM+Z29 DE1004 der ORDERS, mit der die Anfrage zur Beendigung der Rechnungsabwicklung erfolgt ist.
1069    fn evaluate_520(&self, _ctx: &EvaluationContext) -> ConditionResult {
1070        // Hinweis: Wert aus BGM+Z29 DE1004 der ORDERS, mit der die Anfrage zur Beendigung der Rechnungsabwicklung erfolgt ist.
1071        ConditionResult::True
1072    }
1073
1074    /// [521] Hinweis: Wert aus BGM+Z14/Z61/Z62 DE1004 der ORDERS, mit der die Anforderung von Stammdaten erfolgt ist
1075    fn evaluate_521(&self, _ctx: &EvaluationContext) -> ConditionResult {
1076        // Hinweis: Wert aus BGM+Z14/Z61/Z62 DE1004 der ORDERS, mit der die Anforderung von Stammdaten erfolgt ist
1077        // Informational note — documents that the BGM DE1004 value originates from the original ORDERS request.
1078        ConditionResult::True
1079    }
1080
1081    /// [522] Hinweis: Wert aus BGM+7/Z28/Z48 DE1004 der ORDERS, mit der die Anforderung von Werten erfolgt ist.
1082    fn evaluate_522(&self, _ctx: &EvaluationContext) -> ConditionResult {
1083        // Hinweis: Wert aus BGM+7/Z28/Z48 DE1004 der ORDERS — informational note, always applies
1084        ConditionResult::True
1085    }
1086
1087    /// [523] Hinweis: Wert aus BGM+7 DE1004 der ORDERS, mit der die Anforderung Anforderung von Brennwert und Zustandszahl erfolgt ist.
1088    fn evaluate_523(&self, _ctx: &EvaluationContext) -> ConditionResult {
1089        // Hinweis: Wert aus BGM+7 DE1004 der ORDERS — informational note, always applies
1090        ConditionResult::True
1091    }
1092
1093    /// [524] Hinweis: Wert aus BGM+Z14 DE1004 der ORDERS, mit der die Anfrage vom MSB Gas erfolgt ist.
1094    fn evaluate_524(&self, _ctx: &EvaluationContext) -> ConditionResult {
1095        // Hinweis: Wert aus BGM+Z14 DE1004 der ORDERS — informational note, always applies
1096        ConditionResult::True
1097    }
1098
1099    /// [525] Hinweis: Wert aus BGM+Z24 DE1004 der ORDERS, mit der die Anforderung Allokationsliste erfolgt ist
1100    fn evaluate_525(&self, _ctx: &EvaluationContext) -> ConditionResult {
1101        // Hinweis: Wert aus BGM+Z24 DE1004 der ORDERS — informational note, always applies
1102        ConditionResult::True
1103    }
1104
1105    /// [526] Hinweis: Wert aus BGM+Z23 DE1004 der ORDERS, mit der die Anforderung bilanzierte Menge erfolgt ist
1106    fn evaluate_526(&self, _ctx: &EvaluationContext) -> ConditionResult {
1107        // Hinweis: Wert aus BGM+Z23 DE1004 der ORDERS — informational note, always applies
1108        ConditionResult::True
1109    }
1110
1111    /// [527] Hinweis: Wert aus BGM+Z34 DE1004 der ORDERS, mit der die Reklamation von Werten erfolgt ist.
1112    fn evaluate_527(&self, _ctx: &EvaluationContext) -> ConditionResult {
1113        // Hinweis: Wert aus BGM+Z34 DE1004 der ORDERS, mit der die Reklamation von Werten erfolgt ist. — informational note, always applies
1114        ConditionResult::True
1115    }
1116
1117    /// [529] Hinweis: Dokumentennummer aus BGM DE1004 der ORDERS
1118    fn evaluate_529(&self, _ctx: &EvaluationContext) -> ConditionResult {
1119        // Hinweis: Dokumentennummer aus BGM DE1004 der ORDERS — informational note, always applies
1120        ConditionResult::True
1121    }
1122
1123    /// [530] Hinweis: Dokumentennummer aus BGM DE1004 der ORDCHG
1124    fn evaluate_530(&self, _ctx: &EvaluationContext) -> ConditionResult {
1125        // Hinweis: Dokumentennummer aus BGM DE1004 der ORDCHG — informational note, always applies
1126        ConditionResult::True
1127    }
1128
1129    /// [533] Hinweis: Wert aus BGM+Z51 DE1004 der ORDCHG
1130    fn evaluate_533(&self, _ctx: &EvaluationContext) -> ConditionResult {
1131        // Hinweis: Wert aus BGM+Z51 DE1004 der ORDCHG — informational note, always applies
1132        ConditionResult::True
1133    }
1134
1135    /// [534] Hinweis: Wert aus BGM+Z52 DE1004 der ORDCHG
1136    fn evaluate_534(&self, _ctx: &EvaluationContext) -> ConditionResult {
1137        // Hinweis: Wert aus BGM+Z52 DE1004 der ORDCHG — informational note, always applies
1138        ConditionResult::True
1139    }
1140
1141    /// [535] Hinweis: Wert aus BGM+Z13 DE1004 der ORDERS, mit der die Ankündigung Gerätewechselabsicht erfolgt ist.
1142    fn evaluate_535(&self, _ctx: &EvaluationContext) -> ConditionResult {
1143        // Hinweis: Wert aus BGM+Z13 DE1004 der ORDERS — informational note, always applies
1144        ConditionResult::True
1145    }
1146
1147    /// [536] Hinweis: Es ist die MP-ID des Eigentümers (MSB) zur bilateralen Klärung anzugeben, wenn der angefragte MSB nicht selber der Eigentümer ist.
1148    fn evaluate_536(&self, _ctx: &EvaluationContext) -> ConditionResult {
1149        // Hinweis: MP-ID des Eigentümers (MSB) angeben — informational note, always applies
1150        ConditionResult::True
1151    }
1152
1153    /// [537] Hinweis: Wert aus BGM+Z72 DE1004 der ORDERS, mit der die Bestellung Beendigung der Konfiguration erfolgt ist.
1154    fn evaluate_537(&self, _ctx: &EvaluationContext) -> ConditionResult {
1155        // Hinweis: Wert aus BGM+Z72 DE1004 der ORDERS — informational note, always applies
1156        ConditionResult::True
1157    }
1158
1159    /// [538] Hinweis: Wert aus BGM+Z76 DE1004 der ORDERS, mit der die Reklamation der Konfiguration erfolgt ist.
1160    fn evaluate_538(&self, _ctx: &EvaluationContext) -> ConditionResult {
1161        // Hinweis: Wert aus BGM+Z76 DE1004 der ORDERS — informational note, always applies
1162        ConditionResult::True
1163    }
1164
1165    /// [539] Hinweis: Wert aus BGM+Z73/Z74 DE1004 der ORDERS, mit der die Bestellung der Konfiguration erfolgt ist.
1166    fn evaluate_539(&self, _ctx: &EvaluationContext) -> ConditionResult {
1167        // Hinweis: Wert aus BGM+Z73/Z74 DE1004 der ORDERS — informational note, always applies
1168        ConditionResult::True
1169    }
1170
1171    /// [540] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
1172    fn evaluate_540(&self, _ctx: &EvaluationContext) -> ConditionResult {
1173        // Hinweis: Es darf nur eine Information im DE3148 übermittelt werden — informational note, always applies
1174        ConditionResult::True
1175    }
1176
1177    /// [542] Hinweis: Wert aus BGM+Z91 DE1004 der ORDERS, mit der die Bestellung Änderung der Abrechnungsdaten erfolgt ist.
1178    fn evaluate_542(&self, _ctx: &EvaluationContext) -> ConditionResult {
1179        // Hinweis: Wert aus BGM+Z91 DE1004 der ORDERS — informational note about value origin, always applies
1180        ConditionResult::True
1181    }
1182
1183    /// [902] Format: Format: Möglicher Wert: ≥ 0
1184    // REVIEW: Format condition requiring numeric value >= 0. Applied to QTY segment value (elements[0][1]) by convention matching the example pattern. Medium confidence because the exact segment this applies to is not specified in the condition text, but QTY is the standard target for quantity format conditions. (medium confidence)
1185    fn evaluate_902(&self, ctx: &EvaluationContext) -> ConditionResult {
1186        ctx.format_check("QTY", 0, 1, |val| validate_numeric(val, ">=", 0.0))
1187    }
1188
1189    /// [903] Format: Möglicher Wert: 1
1190    // REVIEW: Format condition requiring the value to equal exactly 1. Applied to QTY segment value (elements[0][1]) by convention. Medium confidence as the exact target segment is not stated, but QTY quantity value is the standard target for this kind of format constraint. (medium confidence)
1191    fn evaluate_903(&self, ctx: &EvaluationContext) -> ConditionResult {
1192        ctx.format_check("QTY", 0, 1, |val| validate_numeric(val, "==", 1.0))
1193    }
1194
1195    /// [930] Format: max. 2 Nachkommastellen
1196    // REVIEW: Format condition requiring at most 2 decimal places. Applied to QTY segment value (elements[0][1]) following the standard pattern from example 19. Medium confidence as the exact target segment is not specified in the condition text, but QTY quantity value is the canonical target for decimal place constraints. (medium confidence)
1197    fn evaluate_930(&self, ctx: &EvaluationContext) -> ConditionResult {
1198        ctx.format_check("QTY", 0, 1, |val| validate_max_decimal_places(val, 2))
1199    }
1200
1201    /// [931] Format: ZZZ = +00
1202    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
1203        ctx.format_check("DTM", 0, 1, validate_timezone_utc)
1204    }
1205
1206    /// [932] Format: HHMM = 2200
1207    fn evaluate_932(&self, ctx: &EvaluationContext) -> ConditionResult {
1208        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2200"))
1209    }
1210
1211    /// [933] Format: HHMM = 2300
1212    fn evaluate_933(&self, ctx: &EvaluationContext) -> ConditionResult {
1213        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2300"))
1214    }
1215
1216    /// [934] Format: HHMM = 0400
1217    fn evaluate_934(&self, ctx: &EvaluationContext) -> ConditionResult {
1218        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "0400"))
1219    }
1220
1221    /// [935] Format: HHMM = 0500
1222    fn evaluate_935(&self, ctx: &EvaluationContext) -> ConditionResult {
1223        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "0500"))
1224    }
1225
1226    /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
1227    // REVIEW: Format condition checking that the string contains '@' and '.' — characteristic of an email address format requirement. Applied to COM segment with EM (Electronic Mail) qualifier where elements[0][0] is the address and elements[0][1] is the communication means type code. Returns Unknown when no COM+EM segment is found (condition not applicable). (medium confidence)
1228    fn evaluate_939(&self, ctx: &EvaluationContext) -> ConditionResult {
1229        // Format: string must contain '@' and '.' — email address format check
1230        // Applied to COM segment with EM (Electronic Mail) qualifier
1231        // COM+address:qualifier → elements[0] = ["address", "qualifier"]
1232        let com_segs = ctx.find_segments("COM");
1233        for seg in &com_segs {
1234            if let Some(elem0) = seg.elements.first() {
1235                if elem0.get(1).map(|q| q == "EM").unwrap_or(false) {
1236                    let value = elem0.first().map(|s| s.as_str()).unwrap_or("");
1237                    if value.is_empty() {
1238                        return ConditionResult::Unknown;
1239                    }
1240                    return ConditionResult::from(value.contains('@') && value.contains('.'));
1241                }
1242            }
1243        }
1244        ConditionResult::Unknown
1245    }
1246
1247    /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
1248    // REVIEW: Format condition checking that the string starts with '+' and contains only digits afterwards — the international phone number format (e.g. +4912345678). Applied to COM segments with phone-type qualifiers (TE=Telephone, FX=Telefax, AH=After Hours). Returns Unknown when no COM segment with a phone qualifier is found. Requires at least one digit after '+' (len > 1) since a bare '+' is not a valid phone number. (medium confidence)
1249    fn evaluate_940(&self, ctx: &EvaluationContext) -> ConditionResult {
1250        // Format: string must start with '+' and be followed only by digits — international phone number format
1251        // Applied to COM segments with phone-type qualifiers: TE (Telephone), FX (Telefax), AH (After Hours)
1252        // COM+number:qualifier → elements[0] = ["number", "qualifier"]
1253        let com_segs = ctx.find_segments("COM");
1254        for seg in &com_segs {
1255            if let Some(elem0) = seg.elements.first() {
1256                let qualifier = elem0.get(1).map(|s| s.as_str()).unwrap_or("");
1257                if matches!(qualifier, "TE" | "FX" | "AH") {
1258                    let value = elem0.first().map(|s| s.as_str()).unwrap_or("");
1259                    if value.is_empty() {
1260                        return ConditionResult::Unknown;
1261                    }
1262                    return ConditionResult::from(
1263                        value.starts_with('+')
1264                            && value.len() > 1
1265                            && value[1..].chars().all(|c| c.is_ascii_digit()),
1266                    );
1267                }
1268            }
1269        }
1270        ConditionResult::Unknown
1271    }
1272
1273    /// [2036] Pro Nachricht ist die SG27 genau einmal anzugeben
1274    // REVIEW: Cardinality condition requiring SG27 to appear exactly once per message. SG27 is the transaction group (tx_group) in ORDRSP FV2510. Uses the group navigator to count SG27 instances at the top level. Falls back to Unknown when no navigator is available (e.g., when context is used without a pre-assembled tree). This is a structural cardinality rule rather than a content condition. (medium confidence)
1275    fn evaluate_2036(&self, ctx: &EvaluationContext) -> ConditionResult {
1276        // SG27 must appear exactly once per message
1277        // SG27 is the transaction group (tx_group) in ORDRSP
1278        if let Some(nav) = ctx.navigator() {
1279            let count = nav.group_instance_count(&["SG27"]);
1280            ConditionResult::from(count == 1)
1281        } else {
1282            ConditionResult::Unknown
1283        }
1284    }
1285}
1286
1287/// HAND-EDITED (#334): "Wenn AJT+<answer>[+<list>] vorhanden" where it decides
1288/// SG2's FTX ([27] [28] [33] [43] [44], `[72] ⊻ [73] ⊻ [74]`) reads the AJT of
1289/// that SG2: the free text explains its own answer, and SG2 repeats once per
1290/// answer. Message-wide when the scope does not reach an SG2. An empty `lists`
1291/// takes any list.
1292fn sg2_ajt(ctx: &EvaluationContext, answers: &[&str], lists: &[&str]) -> ConditionResult {
1293    fn component(seg: &OwnedSegment, elem: usize) -> Option<&str> {
1294        seg.elements
1295            .get(elem)
1296            .and_then(|e| e.first())
1297            .map(String::as_str)
1298    }
1299    ConditionResult::from(ctx.scoped_find_segments_in("SG2", "AJT").iter().any(|seg| {
1300        component(seg, 0).is_some_and(|a| answers.contains(&a))
1301            && (lists.is_empty() || component(seg, 1).is_some_and(|l| lists.contains(&l)))
1302    }))
1303}