bo4e_core/com/
tariff_price_position.rs

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