bo4e_core/bo/
external_costs.rs1use serde::{Deserialize, Serialize};
4
5use crate::com::{Amount, ExternalCostBlock, TimePeriod};
6use crate::enums::Division;
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct ExternalCosts {
33 #[serde(flatten)]
35 pub meta: Bo4eMeta,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub designation: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub description: Option<String>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub division: Option<Division>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub period: Option<TimePeriod>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub total_amount: Option<Amount>,
56
57 #[serde(default, skip_serializing_if = "Vec::is_empty")]
59 pub cost_blocks: Vec<ExternalCostBlock>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub external_party: Option<Box<super::BusinessPartner>>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub market_location: Option<Box<super::MarketLocation>>,
68}
69
70impl Bo4eObject for ExternalCosts {
71 fn type_name_german() -> &'static str {
72 "Fremdkosten"
73 }
74
75 fn type_name_english() -> &'static str {
76 "ExternalCosts"
77 }
78
79 fn meta(&self) -> &Bo4eMeta {
80 &self.meta
81 }
82
83 fn meta_mut(&mut self) -> &mut Bo4eMeta {
84 &mut self.meta
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::com::ExternalCostBlock;
92
93 #[test]
94 fn test_external_costs_creation() {
95 let external_costs = ExternalCosts {
96 designation: Some("Netzkosten 2024".to_string()),
97 division: Some(Division::Electricity),
98 total_amount: Some(Amount::eur(350.00)),
99 ..Default::default()
100 };
101
102 assert_eq!(external_costs.total_amount, Some(Amount::eur(350.00)));
103 }
104
105 #[test]
106 fn test_external_costs_with_blocks() {
107 let external_costs = ExternalCosts {
108 designation: Some("Network Costs".to_string()),
109 cost_blocks: vec![
110 ExternalCostBlock {
111 designation: Some("Network usage".to_string()),
112 total_amount: Some(Amount::eur(200.0)),
113 ..Default::default()
114 },
115 ExternalCostBlock {
116 designation: Some("Metering".to_string()),
117 total_amount: Some(Amount::eur(50.0)),
118 ..Default::default()
119 },
120 ],
121 total_amount: Some(Amount::eur(250.0)),
122 ..Default::default()
123 };
124
125 assert_eq!(external_costs.cost_blocks.len(), 2);
126 }
127
128 #[test]
129 fn test_serialize() {
130 let external_costs = ExternalCosts {
131 meta: Bo4eMeta::with_type("Fremdkosten"),
132 designation: Some("Test External Costs".to_string()),
133 total_amount: Some(Amount::eur(100.0)),
134 ..Default::default()
135 };
136
137 let json = serde_json::to_string(&external_costs).unwrap();
138 assert!(json.contains(r#""designation":"Test External Costs""#));
139 assert!(json.contains(r#""_typ":"Fremdkosten""#));
140 }
141
142 #[test]
143 fn test_roundtrip() {
144 let external_costs = ExternalCosts {
145 meta: Bo4eMeta::with_type("Fremdkosten"),
146 designation: Some("Gas Network Costs".to_string()),
147 description: Some("External gas network costs".to_string()),
148 division: Some(Division::Gas),
149 total_amount: Some(Amount::eur(180.0)),
150 ..Default::default()
151 };
152
153 let json = serde_json::to_string(&external_costs).unwrap();
154 let parsed: ExternalCosts = serde_json::from_str(&json).unwrap();
155 assert_eq!(external_costs, parsed);
156 }
157
158 #[test]
159 fn test_bo4e_object_impl() {
160 assert_eq!(ExternalCosts::type_name_german(), "Fremdkosten");
161 assert_eq!(ExternalCosts::type_name_english(), "ExternalCosts");
162 }
163}