use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use crate::enums::Unit;
use crate::traits::{Bo4eMeta, Bo4eObject};
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "json-schema", schemars(rename = "Abrechnungsperiodendaten"))]
#[serde(rename_all = "camelCase")]
pub struct BillingPeriodData {
#[serde(flatten)]
pub meta: Bo4eMeta,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "abrechnungsbeginn"))]
pub period_start: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "abrechnungsende"))]
pub period_end: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "anfangsstand"))]
pub start_reading: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "anfangsablesung"))]
pub start_reading_timestamp: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "endstand"))]
pub end_reading: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "endablesung"))]
pub end_reading_timestamp: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "verbrauchswert"))]
pub consumption_value: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "verbrauchseinheit"))]
pub consumption_unit: Option<Unit>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "json-schema", schemars(rename = "anzahlTage"))]
pub days_in_period: Option<i32>,
}
impl Bo4eObject for BillingPeriodData {
fn type_name_german() -> &'static str {
"Abrechnungsperiodendaten"
}
fn type_name_english() -> &'static str {
"BillingPeriodData"
}
fn meta(&self) -> &Bo4eMeta {
&self.meta
}
fn meta_mut(&mut self) -> &mut Bo4eMeta {
&mut self.meta
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_billing_period_data() {
let data = BillingPeriodData {
period_start: Some(NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()),
period_end: Some(NaiveDate::from_ymd_opt(2024, 12, 31).unwrap()),
start_reading: Some(10000.0),
end_reading: Some(13500.0),
consumption_value: Some(3500.0),
consumption_unit: Some(Unit::KilowattHour),
days_in_period: Some(366),
..Default::default()
};
let json = serde_json::to_string(&data).unwrap();
assert!(json.contains("3500"));
}
#[test]
fn test_roundtrip() {
let data = BillingPeriodData {
period_start: Some(NaiveDate::from_ymd_opt(2024, 1, 1).unwrap()),
period_end: Some(NaiveDate::from_ymd_opt(2024, 6, 30).unwrap()),
consumption_value: Some(1750.0),
..Default::default()
};
let json = serde_json::to_string(&data).unwrap();
let parsed: BillingPeriodData = serde_json::from_str(&json).unwrap();
assert_eq!(data, parsed);
}
#[test]
fn test_bo4e_object_impl() {
assert_eq!(
BillingPeriodData::type_name_german(),
"Abrechnungsperiodendaten"
);
assert_eq!(BillingPeriodData::type_name_english(), "BillingPeriodData");
}
}