use rust_decimal::Decimal;
use rust_decimal::dec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Letztverbrauchergruppe {
#[default]
A,
B,
C,
Befreit,
}
pub const ERSTES_ERFASSTES_JAHR: i32 = 2026;
pub const ENFG_SCHWELLE_KWH: Decimal = dec!(1_000_000);
const SECT19_STROMNEV: &[(i32, Decimal, Decimal, Decimal)] = &[
(2026, dec!(1.559), dec!(0.050), dec!(0.025)),
];
const OFFSHORE_NETZUMLAGE: &[(i32, Decimal)] = &[(2026, dec!(0.941))];
const KWKG_UMLAGE: &[(i32, Decimal)] = &[(2026, dec!(0.446))];
#[must_use]
pub fn sect19_stromnev_ct_per_kwh(year: i32, gruppe: Letztverbrauchergruppe) -> Option<Decimal> {
if gruppe == Letztverbrauchergruppe::Befreit {
return Some(Decimal::ZERO);
}
SECT19_STROMNEV
.iter()
.find(|(y, ..)| *y == year)
.map(|(_, a, b, c)| match gruppe {
Letztverbrauchergruppe::A => *a,
Letztverbrauchergruppe::B => *b,
Letztverbrauchergruppe::C => *c,
Letztverbrauchergruppe::Befreit => Decimal::ZERO,
})
}
#[must_use]
pub fn offshore_netzumlage_ct_per_kwh(
year: i32,
gruppe: Letztverbrauchergruppe,
) -> Option<Decimal> {
if gruppe == Letztverbrauchergruppe::Befreit {
return Some(Decimal::ZERO);
}
OFFSHORE_NETZUMLAGE
.iter()
.find(|(y, _)| *y == year)
.map(|(_, r)| *r)
}
#[must_use]
pub fn kwkg_umlage_ct_per_kwh(year: i32, gruppe: Letztverbrauchergruppe) -> Option<Decimal> {
if gruppe == Letztverbrauchergruppe::Befreit {
return Some(Decimal::ZERO);
}
KWKG_UMLAGE
.iter()
.find(|(y, _)| *y == year)
.map(|(_, r)| *r)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn published_2026_rates() {
use Letztverbrauchergruppe as G;
assert_eq!(sect19_stromnev_ct_per_kwh(2026, G::A), Some(dec!(1.559)));
assert_eq!(sect19_stromnev_ct_per_kwh(2026, G::B), Some(dec!(0.050)));
assert_eq!(sect19_stromnev_ct_per_kwh(2026, G::C), Some(dec!(0.025)));
assert_eq!(
offshore_netzumlage_ct_per_kwh(2026, G::A),
Some(dec!(0.941))
);
assert_eq!(kwkg_umlage_ct_per_kwh(2026, G::A), Some(dec!(0.446)));
}
#[test]
fn exemption_is_zero_not_missing() {
use Letztverbrauchergruppe::Befreit;
for year in [2020, 2026, 2099] {
assert_eq!(
sect19_stromnev_ct_per_kwh(year, Befreit),
Some(Decimal::ZERO)
);
assert_eq!(
offshore_netzumlage_ct_per_kwh(year, Befreit),
Some(Decimal::ZERO)
);
assert_eq!(kwkg_umlage_ct_per_kwh(year, Befreit), Some(Decimal::ZERO));
}
}
#[test]
fn an_uncovered_year_has_no_rate() {
use Letztverbrauchergruppe as G;
assert_eq!(sect19_stromnev_ct_per_kwh(2025, G::A), None);
assert_eq!(offshore_netzumlage_ct_per_kwh(2027, G::A), None);
assert_eq!(kwkg_umlage_ct_per_kwh(1999, G::A), None);
}
#[test]
fn privileged_bands_are_lower_than_the_full_rate() {
use Letztverbrauchergruppe as G;
let a = sect19_stromnev_ct_per_kwh(2026, G::A).unwrap();
let b = sect19_stromnev_ct_per_kwh(2026, G::B).unwrap();
let c = sect19_stromnev_ct_per_kwh(2026, G::C).unwrap();
assert!(b < a, "B′ must be below A′");
assert!(c < b, "C′ must be below B′");
}
}