use crate::version::EegGesetz;
use rust_decimal::Decimal;
use time::Date;
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(tag = "scheme", rename_all = "SCREAMING_SNAKE_CASE")
)]
pub enum SettlementScheme {
FeedInTariff {
verguetungssatz_ct: Decimal,
},
TemporaryFeedInTariff {
verguetungssatz_ct: Decimal,
},
MarketPremium {
direktverm_aw_ct: Decimal,
managementpraemie_ct: Option<Decimal>,
wind_korrekturfaktor: Option<Decimal>,
wind_standort: Option<crate::wind::WindStandort>,
},
TenantElectricity {
verguetungssatz_ct: Decimal,
mieter_zuschlag_ct: Option<Decimal>,
},
PostEeg {
price_floor: Option<Decimal>,
},
KwkSurcharge {
verguetungssatz_ct: Decimal,
kwh_paid_gesamt: Option<Decimal>,
max_kwh: Option<Decimal>,
},
FlexibilityPremium {
verguetungssatz_ct: Decimal,
flex_praemie_ct_kwh: Option<Decimal>,
},
FlexibilitySurcharge {
rate_eur_per_kw_year: Decimal,
},
Eigenverbrauch,
SonstigeDirektvermarktung,
}
impl Default for SettlementScheme {
fn default() -> Self {
Self::FeedInTariff {
verguetungssatz_ct: Decimal::ZERO,
}
}
}
impl SettlementScheme {
#[must_use]
pub fn requires_marktwert(&self) -> bool {
matches!(self, Self::MarketPremium { .. } | Self::PostEeg { .. })
}
#[must_use]
pub fn is_kwh_based(&self) -> bool {
!matches!(
self,
Self::FlexibilitySurcharge { .. }
| Self::Eigenverbrauch
| Self::SonstigeDirektvermarktung
)
}
#[must_use]
pub fn negativpreis_rule_applicable(&self) -> bool {
matches!(
self,
Self::FeedInTariff { .. }
| Self::TenantElectricity { .. }
| Self::TemporaryFeedInTariff { .. }
| Self::FlexibilityPremium { .. }
)
}
#[must_use]
pub fn sect53b_applicable(&self) -> bool {
matches!(
self,
Self::FeedInTariff { .. }
| Self::TenantElectricity { .. }
| Self::FlexibilityPremium { .. }
)
}
#[must_use]
pub fn verguetungssatz_ct(&self) -> Option<Decimal> {
match self {
Self::FeedInTariff { verguetungssatz_ct }
| Self::TemporaryFeedInTariff { verguetungssatz_ct }
| Self::TenantElectricity {
verguetungssatz_ct, ..
}
| Self::KwkSurcharge {
verguetungssatz_ct, ..
}
| Self::FlexibilityPremium {
verguetungssatz_ct, ..
} => Some(*verguetungssatz_ct),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(rename_all = "SCREAMING_SNAKE_CASE", tag = "source")
)]
pub enum TariffSource {
Statutory,
Auction(AusschreibungMetadata),
Transitional(Paragraph100Rule),
}
#[allow(clippy::derivable_impls)]
impl Default for TariffSource {
fn default() -> Self {
Self::Statutory
}
}
impl TariffSource {
#[must_use]
pub fn is_auction(&self) -> bool {
matches!(self, Self::Auction(_))
}
#[must_use]
pub fn is_transitional(&self) -> bool {
matches!(self, Self::Transitional(_))
}
#[must_use]
pub fn is_biogas_sect51b(&self) -> bool {
matches!(self, Self::Auction(m) if m.is_biogas_sect51b)
}
}
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AusschreibungMetadata {
pub zuschlag_id: Option<String>,
pub award_ct: Option<Decimal>,
pub award_date: Option<Date>,
pub award_expired: bool,
pub innovation_auction: bool,
pub is_buergerenergie: bool,
pub is_biogas_sect51b: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
pub enum Paragraph100Rule {
OldPlantBeforeEeg2023,
Eeg2017Negativpreis6h,
BiomassTransition,
SolarpaketITransition,
Pre2016Bestandsschutz,
KwkgTransition,
BiomassOldFuelClassContinuation,
HydropowerEcologicalModernization,
SmallBiomassBelow150kw,
AuctionPoenalTransition,
MieterstromToGgvTransition,
Eeg2012DegressionSchedule,
}
impl Paragraph100Rule {
#[must_use]
pub fn implied_eeg_gesetz(self) -> Option<EegGesetz> {
match self {
Self::Pre2016Bestandsschutz => Some(EegGesetz::Eeg2012),
Self::Eeg2017Negativpreis6h
| Self::BiomassOldFuelClassContinuation
| Self::SmallBiomassBelow150kw => Some(EegGesetz::Eeg2017),
Self::OldPlantBeforeEeg2023 => Some(EegGesetz::Eeg2021),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
pub enum SettlementType {
Initial,
Correction {
original_id: String,
reason: CorrectionReason,
},
Reversal {
original_id: String,
},
}
#[allow(clippy::derivable_impls)]
impl Default for SettlementType {
fn default() -> Self {
Self::Initial
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
pub enum CorrectionReason {
MeterDataCorrected,
TariffCorrected,
MastrRegistrationConfirmed,
CapacityCorrected,
RegulatoryReprocessing,
FoerderendedatumCorrected,
Other,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "SCREAMING_SNAKE_CASE"))]
pub enum MarktpreisKategorie {
Solar,
WindOnshore,
WindOffshore,
Biomasse,
Wasserkraft,
Sonstige,
EpexDayAhead,
}