grid_tariffs/
tax_reductions.rs1use chrono::{Local, NaiveDate};
2use serde::Serialize;
3
4use crate::{Money, minivec::MiniVec};
5
6#[derive(Debug, Clone, Copy, Serialize)]
7#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
8pub enum TaxReductionAppliedBy {
9 KwhFeedIn,
10}
11
12type TaxReductionsInner = MiniVec<&'static TaxReduction, 2>;
14
15pub(crate) struct TaxReductionsBuilder {
16 t: TaxReductionsInner,
17}
18
19impl TaxReductionsBuilder {
20 pub(crate) const fn new() -> Self {
21 Self {
22 t: TaxReductionsInner::new(),
23 }
24 }
25
26 pub(crate) const fn add(mut self, t: &'static TaxReduction) -> Self {
27 self.t.push(t);
28 self
29 }
30
31 pub(crate) const fn build(self) -> TaxReductions {
32 TaxReductions(self.t)
33 }
34}
35
36#[derive(Debug, Clone, Copy, Serialize)]
37#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
38pub struct TaxReductions(TaxReductionsInner);
39
40impl TaxReductions {
41 pub fn for_date(&self, today: NaiveDate) -> Vec<TaxReduction> {
43 self.0
44 .iter()
45 .filter(|tr| tr.valid_for(today))
46 .copied()
47 .collect()
48 }
49
50 pub fn kwh_total(&self, today: NaiveDate) -> Money {
52 self.for_date(today)
53 .into_iter()
54 .filter(|tr| tr.is_kwh_based())
55 .map(|tr| tr.amount())
56 .sum()
57 }
58
59 pub fn with_current_only(mut self) -> TaxReductions {
60 let today = Local::now().date_naive();
61 self.0 = self.0.iter().filter(|tr| tr.valid_for(today)).collect();
62 self
63 }
64}
65
66#[derive(Debug, Clone, Copy, Serialize)]
67#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
68pub struct TaxReduction {
69 description: &'static str,
70 amount: Money,
71 applied_by: TaxReductionAppliedBy,
72 from_date: NaiveDate,
73 to_date: Option<NaiveDate>,
75}
76
77impl TaxReduction {
78 pub(crate) const fn new(
79 description: &'static str,
80 amount: Money,
81 applied_by: TaxReductionAppliedBy,
82 from_date: NaiveDate,
83 to_date: Option<NaiveDate>,
84 ) -> Self {
85 Self {
86 description,
87 amount,
88 applied_by,
89 from_date,
90 to_date,
91 }
92 }
93
94 pub fn amount(&self) -> Money {
95 self.amount
96 }
97
98 pub(crate) fn valid_for(&self, today: NaiveDate) -> bool {
99 today >= self.from_date && self.to_date.is_none_or(|to_date| today <= to_date)
100 }
101
102 pub(crate) fn is_kwh_based(&self) -> bool {
103 matches!(self.applied_by, TaxReductionAppliedBy::KwhFeedIn)
104 }
105}