Skip to main content

automapper_validation/generated/fv2504/
reqote_conditions_fv2504.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2504/REQOTE_AHB_1_0a_Fehlerkorrektur_20250225.xml
4// Generated: 2026-03-12T09:51:49Z
5// </auto-generated>
6
7#[allow(unused_imports)]
8use crate::eval::format_validators::*;
9use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
10
11/// Generated condition evaluator for REQOTE FV2504.
12pub struct ReqoteConditionEvaluatorFV2504 {
13    // External condition IDs that require runtime context.
14    external_conditions: std::collections::HashSet<u32>,
15}
16
17impl Default for ReqoteConditionEvaluatorFV2504 {
18    fn default() -> Self {
19        let mut external_conditions = std::collections::HashSet::new();
20        external_conditions.insert(10);
21        external_conditions.insert(24);
22        external_conditions.insert(28);
23        external_conditions.insert(29);
24        external_conditions.insert(30);
25        external_conditions.insert(31);
26        external_conditions.insert(32);
27        external_conditions.insert(33);
28        external_conditions.insert(35);
29        external_conditions.insert(36);
30        external_conditions.insert(37);
31        external_conditions.insert(38);
32        external_conditions.insert(41);
33        external_conditions.insert(42);
34        external_conditions.insert(43);
35        external_conditions.insert(492);
36        external_conditions.insert(493);
37        external_conditions.insert(2065);
38        external_conditions.insert(2066);
39        Self {
40            external_conditions,
41        }
42    }
43}
44
45impl ConditionEvaluator for ReqoteConditionEvaluatorFV2504 {
46    fn message_type(&self) -> &str {
47        "REQOTE"
48    }
49
50    fn format_version(&self) -> &str {
51        "FV2504"
52    }
53
54    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
55        match condition {
56            1 => self.evaluate_1(ctx),
57            2 => self.evaluate_2(ctx),
58            10 => self.evaluate_10(ctx),
59            15 => self.evaluate_15(ctx),
60            16 => self.evaluate_16(ctx),
61            17 => self.evaluate_17(ctx),
62            18 => self.evaluate_18(ctx),
63            19 => self.evaluate_19(ctx),
64            20 => self.evaluate_20(ctx),
65            21 => self.evaluate_21(ctx),
66            22 => self.evaluate_22(ctx),
67            23 => self.evaluate_23(ctx),
68            24 => self.evaluate_24(ctx),
69            25 => self.evaluate_25(ctx),
70            26 => self.evaluate_26(ctx),
71            27 => self.evaluate_27(ctx),
72            28 => self.evaluate_28(ctx),
73            29 => self.evaluate_29(ctx),
74            30 => self.evaluate_30(ctx),
75            31 => self.evaluate_31(ctx),
76            32 => self.evaluate_32(ctx),
77            33 => self.evaluate_33(ctx),
78            35 => self.evaluate_35(ctx),
79            36 => self.evaluate_36(ctx),
80            37 => self.evaluate_37(ctx),
81            38 => self.evaluate_38(ctx),
82            39 => self.evaluate_39(ctx),
83            40 => self.evaluate_40(ctx),
84            41 => self.evaluate_41(ctx),
85            42 => self.evaluate_42(ctx),
86            43 => self.evaluate_43(ctx),
87            490 => self.evaluate_490(ctx),
88            491 => self.evaluate_491(ctx),
89            492 => self.evaluate_492(ctx),
90            493 => self.evaluate_493(ctx),
91            494 => self.evaluate_494(ctx),
92            500 => self.evaluate_500(ctx),
93            501 => self.evaluate_501(ctx),
94            502 => self.evaluate_502(ctx),
95            503 => self.evaluate_503(ctx),
96            504 => self.evaluate_504(ctx),
97            507 => self.evaluate_507(ctx),
98            508 => self.evaluate_508(ctx),
99            509 => self.evaluate_509(ctx),
100            510 => self.evaluate_510(ctx),
101            511 => self.evaluate_511(ctx),
102            512 => self.evaluate_512(ctx),
103            514 => self.evaluate_514(ctx),
104            515 => self.evaluate_515(ctx),
105            516 => self.evaluate_516(ctx),
106            903 => self.evaluate_903(ctx),
107            906 => self.evaluate_906(ctx),
108            931 => self.evaluate_931(ctx),
109            932 => self.evaluate_932(ctx),
110            933 => self.evaluate_933(ctx),
111            934 => self.evaluate_934(ctx),
112            935 => self.evaluate_935(ctx),
113            939 => self.evaluate_939(ctx),
114            940 => self.evaluate_940(ctx),
115            950 => self.evaluate_950(ctx),
116            951 => self.evaluate_951(ctx),
117            960 => self.evaluate_960(ctx),
118            961 => self.evaluate_961(ctx),
119            962 => self.evaluate_962(ctx),
120            967 => self.evaluate_967(ctx),
121            2005 => self.evaluate_2005(ctx),
122            2060 => self.evaluate_2060(ctx),
123            2061 => self.evaluate_2061(ctx),
124            2062 => self.evaluate_2062(ctx),
125            2063 => self.evaluate_2063(ctx),
126            2064 => self.evaluate_2064(ctx),
127            2065 => self.evaluate_2065(ctx),
128            2066 => self.evaluate_2066(ctx),
129            _ => ConditionResult::Unknown,
130        }
131    }
132
133    fn is_external(&self, condition: u32) -> bool {
134        self.external_conditions.contains(&condition)
135    }
136    fn is_known(&self, condition: u32) -> bool {
137        matches!(
138            condition,
139            1 | 2
140                | 10
141                | 15
142                | 16
143                | 17
144                | 18
145                | 19
146                | 20
147                | 21
148                | 22
149                | 23
150                | 24
151                | 25
152                | 26
153                | 27
154                | 28
155                | 29
156                | 30
157                | 31
158                | 32
159                | 33
160                | 35
161                | 36
162                | 37
163                | 38
164                | 39
165                | 40
166                | 41
167                | 42
168                | 43
169                | 490
170                | 491
171                | 492
172                | 493
173                | 494
174                | 500
175                | 501
176                | 502
177                | 503
178                | 504
179                | 507
180                | 508
181                | 509
182                | 510
183                | 511
184                | 512
185                | 514
186                | 515
187                | 516
188                | 903
189                | 906
190                | 931
191                | 932
192                | 933
193                | 934
194                | 935
195                | 939
196                | 940
197                | 950
198                | 951
199                | 960
200                | 961
201                | 962
202                | 967
203                | 2005
204                | 2060
205                | 2061
206                | 2062
207                | 2063
208                | 2064
209                | 2065
210                | 2066
211        )
212    }
213}
214
215impl ReqoteConditionEvaluatorFV2504 {
216    /// [33] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.4 „Messprodukte mit Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW“ enthalten sind.
217    /// EXTERNAL: Requires context from outside the message.
218    fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
219        ctx.external
220            .evaluate("product_in_konfigurationserlaubnis_typ2_smgw_list")
221    }
222
223    /// [37] Es sind nur die Messprodukt-Position-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.7 „Art der Werte für Messprodukte nach Typ 2“ enthalten sind.
224    /// EXTERNAL: Requires context from outside the message.
225    fn evaluate_37(&self, ctx: &EvaluationContext) -> ConditionResult {
226        ctx.external
227            .evaluate("product_position_code_in_art_der_werte_typ2_list")
228    }
229
230    /// [38] Wenn innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) ein Produkt angegeben ist, das in der Codeliste der Konfigurationen...
231    /// EXTERNAL: Requires context from outside the message.
232    fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
233        ctx.external
234            .evaluate("product_is_schwellwert_triggered_in_konfigurationserlaubnis_list")
235    }
236
237    /// [41] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.6.1 „Werte nach Typ 2 aus Backend“ enthalten sind.
238    /// EXTERNAL: Requires context from outside the message.
239    fn evaluate_41(&self, ctx: &EvaluationContext) -> ConditionResult {
240        ctx.external.evaluate("product_in_werte_typ2_backend_list")
241    }
242
243    /// [42] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.6.2 „Werte nach Typ 2 aus SMGW“ enthalten sind.
244    /// EXTERNAL: Requires context from outside the message.
245    fn evaluate_42(&self, ctx: &EvaluationContext) -> ConditionResult {
246        ctx.external.evaluate("product_in_werte_typ2_smgw_list")
247    }
248
249    /// [43] Wenn innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) ein Produkt angegeben ist, das in der Codeliste der Konfigurationen...
250    /// EXTERNAL: Requires context from outside the message.
251    fn evaluate_43(&self, ctx: &EvaluationContext) -> ConditionResult {
252        ctx.external
253            .evaluate("product_is_schwellwert_ausloeser_typ2_smgw")
254    }
255
256    /// [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...
257    fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
258        let dtm_segs = ctx.find_segments("DTM");
259        match dtm_segs
260            .first()
261            .and_then(|s| s.elements.first())
262            .and_then(|e| e.get(1))
263        {
264            Some(val) => is_mesz_utc(val),
265            None => ConditionResult::False, // segment absent → condition not applicable
266        }
267    }
268
269    /// [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)...
270    fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
271        let dtm_segs = ctx.find_segments("DTM");
272        match dtm_segs
273            .first()
274            .and_then(|s| s.elements.first())
275            .and_then(|e| e.get(1))
276        {
277            Some(val) => is_mez_utc(val),
278            None => ConditionResult::False, // segment absent → condition not applicable
279        }
280    }
281
282    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.
283    fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
284        // TODO: Condition [494] requires manual implementation
285        // Reason: Requires comparing 'this DE' value against the document creation timestamp (DTM+137). Without knowing which specific data element/segment this condition is applied to in the current validation context, a generic implementation cannot be written safely. The condition is context-dependent and the field being validated is not specified in the condition text alone.
286        ConditionResult::Unknown
287    }
288
289    /// [967] Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4
290    fn evaluate_967(&self, _ctx: &EvaluationContext) -> ConditionResult {
291        // TODO: Condition [967] requires manual implementation
292        // Reason: Format: X.509 certificate body per BSI TR-03109-4. Validating an X.509 certificate body requires actual ASN.1/DER parsing — none of the available format validation helpers cover certificate validation. This cannot be implemented with the current EvaluationContext API.
293        ConditionResult::Unknown
294    }
295
296    /// [2065] Diese SG28 ist so oft zu wiederholen, wie zu den unterschiedlichen Messprodukt-Position-Codes zu dem innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis fü...
297    /// EXTERNAL: Requires context from outside the message.
298    fn evaluate_2065(&self, ctx: &EvaluationContext) -> ConditionResult {
299        ctx.external
300            .evaluate("sg28_repeat_count_schwellwert_smgw_config")
301    }
302
303    /// [2066] Diese SG28 ist so oft zu wiederholen, wie zu den unterschiedlichen Messprodukt-Position-Codes zu dem innerhalb derselben SG27 LIN im PIA+5 DE7140 (Erforderliches Produkt Konfigurationserlaubnis fü...
304    /// EXTERNAL: Requires context from outside the message.
305    fn evaluate_2066(&self, ctx: &EvaluationContext) -> ConditionResult {
306        ctx.external
307            .evaluate("sg28_repeat_count_schwellwert_smgw_werte_typ2")
308    }
309
310    /// [1] Wenn DTM+203 (Ausführungsdatum) nicht vorhanden
311    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
312        ctx.lacks_qualifier("DTM", 0, "203")
313    }
314
315    /// [2] Wenn DTM+469 (Beginn zum (nächstmöglichen Termin)) nicht vorhanden
316    fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
317        ctx.lacks_qualifier("DTM", 0, "469")
318    }
319
320    /// [10] MP-ID nur aus Sparte Strom
321    /// EXTERNAL: Requires context from outside the message.
322    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
323        ctx.external.evaluate("mp_id_strom_only")
324    }
325
326    /// [15] Wenn DTM+76 (Datum zum geplanten Leistungsbeginn) nicht vorhanden
327    fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
328        ctx.lacks_qualifier("DTM", 0, "76")
329    }
330
331    /// [16] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) nicht vorhanden
332    fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
333        ctx.lacks_qualifier("RFF", 0, "Z41")
334    }
335
336    /// [17] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) vorhanden
337    fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
338        ctx.has_qualifier("RFF", 0, "Z41")
339    }
340
341    /// [18] Wenn IMD++Z55 (Änderung Konfiguration) vorhanden
342    fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
343        ctx.has_qualifier("IMD", 1, "Z55")
344    }
345
346    /// [19] Wenn SG27 LIN++Z64 (Erforderliches Produkt Schaltzeitdefinitionen) vorhanden
347    fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
348        ctx.has_qualifier("LIN", 1, "Z64")
349    }
350
351    /// [20] Wenn SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) vorhanden
352    fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
353        ctx.has_qualifier("LIN", 1, "Z65")
354    }
355
356    /// [21] Wenn SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) vorhanden
357    fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
358        ctx.has_qualifier("LIN", 1, "Z66")
359    }
360
361    /// [22] Wenn SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) vorhanden
362    fn evaluate_22(&self, ctx: &EvaluationContext) -> ConditionResult {
363        ctx.has_qualifier("LIN", 1, "Z67")
364    }
365
366    /// [23] Wenn SG27 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) vorhanden
367    fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
368        ctx.has_qualifier("LIN", 1, "Z68")
369    }
370
371    /// [24] Wenn Produkt bestellt werden soll
372    /// EXTERNAL: Requires context from outside the message.
373    // REVIEW: Whether a product should be ordered is a business-intent condition. In a REQOTE context this could theoretically be signalled by presence of PIA+5, but the AHB phrasing 'soll bestellt werden' indicates a business decision or workflow state that cannot be reliably inferred from message structure alone. (medium confidence)
374    fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
375        ctx.external.evaluate("product_to_be_ordered")
376    }
377
378    /// [25] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist.
379    fn evaluate_25(&self, ctx: &EvaluationContext) -> ConditionResult {
380        // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist.
381        // LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
382        // Marktlokation ID: 11 digits with Luhn check digit
383        let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
384        match segs
385            .first()
386            .and_then(|s| s.elements.get(1))
387            .and_then(|e| e.first())
388        {
389            Some(val) if !val.is_empty() => validate_malo_id(val),
390            _ => ConditionResult::Unknown,
391        }
392    }
393
394    /// [26] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist.
395    fn evaluate_26(&self, ctx: &EvaluationContext) -> ConditionResult {
396        // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist.
397        // LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
398        // Messlokation ID: 33 alphanumeric characters (Zählpunkt format)
399        let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
400        match segs
401            .first()
402            .and_then(|s| s.elements.get(1))
403            .and_then(|e| e.first())
404        {
405            Some(val) if !val.is_empty() => validate_zahlpunkt(val),
406            _ => ConditionResult::Unknown,
407        }
408    }
409
410    /// [27] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist.
411    // REVIEW: Checks LOC+172 DE3225 value as a Netzlokation ID by exclusion: it is present but does not match Marktlokation format (11-digit Luhn) nor Messlokation format (33 alphanumeric). Medium confidence because there is no dedicated Netzlokation validator — the logic relies on the three location types being mutually exclusive and exhaustive for this qualifier. (medium confidence)
412    fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
413        // Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist.
414        // LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
415        // Netzlokation ID: neither MaLo (11 digits Luhn) nor MeLo (33 alphanumeric)
416        let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
417        match segs
418            .first()
419            .and_then(|s| s.elements.get(1))
420            .and_then(|e| e.first())
421        {
422            Some(val) if !val.is_empty() => {
423                let is_malo = matches!(validate_malo_id(val), ConditionResult::True);
424                let is_melo = matches!(validate_zahlpunkt(val), ConditionResult::True);
425                ConditionResult::from(!is_malo && !is_melo)
426            }
427            _ => ConditionResult::Unknown,
428        }
429    }
430
431    /// [28] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist.
432    /// EXTERNAL: Requires context from outside the message.
433    fn evaluate_28(&self, ctx: &EvaluationContext) -> ConditionResult {
434        ctx.external.evaluate("loc_172_is_steuerbare_ressource")
435    }
436
437    /// [29] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.1 „Konfigurationsprodukte Schaltzeitdefinition“ enthalten sind.
438    /// EXTERNAL: Requires context from outside the message.
439    fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
440        ctx.external
441            .evaluate("product_in_konfiguration_schaltzeitdefinition")
442    }
443
444    /// [30] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.2 „Konfigurationsprodukte Leistungskurvendefinition“ enthalten sind.
445    /// EXTERNAL: Requires context from outside the message.
446    fn evaluate_30(&self, ctx: &EvaluationContext) -> ConditionResult {
447        ctx.external
448            .evaluate("product_in_konfiguration_leistungskurvendefinition")
449    }
450
451    /// [31] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.3 „Konfigurationsprodukte Ad-Hoc-Steuerkanal“ enthalten sind.
452    /// EXTERNAL: Requires context from outside the message.
453    fn evaluate_31(&self, ctx: &EvaluationContext) -> ConditionResult {
454        ctx.external
455            .evaluate("product_in_konfiguration_adhoc_steuerkanal")
456    }
457
458    /// [32] Es sind nur die Messprodukte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.5 „Messprodukte für Werte nach Typ 2 aus Backend für LF und NB“ enthalten sind.
459    /// EXTERNAL: Requires context from outside the message.
460    fn evaluate_32(&self, ctx: &EvaluationContext) -> ConditionResult {
461        ctx.external.evaluate("product_in_messprodukte_typ2_lf_nb")
462    }
463
464    /// [35] Wenn MP-ID in SG11 NAD+MS mit Rolle LF vorhanden
465    /// EXTERNAL: Requires context from outside the message.
466    // REVIEW: NAD+MS identifies the sender by MP-ID (elements[0]=MS), but the market role 'LF' (Lieferant) cannot be determined from the NAD segment alone — it requires an external participant role registry lookup. The segment only carries the ID, not the role. (medium confidence)
467    fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
468        ctx.external.evaluate("sender_is_lf")
469    }
470
471    /// [36] Wenn MP-ID in SG11 NAD+MS mit Rolle NB vorhanden
472    /// EXTERNAL: Requires context from outside the message.
473    // REVIEW: Same pattern as condition 35: NAD+MS carries the sender MP-ID but the market role 'NB' (Netzbetreiber) cannot be inferred from the EDIFACT segment alone — requires external role registry. (medium confidence)
474    fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
475        ctx.external.evaluate("sender_is_nb")
476    }
477
478    /// [39] wenn im DE3155 in demselben COM der Code EM vorhanden ist
479    fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
480        // COM segment: C076 composite — elements[0][0]=DE3148 (address), elements[0][1]=DE3155 (qualifier)
481        let coms = ctx.find_segments("COM");
482        if coms.is_empty() {
483            return ConditionResult::False;
484        }
485        ConditionResult::from(coms.iter().any(|s| {
486            s.elements
487                .first()
488                .and_then(|e| e.get(1))
489                .is_some_and(|v| v == "EM")
490        }))
491    }
492
493    /// [40] wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
494    fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
495        // COM segment: C076 composite — elements[0][0]=DE3148 (address), elements[0][1]=DE3155 (qualifier)
496        // TE=Telephone, FX=Fax, AJ=Unknown, AL=Unknown (telephony-related codes)
497        let coms = ctx.find_segments("COM");
498        if coms.is_empty() {
499            return ConditionResult::False;
500        }
501        ConditionResult::from(coms.iter().any(|s| {
502            s.elements
503                .first()
504                .and_then(|e| e.get(1))
505                .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
506        }))
507    }
508
509    /// [492] wenn MP-ID in NAD+MR aus Sparte Strom
510    /// EXTERNAL: Requires context from outside the message.
511    // REVIEW: Checks whether the MP-ID in NAD+MR belongs to the electricity sector (Sparte Strom). The sector of a market participant cannot be derived from the EDIFACT message structure — it requires external market participant registry lookup. Delegated to external provider. (medium confidence)
512    fn evaluate_492(&self, ctx: &EvaluationContext) -> ConditionResult {
513        ctx.external.evaluate("recipient_is_electricity_sector")
514    }
515
516    /// [493] wenn MP-ID in NAD+MR aus Sparte Gas
517    /// EXTERNAL: Requires context from outside the message.
518    // REVIEW: Checks whether the MP-ID in NAD+MR belongs to the gas sector (Sparte Gas). Same reasoning as condition 492 — sector membership requires external registry lookup. (medium confidence)
519    fn evaluate_493(&self, ctx: &EvaluationContext) -> ConditionResult {
520        ctx.external.evaluate("recipient_is_gas_sector")
521    }
522
523    /// [500] Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
524    fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
525        // Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
526        // Informational note — always applies
527        ConditionResult::True
528    }
529
530    /// [501] Hinweis: Angabe eines Ansprechpartners für die Rechnungsabwicklung
531    fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
532        // Hinweis: Angabe eines Ansprechpartners für die Rechnungsabwicklung
533        // Informational note — always applies
534        ConditionResult::True
535    }
536
537    /// [502] Hinweis: Verwendung der ID der Marktlokation
538    fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
539        // Hinweis: Verwendung der ID der Marktlokation
540        // Informational note — always applies
541        ConditionResult::True
542    }
543
544    /// [503] Hinweis: Verwendung der ID der Messlokation
545    fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
546        // Hinweis: Verwendung der ID der Messlokation
547        // Informational note — always applies
548        ConditionResult::True
549    }
550
551    /// [504] Hinweis: Verwendung der ID der Tranche
552    fn evaluate_504(&self, _ctx: &EvaluationContext) -> ConditionResult {
553        // Hinweis: Verwendung der ID der Tranche — informational note, always applies
554        ConditionResult::True
555    }
556
557    /// [507] Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD mit BGM+E01 mit der die Anmeldung des MSB-Wechsels erfolgt ist.
558    fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
559        // Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD — informational note, always applies
560        ConditionResult::True
561    }
562
563    /// [508] Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
564    fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
565        // Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA — informational note, always applies
566        ConditionResult::True
567    }
568
569    /// [509] Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z73 mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
570    fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
571        // Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA — informational note, always applies
572        ConditionResult::True
573    }
574
575    /// [510] Hinweis: Verwendung der ID der Netzlokation
576    fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
577        // Hinweis: Verwendung der ID der Netzlokation — informational note, always applies
578        ConditionResult::True
579    }
580
581    /// [511] Hinweis: Verwendung der ID der Steuerbaren Ressource
582    fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
583        ConditionResult::True
584    }
585
586    /// [512] Hinweis: Für den Empfang der Werte nach Typ 2 aus dem SMGW.
587    fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
588        ConditionResult::True
589    }
590
591    /// [514] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
592    fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
593        ConditionResult::True
594    }
595
596    /// [515] Hinweis: Es ist eine URI IPv4 für die Bereitstellung der Werte anzugeben.
597    fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
598        ConditionResult::True
599    }
600
601    /// [516] Hinweis: Es ist eine URI IPv6 für die Bereitstellung der Werte anzugeben.
602    fn evaluate_516(&self, _ctx: &EvaluationContext) -> ConditionResult {
603        ConditionResult::True
604    }
605
606    /// [903] Format: Möglicher Wert: 1
607    fn evaluate_903(&self, _ctx: &EvaluationContext) -> ConditionResult {
608        ConditionResult::True
609    }
610
611    /// [906] Format: max. 3 Nachkommastellen
612    fn evaluate_906(&self, _ctx: &EvaluationContext) -> ConditionResult {
613        ConditionResult::True
614    }
615
616    /// [931] Format: ZZZ = +00
617    fn evaluate_931(&self, _ctx: &EvaluationContext) -> ConditionResult {
618        ConditionResult::True
619    }
620
621    /// [932] Format: HHMM = 2200
622    fn evaluate_932(&self, _ctx: &EvaluationContext) -> ConditionResult {
623        ConditionResult::True
624    }
625
626    /// [933] Format: HHMM = 2300
627    fn evaluate_933(&self, _ctx: &EvaluationContext) -> ConditionResult {
628        ConditionResult::True
629    }
630
631    /// [934] Format: HHMM = 0400
632    fn evaluate_934(&self, _ctx: &EvaluationContext) -> ConditionResult {
633        ConditionResult::True
634    }
635
636    /// [935] Format: HHMM = 0500
637    fn evaluate_935(&self, _ctx: &EvaluationContext) -> ConditionResult {
638        ConditionResult::True
639    }
640
641    /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
642    fn evaluate_939(&self, _ctx: &EvaluationContext) -> ConditionResult {
643        ConditionResult::True
644    }
645
646    /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
647    fn evaluate_940(&self, _ctx: &EvaluationContext) -> ConditionResult {
648        ConditionResult::True
649    }
650
651    /// [950] Format: Marktlokations-ID
652    fn evaluate_950(&self, _ctx: &EvaluationContext) -> ConditionResult {
653        ConditionResult::True
654    }
655
656    /// [951] Format: Zählpunktbezeichnung
657    fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
658        let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z17");
659        match segs
660            .first()
661            .and_then(|s| s.elements.get(1))
662            .and_then(|e| e.first())
663        {
664            Some(val) => validate_zahlpunkt(val),
665            None => ConditionResult::False, // segment absent → condition not applicable
666        }
667    }
668
669    /// [960] Format: Netzlokations-ID
670    // REVIEW: Netzlokations-ID uses the same 11-digit Luhn check digit format as Marktlokations-ID. LOC+Z18 is the standard qualifier for Netzlokation. (medium confidence)
671    fn evaluate_960(&self, ctx: &EvaluationContext) -> ConditionResult {
672        let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z18");
673        match segs
674            .first()
675            .and_then(|s| s.elements.get(1))
676            .and_then(|e| e.first())
677        {
678            Some(val) => validate_malo_id(val),
679            None => ConditionResult::False, // segment absent → condition not applicable
680        }
681    }
682
683    /// [961] Format: SR-ID
684    // REVIEW: SR-ID (SteuerbareRessource-ID) uses the same 11-digit Luhn check digit format as MaLo-ID. LOC+Z19 is the standard qualifier for SteuerbareRessource. (medium confidence)
685    fn evaluate_961(&self, ctx: &EvaluationContext) -> ConditionResult {
686        let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z19");
687        match segs
688            .first()
689            .and_then(|s| s.elements.get(1))
690            .and_then(|e| e.first())
691        {
692            Some(val) => validate_malo_id(val),
693            None => ConditionResult::False, // segment absent → condition not applicable
694        }
695    }
696
697    /// [962] Format: max. 6 Vorkommastellen
698    fn evaluate_962(&self, ctx: &EvaluationContext) -> ConditionResult {
699        let segs = ctx.find_segments("QTY");
700        match segs
701            .first()
702            .and_then(|s| s.elements.first())
703            .and_then(|e| e.get(1))
704        {
705            Some(val) => validate_max_integer_digits(val, 6),
706            None => ConditionResult::False, // segment absent → condition not applicable
707        }
708    }
709
710    /// [2005] Pro Nachricht ist die SG27 genau einmal anzugeben
711    // REVIEW: SG27 must appear exactly once per message. LIN is the entry segment for SG27. Counting all LIN segments gives the SG27 instance count. Returns True when exactly one LIN exists. (medium confidence)
712    fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
713        let lin_count = ctx.find_segments("LIN").len();
714        ConditionResult::from(lin_count == 1)
715    }
716
717    /// [2060] Pro Nachricht ist die SG27 LIN+Z64 (Erforderliches Produkt Schaltzeitdefinitionen) maximal einmal anzugeben
718    // REVIEW: LIN with DE1229=Z64 (Erforderliches Produkt Schaltzeitdefinitionen) must appear at most once. Per segment structure reference, DE1229 (Handlung, Code) is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
719    fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
720        let lins = ctx.find_segments("LIN");
721        let count = lins
722            .iter()
723            .filter(|s| {
724                s.elements
725                    .get(1)
726                    .and_then(|e| e.first())
727                    .is_some_and(|v| v == "Z64")
728            })
729            .count();
730        ConditionResult::from(count <= 1)
731    }
732
733    /// [2061] Pro Nachricht ist die SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) maximal einmal anzugeben
734    // REVIEW: LIN with DE1229=Z65 (Erforderliches Produkt Leistungskurvendefinitionen) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
735    fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
736        let lins = ctx.find_segments("LIN");
737        let count = lins
738            .iter()
739            .filter(|s| {
740                s.elements
741                    .get(1)
742                    .and_then(|e| e.first())
743                    .is_some_and(|v| v == "Z65")
744            })
745            .count();
746        ConditionResult::from(count <= 1)
747    }
748
749    /// [2062] Pro Nachricht ist die SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) maximal einmal anzugeben
750    // REVIEW: LIN with DE1229=Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
751    fn evaluate_2062(&self, ctx: &EvaluationContext) -> ConditionResult {
752        let lins = ctx.find_segments("LIN");
753        let count = lins
754            .iter()
755            .filter(|s| {
756                s.elements
757                    .get(1)
758                    .and_then(|e| e.first())
759                    .is_some_and(|v| v == "Z66")
760            })
761            .count();
762        ConditionResult::from(count <= 1)
763    }
764
765    /// [2063] Pro Nachricht ist die SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) maximal einmal anzugeben
766    // REVIEW: LIN with DE1229=Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
767    fn evaluate_2063(&self, ctx: &EvaluationContext) -> ConditionResult {
768        let lins = ctx.find_segments("LIN");
769        let count = lins
770            .iter()
771            .filter(|s| {
772                s.elements
773                    .get(1)
774                    .and_then(|e| e.first())
775                    .is_some_and(|v| v == "Z67")
776            })
777            .count();
778        ConditionResult::from(count <= 1)
779    }
780
781    /// [2064] Pro Nachricht ist die SG27 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) maximal einmal anzugeben
782    // REVIEW: LIN with DE1229=Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) must appear at most once. Per segment structure reference, DE1229 is at elements[1][0]. Returns True when 0 or 1 such LIN segments exist. (medium confidence)
783    fn evaluate_2064(&self, ctx: &EvaluationContext) -> ConditionResult {
784        let lins = ctx.find_segments("LIN");
785        let count = lins
786            .iter()
787            .filter(|s| {
788                s.elements
789                    .get(1)
790                    .and_then(|e| e.first())
791                    .is_some_and(|v| v == "Z68")
792            })
793            .count();
794        ConditionResult::from(count <= 1)
795    }
796}