redispatch-xml 0.17.0

Redispatch 2.0 XML/XSD format parsing and validation for the German electricity grid (CIM/ENTSO-E-based, per BDEW specifications)
Documentation
//! `StatusRequest_MarketDocument` — TSO/DSO request for the current status of a Redispatch resource.
use serde::{Deserialize, Serialize};

use crate::documents::kaskade::ParticipantMrid;
use crate::types::{Mrid, SimpleContent, UtcDateTime};

// ── Namespace ─────────────────────────────────────────────────────────────────

/// Expected XML namespace for `StatusRequest_MarketDocument`.
pub const NAMESPACE: &str = "urn:iec62325.351:tc57wg16:451-5:statusrequestdocument:4:1";

// ── Enumerations ──────────────────────────────────────────────────────────────

/// Document type for `StatusRequest_MarketDocument`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StatusRequestDocType {
    /// Status request.
    #[serde(rename = "A60")]
    StatusRequest,
    /// Catalogue request.
    #[serde(rename = "Z15")]
    CatalogueRequest,
}

/// Sender role for `StatusRequest_MarketDocument`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StatusRequestSenderRole {
    /// Grid operator.
    #[serde(rename = "A18")]
    GridOperator,
    /// Data provider.
    #[serde(rename = "A39")]
    DataProvider,
}

/// Receiver role for `StatusRequest_MarketDocument`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StatusRequestReceiverRole {
    /// Grid operator.
    #[serde(rename = "A18")]
    GridOperator,
    /// Resource provider.
    #[serde(rename = "A27")]
    ResourceProvider,
    /// Other / central.
    #[serde(rename = "Z01")]
    Other,
}

/// Market participant status used in `MktActivityRecord`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ParticipantStatus {
    /// Deactivated.
    #[serde(rename = "A03")]
    Deactivated,
    /// Reactivated.
    #[serde(rename = "A04")]
    Reactivated,
    /// Withdrawn.
    #[serde(rename = "A13")]
    Withdrawn,
}

// ── Sender / receiver ────────────────────────────────────────────────────────
//
// Flat, dotted elements on the wire — `<sender_MarketParticipant.mRID>` and
// `<sender_MarketParticipant.marketRole.type>` — not a nested
// `<sender_MarketParticipant>` container. That is the ENTSO-E CIM convention
// the BDEW XSD follows, and the difference is not cosmetic: a nested document
// fails XSD validation at the counterparty, and an inbound flat one loses the
// sender entirely, because `serde` skips elements the model does not declare.

// ── AttributeInstanceComponent ────────────────────────────────────────────────

/// A generic key–value attribute (used for query parameters in status requests).
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttributeInstanceComponent {
    /// Attribute name.
    #[serde(rename = "attribute")]
    pub attribute: String,
    /// Attribute value.
    #[serde(
        rename = "attributeValue",
        default,
        skip_serializing_if = "Option::is_none"
    )]
    pub attribute_value: Option<String>,
}

// ── MktActivityRecord ─────────────────────────────────────────────────────────

/// Participant status record in a `StatusRequest_MarketDocument`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MktActivityRecord {
    /// Market participant identifier (max 16 chars).
    #[serde(rename = "MarketParticipant.mRID")]
    pub market_participant_m_rid: SimpleContent<String>,
    /// Participant status: deactivated, reactivated, or withdrawn.
    pub status: ParticipantStatus,
}

// ── StatusRequest_MarketDocument ──────────────────────────────────────────────

/// `StatusRequest_MarketDocument` — status request from a grid operator for
/// resource provider participation data.
///
/// XSD version: 1.1 (2025-04-01)  
/// Namespace: `urn:iec62325.351:tc57wg16:451-5:statusrequestdocument:4:1`
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename = "StatusRequest_MarketDocument")]
pub struct StatusRequestMarketDocument {
    /// Unique message identifier (max 35 chars).
    #[serde(rename = "mRID")]
    pub m_rid: Mrid,
    /// Document type.
    #[serde(rename = "type")]
    pub doc_type: StatusRequestDocType,
    /// Sender market participant identifier.
    #[serde(rename = "sender_MarketParticipant.mRID")]
    pub sender_m_rid: ParticipantMrid,
    /// Sender market role.
    #[serde(rename = "sender_MarketParticipant.marketRole.type")]
    pub sender_market_role: StatusRequestSenderRole,
    /// Receiver market participant identifier.
    #[serde(rename = "receiver_MarketParticipant.mRID")]
    pub receiver_m_rid: ParticipantMrid,
    /// Receiver market role.
    #[serde(rename = "receiver_MarketParticipant.marketRole.type")]
    pub receiver_market_role: StatusRequestReceiverRole,
    /// Document creation timestamp (UTC, second precision).
    #[serde(rename = "createdDateTime")]
    pub created_date_time: UtcDateTime,
    /// Generic attribute–value components (query parameters).
    #[serde(
        rename = "AttributeInstanceComponent",
        default,
        skip_serializing_if = "Vec::is_empty"
    )]
    pub attributes: Vec<AttributeInstanceComponent>,
    /// Participant status records.
    #[serde(
        rename = "MktActivityRecord",
        default,
        skip_serializing_if = "Vec::is_empty"
    )]
    pub mkt_activity_records: Vec<MktActivityRecord>,
}