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