Skip to main content

bo4e_core/bo/
location_properties.rs

1//! Location properties (Standorteigenschaften) business object.
2//!
3//! Represents properties and characteristics of a physical location.
4
5use serde::{Deserialize, Serialize};
6
7use crate::com::{Address, GeoCoordinates};
8use crate::traits::{Bo4eMeta, Bo4eObject};
9
10/// Properties of a physical location.
11///
12/// German: Standorteigenschaften
13///
14/// Location properties describe characteristics of a physical
15/// site, such as address, coordinates, and site-specific details.
16///
17/// # Example
18///
19/// ```rust
20/// use bo4e_core::bo::LocationProperties;
21///
22/// let props = LocationProperties {
23///     location_properties_id: Some("LOC001".to_string()),
24///     building_type: Some("Residential".to_string()),
25///     ..Default::default()
26/// };
27/// ```
28#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
29#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
30#[cfg_attr(feature = "json-schema", schemars(rename = "Standorteigenschaften"))]
31#[serde(rename_all = "camelCase")]
32pub struct LocationProperties {
33    /// BO4E metadata
34    #[serde(flatten)]
35    pub meta: Bo4eMeta,
36
37    /// Location properties ID (Standorteigenschaften-ID)
38    #[serde(skip_serializing_if = "Option::is_none")]
39    #[cfg_attr(feature = "json-schema", schemars(rename = "standorteigenschaftenId"))]
40    pub location_properties_id: Option<String>,
41
42    /// Location address (Adresse)
43    #[serde(skip_serializing_if = "Option::is_none")]
44    #[cfg_attr(feature = "json-schema", schemars(rename = "adresse"))]
45    pub address: Option<Address>,
46
47    /// Geographic coordinates (Geokoordinaten)
48    #[serde(skip_serializing_if = "Option::is_none")]
49    #[cfg_attr(feature = "json-schema", schemars(rename = "geokoordinaten"))]
50    pub coordinates: Option<GeoCoordinates>,
51
52    /// Building type (Gebaeudeart)
53    #[serde(skip_serializing_if = "Option::is_none")]
54    #[cfg_attr(feature = "json-schema", schemars(rename = "gebaeudeart"))]
55    pub building_type: Option<String>,
56
57    /// Construction year (Baujahr)
58    #[serde(skip_serializing_if = "Option::is_none")]
59    #[cfg_attr(feature = "json-schema", schemars(rename = "baujahr"))]
60    pub construction_year: Option<i32>,
61
62    /// Floor area in square meters (Flaeche)
63    #[serde(skip_serializing_if = "Option::is_none")]
64    #[cfg_attr(feature = "json-schema", schemars(rename = "flaeche"))]
65    pub floor_area: Option<f64>,
66
67    /// Number of floors (Anzahl Etagen)
68    #[serde(skip_serializing_if = "Option::is_none")]
69    #[cfg_attr(feature = "json-schema", schemars(rename = "anzahlEtagen"))]
70    pub number_of_floors: Option<i32>,
71
72    /// Number of residential units (Anzahl Wohneinheiten)
73    #[serde(skip_serializing_if = "Option::is_none")]
74    #[cfg_attr(feature = "json-schema", schemars(rename = "anzahlWohneinheiten"))]
75    pub number_of_units: Option<i32>,
76
77    /// Heating type (Heizungsart)
78    #[serde(skip_serializing_if = "Option::is_none")]
79    #[cfg_attr(feature = "json-schema", schemars(rename = "heizungsart"))]
80    pub heating_type: Option<String>,
81
82    /// Energy efficiency class (Energieeffizienzklasse)
83    #[serde(skip_serializing_if = "Option::is_none")]
84    #[cfg_attr(feature = "json-schema", schemars(rename = "energieeffizienzklasse"))]
85    pub energy_efficiency_class: Option<String>,
86
87    /// Has solar installation (Hat Solaranlage)
88    #[serde(skip_serializing_if = "Option::is_none")]
89    #[cfg_attr(feature = "json-schema", schemars(rename = "hatSolaranlage"))]
90    pub has_solar: Option<bool>,
91
92    /// Has electric vehicle charging (Hat E-Ladestation)
93    #[serde(skip_serializing_if = "Option::is_none")]
94    #[cfg_attr(feature = "json-schema", schemars(rename = "hatELadestation"))]
95    pub has_ev_charging: Option<bool>,
96
97    /// Has heat pump (Hat Waermepumpe)
98    #[serde(skip_serializing_if = "Option::is_none")]
99    #[cfg_attr(feature = "json-schema", schemars(rename = "hatWaermepumpe"))]
100    pub has_heat_pump: Option<bool>,
101
102    /// Description (Beschreibung)
103    #[serde(skip_serializing_if = "Option::is_none")]
104    #[cfg_attr(feature = "json-schema", schemars(rename = "beschreibung"))]
105    pub description: Option<String>,
106}
107
108impl Bo4eObject for LocationProperties {
109    fn type_name_german() -> &'static str {
110        "Standorteigenschaften"
111    }
112
113    fn type_name_english() -> &'static str {
114        "LocationProperties"
115    }
116
117    fn meta(&self) -> &Bo4eMeta {
118        &self.meta
119    }
120
121    fn meta_mut(&mut self) -> &mut Bo4eMeta {
122        &mut self.meta
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_location_properties_creation() {
132        let props = LocationProperties {
133            location_properties_id: Some("LOC001".to_string()),
134            building_type: Some("Residential".to_string()),
135            ..Default::default()
136        };
137
138        assert_eq!(props.location_properties_id, Some("LOC001".to_string()));
139    }
140
141    #[test]
142    fn test_serialize() {
143        let props = LocationProperties {
144            meta: Bo4eMeta::with_type("Standorteigenschaften"),
145            location_properties_id: Some("LOC001".to_string()),
146            ..Default::default()
147        };
148
149        let json = serde_json::to_string(&props).unwrap();
150        assert!(json.contains(r#""_typ":"Standorteigenschaften""#));
151    }
152
153    #[test]
154    fn test_roundtrip() {
155        let props = LocationProperties {
156            meta: Bo4eMeta::with_type("Standorteigenschaften"),
157            location_properties_id: Some("LOC001".to_string()),
158            building_type: Some("Residential".to_string()),
159            construction_year: Some(2010),
160            floor_area: Some(150.0),
161            number_of_floors: Some(2),
162            has_solar: Some(true),
163            ..Default::default()
164        };
165
166        let json = serde_json::to_string(&props).unwrap();
167        let parsed: LocationProperties = serde_json::from_str(&json).unwrap();
168        assert_eq!(props, parsed);
169    }
170
171    #[test]
172    fn test_bo4e_object_impl() {
173        assert_eq!(
174            LocationProperties::type_name_german(),
175            "Standorteigenschaften"
176        );
177        assert_eq!(
178            LocationProperties::type_name_english(),
179            "LocationProperties"
180        );
181    }
182}