grid_tariffs/
country.rs

1use core::fmt;
2use std::str::FromStr;
3
4use chrono::{NaiveDate, Utc};
5use serde::{Deserialize, Serialize};
6
7use crate::{Money, SE_TAX_REDUCTIONS, SE_TAXES, Tax, TaxAppliedBy, TaxReduction, helpers::date};
8
9#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
10#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
11pub enum Country {
12    SE,
13}
14
15impl Country {
16    pub const fn all() -> &'static [Self] {
17        &[Country::SE]
18    }
19
20    pub const fn taxes(&self) -> &'static [Tax] {
21        match self {
22            Country::SE => SE_TAXES,
23        }
24    }
25
26    pub const fn tax_reductions(&self) -> &'static [TaxReduction] {
27        match self {
28            Country::SE => SE_TAX_REDUCTIONS,
29        }
30    }
31
32    pub fn current_taxes(&self, today: NaiveDate) -> Vec<Tax> {
33        self.taxes()
34            .iter()
35            .filter(|tax| tax.valid_for(today))
36            .copied()
37            .collect()
38    }
39
40    pub fn current_tax_reductions(&self, today: NaiveDate) -> Vec<TaxReduction> {
41        self.tax_reductions()
42            .iter()
43            .filter(|tax| tax.valid_for(today))
44            .copied()
45            .collect()
46    }
47
48    pub(crate) const fn vat_rate(&self) -> f64 {
49        match self {
50            Country::SE => 1.25,
51        }
52    }
53
54    pub(crate) const fn add_vat(&self, value: f64) -> f64 {
55        value * self.vat_rate()
56    }
57
58    pub(crate) fn is_holiday(&self, date_naive: NaiveDate) -> bool {
59        SE_HOLIDAYS.contains(&date_naive)
60    }
61}
62
63impl Country {
64    pub fn code(&self) -> &'static str {
65        match self {
66            Country::SE => "SE",
67        }
68    }
69
70    pub fn english_name(&self) -> &'static str {
71        match self {
72            Country::SE => "Sweden",
73        }
74    }
75}
76
77impl FromStr for Country {
78    type Err = &'static str;
79
80    fn from_str(s: &str) -> Result<Self, Self::Err> {
81        match s.to_ascii_uppercase().as_ref() {
82            "SE" => Ok(Country::SE),
83            _ => Err("no such country"),
84        }
85    }
86}
87
88impl fmt::Display for Country {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        f.write_str(match self {
91            Country::SE => "SE",
92        })
93    }
94}
95
96#[derive(Debug, Serialize)]
97pub struct CountryInfo {
98    country: Country,
99    /// Taxes applied in this country
100    taxes: Vec<Tax>,
101    /// Tax reductions applied in this country
102    tax_reductions: Vec<TaxReduction>,
103}
104
105impl CountryInfo {
106    pub fn current(country: Country) -> Self {
107        let today = Utc::now().date_naive();
108        Self {
109            country,
110            taxes: country.current_taxes(today),
111            tax_reductions: country.current_tax_reductions(today),
112        }
113    }
114}
115
116impl From<Country> for CountryInfo {
117    fn from(country: Country) -> Self {
118        let taxes = country.taxes().to_vec();
119        let tax_reductions = country.tax_reductions().to_vec();
120        Self {
121            country,
122            taxes,
123            tax_reductions,
124        }
125    }
126}
127
128static SE_HOLIDAYS: &[NaiveDate] = &[
129    date(2025, 1, 1),
130    date(2025, 1, 6),
131    date(2025, 4, 18),
132    date(2025, 4, 20),
133    date(2025, 4, 21),
134    date(2025, 5, 1),
135    date(2025, 5, 29),
136    date(2025, 6, 6),
137    date(2025, 6, 8),
138    date(2025, 6, 21),
139    date(2025, 11, 1),
140    date(2025, 12, 24),
141    date(2025, 12, 25),
142    date(2025, 12, 26),
143    date(2025, 12, 31),
144    date(2026, 1, 1),
145    date(2026, 1, 6),
146    date(2026, 4, 3),
147    date(2026, 4, 5),
148    date(2026, 4, 6),
149    date(2026, 5, 1),
150    date(2026, 5, 14),
151    date(2026, 5, 24),
152    date(2026, 6, 6),
153    date(2026, 6, 20),
154    date(2026, 10, 31),
155    date(2026, 12, 24),
156    date(2026, 12, 25),
157    date(2026, 12, 26),
158    date(2026, 12, 31),
159    date(2027, 1, 1),
160    date(2027, 1, 6),
161    date(2027, 3, 26),
162    date(2027, 3, 28),
163    date(2027, 3, 29),
164    date(2027, 5, 1),
165    date(2027, 5, 6),
166    date(2027, 5, 16),
167    date(2027, 6, 6),
168    date(2027, 6, 26),
169    date(2027, 11, 6),
170    date(2027, 12, 24),
171    date(2027, 12, 25),
172    date(2027, 12, 26),
173    date(2027, 12, 31),
174    date(2028, 1, 1),
175    date(2028, 1, 6),
176    date(2028, 4, 14),
177    date(2028, 4, 16),
178    date(2028, 4, 17),
179    date(2028, 5, 1),
180    date(2028, 5, 25),
181    date(2028, 6, 4),
182    date(2028, 6, 6),
183    date(2028, 6, 24),
184    date(2028, 11, 4),
185    date(2028, 12, 24),
186    date(2028, 12, 25),
187    date(2028, 12, 26),
188    date(2028, 12, 31),
189];