Skip to main content

redispatch_xml/documents/
kostenblatt.rs

1//! `Kostenblatt` -- cost sheet for redispatch measures (billing document, ANB to VNB/UNB).
2use serde::{Deserialize, Serialize};
3
4use crate::documents::activation::{ControlZoneRef, ResourceObjectRef};
5use crate::documents::planned_resource_schedule::Product;
6use crate::types::{
7    AttrV, AttrVWithScheme, Direction, DocumentId, DocumentVersion, MarketParticipantId,
8    MarketRoleType, Period, TimeInterval, UtcDateTime,
9};
10
11// ── DocumentType ──────────────────────────────────────────────────────────────
12
13/// `DocumentType` for `Kostenblatt` (always `Z05`).
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum KostenblattDocType {
16    /// Cost sheet (Kostenblatt).
17    #[serde(rename = "Z05")]
18    Kostenblatt,
19}
20
21/// `ProcessType` for `Kostenblatt` (always `A14`).
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum KostenblattProcessType {
24    /// Forecast (Planungsdaten).
25    #[serde(rename = "A14")]
26    Forecast,
27}
28
29/// `BusinessType` codes for `CostTimeSeries`.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub enum CostBusinessType {
32    /// Production — energy-dependent costs (Arbeitspreis).
33    #[serde(rename = "A01")]
34    ProductionEnergy,
35    /// Consumption — energy-dependent costs.
36    #[serde(rename = "A04")]
37    ConsumptionEnergy,
38    /// Startup costs (Anfahrkosten).
39    #[serde(rename = "Z01")]
40    StartupCosts,
41    /// Extra operating-hour costs (Betriebsstundenkosten).
42    #[serde(rename = "Z02")]
43    ExtraOperatingHourCosts,
44    /// Avoided network fees (vermiedene Netzentgelte).
45    #[serde(rename = "Z03")]
46    AvoidedNetworkFees,
47    /// Additional wRDV costs.
48    #[serde(rename = "Z06")]
49    AdditionalWrdvCosts,
50}
51
52// ── CostTimeSeries ────────────────────────────────────────────────────────────
53
54/// A single cost time series within a `Kostenblatt`.
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct CostTimeSeries {
57    /// Unique time-series identifier (max 35 chars).
58    #[serde(rename = "TimeSeriesIdentification")]
59    pub time_series_identification: AttrV<DocumentId>,
60    /// Reference to the original time series when this one corrects it.
61    ///
62    /// Without it a correction cannot be matched to what it corrects, so the
63    /// receiver either applies it twice or not at all.
64    #[serde(
65        rename = "OriginalTimeSeriesIdentification",
66        default,
67        skip_serializing_if = "Option::is_none"
68    )]
69    pub original_time_series_identification: Option<AttrV<DocumentId>>,
70    /// Curve type of the cost series.
71    #[serde(rename = "CurveType", default, skip_serializing_if = "Option::is_none")]
72    pub curve_type: Option<AttrV<String>>,
73    /// Resource provider that operates the resource.
74    #[serde(
75        rename = "ResourceProvider",
76        default,
77        skip_serializing_if = "Option::is_none"
78    )]
79    pub resource_provider: Option<AttrVWithScheme<MarketParticipantId>>,
80    /// Status of the cost series.
81    #[serde(rename = "Status", default, skip_serializing_if = "Option::is_none")]
82    pub status: Option<AttrV<String>>,
83    /// Cost type.
84    #[serde(rename = "BusinessType")]
85    pub business_type: AttrV<CostBusinessType>,
86    /// Direction (optional — absent for startup/fixed costs).
87    #[serde(rename = "Direction", default, skip_serializing_if = "Option::is_none")]
88    pub direction: Option<AttrV<Direction>>,
89    /// Product (always active power `8716867000016`).
90    #[serde(rename = "Product")]
91    pub product: AttrV<Product>,
92    /// Control zone of the resource (optional).
93    #[serde(
94        rename = "ConnectingArea",
95        default,
96        skip_serializing_if = "Option::is_none"
97    )]
98    pub connecting_area: Option<ControlZoneRef>,
99    /// Resource object identifier (BDEW resource code, NDE scheme; optional).
100    #[serde(
101        rename = "ResourceObject",
102        default,
103        skip_serializing_if = "Option::is_none"
104    )]
105    pub resource_object: Option<ResourceObjectRef>,
106    /// Unit the cost figures are expressed in.
107    ///
108    /// The XSD element is `MeasurementUnit`; only the `ActivationDocument`
109    /// uses the shorter `MeasureUnit` spelling, and only in its
110    /// `ActivationTimeSeries`.
111    #[serde(rename = "MeasurementUnit")]
112    pub measurement_unit: AttrV<String>,
113    /// Quarter-hour cost data for the delivery day.
114    #[serde(rename = "Period")]
115    pub period: Period,
116}
117
118// ── Kostenblatt ───────────────────────────────────────────────────────────────
119
120/// `Kostenblatt` — cost sheet for redispatch billing between grid operators.
121///
122/// XSD version: 1.0d (Fehlerkorrektur 2025-04-16)  
123/// No XML namespace.
124///
125/// Contains energy-dependent and fixed cost data for each activated
126/// controllable resource in a given delivery day.
127#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128#[serde(rename = "Kostenblatt")]
129pub struct Kostenblatt {
130    /// Original sender when this document corrects an earlier one.
131    #[serde(
132        rename = "OriginalSenderIdentification",
133        default,
134        skip_serializing_if = "Option::is_none"
135    )]
136    pub original_sender_identification: Option<AttrVWithScheme<MarketParticipantId>>,
137    /// Identifier of the document being corrected.
138    #[serde(
139        rename = "OriginalDocumentIdentification",
140        default,
141        skip_serializing_if = "Option::is_none"
142    )]
143    pub original_document_identification: Option<AttrV<DocumentId>>,
144    /// Version of the document being corrected.
145    #[serde(
146        rename = "OriginalDocumentVersion",
147        default,
148        skip_serializing_if = "Option::is_none"
149    )]
150    pub original_document_version: Option<AttrV<DocumentVersion>>,
151    /// Creation timestamp of the document being corrected.
152    #[serde(
153        rename = "OriginalDocumentDateTime",
154        default,
155        skip_serializing_if = "Option::is_none"
156    )]
157    pub original_document_date_time: Option<AttrV<UtcDateTime>>,
158    /// Unique document identifier (max 35 chars).
159    #[serde(rename = "DocumentIdentification")]
160    pub document_identification: AttrV<DocumentId>,
161    /// Document version number (1–999).
162    #[serde(rename = "DocumentVersion")]
163    pub document_version: AttrV<DocumentVersion>,
164    /// Document type (always `Z05`).
165    #[serde(rename = "DocumentType")]
166    pub document_type: AttrV<KostenblattDocType>,
167    /// Process type (always `A14`).
168    #[serde(rename = "ProcessType")]
169    pub process_type: AttrV<KostenblattProcessType>,
170    /// Sender's market participant identifier.
171    #[serde(rename = "SenderIdentification")]
172    pub sender_identification: AttrVWithScheme<MarketParticipantId>,
173    /// Sender's market role.
174    #[serde(rename = "SenderRole")]
175    pub sender_role: AttrV<MarketRoleType>,
176    /// Receiver's market participant identifier.
177    #[serde(rename = "ReceiverIdentification")]
178    pub receiver_identification: AttrVWithScheme<MarketParticipantId>,
179    /// Receiver's market role.
180    #[serde(rename = "ReceiverRole")]
181    pub receiver_role: AttrV<MarketRoleType>,
182    /// Document creation timestamp (UTC, second precision).
183    #[serde(rename = "DocumentDateTime")]
184    pub document_date_time: AttrV<UtcDateTime>,
185    /// Delivery period covered (UTC interval).
186    #[serde(rename = "TimePeriodCovered")]
187    pub time_period_covered: AttrV<TimeInterval>,
188    /// Cost time series (one or more).
189    #[serde(rename = "CostTimeSeries", default)]
190    pub time_series: Vec<CostTimeSeries>,
191}