bo4e_core/com/
position_surcharge.rs

1//! Position surcharge (PositionsAufAbschlag) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::{Currency, SurchargeType};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// A surcharge or discount applied to a specific position.
9///
10/// German: PositionsAufAbschlag
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::PositionSurcharge;
16///
17/// let surcharge = PositionSurcharge {
18///     description: Some("Sonderrabatt".to_string()),
19///     value: Some(-10.0),
20///     ..Default::default()
21/// };
22/// ```
23#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct PositionSurcharge {
26    /// BO4E metadata
27    #[serde(flatten)]
28    pub meta: Bo4eMeta,
29
30    /// Description (Bezeichnung)
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub description: Option<String>,
33
34    /// Type of surcharge (AufAbschlagstyp)
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub surcharge_type: Option<SurchargeType>,
37
38    /// Value (Wert)
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub value: Option<f64>,
41
42    /// Currency (Waehrung)
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub currency: Option<Currency>,
45}
46
47impl Bo4eObject for PositionSurcharge {
48    fn type_name_german() -> &'static str {
49        "PositionsAufAbschlag"
50    }
51
52    fn type_name_english() -> &'static str {
53        "PositionSurcharge"
54    }
55
56    fn meta(&self) -> &Bo4eMeta {
57        &self.meta
58    }
59
60    fn meta_mut(&mut self) -> &mut Bo4eMeta {
61        &mut self.meta
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_position_surcharge() {
71        let surcharge = PositionSurcharge {
72            description: Some("Position discount".to_string()),
73            surcharge_type: Some(SurchargeType::Absolute),
74            value: Some(-5.0),
75            currency: Some(Currency::Eur),
76            ..Default::default()
77        };
78
79        assert_eq!(surcharge.value, Some(-5.0));
80    }
81
82    #[test]
83    fn test_percentage_surcharge() {
84        let surcharge = PositionSurcharge {
85            description: Some("10% markup".to_string()),
86            surcharge_type: Some(SurchargeType::Relative),
87            value: Some(10.0),
88            ..Default::default()
89        };
90
91        assert_eq!(surcharge.surcharge_type, Some(SurchargeType::Relative));
92    }
93
94    #[test]
95    fn test_default() {
96        let surcharge = PositionSurcharge::default();
97        assert!(surcharge.description.is_none());
98        assert!(surcharge.value.is_none());
99    }
100
101    #[test]
102    fn test_roundtrip() {
103        let surcharge = PositionSurcharge {
104            description: Some("Test surcharge".to_string()),
105            surcharge_type: Some(SurchargeType::Absolute),
106            value: Some(15.50),
107            currency: Some(Currency::Eur),
108            ..Default::default()
109        };
110
111        let json = serde_json::to_string(&surcharge).unwrap();
112        let parsed: PositionSurcharge = serde_json::from_str(&json).unwrap();
113        assert_eq!(surcharge, parsed);
114    }
115
116    #[test]
117    fn test_bo4e_object_impl() {
118        assert_eq!(
119            PositionSurcharge::type_name_german(),
120            "PositionsAufAbschlag"
121        );
122        assert_eq!(PositionSurcharge::type_name_english(), "PositionSurcharge");
123    }
124}