// <auto-generated>
// Generated by automapper-generator generate-conditions
// AHB: xml-migs-and-ahbs/FV2510/REQOTE_AHB_1_1_20250401.xml
// Generated: 2026-03-12T10:31:57Z
// </auto-generated>
#[allow(unused_imports)]
use crate::eval::format_validators::*;
use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
/// Generated condition evaluator for REQOTE FV2510.
pub struct ReqoteConditionEvaluatorFV2510 {
// External condition IDs that require runtime context.
external_conditions: std::collections::HashSet<u32>,
}
impl Default for ReqoteConditionEvaluatorFV2510 {
fn default() -> Self {
let mut external_conditions = std::collections::HashSet::new();
external_conditions.insert(10);
external_conditions.insert(24);
external_conditions.insert(28);
external_conditions.insert(29);
external_conditions.insert(30);
external_conditions.insert(31);
external_conditions.insert(32);
external_conditions.insert(33);
external_conditions.insert(35);
external_conditions.insert(36);
external_conditions.insert(37);
external_conditions.insert(38);
external_conditions.insert(41);
external_conditions.insert(42);
external_conditions.insert(43);
external_conditions.insert(44);
external_conditions.insert(45);
external_conditions.insert(47);
external_conditions.insert(48);
external_conditions.insert(49);
external_conditions.insert(50);
external_conditions.insert(51);
external_conditions.insert(53);
external_conditions.insert(492);
external_conditions.insert(493);
external_conditions.insert(2065);
external_conditions.insert(2066);
Self {
external_conditions,
}
}
}
impl ConditionEvaluator for ReqoteConditionEvaluatorFV2510 {
fn message_type(&self) -> &str {
"REQOTE"
}
fn format_version(&self) -> &str {
"FV2510"
}
fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
match condition {
1 => self.evaluate_1(ctx),
2 => self.evaluate_2(ctx),
10 => self.evaluate_10(ctx),
15 => self.evaluate_15(ctx),
16 => self.evaluate_16(ctx),
17 => self.evaluate_17(ctx),
18 => self.evaluate_18(ctx),
19 => self.evaluate_19(ctx),
20 => self.evaluate_20(ctx),
21 => self.evaluate_21(ctx),
22 => self.evaluate_22(ctx),
23 => self.evaluate_23(ctx),
24 => self.evaluate_24(ctx),
25 => self.evaluate_25(ctx),
26 => self.evaluate_26(ctx),
27 => self.evaluate_27(ctx),
28 => self.evaluate_28(ctx),
29 => self.evaluate_29(ctx),
30 => self.evaluate_30(ctx),
31 => self.evaluate_31(ctx),
32 => self.evaluate_32(ctx),
33 => self.evaluate_33(ctx),
35 => self.evaluate_35(ctx),
36 => self.evaluate_36(ctx),
37 => self.evaluate_37(ctx),
38 => self.evaluate_38(ctx),
39 => self.evaluate_39(ctx),
40 => self.evaluate_40(ctx),
41 => self.evaluate_41(ctx),
42 => self.evaluate_42(ctx),
43 => self.evaluate_43(ctx),
44 => self.evaluate_44(ctx),
45 => self.evaluate_45(ctx),
47 => self.evaluate_47(ctx),
48 => self.evaluate_48(ctx),
49 => self.evaluate_49(ctx),
50 => self.evaluate_50(ctx),
51 => self.evaluate_51(ctx),
52 => self.evaluate_52(ctx),
53 => self.evaluate_53(ctx),
490 => self.evaluate_490(ctx),
491 => self.evaluate_491(ctx),
492 => self.evaluate_492(ctx),
493 => self.evaluate_493(ctx),
494 => self.evaluate_494(ctx),
500 => self.evaluate_500(ctx),
501 => self.evaluate_501(ctx),
502 => self.evaluate_502(ctx),
503 => self.evaluate_503(ctx),
504 => self.evaluate_504(ctx),
507 => self.evaluate_507(ctx),
508 => self.evaluate_508(ctx),
509 => self.evaluate_509(ctx),
510 => self.evaluate_510(ctx),
511 => self.evaluate_511(ctx),
512 => self.evaluate_512(ctx),
514 => self.evaluate_514(ctx),
515 => self.evaluate_515(ctx),
516 => self.evaluate_516(ctx),
517 => self.evaluate_517(ctx),
518 => self.evaluate_518(ctx),
520 => self.evaluate_520(ctx),
521 => self.evaluate_521(ctx),
903 => self.evaluate_903(ctx),
906 => self.evaluate_906(ctx),
911 => self.evaluate_911(ctx),
922 => self.evaluate_922(ctx),
931 => self.evaluate_931(ctx),
932 => self.evaluate_932(ctx),
933 => self.evaluate_933(ctx),
934 => self.evaluate_934(ctx),
935 => self.evaluate_935(ctx),
939 => self.evaluate_939(ctx),
940 => self.evaluate_940(ctx),
950 => self.evaluate_950(ctx),
951 => self.evaluate_951(ctx),
960 => self.evaluate_960(ctx),
961 => self.evaluate_961(ctx),
962 => self.evaluate_962(ctx),
967 => self.evaluate_967(ctx),
2005 => self.evaluate_2005(ctx),
2060 => self.evaluate_2060(ctx),
2061 => self.evaluate_2061(ctx),
2062 => self.evaluate_2062(ctx),
2063 => self.evaluate_2063(ctx),
2064 => self.evaluate_2064(ctx),
2065 => self.evaluate_2065(ctx),
2066 => self.evaluate_2066(ctx),
2067 => self.evaluate_2067(ctx),
2068 => self.evaluate_2068(ctx),
_ => ConditionResult::Unknown,
}
}
fn is_external(&self, condition: u32) -> bool {
self.external_conditions.contains(&condition)
}
fn is_known(&self, condition: u32) -> bool {
matches!(
condition,
1 | 2
| 10
| 15
| 16
| 17
| 18
| 19
| 20
| 21
| 22
| 23
| 24
| 25
| 26
| 27
| 28
| 29
| 30
| 31
| 32
| 33
| 35
| 36
| 37
| 38
| 39
| 40
| 41
| 42
| 43
| 44
| 45
| 47
| 48
| 49
| 50
| 51
| 52
| 53
| 490
| 491
| 492
| 493
| 494
| 500
| 501
| 502
| 503
| 504
| 507
| 508
| 509
| 510
| 511
| 512
| 514
| 515
| 516
| 517
| 518
| 520
| 521
| 903
| 906
| 911
| 922
| 931
| 932
| 933
| 934
| 935
| 939
| 940
| 950
| 951
| 960
| 961
| 962
| 967
| 2005
| 2060
| 2061
| 2062
| 2063
| 2064
| 2065
| 2066
| 2067
| 2068
)
}
}
impl ReqoteConditionEvaluatorFV2510 {
/// [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.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("messprodukt_in_konfigurationserlaubnis_smgw_list")
}
/// [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.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_37(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("messprodukt_position_in_kapitel_4_7_list")
}
/// [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...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("pia_product_triggers_schwellwert")
}
/// [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.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_41(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("messprodukt_in_kapitel_4_6_1_backend_list")
}
/// [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.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_42(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("messprodukt_in_kapitel_4_6_2_smgw_list")
}
/// [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...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_43(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("pia_config_schwellwert_ausloeser")
}
/// [44] Wenn in SG27 LIN (Erforderliches Produkt der Messlokation) das PIA+5 DE7140 mit einem Produkt-Code vorhanden ist der in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_44(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("pia_messlokation_weitere_energieflussrichtung")
}
/// [45] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_45(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("loc_172_is_steuerbare_ressource")
}
/// [47] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Ebene" mit dem Wert "Mess...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_47(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("pia_product_code_messlokation_ebene")
}
/// [48] Es sind weiterhin nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Produkt gegenü...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_48(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("pia_product_code_nb_bestellbar")
}
/// [49] Es sind weiterhin nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Produkt gegenü...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_49(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("product_code_allowed_for_lf")
}
/// [50] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Ebene" mit dem Wert "Netz...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_50(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("product_code_level_netzlokation")
}
/// [51] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 7 "Produkte zur Bestellung einer Änderung an einer Lokation" die in der Spalte "Ebene" mit dem Wert "Steu...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_51(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("product_code_level_steuerbare_ressource")
}
/// [52] wenn im DE3155 in demselben COM der Code TE / AL vorhanden ist
fn evaluate_52(&self, ctx: &EvaluationContext) -> ConditionResult {
// wenn im DE3155 in demselben COM der Code TE / AL vorhanden ist
// COM segment: elements[0][0] = D3148 (address), elements[0][1] = D3155 (channel qualifier)
let com_segs = ctx.find_segments("COM");
if com_segs.is_empty() {
return ConditionResult::Unknown;
}
for seg in &com_segs {
if let Some(code) = seg.elements.first().and_then(|e| e.get(1)) {
if code == "TE" || code == "AL" {
return ConditionResult::True;
}
}
}
ConditionResult::False
}
/// [53] wenn der LF der Marktlokation der genannten Lokation im gewünschten Umsetzungszeitraum nicht zugeordnet ist.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_53(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("lf_not_assigned_to_lokation_in_umsetzungszeitraum")
}
/// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt.
fn evaluate_494(&self, _ctx: &EvaluationContext) -> ConditionResult {
// TODO: Condition [494] requires manual implementation
// Reason: Condition states the date must be the document creation time or earlier. This requires knowing which specific DTM qualifier 'the date mentioned here' refers to in the field context, and comparing it against the document creation DTM. Without field-level context in the evaluator (only message-wide segment access), the correct source qualifier is ambiguous. Likely requires comparing a specific DTM against DTM+137 (document creation), but which qualifier is 'das hier genannte Datum' cannot be determined from the condition text alone.
ConditionResult::Unknown
}
/// [517] Hinweis: Verwendung der ID der Technischen Ressource
fn evaluate_517(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Verwendung der ID der Technischen Ressource — informational note, always applies
ConditionResult::True
}
/// [518] Hinweis: zur Angabe von Kontaktdaten des Kunden des Lieferanten um die Änderung an der Technik zu vereinfachen.
fn evaluate_518(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Angabe von Kontaktdaten des Kunden des Lieferanten — informational note, always applies
ConditionResult::True
}
/// [520] Hinweis: Angabe des Beginnzeitpunkts des gewünschten Umsetzungstermins aus Sicht des Anfragenden.
fn evaluate_520(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Angabe des Beginnzeitpunkts des gewünschten Umsetzungstermins — informational note, always applies
ConditionResult::True
}
/// [521] Hinweis: Angabe des Endezeitpunkts des gewünschten Umsetzungstermins aus Sicht des Anfragenden.
fn evaluate_521(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Angabe des Endezeitpunkts des gewünschten Umsetzungstermins — informational note, always applies
ConditionResult::True
}
/// [911] Format: Mögliche Werte: 1 bis n, je Nachricht oder Segmentgruppe bei 1 beginnend und fortlaufend aufsteigend
fn evaluate_911(&self, _ctx: &EvaluationContext) -> ConditionResult {
// TODO: Condition [911] requires manual implementation
// Reason: Sequential numbering validation (1..n, monotonically increasing per message or segment group) requires knowing the specific segment and element to inspect, plus iterating across all group instances to verify ordering. The condition description does not specify which segment/element carries the sequence number in this REQOTE SG28 context, and no relevant segment structure is provided. Cannot implement without that information.
ConditionResult::Unknown
}
/// [922] Format: TR-ID
fn evaluate_922(&self, _ctx: &EvaluationContext) -> ConditionResult {
// TODO: Condition [922] requires manual implementation
// Reason: Format: TR-ID validation requires knowing which specific segment and element in REQOTE SG28 carries the TR-ID value. The validate_tr_id helper is available, but the segment structure reference provided does not include the segment (e.g., RFF, IDE, or similar) that holds this identifier in SG28. Cannot safely implement without that context.
ConditionResult::Unknown
}
/// [967] Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4
fn evaluate_967(&self, _ctx: &EvaluationContext) -> ConditionResult {
// TODO: Condition [967] requires manual implementation
// Reason: Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4 requires X.509 certificate body parsing/validation. No helper for certificate format validation exists in the available API (validate_* functions cover numeric, DTM, email, phone, MaLo-ID, TR-ID, etc. — not binary certificate bodies). This would require a cryptographic library integration outside the current EvaluationContext API.
ConditionResult::Unknown
}
/// [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ü...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_2065(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("sg28_repetition_schwellwert_konfigurationserlaubnis_smgw")
}
/// [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ü...
/// EXTERNAL: Requires context from outside the message.
fn evaluate_2066(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("sg28_repetition_schwellwert_werte_typ2_smgw")
}
/// [2067] Die SG12 RFF+Z37 Referenz auf ID der Technischen Ressource ist so oft zu wiederholen, bis alle IDs der Technischen Ressourcen angegeben sind, die der Steuerbaren Ressource in LOC+172 DE3225 (Meldep...
fn evaluate_2067(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: SG12 RFF+Z37 (Referenz auf ID der Technischen Ressource) ist so oft zu wiederholen,
// bis alle IDs der Technischen Ressourcen angegeben sind, die der Steuerbaren Ressource in
// LOC+172 DE3225 (Meldepunkt) zugeordnet werden sollen — informational repetition cardinality note.
ConditionResult::True
}
/// [2068] Diese SG27 ist so oft zu wiederholen, dass alle Produkte zur Lokation die innerhalb des gewünschten Umsetzungstermins (Zeitintervall aus DTM+469 (Startdatum oder Zeitpunkt) und DTM+472 (Endedatum...
fn evaluate_2068(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: SG27 ist so oft zu wiederholen, dass alle gewünschten Produkte zur Lokation
// innerhalb des Umsetzungstermins (DTM+469 bis DTM+472) genannt sind, deren Kombination
// gemäß Codeliste Kapitel 7 möglich ist — informational repetition cardinality note.
ConditionResult::True
}
/// [1] Wenn DTM+203 (Ausführungsdatum) nicht vorhanden
fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.lacks_qualifier("DTM", 0, "203")
}
/// [2] Wenn DTM+469 (Beginn zum (nächstmöglichen Termin)) nicht vorhanden
fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.lacks_qualifier("DTM", 0, "469")
}
/// [10] MP-ID nur aus Sparte Strom
/// EXTERNAL: Requires context from outside the message.
fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("mp_id_strom_only")
}
/// [15] Wenn DTM+76 (Datum zum geplanten Leistungsbeginn) nicht vorhanden
fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.lacks_qualifier("DTM", 0, "76")
}
/// [16] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) nicht vorhanden
fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.lacks_qualifier("RFF", 0, "Z41")
}
/// [17] Wenn SG1 RFF+Z41 (Referenznummer des Vorgangs der Anmeldung nach WiM) vorhanden
fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("RFF", 0, "Z41")
}
/// [18] Wenn IMD++Z55 (Änderung Konfiguration) vorhanden
fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("IMD", 1, "Z55")
}
/// [19] Wenn SG27 LIN++Z64 (Erforderliches Produkt Schaltzeitdefinitionen) vorhanden
fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("LIN", 1, "Z64")
}
/// [20] Wenn SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) vorhanden
fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("LIN", 1, "Z65")
}
/// [21] Wenn SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) vorhanden
fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("LIN", 1, "Z66")
}
/// [22] Wenn SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) vorhanden
fn evaluate_22(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("LIN", 1, "Z67")
}
/// [23] Wenn SG27 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) vorhanden
fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_qualifier("LIN", 1, "Z68")
}
/// [24] Wenn Produkt bestellt werden soll
/// EXTERNAL: Requires context from outside the message.
// 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)
fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("product_to_be_ordered")
}
/// [25] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist.
fn evaluate_25(&self, ctx: &EvaluationContext) -> ConditionResult {
// Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Marktlokation angegeben ist.
// LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
// Marktlokation ID: 11 digits with Luhn check digit
let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
match segs
.first()
.and_then(|s| s.elements.get(1))
.and_then(|e| e.first())
{
Some(val) if !val.is_empty() => validate_malo_id(val),
_ => ConditionResult::Unknown,
}
}
/// [26] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist.
fn evaluate_26(&self, ctx: &EvaluationContext) -> ConditionResult {
// Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Messlokation angegeben ist.
// LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
// Messlokation ID: 33 alphanumeric characters (Zählpunkt format)
let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
match segs
.first()
.and_then(|s| s.elements.get(1))
.and_then(|e| e.first())
{
Some(val) if !val.is_empty() => validate_zahlpunkt(val),
_ => ConditionResult::Unknown,
}
}
/// [27] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist.
// 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)
fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
// Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Netzlokation angegeben ist.
// LOC elements[0][0] == "172" (qualifier), elements[1][0] == DE3225 (Identifikator)
// Netzlokation ID: neither MaLo (11 digits Luhn) nor MeLo (33 alphanumeric)
let segs = ctx.find_segments_with_qualifier("LOC", 0, "172");
match segs
.first()
.and_then(|s| s.elements.get(1))
.and_then(|e| e.first())
{
Some(val) if !val.is_empty() => {
let is_malo = matches!(validate_malo_id(val), ConditionResult::True);
let is_melo = matches!(validate_zahlpunkt(val), ConditionResult::True);
ConditionResult::from(!is_malo && !is_melo)
}
_ => ConditionResult::Unknown,
}
}
/// [28] Wenn in LOC+172 DE3225 (Meldepunkt) die ID einer Steuerbaren Ressource angegeben ist.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_28(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("loc_172_is_steuerbare_ressource")
}
/// [29] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.1 „Konfigurationsprodukte Schaltzeitdefinition“ enthalten sind.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("product_in_konfiguration_schaltzeitdefinition")
}
/// [30] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.2 „Konfigurationsprodukte Leistungskurvendefinition“ enthalten sind.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_30(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("product_in_konfiguration_leistungskurvendefinition")
}
/// [31] Es sind nur die Konfigurations-Produkte erlaubt, die in der Codeliste der Konfigurationen im Kapitel 4.3 „Konfigurationsprodukte Ad-Hoc-Steuerkanal“ enthalten sind.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_31(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external
.evaluate("product_in_konfiguration_adhoc_steuerkanal")
}
/// [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.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_32(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("product_in_messprodukte_typ2_lf_nb")
}
/// [35] Wenn MP-ID in SG11 NAD+MS mit Rolle LF vorhanden
/// EXTERNAL: Requires context from outside the message.
// 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)
fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("sender_is_lf")
}
/// [36] Wenn MP-ID in SG11 NAD+MS mit Rolle NB vorhanden
/// EXTERNAL: Requires context from outside the message.
// 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)
fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("sender_is_nb")
}
/// [39] wenn im DE3155 in demselben COM der Code EM vorhanden ist
fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
// COM segment: C076 composite — elements[0][0]=DE3148 (address), elements[0][1]=DE3155 (qualifier)
let coms = ctx.find_segments("COM");
if coms.is_empty() {
return ConditionResult::False;
}
ConditionResult::from(coms.iter().any(|s| {
s.elements
.first()
.and_then(|e| e.get(1))
.is_some_and(|v| v == "EM")
}))
}
/// [40] wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
// COM segment: C076 composite — elements[0][0]=DE3148 (address), elements[0][1]=DE3155 (qualifier)
// TE=Telephone, FX=Fax, AJ=Unknown, AL=Unknown (telephony-related codes)
let coms = ctx.find_segments("COM");
if coms.is_empty() {
return ConditionResult::False;
}
ConditionResult::from(coms.iter().any(|s| {
s.elements
.first()
.and_then(|e| e.get(1))
.is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
}))
}
/// [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...
fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
let dtm_segs = ctx.find_segments("DTM");
match dtm_segs
.first()
.and_then(|s| s.elements.first())
.and_then(|e| e.get(1))
{
Some(val) => is_mesz_utc(val),
None => ConditionResult::False, // segment absent → condition not applicable
}
}
/// [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)...
fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
let dtm_segs = ctx.find_segments("DTM");
match dtm_segs
.first()
.and_then(|s| s.elements.first())
.and_then(|e| e.get(1))
{
Some(val) => is_mez_utc(val),
None => ConditionResult::False, // segment absent → condition not applicable
}
}
/// [492] wenn MP-ID in NAD+MR aus Sparte Strom
/// EXTERNAL: Requires context from outside the message.
// 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)
fn evaluate_492(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("recipient_is_electricity_sector")
}
/// [493] wenn MP-ID in NAD+MR aus Sparte Gas
/// EXTERNAL: Requires context from outside the message.
// 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)
fn evaluate_493(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("recipient_is_gas_sector")
}
/// [500] Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Angabe eines technischen Ansprechpartners für die Geräteübernahme
// Informational note — always applies
ConditionResult::True
}
/// [501] Hinweis: Angabe eines Ansprechpartners für die Rechnungsabwicklung
fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Angabe eines Ansprechpartners für die Rechnungsabwicklung
// Informational note — always applies
ConditionResult::True
}
/// [502] Hinweis: Verwendung der ID der Marktlokation
fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Verwendung der ID der Marktlokation
// Informational note — always applies
ConditionResult::True
}
/// [503] Hinweis: Verwendung der ID der Messlokation
fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Verwendung der ID der Messlokation
// Informational note — always applies
ConditionResult::True
}
/// [504] Hinweis: Verwendung der ID der Tranche
fn evaluate_504(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Verwendung der ID der Tranche — informational note, always applies
ConditionResult::True
}
/// [507] Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD mit BGM+E01 mit der die Anmeldung des MSB-Wechsels erfolgt ist.
fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Vorgangsnummer aus SG4 IDE+24 DE7402 der UTILMD — informational note, always applies
ConditionResult::True
}
/// [508] Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Wert aus BGM+Z73 DE1004 der IFTSTA — informational note, always applies
ConditionResult::True
}
/// [509] Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA mit BGM+Z73 mit der die Antwort auf die Bestellung der Konfiguration übermittelt wurde
fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Vorgangsnummer aus CNI DE1490 der IFTSTA — informational note, always applies
ConditionResult::True
}
/// [510] Hinweis: Verwendung der ID der Netzlokation
fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
// Hinweis: Verwendung der ID der Netzlokation — informational note, always applies
ConditionResult::True
}
/// [511] Hinweis: Verwendung der ID der Steuerbaren Ressource
fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [512] Hinweis: Für den Empfang der Werte nach Typ 2 aus dem SMGW.
fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [514] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [515] Hinweis: Es ist eine URI IPv4 für die Bereitstellung der Werte anzugeben.
fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [516] Hinweis: Es ist eine URI IPv6 für die Bereitstellung der Werte anzugeben.
fn evaluate_516(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [903] Format: Möglicher Wert: 1
fn evaluate_903(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [906] Format: max. 3 Nachkommastellen
fn evaluate_906(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [931] Format: ZZZ = +00
fn evaluate_931(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [932] Format: HHMM = 2200
fn evaluate_932(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [933] Format: HHMM = 2300
fn evaluate_933(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [934] Format: HHMM = 0400
fn evaluate_934(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [935] Format: HHMM = 0500
fn evaluate_935(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
fn evaluate_939(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
fn evaluate_940(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [950] Format: Marktlokations-ID
fn evaluate_950(&self, _ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::True
}
/// [951] Format: Zählpunktbezeichnung
fn evaluate_951(&self, ctx: &EvaluationContext) -> ConditionResult {
let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z17");
match segs
.first()
.and_then(|s| s.elements.get(1))
.and_then(|e| e.first())
{
Some(val) => validate_zahlpunkt(val),
None => ConditionResult::False, // segment absent → condition not applicable
}
}
/// [960] Format: Netzlokations-ID
// 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)
fn evaluate_960(&self, ctx: &EvaluationContext) -> ConditionResult {
let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z18");
match segs
.first()
.and_then(|s| s.elements.get(1))
.and_then(|e| e.first())
{
Some(val) => validate_malo_id(val),
None => ConditionResult::False, // segment absent → condition not applicable
}
}
/// [961] Format: SR-ID
// 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)
fn evaluate_961(&self, ctx: &EvaluationContext) -> ConditionResult {
let segs = ctx.find_segments_with_qualifier("LOC", 0, "Z19");
match segs
.first()
.and_then(|s| s.elements.get(1))
.and_then(|e| e.first())
{
Some(val) => validate_malo_id(val),
None => ConditionResult::False, // segment absent → condition not applicable
}
}
/// [962] Format: max. 6 Vorkommastellen
fn evaluate_962(&self, ctx: &EvaluationContext) -> ConditionResult {
let segs = ctx.find_segments("QTY");
match segs
.first()
.and_then(|s| s.elements.first())
.and_then(|e| e.get(1))
{
Some(val) => validate_max_integer_digits(val, 6),
None => ConditionResult::False, // segment absent → condition not applicable
}
}
/// [2005] Pro Nachricht ist die SG27 genau einmal anzugeben
// 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)
fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
let lin_count = ctx.find_segments("LIN").len();
ConditionResult::from(lin_count == 1)
}
/// [2060] Pro Nachricht ist die SG27 LIN+Z64 (Erforderliches Produkt Schaltzeitdefinitionen) maximal einmal anzugeben
// 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)
fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
let lins = ctx.find_segments("LIN");
let count = lins
.iter()
.filter(|s| {
s.elements
.get(1)
.and_then(|e| e.first())
.is_some_and(|v| v == "Z64")
})
.count();
ConditionResult::from(count <= 1)
}
/// [2061] Pro Nachricht ist die SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) maximal einmal anzugeben
// 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)
fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
let lins = ctx.find_segments("LIN");
let count = lins
.iter()
.filter(|s| {
s.elements
.get(1)
.and_then(|e| e.first())
.is_some_and(|v| v == "Z65")
})
.count();
ConditionResult::from(count <= 1)
}
/// [2062] Pro Nachricht ist die SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) maximal einmal anzugeben
// 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)
fn evaluate_2062(&self, ctx: &EvaluationContext) -> ConditionResult {
let lins = ctx.find_segments("LIN");
let count = lins
.iter()
.filter(|s| {
s.elements
.get(1)
.and_then(|e| e.first())
.is_some_and(|v| v == "Z66")
})
.count();
ConditionResult::from(count <= 1)
}
/// [2063] Pro Nachricht ist die SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) maximal einmal anzugeben
// 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)
fn evaluate_2063(&self, ctx: &EvaluationContext) -> ConditionResult {
let lins = ctx.find_segments("LIN");
let count = lins
.iter()
.filter(|s| {
s.elements
.get(1)
.and_then(|e| e.first())
.is_some_and(|v| v == "Z67")
})
.count();
ConditionResult::from(count <= 1)
}
/// [2064] Pro Nachricht ist die SG27 LIN++Z68 (Erforderliches Produkt Konfigurationserlaubnis für Werte nach Typ 2 aus SMGW) maximal einmal anzugeben
// 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)
fn evaluate_2064(&self, ctx: &EvaluationContext) -> ConditionResult {
let lins = ctx.find_segments("LIN");
let count = lins
.iter()
.filter(|s| {
s.elements
.get(1)
.and_then(|e| e.first())
.is_some_and(|v| v == "Z68")
})
.count();
ConditionResult::from(count <= 1)
}
}