grid_tariffs/
feed_in_revenue.rs

1use serde::Serialize;
2
3use crate::{Cost, CostPeriods, CostPeriodsSimple, Language, Money, currency::Currency};
4
5/// Feed-in revenue, per kWh (usually from solar production)
6/// A Swedish concept for "thanking" micro producers (<=43,5 kW) for reducing losses in the grid
7#[derive(Debug, Clone, Copy, Serialize)]
8#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
9pub enum FeedInRevenue {
10    Simple(Cost),
11    /// Not yet checked
12    Unverified,
13    /// Could not be located on their website or elsewhere
14    Unlisted,
15    /// Varies by the current spot price
16    SpotPriceVariable {
17        base_cost: Money,
18        spot_price_multiplier: f64,
19        /// If this is approximated from actual data, or if it's based on documented pricing
20        approximated: bool,
21    },
22    Periods(CostPeriods),
23}
24
25impl FeedInRevenue {
26    pub const fn is_unverified(&self) -> bool {
27        matches!(self, Self::Unverified)
28    }
29
30    pub(super) const fn new_periods(periods: CostPeriods) -> Self {
31        Self::Periods(periods)
32    }
33
34    pub(super) const fn fixed_subunit(subunit: f64) -> Self {
35        Self::Simple(Cost::fixed_subunit(subunit))
36    }
37
38    pub fn simplified(
39        &self,
40        fuse_size: u16,
41        yearly_consumption: u32,
42        language: Language,
43    ) -> FeedInRevenueSimplified {
44        FeedInRevenueSimplified::new(self, fuse_size, yearly_consumption, language)
45    }
46}
47
48/// Feed-in revenue, per kWh (usually from solar production)
49/// Like FeedInRevenue, but with costs being simple Money objects
50#[derive(Debug, Clone, Serialize)]
51#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
52pub enum FeedInRevenueSimplified {
53    Simple(Option<Money>),
54    /// Not yet checked
55    Unverified,
56    /// Could not be located on their website or elsewhere
57    Unlisted,
58    /// Varies by the current spot price
59    SpotPriceVariable {
60        base_cost: Money,
61        spot_price_multiplier: f64,
62        /// If this is approximated from actual data, or if it's based on documented pricing
63        approximated: bool,
64        info: String,
65    },
66    Periods(CostPeriodsSimple),
67}
68
69impl FeedInRevenueSimplified {
70    fn new(
71        revenue: &FeedInRevenue,
72        fuse_size: u16,
73        yearly_consumption: u32,
74        language: Language,
75    ) -> Self {
76        match *revenue {
77            FeedInRevenue::Unlisted => Self::Unlisted,
78            FeedInRevenue::Unverified => Self::Unverified,
79            FeedInRevenue::Simple(cost) => {
80                Self::Simple(cost.cost_for(fuse_size, yearly_consumption))
81            }
82            FeedInRevenue::SpotPriceVariable {
83                base_cost,
84                spot_price_multiplier,
85                approximated,
86            } => Self::SpotPriceVariable {
87                base_cost,
88                spot_price_multiplier,
89                approximated,
90                info: Default::default(),
91            },
92            FeedInRevenue::Periods(periods) => Self::Periods(CostPeriodsSimple::new(
93                periods,
94                fuse_size,
95                yearly_consumption,
96                language,
97            )),
98        }
99        .add_info(language)
100    }
101
102    fn add_info(mut self, language: Language) -> Self {
103        match self {
104            FeedInRevenueSimplified::SpotPriceVariable {
105                base_cost,
106                spot_price_multiplier,
107                approximated,
108                info,
109            } => {
110                let percentage = spot_price_multiplier * 100.;
111                let mut info = match language {
112                    Language::En => format!(
113                        "The grid operator bases its feed-in revenue on a fixed part of {} and {}% of the current spot price.",
114                        base_cost.display(Currency::SEK),
115                        percentage
116                    ),
117                    Language::Sv => format!(
118                        "Nätbolaget baserar sin nätnytta på en fast del om {} samt {}% av spotpriset.",
119                        base_cost.display(Currency::SEK),
120                        percentage
121                    ),
122                };
123                if approximated {
124                    info.push_str(&match language {
125                        Language::En => format!(
126                            " The percentage is estimated as the grid operator doesn't list it on their website."
127                        ),
128                        Language::Sv => format!(
129                            " Procentsatsen är uppskattad eftersom nätbolaget inte skriver ut exakt vad den är på sin webbplats."
130                        ),
131                    })
132                }
133                FeedInRevenueSimplified::SpotPriceVariable {
134                    base_cost,
135                    spot_price_multiplier,
136                    approximated,
137                    info,
138                }
139            }
140            _ => self,
141        }
142    }
143}