use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use serde::{Deserialize, Serialize};
use crate::tariff::TariffInput;
const BEHG_EUR_PER_T: &[(i32, u32)] = &[
(2021, 25),
(2022, 30),
(2023, 30),
(2024, 45),
(2025, 55),
(2026, 65),
];
pub const BEHG_CO2_FACTOR_H_GAS: Decimal = dec!(0.20160);
const STROMSTEUER_HISTORY: &[(i32, &str)] = &[
(2003, "2.05"),
(2004, "2.05"),
(2005, "2.05"),
(2006, "2.05"),
(2007, "2.05"),
(2008, "2.05"),
(2009, "2.05"),
(2010, "2.05"),
(2011, "2.05"),
(2012, "2.05"),
(2013, "2.05"),
(2014, "2.05"),
(2015, "2.05"),
(2016, "2.05"),
(2017, "2.05"),
(2018, "2.05"),
(2019, "2.05"),
(2020, "2.05"),
(2021, "2.05"),
(2022, "2.05"),
(2023, "2.05"),
(2024, "2.05"),
(2025, "2.05"),
(2026, "2.05"),
];
#[must_use]
pub fn stromsteuer_for_year(year: i32) -> Option<Decimal> {
STROMSTEUER_HISTORY
.iter()
.find(|(y, _)| *y == year)
.map(|(_, rate)| rate.parse().expect("rate is a valid decimal literal"))
}
const ENERGIESTEUER_GAS_HISTORY: &[(i32, &str)] = &[
(2022, "0.00"),
(2023, "0.55"),
(2024, "0.55"),
(2025, "0.55"),
(2026, "0.55"),
];
#[must_use]
pub fn energiesteuer_gas_for_year(year: i32) -> Option<Decimal> {
ENERGIESTEUER_GAS_HISTORY
.iter()
.find(|(y, _)| *y == year)
.map(|(_, rate)| rate.parse().expect("rate is a valid decimal literal"))
}
#[must_use]
pub fn behg_ct_per_kwh_for_year(year: i32) -> Option<Decimal> {
BEHG_EUR_PER_T
.iter()
.find(|(y, _)| *y == year)
.map(|(_, eur_per_t)| {
Decimal::from(*eur_per_t) * BEHG_CO2_FACTOR_H_GAS / dec!(10)
})
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegulatoryRates {
pub stromsteuer_ct_per_kwh: Decimal,
pub energiesteuer_gas_ct_per_kwh: Decimal,
pub behg_gas_ct_per_kwh: Decimal,
pub mwst_rate: Decimal,
}
impl Default for RegulatoryRates {
fn default() -> Self {
Self {
stromsteuer_ct_per_kwh: dec!(2.05),
energiesteuer_gas_ct_per_kwh: dec!(0.55),
behg_gas_ct_per_kwh: dec!(1.310), mwst_rate: dec!(0.19),
}
}
}
impl RegulatoryRates {
pub fn effective_stromsteuer(&self, tariff: &TariffInput) -> Decimal {
tariff
.stromsteuer_ct_per_kwh_override
.unwrap_or(self.stromsteuer_ct_per_kwh)
}
pub fn effective_energiesteuer_gas(&self, tariff: &TariffInput) -> Decimal {
tariff
.energiesteuer_gas_ct_per_kwh_override
.unwrap_or(self.energiesteuer_gas_ct_per_kwh)
}
pub fn effective_behg_gas(&self, tariff: &TariffInput) -> Decimal {
tariff
.behg_gas_ct_per_kwh_override
.unwrap_or(self.behg_gas_ct_per_kwh)
}
pub fn effective_behg_gas_for_year(&self, tariff: &TariffInput, year: i32) -> Decimal {
if let Some(o) = tariff.behg_gas_ct_per_kwh_override {
return o;
}
behg_ct_per_kwh_for_year(year).unwrap_or(self.behg_gas_ct_per_kwh)
}
pub fn effective_stromsteuer_for_year(&self, tariff: &TariffInput, year: i32) -> Decimal {
if let Some(o) = tariff.stromsteuer_ct_per_kwh_override {
return o;
}
stromsteuer_for_year(year).unwrap_or(self.stromsteuer_ct_per_kwh)
}
pub fn effective_energiesteuer_gas_for_year(&self, tariff: &TariffInput, year: i32) -> Decimal {
if let Some(o) = tariff.energiesteuer_gas_ct_per_kwh_override {
return o;
}
energiesteuer_gas_for_year(year).unwrap_or(self.energiesteuer_gas_ct_per_kwh)
}
pub fn effective_mwst(&self, tariff: &TariffInput) -> Decimal {
if let Some(override_rate) = tariff.mwst_rate_override {
return override_rate;
}
if tariff
.anlage_kwp
.is_some_and(|kwp| kwp <= rust_decimal_macros::dec!(30))
{
return Decimal::ZERO;
}
self.mwst_rate
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn behg_year_table_2026_matches_expected() {
let ct = behg_ct_per_kwh_for_year(2026).unwrap();
let expected = dec!(65) * dec!(0.20160) / dec!(10);
assert_eq!(ct, expected);
}
#[test]
fn behg_year_table_2024_matches_expected() {
let ct = behg_ct_per_kwh_for_year(2024).unwrap();
let expected = dec!(45) * dec!(0.20160) / dec!(10);
assert_eq!(ct, expected);
}
#[test]
fn behg_unknown_year_returns_none() {
assert!(behg_ct_per_kwh_for_year(2020).is_none());
assert!(behg_ct_per_kwh_for_year(2030).is_none());
}
#[test]
fn effective_behg_for_year_prefers_override() {
let rates = RegulatoryRates::default();
let tariff = crate::tariff::TariffInput {
behg_gas_ct_per_kwh_override: Some(dec!(0.99)),
..Default::default()
};
assert_eq!(rates.effective_behg_gas_for_year(&tariff, 2024), dec!(0.99));
}
}