Skip to main content

automapper_validation/generated/fv2504/
ordrsp_conditions_fv2504.rs

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