bo4e_core/bo/
location_assignment.rs

1//! Location assignment (Lokationszuordnung) business object.
2//!
3//! Represents the assignment/relationship between different location types.
4
5use serde::{Deserialize, Serialize};
6
7use crate::com::TimePeriod;
8use crate::enums::{ArithmeticOperation, LocationType};
9use crate::traits::{Bo4eMeta, Bo4eObject};
10
11/// An assignment between locations in the energy market.
12///
13/// German: Lokationszuordnung
14///
15/// This business object represents the relationship between different
16/// types of locations (market, metering, network).
17///
18/// # Example
19///
20/// ```rust
21/// use bo4e_core::bo::LocationAssignment;
22///
23/// let assignment = LocationAssignment {
24///     market_location_id: Some("12345678901".to_string()),
25///     metering_location_id: Some("DE00012345678901234567890123456789".to_string()),
26///     ..Default::default()
27/// };
28/// ```
29#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub struct LocationAssignment {
32    /// BO4E metadata
33    #[serde(flatten)]
34    pub meta: Bo4eMeta,
35
36    /// Market location ID (Marktlokations-ID)
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub market_location_id: Option<String>,
39
40    /// Metering location ID (Messlokations-ID)
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub metering_location_id: Option<String>,
43
44    /// Network location ID (Netzlokations-ID)
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub network_location_id: Option<String>,
47
48    /// Technical resource ID (Technische-Ressource-ID)
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub technical_resource_id: Option<String>,
51
52    /// Controllable resource ID (Steuerbare-Ressource-ID)
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub controllable_resource_id: Option<String>,
55
56    /// Location type (Lokationstyp)
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub location_type: Option<LocationType>,
59
60    /// Arithmetic operation for combination (Rechenoperation)
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub arithmetic_operation: Option<ArithmeticOperation>,
63
64    /// Validity period (Gueltigkeitszeitraum)
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub validity_period: Option<TimePeriod>,
67
68    /// Sequence/order number (Reihenfolge)
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub sequence: Option<i32>,
71}
72
73impl Bo4eObject for LocationAssignment {
74    fn type_name_german() -> &'static str {
75        "Lokationszuordnung"
76    }
77
78    fn type_name_english() -> &'static str {
79        "LocationAssignment"
80    }
81
82    fn meta(&self) -> &Bo4eMeta {
83        &self.meta
84    }
85
86    fn meta_mut(&mut self) -> &mut Bo4eMeta {
87        &mut self.meta
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn test_assignment_creation() {
97        let assignment = LocationAssignment {
98            market_location_id: Some("12345678901".to_string()),
99            metering_location_id: Some("DE00012345678901234567890123456789".to_string()),
100            ..Default::default()
101        };
102
103        assert!(assignment.market_location_id.is_some());
104        assert!(assignment.metering_location_id.is_some());
105    }
106
107    #[test]
108    fn test_serialize() {
109        let assignment = LocationAssignment {
110            meta: Bo4eMeta::with_type("Lokationszuordnung"),
111            market_location_id: Some("12345678901".to_string()),
112            ..Default::default()
113        };
114
115        let json = serde_json::to_string(&assignment).unwrap();
116        assert!(json.contains(r#""_typ":"Lokationszuordnung""#));
117    }
118
119    #[test]
120    fn test_roundtrip() {
121        let assignment = LocationAssignment {
122            meta: Bo4eMeta::with_type("Lokationszuordnung"),
123            market_location_id: Some("12345678901".to_string()),
124            metering_location_id: Some("DE00012345678901234567890123456789".to_string()),
125            arithmetic_operation: Some(ArithmeticOperation::Addition),
126            sequence: Some(1),
127            ..Default::default()
128        };
129
130        let json = serde_json::to_string(&assignment).unwrap();
131        let parsed: LocationAssignment = serde_json::from_str(&json).unwrap();
132        assert_eq!(assignment, parsed);
133    }
134
135    #[test]
136    fn test_bo4e_object_impl() {
137        assert_eq!(LocationAssignment::type_name_german(), "Lokationszuordnung");
138        assert_eq!(
139            LocationAssignment::type_name_english(),
140            "LocationAssignment"
141        );
142    }
143}