bo4e_core/bo/
service_price_sheet.rs

1//! Service price sheet (PreisblattDienstleistung) business object.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::com::{ServicePrice, TimePeriod};
7use crate::enums::{Division, ServiceType};
8use crate::traits::{Bo4eMeta, Bo4eObject};
9
10/// A price sheet for services (e.g., metering, billing).
11///
12/// German: PreisblattDienstleistung
13///
14/// # Example
15///
16/// ```rust
17/// use bo4e_core::bo::ServicePriceSheet;
18/// use bo4e_core::enums::{Division, ServiceType};
19///
20/// let price_sheet = ServicePriceSheet {
21///     designation: Some("Dienstleistungspreisblatt 2024".to_string()),
22///     division: Some(Division::Electricity),
23///     service_type: Some(ServiceType::RemoteReading),
24///     ..Default::default()
25/// };
26/// ```
27#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
28#[serde(rename_all = "camelCase")]
29pub struct ServicePriceSheet {
30    /// BO4E metadata
31    #[serde(flatten)]
32    pub meta: Bo4eMeta,
33
34    /// Name/designation of the price sheet (Bezeichnung)
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub designation: Option<String>,
37
38    /// Description (Beschreibung)
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub description: Option<String>,
41
42    /// Energy division (Sparte)
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub division: Option<Division>,
45
46    /// Type of service (Dienstleistungsart)
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub service_type: Option<ServiceType>,
49
50    /// Price sheet number/identifier (Preisblattnummer)
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub price_sheet_number: Option<String>,
53
54    /// Validity period (Gueltigkeitszeitraum)
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub validity_period: Option<TimePeriod>,
57
58    /// Valid from date (Gueltig ab)
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub valid_from: Option<DateTime<Utc>>,
61
62    /// Valid until date (Gueltig bis)
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub valid_until: Option<DateTime<Utc>>,
65
66    /// Service prices (Dienstleistungspreise)
67    #[serde(default, skip_serializing_if = "Vec::is_empty")]
68    pub prices: Vec<ServicePrice>,
69
70    /// Service provider
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub provider: Option<Box<super::BusinessPartner>>,
73}
74
75impl Bo4eObject for ServicePriceSheet {
76    fn type_name_german() -> &'static str {
77        "PreisblattDienstleistung"
78    }
79
80    fn type_name_english() -> &'static str {
81        "ServicePriceSheet"
82    }
83
84    fn meta(&self) -> &Bo4eMeta {
85        &self.meta
86    }
87
88    fn meta_mut(&mut self) -> &mut Bo4eMeta {
89        &mut self.meta
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_service_price_sheet_creation() {
99        let price_sheet = ServicePriceSheet {
100            designation: Some("Dienstleistungspreisblatt 2024".to_string()),
101            division: Some(Division::Electricity),
102            service_type: Some(ServiceType::RemoteReading),
103            price_sheet_number: Some("DL-2024-001".to_string()),
104            ..Default::default()
105        };
106
107        assert_eq!(price_sheet.service_type, Some(ServiceType::RemoteReading));
108    }
109
110    #[test]
111    fn test_serialize() {
112        let price_sheet = ServicePriceSheet {
113            meta: Bo4eMeta::with_type("PreisblattDienstleistung"),
114            designation: Some("Service Prices".to_string()),
115            ..Default::default()
116        };
117
118        let json = serde_json::to_string(&price_sheet).unwrap();
119        assert!(json.contains(r#""designation":"Service Prices""#));
120        assert!(json.contains(r#""_typ":"PreisblattDienstleistung""#));
121    }
122
123    #[test]
124    fn test_roundtrip() {
125        let price_sheet = ServicePriceSheet {
126            meta: Bo4eMeta::with_type("PreisblattDienstleistung"),
127            designation: Some("Billing Services".to_string()),
128            description: Some("Standard billing service prices".to_string()),
129            division: Some(Division::Electricity),
130            price_sheet_number: Some("BS-2024".to_string()),
131            ..Default::default()
132        };
133
134        let json = serde_json::to_string(&price_sheet).unwrap();
135        let parsed: ServicePriceSheet = serde_json::from_str(&json).unwrap();
136        assert_eq!(price_sheet, parsed);
137    }
138
139    #[test]
140    fn test_bo4e_object_impl() {
141        assert_eq!(
142            ServicePriceSheet::type_name_german(),
143            "PreisblattDienstleistung"
144        );
145        assert_eq!(ServicePriceSheet::type_name_english(), "ServicePriceSheet");
146    }
147}