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 kwh_tax_total(&self, today: NaiveDate) -> Money {
42 self.current_taxes(today)
43 .into_iter()
44 .filter(|tax| tax.is_kwh_based())
45 .map(|tax| tax.amount())
46 .sum()
47 }
48
49 pub fn current_tax_reductions(&self, today: NaiveDate) -> Vec<TaxReduction> {
50 self.tax_reductions()
51 .iter()
52 .filter(|tax| tax.valid_for(today))
53 .copied()
54 .collect()
55 }
56
57 pub fn kwh_tax_reduction_total(&self, today: NaiveDate) -> Money {
59 self.current_tax_reductions(today)
60 .into_iter()
61 .filter(|tr| tr.is_kwh_based())
62 .map(|tr| tr.amount())
63 .sum()
64 }
65
66 pub(crate) const fn vat_rate(&self) -> f64 {
67 match self {
68 Country::SE => 1.25,
69 }
70 }
71
72 pub(crate) const fn add_vat(&self, value: f64) -> f64 {
73 value * self.vat_rate()
74 }
75
76 pub(crate) fn is_holiday(&self, date_naive: NaiveDate) -> bool {
77 SE_HOLIDAYS.contains(&date_naive)
78 }
79}
80
81impl Country {
82 pub fn code(&self) -> &'static str {
83 match self {
84 Country::SE => "SE",
85 }
86 }
87
88 pub fn english_name(&self) -> &'static str {
89 match self {
90 Country::SE => "Sweden",
91 }
92 }
93}
94
95impl FromStr for Country {
96 type Err = &'static str;
97
98 fn from_str(s: &str) -> Result<Self, Self::Err> {
99 match s.to_ascii_uppercase().as_ref() {
100 "SE" => Ok(Country::SE),
101 _ => Err("no such country"),
102 }
103 }
104}
105
106impl fmt::Display for Country {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 f.write_str(match self {
109 Country::SE => "SE",
110 })
111 }
112}
113
114#[derive(Debug, Serialize)]
115pub struct CountryInfo {
116 country: Country,
117 taxes: Vec<Tax>,
119 tax_reductions: Vec<TaxReduction>,
121}
122
123impl CountryInfo {
124 pub fn current(country: Country) -> Self {
125 let today = Utc::now().date_naive();
126 Self {
127 country,
128 taxes: country.current_taxes(today),
129 tax_reductions: country.current_tax_reductions(today),
130 }
131 }
132}
133
134impl From<Country> for CountryInfo {
135 fn from(country: Country) -> Self {
136 let taxes = country.taxes().to_vec();
137 let tax_reductions = country.tax_reductions().to_vec();
138 Self {
139 country,
140 taxes,
141 tax_reductions,
142 }
143 }
144}
145
146static SE_HOLIDAYS: &[NaiveDate] = &[
147 date(2025, 1, 1),
148 date(2025, 1, 6),
149 date(2025, 4, 18),
150 date(2025, 4, 20),
151 date(2025, 4, 21),
152 date(2025, 5, 1),
153 date(2025, 5, 29),
154 date(2025, 6, 6),
155 date(2025, 6, 8),
156 date(2025, 6, 21),
157 date(2025, 11, 1),
158 date(2025, 12, 24),
159 date(2025, 12, 25),
160 date(2025, 12, 26),
161 date(2025, 12, 31),
162 date(2026, 1, 1),
163 date(2026, 1, 6),
164 date(2026, 4, 3),
165 date(2026, 4, 5),
166 date(2026, 4, 6),
167 date(2026, 5, 1),
168 date(2026, 5, 14),
169 date(2026, 5, 24),
170 date(2026, 6, 6),
171 date(2026, 6, 20),
172 date(2026, 10, 31),
173 date(2026, 12, 24),
174 date(2026, 12, 25),
175 date(2026, 12, 26),
176 date(2026, 12, 31),
177 date(2027, 1, 1),
178 date(2027, 1, 6),
179 date(2027, 3, 26),
180 date(2027, 3, 28),
181 date(2027, 3, 29),
182 date(2027, 5, 1),
183 date(2027, 5, 6),
184 date(2027, 5, 16),
185 date(2027, 6, 6),
186 date(2027, 6, 26),
187 date(2027, 11, 6),
188 date(2027, 12, 24),
189 date(2027, 12, 25),
190 date(2027, 12, 26),
191 date(2027, 12, 31),
192 date(2028, 1, 1),
193 date(2028, 1, 6),
194 date(2028, 4, 14),
195 date(2028, 4, 16),
196 date(2028, 4, 17),
197 date(2028, 5, 1),
198 date(2028, 5, 25),
199 date(2028, 6, 4),
200 date(2028, 6, 6),
201 date(2028, 6, 24),
202 date(2028, 11, 4),
203 date(2028, 12, 24),
204 date(2028, 12, 25),
205 date(2028, 12, 26),
206 date(2028, 12, 31),
207];