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}