grid_tariffs/
fees.rs

1use serde::Serialize;
2
3use crate::{
4    Cost, Money,
5    costs::{CostPeriods, CostPeriodsSimple},
6};
7
8#[derive(Debug, Clone, Copy, Serialize)]
9#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
10#[serde(tag = "type", content = "value")]
11pub enum TransferFee {
12    /// Price was not listed on their website
13    Unlisted,
14    /// Transfer fee has not been verified by us
15    Unverified,
16    /// Fee does not change except possibly by fuse size
17    Simple(Cost),
18    /// Transfer fee that varies by the current spot price
19    /// We have currently only observed that Växjö Energi uses this variant
20    SpotPriceVariable {
21        base_cost: Money,
22        spot_price_multiplier: f64,
23        approximated: bool,
24    },
25    Periods {
26        #[serde(flatten)]
27        periods: CostPeriods,
28    },
29}
30
31impl TransferFee {
32    pub const fn is_unverified(&self) -> bool {
33        matches!(self, Self::Unverified)
34    }
35
36    pub const fn simple_cost(&self) -> Option<Cost> {
37        match self {
38            Self::Simple(cost) => Some(*cost),
39            _ => None,
40        }
41    }
42
43    pub fn simplified(&self, fuse_size: u16, yearly_consumption: u32) -> TransferFeeSimplified {
44        TransferFeeSimplified::new(self, fuse_size, yearly_consumption)
45    }
46
47    pub(super) const fn new_periods(periods: CostPeriods) -> Self {
48        Self::Periods { periods }
49    }
50
51    pub(super) const fn fixed(int: i64, fract: u8) -> Self {
52        Self::Simple(Cost::fixed(int, fract))
53    }
54
55    pub(super) const fn fixed_subunit(subunit: f64) -> Self {
56        Self::Simple(Cost::fixed_subunit(subunit))
57    }
58
59    pub(super) fn is_yearly_consumption_based(&self, fuse_size: u16) -> bool {
60        match self {
61            TransferFee::Unlisted
62            | TransferFee::Unverified
63            | TransferFee::SpotPriceVariable { .. } => false,
64            TransferFee::Simple(cost) => cost.is_yearly_consumption_based(fuse_size),
65            TransferFee::Periods { periods } => periods.is_yearly_consumption_based(fuse_size),
66        }
67    }
68}
69
70/// Like TransferFee, but with costs being simple Money objects
71#[derive(Debug, Clone, Serialize)]
72#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
73#[serde(tag = "type", content = "value")]
74pub enum TransferFeeSimplified {
75    /// Price was not listed on their website
76    Unlisted,
77    /// Transfer fee has not been verified by us
78    Unverified,
79    /// Fee does not change except possibly by fuse size
80    Simple(Option<Money>),
81    /// Transfer fee that varies by the current spot price
82    /// We have currently only observed that Växjö Energi uses this variant
83    SpotPriceVariable {
84        base_cost: Money,
85        spot_price_multiplier: f64,
86        approximated: bool,
87    },
88    Periods {
89        #[serde(flatten)]
90        periods: CostPeriodsSimple,
91    },
92}
93
94impl TransferFeeSimplified {
95    fn new(fee: &TransferFee, fuse_size: u16, yearly_consumption: u32) -> Self {
96        match *fee {
97            TransferFee::Unlisted => TransferFeeSimplified::Unlisted,
98            TransferFee::Unverified => TransferFeeSimplified::Unverified,
99            TransferFee::Simple(cost) => {
100                TransferFeeSimplified::Simple(cost.cost_for(fuse_size, yearly_consumption))
101            }
102            TransferFee::SpotPriceVariable {
103                base_cost,
104                spot_price_multiplier,
105                approximated,
106            } => TransferFeeSimplified::SpotPriceVariable {
107                base_cost,
108                spot_price_multiplier,
109                approximated,
110            },
111            TransferFee::Periods { periods } => TransferFeeSimplified::Periods {
112                periods: CostPeriodsSimple::new(periods, fuse_size, yearly_consumption),
113            },
114        }
115    }
116}