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#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
32#[cfg_attr(feature = "json-schema", schemars(rename = "Fremdkosten"))]
33#[serde(rename_all = "camelCase")]
34pub struct ExternalCosts {
35 #[serde(flatten)]
37 pub meta: Bo4eMeta,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
41 #[cfg_attr(feature = "json-schema", schemars(rename = "bezeichnung"))]
42 pub designation: Option<String>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
46 #[cfg_attr(feature = "json-schema", schemars(rename = "beschreibung"))]
47 pub description: Option<String>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 #[cfg_attr(feature = "json-schema", schemars(rename = "sparte"))]
52 pub division: Option<Division>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 #[cfg_attr(feature = "json-schema", schemars(rename = "abrechnungszeitraum"))]
57 pub period: Option<TimePeriod>,
58
59 #[serde(skip_serializing_if = "Option::is_none")]
61 #[cfg_attr(feature = "json-schema", schemars(rename = "gesamtbetrag"))]
62 pub total_amount: Option<Amount>,
63
64 #[serde(default, skip_serializing_if = "Vec::is_empty")]
66 #[cfg_attr(feature = "json-schema", schemars(rename = "fremdkostenbloecke"))]
67 pub cost_blocks: Vec<ExternalCostBlock>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 #[cfg_attr(feature = "json-schema", schemars(rename = "fremdpartei"))]
72 pub external_party: Option<Box<super::BusinessPartner>>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 #[cfg_attr(feature = "json-schema", schemars(rename = "marktlokation"))]
77 pub market_location: Option<Box<super::MarketLocation>>,
78}
79
80impl Bo4eObject for ExternalCosts {
81 fn type_name_german() -> &'static str {
82 "Fremdkosten"
83 }
84
85 fn type_name_english() -> &'static str {
86 "ExternalCosts"
87 }
88
89 fn meta(&self) -> &Bo4eMeta {
90 &self.meta
91 }
92
93 fn meta_mut(&mut self) -> &mut Bo4eMeta {
94 &mut self.meta
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::com::ExternalCostBlock;
102
103 #[test]
104 fn test_external_costs_creation() {
105 let external_costs = ExternalCosts {
106 designation: Some("Netzkosten 2024".to_string()),
107 division: Some(Division::Electricity),
108 total_amount: Some(Amount::eur(350.00)),
109 ..Default::default()
110 };
111
112 assert_eq!(external_costs.total_amount, Some(Amount::eur(350.00)));
113 }
114
115 #[test]
116 fn test_external_costs_with_blocks() {
117 let external_costs = ExternalCosts {
118 designation: Some("Network Costs".to_string()),
119 cost_blocks: vec![
120 ExternalCostBlock {
121 designation: Some("Network usage".to_string()),
122 total_amount: Some(Amount::eur(200.0)),
123 ..Default::default()
124 },
125 ExternalCostBlock {
126 designation: Some("Metering".to_string()),
127 total_amount: Some(Amount::eur(50.0)),
128 ..Default::default()
129 },
130 ],
131 total_amount: Some(Amount::eur(250.0)),
132 ..Default::default()
133 };
134
135 assert_eq!(external_costs.cost_blocks.len(), 2);
136 }
137
138 #[test]
139 fn test_serialize() {
140 let external_costs = ExternalCosts {
141 meta: Bo4eMeta::with_type("Fremdkosten"),
142 designation: Some("Test External Costs".to_string()),
143 total_amount: Some(Amount::eur(100.0)),
144 ..Default::default()
145 };
146
147 let json = serde_json::to_string(&external_costs).unwrap();
148 assert!(json.contains(r#""designation":"Test External Costs""#));
149 assert!(json.contains(r#""_typ":"Fremdkosten""#));
150 }
151
152 #[test]
153 fn test_roundtrip() {
154 let external_costs = ExternalCosts {
155 meta: Bo4eMeta::with_type("Fremdkosten"),
156 designation: Some("Gas Network Costs".to_string()),
157 description: Some("External gas network costs".to_string()),
158 division: Some(Division::Gas),
159 total_amount: Some(Amount::eur(180.0)),
160 ..Default::default()
161 };
162
163 let json = serde_json::to_string(&external_costs).unwrap();
164 let parsed: ExternalCosts = serde_json::from_str(&json).unwrap();
165 assert_eq!(external_costs, parsed);
166 }
167
168 #[test]
169 fn test_bo4e_object_impl() {
170 assert_eq!(ExternalCosts::type_name_german(), "Fremdkosten");
171 assert_eq!(ExternalCosts::type_name_english(), "ExternalCosts");
172 }
173}