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 const fn spot_price_variable(
39        base_cost_subunit: f64,
40        spot_price_multiplier: f64,
41        approximated: bool,
42    ) -> Self {
43        Self::SpotPriceVariable {
44            base_cost: Money::new_subunit(base_cost_subunit),
45            spot_price_multiplier,
46            approximated,
47        }
48    }
49
50    pub fn simplified(
51        &self,
52        fuse_size: u16,
53        yearly_consumption: u32,
54        language: Language,
55    ) -> FeedInRevenueSimplified {
56        FeedInRevenueSimplified::new(self, fuse_size, yearly_consumption, language)
57    }
58}
59
60/// Feed-in revenue, per kWh (usually from solar production)
61/// Like FeedInRevenue, but with costs being simple Money objects
62#[derive(Debug, Clone, Serialize)]
63#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
64pub enum FeedInRevenueSimplified {
65    Simple(Option<Money>),
66    /// Not yet checked
67    Unverified,
68    /// Could not be located on their website or elsewhere
69    Unlisted,
70    /// Varies by the current spot price
71    SpotPriceVariable {
72        base_cost: Money,
73        spot_price_multiplier: f64,
74        /// If this is approximated from actual data, or if it's based on documented pricing
75        approximated: bool,
76        info: String,
77    },
78    Periods(CostPeriodsSimple),
79}
80
81impl FeedInRevenueSimplified {
82    fn new(
83        revenue: &FeedInRevenue,
84        fuse_size: u16,
85        yearly_consumption: u32,
86        language: Language,
87    ) -> Self {
88        match *revenue {
89            FeedInRevenue::Unlisted => Self::Unlisted,
90            FeedInRevenue::Unverified => Self::Unverified,
91            FeedInRevenue::Simple(cost) => {
92                Self::Simple(cost.cost_for(fuse_size, yearly_consumption))
93            }
94            FeedInRevenue::SpotPriceVariable {
95                base_cost,
96                spot_price_multiplier,
97                approximated,
98            } => Self::SpotPriceVariable {
99                base_cost,
100                spot_price_multiplier,
101                approximated,
102                info: Default::default(),
103            },
104            FeedInRevenue::Periods(periods) => Self::Periods(CostPeriodsSimple::new(
105                periods,
106                fuse_size,
107                yearly_consumption,
108                language,
109            )),
110        }
111        .add_info(language)
112    }
113
114    fn add_info(mut self, language: Language) -> Self {
115        match self {
116            FeedInRevenueSimplified::SpotPriceVariable {
117                base_cost,
118                spot_price_multiplier,
119                approximated,
120                info,
121            } => {
122                let percentage = spot_price_multiplier * 100.;
123                let mut info = match language {
124                    Language::En => format!(
125                        "The grid operator bases its feed-in revenue on a fixed part of {} and {}% of the current spot price.",
126                        base_cost.display(Currency::SEK),
127                        percentage
128                    ),
129                    Language::Sv => format!(
130                        "Nätbolaget baserar sin nätnytta på en fast del om {} samt {}% av spotpriset.",
131                        base_cost.display(Currency::SEK),
132                        percentage
133                    ),
134                };
135                if approximated {
136                    info.push_str(match language {
137                        Language::En => " The base fee and percentage are estimated, as the grid operator doesn't list them on their website.",
138                        Language::Sv => " Basavgift och procentsats är uppskattade, eftersom nätbolaget inte skriver ut exakt vad de är på sin webbplats.",
139                    })
140                }
141                FeedInRevenueSimplified::SpotPriceVariable {
142                    base_cost,
143                    spot_price_multiplier,
144                    approximated,
145                    info,
146                }
147            }
148            _ => self,
149        }
150    }
151}