grid_tariffs/
price_list.rs

1use chrono::{DateTime, NaiveDate, TimeZone};
2use serde::Serialize;
3
4use crate::{
5    FeedInRevenueSimplified, GridOperator, Language, Money, PowerTariff, PowerTariffSimplified,
6    TransferFeeSimplified, costs::Cost, feed_in_revenue::FeedInRevenue, helpers,
7    transfer_fee::TransferFee,
8};
9
10#[derive(Debug, Clone, Serialize)]
11#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
12pub struct PriceList {
13    variant: Option<&'static str>,
14    from_date: NaiveDate,
15    /// Fixed monthly fee
16    monthly_fee: Cost,
17    /// Fixed monthly fee for allowing energy production
18    monthly_production_fee: Cost,
19    transfer_fee: TransferFee,
20    feed_in_revenue: FeedInRevenue,
21    power_tariff: PowerTariff,
22}
23
24impl PriceList {
25    pub const fn builder() -> PriceListBuilder {
26        PriceListBuilder::new()
27    }
28
29    pub const fn variant(&self) -> Option<&'static str> {
30        self.variant
31    }
32
33    pub const fn from_date(&self) -> NaiveDate {
34        self.from_date
35    }
36
37    pub const fn monthly_fee(&self) -> &Cost {
38        &self.monthly_fee
39    }
40
41    pub const fn monthly_production_fee(&self) -> &Cost {
42        &self.monthly_production_fee
43    }
44
45    pub const fn transfer_fee(&self) -> &TransferFee {
46        &self.transfer_fee
47    }
48
49    pub const fn feed_in_revenue(&self) -> &FeedInRevenue {
50        &self.feed_in_revenue
51    }
52
53    pub const fn power_tariff(&self) -> &PowerTariff {
54        &self.power_tariff
55    }
56
57    /// Total fee per kWh
58    ///
59    /// Please note that taxes are not included.
60    ///
61    pub fn kwh_fee<Tz: TimeZone>(
62        &self,
63        timestamp: DateTime<Tz>,
64        spotprice: Money,
65        fuse_size: u16,
66        yearly_consumption: u32,
67    ) -> Money
68    where
69        DateTime<Tz>: Copy,
70    {
71        self.transfer_fee()
72            .kwh_cost(timestamp, spotprice, fuse_size, yearly_consumption)
73    }
74
75    /// Total revenue per kWh
76    ///
77    /// Please note that tax reductions are not included.
78    ///
79    pub fn kwh_revenue<Tz: TimeZone>(
80        &self,
81        timestamp: DateTime<Tz>,
82        spotprice: Money,
83        fuse_size: u16,
84        yearly_consumption: u32,
85    ) -> Money
86    where
87        DateTime<Tz>: Copy,
88    {
89        self.feed_in_revenue()
90            .kwh_revenue(timestamp, spotprice, fuse_size, yearly_consumption)
91    }
92
93    pub fn simplified(
94        &self,
95        op: &GridOperator,
96        fuse_size: u16,
97        yearly_consumption: u32,
98        language: Language,
99    ) -> PriceListSimplified {
100        PriceListSimplified::new(op, self, fuse_size, yearly_consumption, language)
101    }
102}
103
104#[derive(Debug, Clone)]
105pub struct PriceListBuilder {
106    variant: Option<&'static str>,
107    from_date: Option<NaiveDate>,
108    /// Fixed monthly fee
109    monthly_fee: Option<Cost>,
110    /// Fixed monthly fee for allowing energy production
111    monthly_production_fee: Option<Cost>,
112    transfer_fee: Option<TransferFee>,
113    feed_in_revenue: Option<FeedInRevenue>,
114    power_tariff: Option<PowerTariff>,
115}
116
117impl Default for PriceListBuilder {
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123impl PriceListBuilder {
124    pub const fn new() -> Self {
125        Self {
126            variant: None,
127            from_date: None,
128            monthly_fee: None,
129            monthly_production_fee: None,
130            transfer_fee: None,
131            feed_in_revenue: None,
132            power_tariff: None,
133        }
134    }
135
136    pub const fn build(self) -> PriceList {
137        PriceList {
138            variant: self.variant,
139            from_date: self.from_date.expect("`from_date` required"),
140            monthly_fee: self.monthly_fee.expect("`monthly_fee` required"),
141            monthly_production_fee: self
142                .monthly_production_fee
143                .expect("`monthly_production_fee` required"),
144            transfer_fee: self.transfer_fee.expect("`transfer_fee` required"),
145            feed_in_revenue: self.feed_in_revenue.expect("`feed_in_revenue` required"),
146            power_tariff: self.power_tariff.expect("`grid_tariff` required"),
147        }
148    }
149
150    pub const fn variant(mut self, name: &'static str) -> Self {
151        self.variant = Some(name);
152        self
153    }
154
155    #[allow(clippy::wrong_self_convention)]
156    pub const fn from_date(mut self, year: i32, month: u32, day: u32) -> Self {
157        self.from_date = Some(helpers::date(year, month, day));
158        self
159    }
160
161    pub const fn monthly_fee(mut self, monthly_fee: Cost) -> Self {
162        self.monthly_fee = Some(monthly_fee);
163        self
164    }
165
166    pub const fn monthly_production_fee(mut self, monthly_production_fee: Cost) -> Self {
167        self.monthly_production_fee = Some(monthly_production_fee);
168        self
169    }
170
171    pub const fn transfer_fee(mut self, transfer_fee: TransferFee) -> Self {
172        self.transfer_fee = Some(transfer_fee);
173        self
174    }
175
176    /// Feed in revenue per kWh. Should be specified without VAT (at least for SE)
177    pub const fn feed_in_revenue(mut self, feed_in_revenue: FeedInRevenue) -> Self {
178        self.feed_in_revenue = Some(feed_in_revenue);
179        self
180    }
181
182    pub const fn power_tariff(mut self, power_tariff: PowerTariff) -> Self {
183        self.power_tariff = Some(power_tariff);
184        self
185    }
186}
187
188#[derive(Debug, Clone, Serialize)]
189#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
190pub struct PriceListSimplified {
191    variant: Option<&'static str>,
192    fuse_size: u16,
193    /// If the energy consumption of the household affects the costs and/or fees for this fuse size
194    yearly_consumption_based: bool,
195    from_date: NaiveDate,
196    /// Fixed monthly fee
197    monthly_fee: Option<Money>,
198    /// Fixed monthly fee for allowing energy production
199    monthly_production_fee: Option<Money>,
200    transfer_fee: TransferFeeSimplified,
201    feed_in_revenue: FeedInRevenueSimplified,
202    power_tariff: PowerTariffSimplified,
203}
204
205impl PriceListSimplified {
206    fn new(
207        op: &GridOperator,
208        pl: &PriceList,
209        fuse_size: u16,
210        yearly_consumption: u32,
211        language: Language,
212    ) -> Self {
213        Self {
214            variant: pl.variant,
215            fuse_size,
216            yearly_consumption_based: pl.monthly_fee.is_yearly_consumption_based(fuse_size)
217                || pl
218                    .monthly_production_fee
219                    .is_yearly_consumption_based(fuse_size)
220                || pl.transfer_fee.is_yearly_consumption_based(fuse_size),
221            from_date: pl.from_date,
222            monthly_fee: pl.monthly_fee.cost_for(fuse_size, yearly_consumption),
223            monthly_production_fee: pl
224                .monthly_production_fee
225                .cost_for(fuse_size, yearly_consumption),
226            transfer_fee: pl
227                .transfer_fee
228                .simplified(fuse_size, yearly_consumption, language),
229            feed_in_revenue: pl
230                .feed_in_revenue
231                .simplified(fuse_size, yearly_consumption, language),
232            power_tariff: pl
233                .power_tariff
234                .simplified(op, fuse_size, yearly_consumption, language),
235        }
236    }
237}