1use chrono::{DateTime, TimeZone};
2use serde::Serialize;
3
4use crate::{Cost, CostPeriods, CostPeriodsSimple, Language, Money, currency::Currency};
5
6#[derive(Debug, Clone, Copy, Serialize)]
9#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
10pub enum FeedInRevenue {
11 Simple(Cost),
12 Unverified,
14 Unlisted,
16 SpotPriceVariable {
18 base_cost: Money,
19 spot_price_multiplier: f64,
20 approximated: bool,
22 },
23 Periods(CostPeriods),
24}
25
26impl FeedInRevenue {
27 pub const fn is_unverified(&self) -> bool {
28 matches!(self, Self::Unverified)
29 }
30
31 pub(crate) const fn new_periods(periods: CostPeriods) -> Self {
32 Self::Periods(periods)
33 }
34
35 pub(crate) const fn fixed_subunit(subunit: f64) -> Self {
36 Self::Simple(Cost::fixed_subunit(subunit))
37 }
38
39 pub const fn spot_price_variable(
40 base_cost_subunit: f64,
41 spot_price_multiplier: f64,
42 approximated: bool,
43 ) -> Self {
44 Self::SpotPriceVariable {
45 base_cost: Money::new_subunit(base_cost_subunit),
46 spot_price_multiplier,
47 approximated,
48 }
49 }
50
51 pub fn simplified(
52 &self,
53 fuse_size: u16,
54 yearly_consumption: u32,
55 language: Language,
56 ) -> FeedInRevenueSimplified {
57 FeedInRevenueSimplified::new(self, fuse_size, yearly_consumption, language)
58 }
59
60 pub fn kwh_revenue<Tz: TimeZone>(
61 &self,
62 timestamp: DateTime<Tz>,
63 spotprice: Money,
64 fuse_size: u16,
65 yearly_consumption: u32,
66 ) -> Money
67 where
68 DateTime<Tz>: Copy,
69 {
70 match *self {
71 FeedInRevenue::Unverified | FeedInRevenue::Unlisted => Money::ZERO,
72 FeedInRevenue::Simple(cost) => cost
73 .cost_for(fuse_size, yearly_consumption)
74 .unwrap_or_default(),
75 FeedInRevenue::SpotPriceVariable {
76 base_cost,
77 spot_price_multiplier,
78 approximated: _,
79 } => base_cost + (spotprice * spot_price_multiplier),
80 FeedInRevenue::Periods(cost_periods) => cost_periods
81 .matching_periods(timestamp)
82 .into_iter()
83 .flat_map(|period| period.cost().cost_for(fuse_size, yearly_consumption))
84 .sum(),
85 }
86 }
87}
88
89#[derive(Debug, Clone, Serialize)]
92#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
93pub enum FeedInRevenueSimplified {
94 Simple(Option<Money>),
95 Unverified,
97 Unlisted,
99 SpotPriceVariable {
101 base_cost: Money,
102 spot_price_multiplier: f64,
103 approximated: bool,
105 info: String,
106 },
107 Periods(CostPeriodsSimple),
108}
109
110impl FeedInRevenueSimplified {
111 fn new(
112 revenue: &FeedInRevenue,
113 fuse_size: u16,
114 yearly_consumption: u32,
115 language: Language,
116 ) -> Self {
117 match *revenue {
118 FeedInRevenue::Unlisted => Self::Unlisted,
119 FeedInRevenue::Unverified => Self::Unverified,
120 FeedInRevenue::Simple(cost) => {
121 Self::Simple(cost.cost_for(fuse_size, yearly_consumption))
122 }
123 FeedInRevenue::SpotPriceVariable {
124 base_cost,
125 spot_price_multiplier,
126 approximated,
127 } => Self::SpotPriceVariable {
128 base_cost,
129 spot_price_multiplier,
130 approximated,
131 info: Default::default(),
132 },
133 FeedInRevenue::Periods(periods) => Self::Periods(CostPeriodsSimple::new(
134 periods,
135 fuse_size,
136 yearly_consumption,
137 language,
138 )),
139 }
140 .add_info(language)
141 }
142
143 fn add_info(self, language: Language) -> Self {
144 match self {
145 FeedInRevenueSimplified::SpotPriceVariable {
146 base_cost,
147 spot_price_multiplier,
148 approximated,
149 info: _,
150 } => {
151 let percentage = spot_price_multiplier * 100.;
152 let mut info = match language {
153 Language::En => format!(
154 "The grid operator bases its feed-in revenue on a fixed part of {} and {}% of the current spot price.",
155 base_cost.display(Currency::SEK),
156 percentage
157 ),
158 Language::Sv => format!(
159 "Nätbolaget baserar sin nätnytta på en fast del om {} samt {}% av spotpriset.",
160 base_cost.display(Currency::SEK),
161 percentage
162 ),
163 };
164 if approximated {
165 info.push_str(match language {
166 Language::En => " The base fee and percentage are estimated, as the grid operator doesn't list them on their website.",
167 Language::Sv => " Basavgift och procentsats är uppskattade, eftersom nätbolaget inte skriver ut exakt vad de är på sin webbplats.",
168 })
169 }
170 FeedInRevenueSimplified::SpotPriceVariable {
171 base_cost,
172 spot_price_multiplier,
173 approximated,
174 info,
175 }
176 }
177 _ => self,
178 }
179 }
180}