bo4e_core/com/
tariff_price.rs

1//! Tariff price (Tarifpreis) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::{Currency, PriceType, Unit};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// A tariff price with its type and value.
9///
10/// German: Tarifpreis
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::TariffPrice;
16/// use bo4e_core::enums::{Currency, PriceType, Unit};
17///
18/// let tariff_price = TariffPrice {
19///     price_type: Some(PriceType::WorkingPriceSingleTariff),
20///     value: Some(0.30),
21///     currency: Some(Currency::Eur),
22///     reference_unit: Some(Unit::KilowattHour),
23///     ..Default::default()
24/// };
25/// ```
26#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[serde(rename_all = "camelCase")]
28pub struct TariffPrice {
29    /// BO4E metadata
30    #[serde(flatten)]
31    pub meta: Bo4eMeta,
32
33    /// Type of tariff price (Preistyp)
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub price_type: Option<PriceType>,
36
37    /// Price value (Wert)
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub value: Option<f64>,
40
41    /// Currency (Waehrung)
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub currency: Option<Currency>,
44
45    /// Reference unit (Bezugseinheit)
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub reference_unit: Option<Unit>,
48
49    /// Description (Beschreibung)
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub description: Option<String>,
52}
53
54impl Bo4eObject for TariffPrice {
55    fn type_name_german() -> &'static str {
56        "Tarifpreis"
57    }
58
59    fn type_name_english() -> &'static str {
60        "TariffPrice"
61    }
62
63    fn meta(&self) -> &Bo4eMeta {
64        &self.meta
65    }
66
67    fn meta_mut(&mut self) -> &mut Bo4eMeta {
68        &mut self.meta
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_work_price() {
78        let price = TariffPrice {
79            price_type: Some(PriceType::WorkingPriceSingleTariff),
80            value: Some(30.5),
81            currency: Some(Currency::Eur),
82            reference_unit: Some(Unit::KilowattHour),
83            ..Default::default()
84        };
85
86        assert_eq!(price.price_type, Some(PriceType::WorkingPriceSingleTariff));
87        assert_eq!(price.value, Some(30.5));
88    }
89
90    #[test]
91    fn test_base_price() {
92        let price = TariffPrice {
93            price_type: Some(PriceType::BasePrice),
94            value: Some(12.50),
95            currency: Some(Currency::Eur),
96            reference_unit: Some(Unit::Month),
97            description: Some("Monthly base fee".to_string()),
98            ..Default::default()
99        };
100
101        assert_eq!(price.price_type, Some(PriceType::BasePrice));
102    }
103
104    #[test]
105    fn test_default() {
106        let price = TariffPrice::default();
107        assert!(price.price_type.is_none());
108        assert!(price.value.is_none());
109    }
110
111    #[test]
112    fn test_roundtrip() {
113        let price = TariffPrice {
114            price_type: Some(PriceType::WorkingPriceSingleTariff),
115            value: Some(25.75),
116            currency: Some(Currency::Eur),
117            reference_unit: Some(Unit::KilowattHour),
118            description: Some("Peak rate".to_string()),
119            ..Default::default()
120        };
121
122        let json = serde_json::to_string(&price).unwrap();
123        let parsed: TariffPrice = serde_json::from_str(&json).unwrap();
124        assert_eq!(price, parsed);
125    }
126
127    #[test]
128    fn test_bo4e_object_impl() {
129        assert_eq!(TariffPrice::type_name_german(), "Tarifpreis");
130        assert_eq!(TariffPrice::type_name_english(), "TariffPrice");
131    }
132}