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#[serde(rename_all = "camelCase")]
30pub struct BillingPeriodData {
31 #[serde(flatten)]
33 pub meta: Bo4eMeta,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub period_start: Option<NaiveDate>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub period_end: Option<NaiveDate>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub start_reading: Option<f64>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub start_reading_timestamp: Option<DateTime<Utc>>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub end_reading: Option<f64>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub end_reading_timestamp: Option<DateTime<Utc>>,
58
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub consumption_value: Option<f64>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub consumption_unit: Option<Unit>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub days_in_period: Option<i32>,
70}
71
72impl Bo4eObject for BillingPeriodData {
73 fn type_name_german() -> &'static str {
74 "Abrechnungsperiodendaten"
75 }
76
77 fn type_name_english() -> &'static str {
78 "BillingPeriodData"
79 }
80
81 fn meta(&self) -> &Bo4eMeta {
82 &self.meta
83 }
84
85 fn meta_mut(&mut self) -> &mut Bo4eMeta {
86 &mut self.meta
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93
94 #[test]
95 fn test_billing_period_data() {
96 let data = BillingPeriodData {
97 period_start: Some(NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()),
98 period_end: Some(NaiveDate::from_ymd_opt(2024, 12, 31).unwrap()),
99 start_reading: Some(10000.0),
100 end_reading: Some(13500.0),
101 consumption_value: Some(3500.0),
102 consumption_unit: Some(Unit::KilowattHour),
103 days_in_period: Some(366),
104 ..Default::default()
105 };
106
107 let json = serde_json::to_string(&data).unwrap();
108 assert!(json.contains("3500"));
109 }
110
111 #[test]
112 fn test_roundtrip() {
113 let data = BillingPeriodData {
114 period_start: Some(NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()),
115 period_end: Some(NaiveDate::from_ymd_opt(2024, 6, 30).unwrap()),
116 consumption_value: Some(1750.0),
117 ..Default::default()
118 };
119
120 let json = serde_json::to_string(&data).unwrap();
121 let parsed: BillingPeriodData = serde_json::from_str(&json).unwrap();
122 assert_eq!(data, parsed);
123 }
124
125 #[test]
126 fn test_bo4e_object_impl() {
127 assert_eq!(
128 BillingPeriodData::type_name_german(),
129 "Abrechnungsperiodendaten"
130 );
131 assert_eq!(BillingPeriodData::type_name_english(), "BillingPeriodData");
132 }
133}