automapper-validation 0.1.64

AHB condition expression parsing, evaluation, and EDIFACT validation
Documentation
// <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)
    }
}