grid_tariffs/
operator.rs

1use chrono::Utc;
2use indexmap::IndexMap;
3use serde::Serialize;
4
5use crate::{
6    Country, Links, MainFuseSizes, PriceList, currency::Currency, price_list::PriceListSimplified,
7    registry::sweden,
8};
9
10#[derive(Debug, Clone, Serialize)]
11#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
12pub struct GridOperator {
13    name: &'static str,
14    vat_number: &'static str,
15    /// Costs are specified in this currency
16    country: Country,
17    /// The main fuse size range that this info covers
18    main_fuses: MainFuseSizes,
19    price_lists: &'static [PriceList],
20    links: Links,
21}
22
23impl GridOperator {
24    pub const fn name(&self) -> &str {
25        &self.name
26    }
27
28    pub const fn vat_number(&self) -> &str {
29        &self.vat_number
30    }
31
32    pub const fn country(&self) -> Country {
33        self.country
34    }
35
36    pub const fn links(&self) -> &Links {
37        &self.links
38    }
39
40    pub fn active_price_lists(&self) -> Vec<&'static PriceList> {
41        let now = Utc::now().date_naive();
42        let mut map: IndexMap<Option<&str>, &PriceList> = IndexMap::new();
43        for pl in self.price_lists {
44            if now >= pl.from_date() {
45                if let Some(current_max_date) = map.get(&pl.variant()).map(|pl| pl.from_date()) {
46                    if pl.from_date() > current_max_date {
47                        map.insert(pl.variant(), pl);
48                    }
49                } else {
50                    map.insert(pl.variant(), pl);
51                }
52            }
53        }
54        map.into_values().collect()
55    }
56
57    pub fn active_price_list(&self, variant: Option<&str>) -> Option<&'static PriceList> {
58        self.active_price_lists()
59            .iter()
60            .filter(|pl| pl.variant() == variant)
61            .last()
62            .copied()
63    }
64
65    pub fn price_lists(&self) -> &'static [PriceList] {
66        self.price_lists
67    }
68
69    pub const fn currency(&self) -> Currency {
70        match self.country {
71            Country::SE => Currency::SEK,
72        }
73    }
74
75    pub fn get(country: Country, name: &str) -> Option<&'static Self> {
76        match country {
77            Country::SE => sweden::GRID_OPERATORS
78                .iter()
79                .find(|o| o.name == name)
80                .copied(),
81        }
82    }
83
84    pub fn all() -> Vec<&'static Self> {
85        sweden::GRID_OPERATORS.iter().copied().collect()
86    }
87
88    pub fn all_for_country(country: Country) -> &'static [&'static Self] {
89        match country {
90            Country::SE => sweden::GRID_OPERATORS,
91        }
92    }
93
94    pub(crate) const fn builder() -> GridOperatorBuilder {
95        GridOperatorBuilder::new()
96    }
97
98    pub fn simplified(&self, fuse_size: u16, yearly_consumption: u32) -> GridOperatorSimplified {
99        GridOperatorSimplified::new(self, fuse_size, yearly_consumption)
100    }
101}
102
103/// Grid operator with only current prices
104#[derive(Debug, Clone, Serialize)]
105#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
106pub struct GridOperatorSimplified {
107    name: &'static str,
108    vat_number: &'static str,
109    /// Costs are specified in this currency
110    country: Country,
111    price_lists: Vec<PriceListSimplified>,
112}
113
114impl GridOperatorSimplified {
115    pub fn name(&self) -> &'static str {
116        self.name
117    }
118
119    pub fn vat_number(&self) -> &'static str {
120        self.vat_number
121    }
122
123    pub fn country(&self) -> Country {
124        self.country
125    }
126
127    pub fn price_lists(&self) -> &[PriceListSimplified] {
128        &self.price_lists
129    }
130}
131
132impl GridOperatorSimplified {
133    fn new(op: &GridOperator, fuse_size: u16, yearly_consumption: u32) -> Self {
134        Self {
135            name: op.name,
136            vat_number: op.vat_number,
137            country: op.country(),
138            price_lists: op
139                .active_price_lists()
140                .into_iter()
141                .map(|pl| pl.simplified(fuse_size, yearly_consumption))
142                .collect(),
143        }
144    }
145}
146
147#[derive(Debug, Clone)]
148pub(crate) struct GridOperatorBuilder {
149    name: Option<&'static str>,
150    vat_number: Option<&'static str>,
151    /// Costs are specified in this currency
152    country: Option<Country>,
153    /// The main fuse size range that this info covers
154    main_fuses: Option<MainFuseSizes>,
155    price_lists: Option<&'static [PriceList]>,
156    links: Option<Links>,
157}
158
159impl GridOperatorBuilder {
160    pub(crate) const fn new() -> Self {
161        Self {
162            name: None,
163            vat_number: None,
164            country: None,
165            main_fuses: None,
166            price_lists: None,
167            links: None,
168        }
169    }
170
171    pub(crate) const fn name(mut self, name: &'static str) -> Self {
172        self.name = Some(name);
173        self
174    }
175
176    pub(crate) const fn vat_number(mut self, vat_number: &'static str) -> Self {
177        self.vat_number = Some(vat_number);
178        self
179    }
180
181    pub(crate) const fn country(mut self, country: Country) -> Self {
182        self.country = Some(country);
183        self
184    }
185
186    pub(crate) const fn main_fuses(mut self, main_fuses: MainFuseSizes) -> Self {
187        self.main_fuses = Some(main_fuses);
188        self
189    }
190
191    pub(crate) const fn links(mut self, links: Links) -> Self {
192        self.links = Some(links);
193        self
194    }
195
196    pub(crate) const fn price_lists(mut self, price_lists: &'static [PriceList]) -> Self {
197        self.price_lists = Some(price_lists);
198        self
199    }
200
201    pub(crate) const fn build(self) -> GridOperator {
202        GridOperator {
203            name: self.name.expect("`name` required"),
204            vat_number: self.vat_number.expect("`vat_number` required"),
205            country: self.country.expect("`country` required"),
206            main_fuses: self.main_fuses.expect("`main_fuses` required"),
207            price_lists: self.price_lists.expect("`price_lists` expected"),
208            links: self.links.expect("`links` required"),
209        }
210    }
211}