bo4e_core/com/
billing_period_data.rs1use chrono::{DateTime, NaiveDate, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::enums::Unit;
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
29#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
30#[cfg_attr(feature = "json-schema", schemars(rename = "Abrechnungsperiodendaten"))]
31#[serde(rename_all = "camelCase")]
32pub struct BillingPeriodData {
33 #[serde(flatten)]
35 pub meta: Bo4eMeta,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 #[cfg_attr(feature = "json-schema", schemars(rename = "abrechnungsbeginn"))]
40 pub period_start: Option<NaiveDate>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 #[cfg_attr(feature = "json-schema", schemars(rename = "abrechnungsende"))]
45 pub period_end: Option<NaiveDate>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 #[cfg_attr(feature = "json-schema", schemars(rename = "anfangsstand"))]
50 pub start_reading: Option<f64>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 #[cfg_attr(feature = "json-schema", schemars(rename = "anfangsablesung"))]
55 pub start_reading_timestamp: Option<DateTime<Utc>>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 #[cfg_attr(feature = "json-schema", schemars(rename = "endstand"))]
60 pub end_reading: Option<f64>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 #[cfg_attr(feature = "json-schema", schemars(rename = "endablesung"))]
65 pub end_reading_timestamp: Option<DateTime<Utc>>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
69 #[cfg_attr(feature = "json-schema", schemars(rename = "verbrauchswert"))]
70 pub consumption_value: Option<f64>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 #[cfg_attr(feature = "json-schema", schemars(rename = "verbrauchseinheit"))]
75 pub consumption_unit: Option<Unit>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 #[cfg_attr(feature = "json-schema", schemars(rename = "anzahlTage"))]
80 pub days_in_period: Option<i32>,
81}
82
83impl Bo4eObject for BillingPeriodData {
84 fn type_name_german() -> &'static str {
85 "Abrechnungsperiodendaten"
86 }
87
88 fn type_name_english() -> &'static str {
89 "BillingPeriodData"
90 }
91
92 fn meta(&self) -> &Bo4eMeta {
93 &self.meta
94 }
95
96 fn meta_mut(&mut self) -> &mut Bo4eMeta {
97 &mut self.meta
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_billing_period_data() {
107 let data = BillingPeriodData {
108 period_start: Some(NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()),
109 period_end: Some(NaiveDate::from_ymd_opt(2024, 12, 31).unwrap()),
110 start_reading: Some(10000.0),
111 end_reading: Some(13500.0),
112 consumption_value: Some(3500.0),
113 consumption_unit: Some(Unit::KilowattHour),
114 days_in_period: Some(366),
115 ..Default::default()
116 };
117
118 let json = serde_json::to_string(&data).unwrap();
119 assert!(json.contains("3500"));
120 }
121
122 #[test]
123 fn test_roundtrip() {
124 let data = BillingPeriodData {
125 period_start: Some(NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()),
126 period_end: Some(NaiveDate::from_ymd_opt(2024, 6, 30).unwrap()),
127 consumption_value: Some(1750.0),
128 ..Default::default()
129 };
130
131 let json = serde_json::to_string(&data).unwrap();
132 let parsed: BillingPeriodData = serde_json::from_str(&json).unwrap();
133 assert_eq!(data, parsed);
134 }
135
136 #[test]
137 fn test_bo4e_object_impl() {
138 assert_eq!(
139 BillingPeriodData::type_name_german(),
140 "Abrechnungsperiodendaten"
141 );
142 assert_eq!(BillingPeriodData::type_name_english(), "BillingPeriodData");
143 }
144}