Skip to main content

redispatch_xml/documents/
activation.rs

1//! `ActivationDocument` -- redispatch activation orders (ACO), confirmations (ACR), and activation adjustments (AAR).
2use serde::{Deserialize, Serialize};
3
4use crate::types::{
5    AttrV, AttrVWithScheme, ControlZone, Direction, DocumentId, DocumentVersion,
6    MarketParticipantId, MarketRoleType, MeasureUnit, Period, TimeInterval, UtcDateTime,
7};
8
9// ── Namespace ─────────────────────────────────────────────────────────────────
10
11/// Expected XML namespace for `ActivationDocument`.
12pub const NAMESPACE: &str = "urn:entsoe.eu:wgedi:errp:activationdocument:5:0";
13
14// ── DocumentType ─────────────────────────────────────────────────────────────
15
16/// `DocumentType` codes for `ActivationDocument`.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub enum ActivationDocType {
19    /// Activation response (ACR).
20    #[serde(rename = "A41")]
21    ActivationResponse,
22    /// Tender reduction (AAR).
23    #[serde(rename = "A42")]
24    TenderReduction,
25    /// Redispatch activation document (ACO).
26    #[serde(rename = "A96")]
27    RedispatchActivation,
28}
29
30/// `ProcessType` codes for `ActivationDocument`.
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
32pub enum ActivationProcessType {
33    /// Redispatch activation process.
34    #[serde(rename = "A41")]
35    Redispatch,
36    /// Test / other.
37    #[serde(rename = "Z01")]
38    Other,
39}
40
41/// `Status` codes used in `ActivationTimeSeries`.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
43pub enum TimeSeriesStatus {
44    /// Volumes available (used for partial-rejection ACR).
45    #[serde(rename = "A06")]
46    Available,
47    /// Quantities activated (Information).
48    #[serde(rename = "A07")]
49    Activated,
50    /// Quantities ordered (Anweisung / ACO).
51    #[serde(rename = "A10")]
52    Ordered,
53}
54
55/// `BusinessType` codes used in `ActivationTimeSeries`.
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
57pub enum TimeSeriesBusinessType {
58    /// System Operator redispatching (Deltaanweisung).
59    #[serde(rename = "A46")]
60    SystemOperatorRedispatching,
61    /// Internal redispatch (Sollwertvorgabe).
62    #[serde(rename = "A85")]
63    InternalRedispatch,
64}
65
66// ── Document-level Reason ─────────────────────────────────────────────────────
67
68/// Reason code at the `ActivationDocument` root level (document-level
69/// acceptance/rejection).
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
71pub enum DocumentReasonCode {
72    /// Deadline exceeded (Frist abgelaufen).
73    #[serde(rename = "A57")]
74    DeadlineExceeded,
75    /// Complementary information.
76    #[serde(rename = "A95")]
77    ComplementaryInfo,
78    /// Technical constraint.
79    #[serde(rename = "A96")]
80    TechnicalConstraint,
81}
82
83/// Root-level reason attached to an `ActivationDocument`.
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub struct DocumentReason {
86    /// Document-level reason code.
87    #[serde(rename = "ReasonCode")]
88    pub code: AttrV<DocumentReasonCode>,
89    /// Optional free-text description.
90    #[serde(
91        rename = "ReasonText",
92        default,
93        skip_serializing_if = "Option::is_none"
94    )]
95    pub text: Option<String>,
96}
97
98// ── ActivationTimeSeries ──────────────────────────────────────────────────────
99
100/// Reference to a `ResourceObject` with its NDE coding scheme.
101pub type ResourceObjectRef = AttrVWithScheme<String, ResourceObjectCodingScheme>;
102
103/// Coding scheme for resource object identifiers.
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
105pub enum ResourceObjectCodingScheme {
106    /// Germany National coding scheme (BDEW resource code).
107    #[serde(rename = "NDE")]
108    Nde,
109}
110
111/// Reference to a control zone (EIC) with `codingScheme = "A01"`.
112pub type ControlZoneRef = AttrVWithScheme<ControlZone, EicCodingScheme>;
113
114/// Coding scheme for EIC-coded identifiers (always `A01`).
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
116pub enum EicCodingScheme {
117    /// EIC — Energy Identification Coding Scheme.
118    #[serde(rename = "A01")]
119    Eic,
120}
121
122/// A single activated time series within an `ActivationDocument`.
123///
124/// Each `ActivationTimeSeries` covers one direction (up/down) for one
125/// `ResourceObject`. An `ActivationDocument` may contain up to two time
126/// series (one per direction).
127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128pub struct ActivationTimeSeries {
129    /// Unique time-series identifier within this document.
130    #[serde(rename = "AllocationIdentification")]
131    pub allocation_identification: AttrV<DocumentId>,
132    /// Resource provider (EIV or NB) — optional when sender is the provider.
133    #[serde(
134        rename = "ResourceProvider",
135        default,
136        skip_serializing_if = "Option::is_none"
137    )]
138    pub resource_provider: Option<AttrVWithScheme<MarketParticipantId>>,
139    /// Business type: delta instruction (`A46`) or setpoint (`A85`).
140    #[serde(rename = "BusinessType")]
141    pub business_type: AttrV<TimeSeriesBusinessType>,
142    /// German TSO control block (always `10YCB-GERMANY--8`, EIC).
143    #[serde(rename = "AcquiringArea")]
144    pub acquiring_area: AttrVWithScheme<String, EicCodingScheme>,
145    /// Connecting control zone where the resource object is connected.
146    #[serde(rename = "ConnectingArea")]
147    pub connecting_area: ControlZoneRef,
148    /// Physical unit of the quantity values (`MAW` or `P1`).
149    #[serde(rename = "MeasureUnit")]
150    pub measure_unit: AttrV<MeasureUnit>,
151    /// Redispatch direction: up (`A01`) or down (`A02`).
152    #[serde(rename = "Direction")]
153    pub direction: AttrV<Direction>,
154    /// Activation / order / availability status.
155    #[serde(rename = "Status")]
156    pub status: AttrV<TimeSeriesStatus>,
157    /// Resource object identifier (BDEW resource code, NDE scheme).
158    #[serde(rename = "ResourceObject")]
159    pub resource_object: ResourceObjectRef,
160    /// `DocumentIdentification` of the originating planning data (optional).
161    #[serde(
162        rename = "SendersDocumentIdentification",
163        default,
164        skip_serializing_if = "Option::is_none"
165    )]
166    pub senders_document_identification: Option<AttrV<DocumentId>>,
167    /// `DocumentVersion` of the originating planning data (optional).
168    #[serde(
169        rename = "SendersDocumentVersion",
170        default,
171        skip_serializing_if = "Option::is_none"
172    )]
173    pub senders_document_version: Option<AttrV<DocumentVersion>>,
174    /// `CreationDateTime` of the originating planning data (optional).
175    #[serde(
176        rename = "SendersDocumentDateTime",
177        default,
178        skip_serializing_if = "Option::is_none"
179    )]
180    pub senders_document_date_time: Option<AttrV<UtcDateTime>>,
181    /// Original `TimeSeriesIdentification` (not used in practice).
182    #[serde(
183        rename = "SendersTimeSeriesIdentification",
184        default,
185        skip_serializing_if = "Option::is_none"
186    )]
187    pub senders_time_series_identification: Option<AttrV<DocumentId>>,
188    /// Original sender's market participant ID when forwarded via data provider.
189    #[serde(
190        rename = "OriginalSenderIdentification",
191        default,
192        skip_serializing_if = "Option::is_none"
193    )]
194    pub original_sender_identification: Option<AttrVWithScheme<MarketParticipantId>>,
195    /// Original `DocumentIdentification` when forwarded.
196    #[serde(
197        rename = "OriginalDocumentIdentification",
198        default,
199        skip_serializing_if = "Option::is_none"
200    )]
201    pub original_document_identification: Option<AttrV<DocumentId>>,
202    /// Original `DocumentVersion` when forwarded.
203    #[serde(
204        rename = "OriginalDocumentVersion",
205        default,
206        skip_serializing_if = "Option::is_none"
207    )]
208    pub original_document_version: Option<AttrV<DocumentVersion>>,
209    /// Original `CreationDateTime` when forwarded.
210    #[serde(
211        rename = "OriginalDocumentDateTime",
212        default,
213        skip_serializing_if = "Option::is_none"
214    )]
215    pub original_document_date_time: Option<AttrV<UtcDateTime>>,
216    /// Original `AllocationIdentification` when forwarded.
217    #[serde(
218        rename = "OriginalAllocationIdentification",
219        default,
220        skip_serializing_if = "Option::is_none"
221    )]
222    pub original_allocation_identification: Option<AttrV<DocumentId>>,
223    /// Quarter-hour activation data for the delivery day.
224    #[serde(rename = "Period")]
225    pub period: Period,
226}
227
228// ── ActivationDocument ────────────────────────────────────────────────────────
229
230/// One korrespondierender Fahrplan of an `ActivationDocument`.
231///
232/// This is how the bilanzielle Ausgleich is actually executed: `BilAReM`
233/// Kap. 2.1.2 — „Der bilanzielle Ausgleich erfolgt durch die **Anmeldung
234/// korrespondierender Fahrpläne**. Jeder Netzbetreiber verwendet genau einen
235/// Bilanzkreis als Redispatch-Bilanzkreis." The four area/party fields are that
236/// correspondence: energy leaves one balance area/party and arrives in the
237/// other, so a negative Redispatch schedules out of the NB's
238/// Redispatch-Bilanzkreis into the betroffener Bilanzkreis, and a positive one
239/// the reverse.
240///
241/// Dropping the group leaves an activation with no counterpart schedule at all,
242/// which is the half of the process that moves the energy on paper.
243#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
244pub struct ScheduleTimeSeries {
245    /// Unique time-series identifier.
246    #[serde(rename = "TimeSeriesIdentification")]
247    pub time_series_identification: AttrV<DocumentId>,
248    /// Business type of the schedule.
249    #[serde(rename = "BusinessType")]
250    pub business_type: AttrV<String>,
251    /// Product (always active power).
252    #[serde(rename = "Product")]
253    pub product: AttrV<String>,
254    /// Balance area energy flows **into**.
255    #[serde(rename = "InArea")]
256    pub in_area: AttrVWithScheme<String, EicCodingScheme>,
257    /// Balance area energy flows **out of**.
258    #[serde(rename = "OutArea")]
259    pub out_area: AttrVWithScheme<String, EicCodingScheme>,
260    /// Balance party energy flows **into** — the receiving Bilanzkreis.
261    #[serde(rename = "InParty")]
262    pub in_party: AttrVWithScheme<String, EicCodingScheme>,
263    /// Balance party energy flows **out of** — the sending Bilanzkreis.
264    #[serde(rename = "OutParty")]
265    pub out_party: AttrVWithScheme<String, EicCodingScheme>,
266    /// Unit of the scheduled quantities.
267    #[serde(rename = "MeasurementUnit")]
268    pub measurement_unit: AttrV<MeasureUnit>,
269    /// The quarter-hour schedule.
270    #[serde(rename = "Period")]
271    pub period: Period,
272}
273
274/// `ActivationDocument` — Redispatch 2.0 activation instruction, response, or
275/// reduction document.
276///
277/// XSD version: 1.1f (Fehlerkorrektur 2026-02-19)  
278/// Namespace: `urn:entsoe.eu:wgedi:errp:activationdocument:5:0`
279///
280/// Three document types share this format:
281/// - **ACO** (`A96`): Activation order sent by the requesting NB to the
282///   resource provider's NB.
283/// - **ACR** (`A41`): Activation response from the resource provider's NB.
284/// - **AAR** (`A42`): Tender reduction sent by the requesting NB when it
285///   reduces or cancels a previously issued ACO.
286#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
287#[serde(rename = "ActivationDocument")]
288pub struct ActivationDocument {
289    /// Unique document identifier (max 35 chars, case-sensitive).
290    #[serde(rename = "DocumentIdentification")]
291    pub document_identification: AttrV<DocumentId>,
292    /// Document version number (1–999).
293    #[serde(rename = "DocumentVersion")]
294    pub document_version: AttrV<DocumentVersion>,
295    /// Document type: ACR (`A41`), AAR (`A42`), or ACO (`A96`).
296    #[serde(rename = "DocumentType")]
297    pub document_type: AttrV<ActivationDocType>,
298    /// Process type: always `A41` (redispatch process).
299    #[serde(rename = "ProcessType")]
300    pub process_type: AttrV<ActivationProcessType>,
301    /// Sender's market participant identifier.
302    #[serde(rename = "SenderIdentification")]
303    pub sender_identification: AttrVWithScheme<MarketParticipantId>,
304    /// Sender's market role.
305    #[serde(rename = "SenderRole")]
306    pub sender_role: AttrV<MarketRoleType>,
307    /// Receiver's market participant identifier.
308    #[serde(rename = "ReceiverIdentification")]
309    pub receiver_identification: AttrVWithScheme<MarketParticipantId>,
310    /// Receiver's market role.
311    #[serde(rename = "ReceiverRole")]
312    pub receiver_role: AttrV<MarketRoleType>,
313    /// Document creation timestamp (UTC, second precision).
314    #[serde(rename = "CreationDateTime")]
315    pub creation_date_time: AttrV<UtcDateTime>,
316    /// Delivery day covered by this document (UTC interval, minute precision).
317    #[serde(rename = "ActivationTimeInterval")]
318    pub activation_time_interval: AttrV<TimeInterval>,
319    /// `DocumentIdentification` of the ACO this ACR/AAR responds to (optional).
320    #[serde(
321        rename = "OrderIdentification",
322        default,
323        skip_serializing_if = "Option::is_none"
324    )]
325    pub order_identification: Option<AttrV<DocumentId>>,
326    /// `DocumentVersion` of the ACO this ACR/AAR responds to (optional).
327    #[serde(
328        rename = "OrderIdentificationVersion",
329        default,
330        skip_serializing_if = "Option::is_none"
331    )]
332    pub order_identification_version: Option<AttrV<DocumentVersion>>,
333    /// Korrespondierende Fahrpläne accompanying the activation — how the
334    /// bilanzielle Ausgleich is executed (`BilAReM` Kap. 2.1.2).
335    #[serde(
336        rename = "ScheduleTimeSeries",
337        default,
338        skip_serializing_if = "Vec::is_empty"
339    )]
340    pub schedule_time_series: Vec<ScheduleTimeSeries>,
341    /// Activated time series (1–2 entries; one per direction).
342    #[serde(rename = "ActivationTimeSeries", default)]
343    pub time_series: Vec<ActivationTimeSeries>,
344    /// Document-level reason (optional; present on full rejections).
345    #[serde(rename = "Reason", default, skip_serializing_if = "Option::is_none")]
346    pub reason: Option<DocumentReason>,
347}