use rust_decimal::Decimal;
use rust_decimal::dec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub enum MessstellenKategorie {
Pflichteinbau(PflichtBand),
OptionalerEinbau,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
pub enum PflichtBand {
Bis10000,
Bis20000,
Bis50000,
Bis100000,
Ueber100000,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub enum Entgeltschuldner {
Netzbetreiber,
Letztverbraucher,
}
#[must_use]
pub fn preisobergrenze_eur_per_jahr(
kategorie: MessstellenKategorie,
schuldner: Entgeltschuldner,
) -> Option<Decimal> {
use Entgeltschuldner as E;
use MessstellenKategorie as K;
use PflichtBand as B;
match (kategorie, schuldner) {
(K::Pflichteinbau(_), E::Netzbetreiber) => Some(dec!(80)),
(K::Pflichteinbau(B::Bis10000), E::Letztverbraucher) => Some(dec!(40)),
(K::Pflichteinbau(B::Bis20000), E::Letztverbraucher) => Some(dec!(50)),
(K::Pflichteinbau(B::Bis50000), E::Letztverbraucher) => Some(dec!(110)),
(K::Pflichteinbau(B::Bis100000), E::Letztverbraucher) => Some(dec!(140)),
(K::Pflichteinbau(B::Ueber100000), E::Letztverbraucher) => None,
(K::OptionalerEinbau, _) => Some(dec!(30)),
}
}
#[must_use]
pub fn gesamtobergrenze_eur_per_jahr(kategorie: MessstellenKategorie) -> Option<Decimal> {
let nb = preisobergrenze_eur_per_jahr(kategorie, Entgeltschuldner::Netzbetreiber)?;
let lv = preisobergrenze_eur_per_jahr(kategorie, Entgeltschuldner::Letztverbraucher)?;
Some(nb + lv)
}
pub const STEUEREINRICHTUNG_OBERGRENZE_EUR_PER_JAHR: Decimal = dec!(50);
#[cfg(test)]
mod tests {
use super::*;
use Entgeltschuldner as E;
use MessstellenKategorie as K;
use PflichtBand as B;
#[test]
fn the_pflichteinbau_schedule() {
for (band, lv, total) in [
(B::Bis10000, dec!(40), dec!(120)),
(B::Bis20000, dec!(50), dec!(130)),
(B::Bis50000, dec!(110), dec!(190)),
(B::Bis100000, dec!(140), dec!(220)),
] {
let k = K::Pflichteinbau(band);
assert_eq!(
preisobergrenze_eur_per_jahr(k, E::Netzbetreiber),
Some(dec!(80))
);
assert_eq!(
preisobergrenze_eur_per_jahr(k, E::Letztverbraucher),
Some(lv)
);
assert_eq!(gesamtobergrenze_eur_per_jahr(k), Some(total));
}
}
#[test]
fn the_top_band_caps_only_the_grid_operators_share() {
let k = K::Pflichteinbau(B::Ueber100000);
assert_eq!(
preisobergrenze_eur_per_jahr(k, E::Netzbetreiber),
Some(dec!(80))
);
assert_eq!(preisobergrenze_eur_per_jahr(k, E::Letztverbraucher), None);
assert_eq!(
gesamtobergrenze_eur_per_jahr(k),
None,
"no total where one share is open"
);
}
#[test]
fn an_optional_installation_is_capped_at_thirty_each() {
for schuldner in [E::Netzbetreiber, E::Letztverbraucher] {
assert_eq!(
preisobergrenze_eur_per_jahr(K::OptionalerEinbau, schuldner),
Some(dec!(30))
);
}
assert_eq!(
gesamtobergrenze_eur_per_jahr(K::OptionalerEinbau),
Some(dec!(60))
);
}
#[test]
fn the_bands_rise_monotonically() {
let bands = [B::Bis10000, B::Bis20000, B::Bis50000, B::Bis100000];
let mut previous = Decimal::ZERO;
for band in bands {
let ceiling = preisobergrenze_eur_per_jahr(K::Pflichteinbau(band), E::Letztverbraucher)
.expect("a fixed ceiling");
assert!(ceiling > previous, "{band:?} must exceed the band below it");
previous = ceiling;
}
}
}