Skip to main content

redispatch_xml/documents/
network_constraint.rs

1//! `NetworkConstraintDocument` -- network constraint declaration sent by TSO or DSO.
2use serde::{Deserialize, Serialize};
3
4use crate::documents::activation::{ControlZoneRef, ResourceObjectRef};
5use crate::documents::planned_resource_schedule::GridElementCodingScheme;
6use crate::types::{
7    AttrV, AttrVWithScheme, Direction, DocumentId, DocumentVersion, MarketParticipantId,
8    MarketRoleType, MeasureUnit, Period, TimeInterval, UtcDateTime,
9};
10
11// ── DocumentType ──────────────────────────────────────────────────────────────
12
13/// `DocumentType` for `NetworkConstraintDocument` (always `B15`).
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum NcdDocType {
16    /// Network constraint document.
17    #[serde(rename = "B15")]
18    NetworkConstraint,
19}
20
21/// `ProcessType` for `NetworkConstraintDocument` (always `A14`).
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum NcdProcessType {
24    /// Forecast.
25    #[serde(rename = "A14")]
26    Forecast,
27}
28
29/// `BusinessType` for `NetworkConstraintTimeSeries`.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub enum NcdBusinessType {
32    /// Dispatchable production (eligible resource).
33    #[serde(rename = "A77")]
34    ProductionDispatchable,
35    /// Network element constraint.
36    #[serde(rename = "B59")]
37    NetworkElement,
38}
39
40/// Status codes for `NetworkConstraintTimeSeries`.
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
42pub enum NcdStatus {
43    /// Activated.
44    #[serde(rename = "A07")]
45    Activated,
46    /// Planned.
47    #[serde(rename = "A36")]
48    Planned,
49    /// Demand.
50    #[serde(rename = "Z06")]
51    Demand,
52}
53
54/// Optional document withdrawal status.
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct NcdDocStatus {
57    /// Withdrawal code (only `"A13"` used).
58    #[serde(rename = "@v")]
59    pub v: String,
60}
61
62// ── NetworkConstraintTimeSeries ───────────────────────────────────────────────
63
64/// A single constraint time series within a `NetworkConstraintDocument`.
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
66pub struct NetworkConstraintTimeSeries {
67    /// Unique time-series identifier (max 35 chars).
68    #[serde(rename = "TimeSeriesIdentification")]
69    pub time_series_identification: AttrV<DocumentId>,
70    /// Reference to the original time series when this one corrects it.
71    ///
72    /// Without it a correction cannot be matched to what it corrects, so the
73    /// receiver either applies it twice or not at all.
74    #[serde(
75        rename = "OriginalTimeSeriesIdentification",
76        default,
77        skip_serializing_if = "Option::is_none"
78    )]
79    pub original_time_series_identification: Option<AttrV<DocumentId>>,
80    /// The **anfordernder Netzbetreiber** — the operator that identified the
81    /// Netzengpass and requested the Maßnahme (`BilAReM` Kap. 1).
82    ///
83    /// It is not necessarily the anweisende Netzbetreiber: a request travels up
84    /// the cascade, and Kap. 17.3.4 of the `MaBiS` Anlage puts a whole
85    /// Ausfallarbeit exchange between the two. Dropping it leaves the
86    /// Ausfallarbeit with no addressee.
87    #[serde(
88        rename = "RequestingGridOperator",
89        default,
90        skip_serializing_if = "Option::is_none"
91    )]
92    pub requesting_grid_operator: Option<AttrVWithScheme<MarketParticipantId>>,
93    /// Business type: dispatchable production (`A77`) or network element (`B59`).
94    #[serde(rename = "BusinessType")]
95    pub business_type: AttrV<NcdBusinessType>,
96    /// Direction: up (`A01`) or down (`A02`).
97    #[serde(rename = "Direction")]
98    pub direction: AttrV<Direction>,
99    /// Control zone where the resource / element is located.
100    #[serde(rename = "ConnectingArea")]
101    pub connecting_area: ControlZoneRef,
102    /// Resource object identifier (BDEW resource code, NDE scheme).
103    #[serde(rename = "ResourceObject")]
104    pub resource_object: ResourceObjectRef,
105    /// Grid element EIC or resource code.
106    #[serde(rename = "GridElement")]
107    pub grid_element: AttrVWithScheme<String, GridElementCodingScheme>,
108    /// Physical unit of quantity values.
109    #[serde(rename = "MeasurementUnit")]
110    pub measurement_unit: AttrV<MeasureUnit>,
111    /// Optional activation status.
112    /// Resource provider that operates the resource.
113    #[serde(
114        rename = "ResourceProvider",
115        default,
116        skip_serializing_if = "Option::is_none"
117    )]
118    pub resource_provider: Option<AttrVWithScheme<MarketParticipantId>>,
119    /// Status of the constraint series.
120    #[serde(rename = "Status", default, skip_serializing_if = "Option::is_none")]
121    pub status: Option<AttrV<NcdStatus>>,
122    /// Quarter-hour constraint data for the delivery day.
123    #[serde(rename = "Period")]
124    pub period: Period,
125}
126
127// ── NetworkConstraintDocument ─────────────────────────────────────────────────
128
129/// `NetworkConstraintDocument` — grid congestion constraint data submitted
130/// by TSOs to resource providers' NB.
131///
132/// XSD version: 1.1b (2025-04-01)  
133/// No XML namespace.
134#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
135#[serde(rename = "NetworkConstraintDocument")]
136pub struct NetworkConstraintDocument {
137    /// Original sender when this document corrects an earlier one.
138    #[serde(
139        rename = "OriginalSenderIdentification",
140        default,
141        skip_serializing_if = "Option::is_none"
142    )]
143    pub original_sender_identification: Option<AttrVWithScheme<MarketParticipantId>>,
144    /// Identifier of the document being corrected.
145    #[serde(
146        rename = "OriginalDocumentIdentification",
147        default,
148        skip_serializing_if = "Option::is_none"
149    )]
150    pub original_document_identification: Option<AttrV<DocumentId>>,
151    /// Version of the document being corrected.
152    #[serde(
153        rename = "OriginalDocumentVersion",
154        default,
155        skip_serializing_if = "Option::is_none"
156    )]
157    pub original_document_version: Option<AttrV<DocumentVersion>>,
158    /// Creation timestamp of the document being corrected.
159    #[serde(
160        rename = "OriginalDocumentDateTime",
161        default,
162        skip_serializing_if = "Option::is_none"
163    )]
164    pub original_document_date_time: Option<AttrV<UtcDateTime>>,
165    /// Unique document identifier (max 35 chars).
166    #[serde(rename = "DocumentIdentification")]
167    pub document_identification: AttrV<DocumentId>,
168    /// Document version number (1–999).
169    #[serde(rename = "DocumentVersion")]
170    pub document_version: AttrV<DocumentVersion>,
171    /// Document type (always `B15`).
172    #[serde(rename = "DocumentType")]
173    pub document_type: AttrV<NcdDocType>,
174    /// Process type (always `A14`).
175    #[serde(rename = "ProcessType")]
176    pub process_type: AttrV<NcdProcessType>,
177    /// Sender's market participant identifier.
178    #[serde(rename = "SenderIdentification")]
179    pub sender_identification: AttrVWithScheme<MarketParticipantId>,
180    /// Sender's market role.
181    #[serde(rename = "SenderRole")]
182    pub sender_role: AttrV<MarketRoleType>,
183    /// Receiver's market participant identifier.
184    #[serde(rename = "ReceiverIdentification")]
185    pub receiver_identification: AttrVWithScheme<MarketParticipantId>,
186    /// Receiver's market role.
187    #[serde(rename = "ReceiverRole")]
188    pub receiver_role: AttrV<MarketRoleType>,
189    /// Document creation timestamp (UTC, second precision).
190    #[serde(rename = "DocumentDateTime")]
191    pub document_date_time: AttrV<UtcDateTime>,
192    /// Delivery period covered (UTC interval).
193    #[serde(rename = "TimePeriodCovered")]
194    pub time_period_covered: AttrV<TimeInterval>,
195    /// Optional withdrawal status.
196    #[serde(rename = "DocStatus", default, skip_serializing_if = "Option::is_none")]
197    pub doc_status: Option<NcdDocStatus>,
198    /// Network constraint time series (0+; absent when `doc_status` is set).
199    #[serde(
200        rename = "NetworkConstraintTimeSeries",
201        default,
202        skip_serializing_if = "Vec::is_empty"
203    )]
204    pub time_series: Vec<NetworkConstraintTimeSeries>,
205}