Skip to main content

bo4e_core/com/
price_guarantee.rs

1//! Price guarantee (Preisgarantie) component.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::enums::PriceGuaranteeType;
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9/// A price guarantee specifying which price components are fixed.
10///
11/// German: Preisgarantie
12///
13/// # Example
14///
15/// ```rust
16/// use bo4e_core::com::PriceGuarantee;
17/// use bo4e_core::enums::PriceGuaranteeType;
18///
19/// let guarantee = PriceGuarantee {
20///     guarantee_type: Some(PriceGuaranteeType::AllComponentsGross),
21///     description: Some("12-month price guarantee".to_string()),
22///     ..Default::default()
23/// };
24/// ```
25#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
27#[cfg_attr(feature = "json-schema", schemars(rename = "Preisgarantie"))]
28#[serde(rename_all = "camelCase")]
29pub struct PriceGuarantee {
30    /// BO4E metadata
31    #[serde(flatten)]
32    pub meta: Bo4eMeta,
33
34    /// Type of price guarantee (Preisgarantietyp)
35    #[serde(skip_serializing_if = "Option::is_none")]
36    #[cfg_attr(feature = "json-schema", schemars(rename = "preisgarantietyp"))]
37    pub guarantee_type: Option<PriceGuaranteeType>,
38
39    /// Start of validity period (Zeitliche Gültigkeit - Von)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    #[cfg_attr(feature = "json-schema", schemars(rename = "zeitlicheGueltigkeit"))]
42    pub valid_from: Option<DateTime<Utc>>,
43
44    /// End of validity period (Zeitliche Gültigkeit - Bis)
45    #[serde(skip_serializing_if = "Option::is_none")]
46    #[cfg_attr(feature = "json-schema", schemars(rename = "zeitlicheGueltigkeitBis"))]
47    pub valid_until: Option<DateTime<Utc>>,
48
49    /// Description of the guarantee (Beschreibung)
50    #[serde(skip_serializing_if = "Option::is_none")]
51    #[cfg_attr(feature = "json-schema", schemars(rename = "beschreibung"))]
52    pub description: Option<String>,
53}
54
55impl Bo4eObject for PriceGuarantee {
56    fn type_name_german() -> &'static str {
57        "Preisgarantie"
58    }
59
60    fn type_name_english() -> &'static str {
61        "PriceGuarantee"
62    }
63
64    fn meta(&self) -> &Bo4eMeta {
65        &self.meta
66    }
67
68    fn meta_mut(&mut self) -> &mut Bo4eMeta {
69        &mut self.meta
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_complete_price_guarantee() {
79        let guarantee = PriceGuarantee {
80            guarantee_type: Some(PriceGuaranteeType::AllComponentsGross),
81            description: Some("Full price guarantee for 12 months".to_string()),
82            ..Default::default()
83        };
84
85        assert_eq!(
86            guarantee.guarantee_type,
87            Some(PriceGuaranteeType::AllComponentsGross)
88        );
89    }
90
91    #[test]
92    fn test_energy_price_guarantee() {
93        let guarantee = PriceGuarantee {
94            guarantee_type: Some(PriceGuaranteeType::EnergyPriceOnly),
95            description: Some("Energy price guaranteed".to_string()),
96            ..Default::default()
97        };
98
99        assert_eq!(
100            guarantee.guarantee_type,
101            Some(PriceGuaranteeType::EnergyPriceOnly)
102        );
103    }
104
105    #[test]
106    fn test_default() {
107        let guarantee = PriceGuarantee::default();
108        assert!(guarantee.guarantee_type.is_none());
109        assert!(guarantee.valid_from.is_none());
110        assert!(guarantee.valid_until.is_none());
111        assert!(guarantee.description.is_none());
112    }
113
114    #[test]
115    fn test_serialize() {
116        let guarantee = PriceGuarantee {
117            guarantee_type: Some(PriceGuaranteeType::AllComponentsGross),
118            description: Some("Test guarantee".to_string()),
119            ..Default::default()
120        };
121
122        let json = serde_json::to_string(&guarantee).unwrap();
123        assert!(json.contains(r#""guaranteeType":"ALLE_PREISBESTANDTEILE_BRUTTO""#));
124        assert!(json.contains(r#""description":"Test guarantee""#));
125    }
126
127    #[test]
128    fn test_roundtrip() {
129        let guarantee = PriceGuarantee {
130            guarantee_type: Some(PriceGuaranteeType::EnergyPriceOnly),
131            description: Some("Energy price fixed".to_string()),
132            valid_from: Some(
133                DateTime::parse_from_rfc3339("2024-01-01T00:00:00Z")
134                    .unwrap()
135                    .into(),
136            ),
137            valid_until: Some(
138                DateTime::parse_from_rfc3339("2024-12-31T23:59:59Z")
139                    .unwrap()
140                    .into(),
141            ),
142            ..Default::default()
143        };
144
145        let json = serde_json::to_string(&guarantee).unwrap();
146        let parsed: PriceGuarantee = serde_json::from_str(&json).unwrap();
147        assert_eq!(guarantee, parsed);
148    }
149
150    #[test]
151    fn test_bo4e_object_impl() {
152        assert_eq!(PriceGuarantee::type_name_german(), "Preisgarantie");
153        assert_eq!(PriceGuarantee::type_name_english(), "PriceGuarantee");
154    }
155}