bo4e_core/com/
service_price.rs

1//! Service price (Dienstleistungspreis) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::{Currency, ServiceType, Unit};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// A price for a service.
9///
10/// German: Dienstleistungspreis
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::ServicePrice;
16/// use bo4e_core::enums::ServiceType;
17///
18/// let price = ServicePrice {
19///     service_type: Some(ServiceType::Disconnection),
20///     value: Some(75.0),
21///     ..Default::default()
22/// };
23/// ```
24#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct ServicePrice {
27    /// BO4E metadata
28    #[serde(flatten)]
29    pub meta: Bo4eMeta,
30
31    /// Type of service (Dienstleistungstyp)
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub service_type: Option<ServiceType>,
34
35    /// Price value (Wert)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub value: Option<f64>,
38
39    /// Currency (Waehrung)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub currency: Option<Currency>,
42
43    /// Reference unit (Bezugseinheit)
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub reference_unit: Option<Unit>,
46
47    /// Description (Beschreibung)
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub description: Option<String>,
50}
51
52impl Bo4eObject for ServicePrice {
53    fn type_name_german() -> &'static str {
54        "Dienstleistungspreis"
55    }
56
57    fn type_name_english() -> &'static str {
58        "ServicePrice"
59    }
60
61    fn meta(&self) -> &Bo4eMeta {
62        &self.meta
63    }
64
65    fn meta_mut(&mut self) -> &mut Bo4eMeta {
66        &mut self.meta
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_installation_service() {
76        let price = ServicePrice {
77            service_type: Some(ServiceType::Disconnection),
78            value: Some(75.0),
79            currency: Some(Currency::Eur),
80            description: Some("Zählerinstallation".to_string()),
81            ..Default::default()
82        };
83
84        assert_eq!(price.service_type, Some(ServiceType::Disconnection));
85        assert_eq!(price.value, Some(75.0));
86    }
87
88    #[test]
89    fn test_default() {
90        let price = ServicePrice::default();
91        assert!(price.service_type.is_none());
92        assert!(price.value.is_none());
93    }
94
95    #[test]
96    fn test_roundtrip() {
97        let price = ServicePrice {
98            service_type: Some(ServiceType::ManualReadingMonthly),
99            value: Some(50.0),
100            currency: Some(Currency::Eur),
101            reference_unit: Some(Unit::Hour),
102            description: Some("Energieberatung".to_string()),
103            ..Default::default()
104        };
105
106        let json = serde_json::to_string(&price).unwrap();
107        let parsed: ServicePrice = serde_json::from_str(&json).unwrap();
108        assert_eq!(price, parsed);
109    }
110
111    #[test]
112    fn test_bo4e_object_impl() {
113        assert_eq!(ServicePrice::type_name_german(), "Dienstleistungspreis");
114        assert_eq!(ServicePrice::type_name_english(), "ServicePrice");
115    }
116}