1use serde::{Deserialize, Serialize};
4
5use crate::enums::{Currency, PriceStatus, PriceType, Unit};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
27#[cfg_attr(feature = "json-schema", schemars(rename = "Preis"))]
28#[serde(rename_all = "camelCase")]
29pub struct Price {
30 #[serde(flatten)]
32 pub meta: Bo4eMeta,
33
34 #[serde(skip_serializing_if = "Option::is_none")]
36 #[cfg_attr(feature = "json-schema", schemars(rename = "wert"))]
37 pub value: Option<f64>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
41 #[cfg_attr(feature = "json-schema", schemars(rename = "waehrung"))]
42 pub currency: Option<Currency>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
46 #[cfg_attr(feature = "json-schema", schemars(rename = "bezugswert"))]
47 pub reference_unit: Option<Unit>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 #[cfg_attr(feature = "json-schema", schemars(rename = "preistyp"))]
52 pub price_type: Option<PriceType>,
53
54 #[serde(skip_serializing_if = "Option::is_none")]
56 #[cfg_attr(feature = "json-schema", schemars(rename = "preisstatus"))]
57 pub status: Option<PriceStatus>,
58}
59
60impl Bo4eObject for Price {
61 fn type_name_german() -> &'static str {
62 "Preis"
63 }
64
65 fn type_name_english() -> &'static str {
66 "Price"
67 }
68
69 fn meta(&self) -> &Bo4eMeta {
70 &self.meta
71 }
72
73 fn meta_mut(&mut self) -> &mut Bo4eMeta {
74 &mut self.meta
75 }
76}
77
78impl Price {
79 pub fn eur_per_kwh(value: f64) -> Self {
81 Self {
82 value: Some(value),
83 currency: Some(Currency::Eur),
84 reference_unit: Some(Unit::KilowattHour),
85 ..Default::default()
86 }
87 }
88
89 pub fn eur_per_month(value: f64) -> Self {
91 Self {
92 value: Some(value),
93 currency: Some(Currency::Eur),
94 reference_unit: Some(Unit::Month),
95 price_type: Some(PriceType::BasePrice),
96 ..Default::default()
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_energy_price() {
107 let price = Price::eur_per_kwh(0.30);
108 assert_eq!(price.value, Some(0.30));
109 assert_eq!(price.currency, Some(Currency::Eur));
110 assert_eq!(price.reference_unit, Some(Unit::KilowattHour));
111 }
112
113 #[test]
114 fn test_base_price() {
115 let price = Price::eur_per_month(12.50);
116 assert_eq!(price.value, Some(12.50));
117 assert_eq!(price.currency, Some(Currency::Eur));
118 assert_eq!(price.reference_unit, Some(Unit::Month));
119 assert_eq!(price.price_type, Some(PriceType::BasePrice));
120 }
121
122 #[test]
123 fn test_serialize() {
124 let price = Price {
125 value: Some(12.50),
126 currency: Some(Currency::Eur),
127 ..Default::default()
128 };
129
130 let json = serde_json::to_string(&price).unwrap();
131 assert!(json.contains(r#""value":12.5"#));
132 assert!(json.contains(r#""currency":"EUR""#));
133 }
134
135 #[test]
136 fn test_roundtrip() {
137 let price = Price::eur_per_kwh(0.2567);
138 let json = serde_json::to_string(&price).unwrap();
139 let parsed: Price = serde_json::from_str(&json).unwrap();
140 assert_eq!(price, parsed);
141 }
142
143 #[test]
144 fn test_bo4e_object_impl() {
145 assert_eq!(Price::type_name_german(), "Preis");
146 assert_eq!(Price::type_name_english(), "Price");
147 }
148}