bo4e_core/com/
offer_part.rs1use serde::{Deserialize, Serialize};
4
5use crate::traits::{Bo4eMeta, Bo4eObject};
6
7#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
27#[cfg_attr(feature = "json-schema", schemars(rename = "Angebotsteil"))]
28#[serde(rename_all = "camelCase")]
29pub struct OfferPart {
30 #[serde(flatten)]
32 pub meta: Bo4eMeta,
33
34 #[serde(skip_serializing_if = "Option::is_none")]
36 #[cfg_attr(feature = "json-schema", schemars(rename = "anfrageSubreferenz"))]
37 pub request_sub_reference: Option<String>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
44 #[cfg_attr(feature = "json-schema", schemars(rename = "anzahlPositionen"))]
45 pub position_count: Option<i32>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 #[cfg_attr(feature = "json-schema", schemars(rename = "gesamtmengeAngebotsteil"))]
50 pub total_quantity_value: Option<f64>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 #[cfg_attr(feature = "json-schema", schemars(rename = "gesamtkostenAngebotsteil"))]
55 pub total_cost_value: Option<f64>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 #[cfg_attr(feature = "json-schema", schemars(rename = "lieferzeitraumBeginn"))]
60 pub delivery_period_start: Option<String>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 #[cfg_attr(feature = "json-schema", schemars(rename = "lieferzeitraumEnde"))]
65 pub delivery_period_end: Option<String>,
66}
67
68impl Bo4eObject for OfferPart {
69 fn type_name_german() -> &'static str {
70 "Angebotsteil"
71 }
72
73 fn type_name_english() -> &'static str {
74 "OfferPart"
75 }
76
77 fn meta(&self) -> &Bo4eMeta {
78 &self.meta
79 }
80
81 fn meta_mut(&mut self) -> &mut Bo4eMeta {
82 &mut self.meta
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_offer_part_default() {
92 let part = OfferPart::default();
93 assert!(part.request_sub_reference.is_none());
94 assert!(part.total_cost_value.is_none());
95 }
96
97 #[test]
98 fn test_offer_part_serialize() {
99 let part = OfferPart {
100 request_sub_reference: Some("LOT-001".to_string()),
101 position_count: Some(5),
102 total_quantity_value: Some(50000.0),
103 total_cost_value: Some(12500.0),
104 ..Default::default()
105 };
106
107 let json = serde_json::to_string(&part).unwrap();
108 assert!(json.contains(r#""requestSubReference":"LOT-001""#));
109 assert!(json.contains(r#""positionCount":5"#));
110 }
111
112 #[test]
113 fn test_offer_part_roundtrip() {
114 let part = OfferPart {
115 meta: Bo4eMeta::with_type("Angebotsteil"),
116 request_sub_reference: Some("LOT-002".to_string()),
117 position_count: Some(3),
118 total_quantity_value: Some(30000.0),
119 total_cost_value: Some(7500.0),
120 delivery_period_start: Some("2024-01-01T00:00:00+01:00".to_string()),
121 delivery_period_end: Some("2024-12-31T23:59:59+01:00".to_string()),
122 };
123
124 let json = serde_json::to_string(&part).unwrap();
125 let parsed: OfferPart = serde_json::from_str(&json).unwrap();
126 assert_eq!(part, parsed);
127 }
128
129 #[test]
130 fn test_bo4e_object_impl() {
131 assert_eq!(OfferPart::type_name_german(), "Angebotsteil");
132 assert_eq!(OfferPart::type_name_english(), "OfferPart");
133 }
134}