bo4e_core/bo/
price_sheet.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::com::{PricePosition, TimePeriod};
7use crate::enums::Division;
8use crate::traits::{Bo4eMeta, Bo4eObject};
9
10#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
28#[cfg_attr(feature = "json-schema", schemars(rename = "Preisblatt"))]
29#[serde(rename_all = "camelCase")]
30pub struct PriceSheet {
31 #[serde(flatten)]
33 pub meta: Bo4eMeta,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
37 #[cfg_attr(feature = "json-schema", schemars(rename = "bezeichnung"))]
38 pub designation: Option<String>,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 #[cfg_attr(feature = "json-schema", schemars(rename = "beschreibung"))]
43 pub description: Option<String>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 #[cfg_attr(feature = "json-schema", schemars(rename = "sparte"))]
48 pub division: Option<Division>,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
52 #[cfg_attr(feature = "json-schema", schemars(rename = "preisnummer"))]
53 pub price_number: Option<String>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
57 #[cfg_attr(feature = "json-schema", schemars(rename = "gueltigkeitszeitraum"))]
58 pub validity_period: Option<TimePeriod>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 #[cfg_attr(feature = "json-schema", schemars(rename = "gueltigAb"))]
63 pub valid_from: Option<DateTime<Utc>>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 #[cfg_attr(feature = "json-schema", schemars(rename = "gueltigBis"))]
68 pub valid_until: Option<DateTime<Utc>>,
69
70 #[serde(default, skip_serializing_if = "Vec::is_empty")]
72 #[cfg_attr(feature = "json-schema", schemars(rename = "preispositionen"))]
73 pub positions: Vec<PricePosition>,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
77 #[cfg_attr(feature = "json-schema", schemars(rename = "herausgeber"))]
78 pub publisher: Option<Box<super::BusinessPartner>>,
79}
80
81impl Bo4eObject for PriceSheet {
82 fn type_name_german() -> &'static str {
83 "Preisblatt"
84 }
85
86 fn type_name_english() -> &'static str {
87 "PriceSheet"
88 }
89
90 fn meta(&self) -> &Bo4eMeta {
91 &self.meta
92 }
93
94 fn meta_mut(&mut self) -> &mut Bo4eMeta {
95 &mut self.meta
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_price_sheet_creation() {
105 let price_sheet = PriceSheet {
106 designation: Some("Standardpreisblatt 2024".to_string()),
107 division: Some(Division::Electricity),
108 price_number: Some("PB-2024-001".to_string()),
109 ..Default::default()
110 };
111
112 assert_eq!(
113 price_sheet.designation,
114 Some("Standardpreisblatt 2024".to_string())
115 );
116 assert_eq!(price_sheet.division, Some(Division::Electricity));
117 }
118
119 #[test]
120 fn test_serialize() {
121 let price_sheet = PriceSheet {
122 meta: Bo4eMeta::with_type("Preisblatt"),
123 designation: Some("Test Price Sheet".to_string()),
124 ..Default::default()
125 };
126
127 let json = serde_json::to_string(&price_sheet).unwrap();
128 assert!(json.contains(r#""designation":"Test Price Sheet""#));
129 assert!(json.contains(r#""_typ":"Preisblatt""#));
130 }
131
132 #[test]
133 fn test_roundtrip() {
134 let price_sheet = PriceSheet {
135 meta: Bo4eMeta::with_type("Preisblatt"),
136 designation: Some("Network Fee Sheet".to_string()),
137 description: Some("Standard network fees".to_string()),
138 division: Some(Division::Electricity),
139 price_number: Some("NF-2024".to_string()),
140 ..Default::default()
141 };
142
143 let json = serde_json::to_string(&price_sheet).unwrap();
144 let parsed: PriceSheet = serde_json::from_str(&json).unwrap();
145 assert_eq!(price_sheet, parsed);
146 }
147
148 #[test]
149 fn test_bo4e_object_impl() {
150 assert_eq!(PriceSheet::type_name_german(), "Preisblatt");
151 assert_eq!(PriceSheet::type_name_english(), "PriceSheet");
152 }
153}