1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// <auto-generated>
// Generated by automapper-generator generate-conditions
// AHB: xml-migs-and-ahbs/FV2610/REQOTE_AHB_1_2_20260401.xml
// Generated: 2026-04-22T18:16:49Z
// Delegates unchanged conditions to ReqoteConditionEvaluatorFV2510 (FV2510).
// </auto-generated>
#![allow(clippy::style, clippy::complexity)]
#[allow(unused_imports)]
use crate::eval::format_validators::*;
use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
use crate::generated::fv2510::ReqoteConditionEvaluatorFV2510;
/// Condition evaluator for REQOTE FV2610.
///
/// Delegates to [`ReqoteConditionEvaluatorFV2510`] for conditions whose AHB description is
/// unchanged from that version. Local overrides: [1, 2, 16, 17, 18, 19, 20, 21, 22, 23, 24, 35, 36, 39, 40, 52, 53, 490, 491, 492, 493, 2005, 2060, 2061, 2062, 2063, 2064].
pub struct ReqoteConditionEvaluatorFV2610 {
fallback: ReqoteConditionEvaluatorFV2510,
}
impl Default for ReqoteConditionEvaluatorFV2610 {
fn default() -> Self {
Self {
fallback: ReqoteConditionEvaluatorFV2510::default(),
}
}
}
/// Condition IDs whose implementation differs from the fallback.
const FV2610_OVERRIDES: &[u32] = &[
1, 2, 16, 17, 18, 19, 20, 21, 22, 23, 24, 35, 36, 39, 40, 52, 53, 490, 491, 492, 493, 2005,
2060, 2061, 2062, 2063, 2064,
];
impl ConditionEvaluator for ReqoteConditionEvaluatorFV2610 {
fn message_type(&self) -> &str {
"REQOTE"
}
fn format_version(&self) -> &str {
"FV2610"
}
fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
match condition {
1 => self.evaluate_1(ctx),
2 => self.evaluate_2(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),
35 => self.evaluate_35(ctx),
36 => self.evaluate_36(ctx),
39 => self.evaluate_39(ctx),
40 => self.evaluate_40(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),
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),
other => self.fallback.evaluate(other, ctx),
}
}
fn is_external(&self, condition: u32) -> bool {
matches!(condition, 24 | 35 | 36 | 53 | 492 | 493) || self.fallback.is_external(condition)
}
fn is_known(&self, condition: u32) -> bool {
FV2610_OVERRIDES.contains(&condition) || self.fallback.is_known(condition)
}
}
impl ReqoteConditionEvaluatorFV2610 {
/// [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")
}
/// [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_segment_matching("IMD", &[(1, 0, "Z55")])
}
/// [19] Wenn SG27 LIN++Z64 (Erforderliches Produkt Schaltzeitdefinitionen) vorhanden.
fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_segment_matching("LIN", &[(1, 0, "Z64")])
}
/// [20] Wenn SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) vorhanden.
fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_segment_matching("LIN", &[(1, 0, "Z65")])
}
/// [21] Wenn SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) vorhanden.
fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.has_segment_matching("LIN", &[(1, 0, "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_segment_matching("LIN", &[(1, 0, "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_segment_matching("LIN", &[(1, 0, "Z68")])
}
/// [24] Wenn Produkt bestellt werden soll.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("product_to_be_ordered")
}
/// [35] Wenn MP-ID in SG11 NAD+MS mit Rolle LF vorhanden.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("nad_ms_has_role_lf")
}
/// [36] Wenn MP-ID in SG11 NAD+MS mit Rolle NB vorhanden.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("nad_ms_has_role_nb")
}
/// [39] Wenn im DE3155 in demselben COM der Code EM vorhanden ist.
fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
// Wenn im DE3155 in demselben COM der Code EM vorhanden ist
// DE3155 is the communication qualifier at COM elements[0][1]
ConditionResult::from(ctx.self_segment_value_equals("COM", 0, 1, "EM"))
}
/// [40] Wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist.
fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
// Wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
// DE3155 is the communication qualifier at COM elements[0][1]
match ctx.self_segment_value("COM", 0, 1) {
Some(code) => ConditionResult::from(matches!(code, "TE" | "FX" | "AJ" | "AL")),
None => ConditionResult::Unknown,
}
}
/// [52] Wenn im DE3155 in demselben COM der Code TE / AL Worhanden ist.
fn evaluate_52(&self, ctx: &EvaluationContext) -> ConditionResult {
// Wenn im DE3155 in demselben COM der Code TE / AL vorhanden ist
// DE3155 is the communication qualifier at COM elements[0][1]
match ctx.self_segment_value("COM", 0, 1) {
Some(code) => ConditionResult::from(matches!(code, "TE" | "AL")),
None => ConditionResult::Unknown,
}
}
/// [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_period")
}
/// [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 {
// Wert an Stelle CCYYMMDDHHMM liegt in deutschem Sommerzeit-Zeitraum (MESZ) in UTC
ctx.format_check("DTM", 0, 1, is_mesz_utc)
}
/// [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 {
// Wert an Stelle CCYYMMDDHHMM liegt in deutschem Winterzeit-Zeitraum (MEZ) in UTC
ctx.format_check("DTM", 0, 1, is_mez_utc)
}
/// [492] Wenn MP-ID in NAD+MR aus Sparte Strom.
/// EXTERNAL: Requires context from outside the message.
fn evaluate_492(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("nad_mr_is_strom_sector")
}
/// [493] Wenn MP-ID in NAD+MR aus Sparte Gas.
/// EXTERNAL: Requires context from outside the message.
// REVIEW: Whether the NAD+MR market participant ID belongs to the gas sector (Sparte Gas) cannot be determined from the EDIFACT message content alone — it requires an external market participant registry lookup. (medium confidence)
fn evaluate_493(&self, ctx: &EvaluationContext) -> ConditionResult {
ctx.external.evaluate("recipient_is_gas_sector")
}
/// [2005] Pro Nachricht ist die SG27 genau einmal anzugeben.
// REVIEW: SG27 must appear exactly once per message. LIN is the entry segment of SG27, so counting LIN instances in the SG27 group path gives the SG27 repetition count. Returns True only when exactly one SG27 is present. (medium confidence)
fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::from(ctx.count_in_group("LIN", &["SG27"]) == 1)
}
/// [2060] Pro Nachricht ist die SG27 LIN+Z64 (Erforderliches Produkt Schaltzeitdefinitionen) maximal einmal anzugeben.
// REVIEW: LIN+Z64 (Erforderliches Produkt Schaltzeitdefinitionen) may appear at most once per message in SG27. Notation LIN+Z64 means elements[0][0]=="Z64". Count via count_qualified_in_group at element index 0. Zero occurrences also satisfies <= 1. (medium confidence)
fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::from(ctx.count_qualified_in_group("LIN", 0, "Z64", &["SG27"]) <= 1)
}
/// [2061] Pro Nachricht ist die SG27 LIN++Z65 (Erforderliches Produkt Leistungskurvendefinitionen) maximal einmal anzugeben.
// REVIEW: LIN++Z65 means elements[0] is empty and elements[1][0]=="Z65". count_qualified_in_group checks element index 1 for qualifier Z65 in SG27 group. At most one occurrence satisfies the constraint. (medium confidence)
fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::from(ctx.count_qualified_in_group("LIN", 1, "Z65", &["SG27"]) <= 1)
}
/// [2062] Pro Nachricht ist die SG27 LIN++Z66 (Erforderliches Produkt Ad-hoc-Steuerkanal) maximal einmal anzugeben.
// REVIEW: LIN++Z66 means elements[1][0]=="Z66" (Ad-hoc-Steuerkanal product). Parallel to condition 2061 but for Z66. At most one occurrence per message in SG27. (medium confidence)
fn evaluate_2062(&self, ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::from(ctx.count_qualified_in_group("LIN", 1, "Z66", &["SG27"]) <= 1)
}
/// [2063] Pro Nachricht ist die SG27 LIN++Z67 (Erforderliches Messprodukt für Werte nach Typ 2 aus Backend) maximal einmal anzugeben.
// REVIEW: LIN++Z67 means elements[1][0]=="Z67" (Erforderliches Messprodukt Typ 2 Backend). Parallel to 2061/2062 for Z67. At most one occurrence per message in SG27. (medium confidence)
fn evaluate_2063(&self, ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::from(ctx.count_qualified_in_group("LIN", 1, "Z67", &["SG27"]) <= 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++Z68 means elements[1][0]=="Z68" (Konfigurationserlaubnis Typ 2 SMGW). Parallel pattern for Z68. At most one occurrence per message in SG27. (medium confidence)
fn evaluate_2064(&self, ctx: &EvaluationContext) -> ConditionResult {
ConditionResult::from(ctx.count_qualified_in_group("LIN", 1, "Z68", &["SG27"]) <= 1)
}
}