Skip to main content

bo4e_core/com/
regional_surcharge.rs

1//! Regional surcharge (AufAbschlagRegional) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::TariffRegionCriterion;
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8use super::Surcharge;
9
10/// A surcharge that applies to a specific regional criterion.
11///
12/// German: AufAbschlagRegional
13///
14/// # Example
15///
16/// ```rust
17/// use bo4e_core::com::RegionalSurcharge;
18/// use bo4e_core::enums::TariffRegionCriterion;
19///
20/// let surcharge = RegionalSurcharge {
21///     region_criterion: Some(TariffRegionCriterion::PostalCode),
22///     region_code: Some("50*".to_string()),
23///     ..Default::default()
24/// };
25/// ```
26#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
28#[cfg_attr(feature = "json-schema", schemars(rename = "AufAbschlagRegional"))]
29#[serde(rename_all = "camelCase")]
30pub struct RegionalSurcharge {
31    /// BO4E metadata
32    #[serde(flatten)]
33    pub meta: Bo4eMeta,
34
35    /// Type of regional criterion (Tarifregionskriterium)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    #[cfg_attr(feature = "json-schema", schemars(rename = "tarifregionskriterium"))]
38    pub region_criterion: Option<TariffRegionCriterion>,
39
40    /// Region code/value (Regionscode)
41    #[serde(skip_serializing_if = "Option::is_none")]
42    #[cfg_attr(feature = "json-schema", schemars(rename = "regionscode"))]
43    pub region_code: Option<String>,
44
45    /// Surcharges applicable to this region (AufAbschläge)
46    #[serde(default, skip_serializing_if = "Vec::is_empty")]
47    #[cfg_attr(feature = "json-schema", schemars(rename = "aufAbschlaege"))]
48    pub surcharges: Vec<Surcharge>,
49}
50
51impl Bo4eObject for RegionalSurcharge {
52    fn type_name_german() -> &'static str {
53        "AufAbschlagRegional"
54    }
55
56    fn type_name_english() -> &'static str {
57        "RegionalSurcharge"
58    }
59
60    fn meta(&self) -> &Bo4eMeta {
61        &self.meta
62    }
63
64    fn meta_mut(&mut self) -> &mut Bo4eMeta {
65        &mut self.meta
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_postal_region_surcharge() {
75        let surcharge = RegionalSurcharge {
76            region_criterion: Some(TariffRegionCriterion::PostalCode),
77            region_code: Some("50*".to_string()),
78            surcharges: vec![Surcharge {
79                description: Some("Regional discount".to_string()),
80                value: Some(-5.0),
81                ..Default::default()
82            }],
83            ..Default::default()
84        };
85
86        assert_eq!(
87            surcharge.region_criterion,
88            Some(TariffRegionCriterion::PostalCode)
89        );
90        assert_eq!(surcharge.surcharges.len(), 1);
91    }
92
93    #[test]
94    fn test_default() {
95        let surcharge = RegionalSurcharge::default();
96        assert!(surcharge.region_criterion.is_none());
97        assert!(surcharge.surcharges.is_empty());
98    }
99
100    #[test]
101    fn test_roundtrip() {
102        let surcharge = RegionalSurcharge {
103            region_criterion: Some(TariffRegionCriterion::NetworkNumber),
104            region_code: Some("9990001".to_string()),
105            ..Default::default()
106        };
107
108        let json = serde_json::to_string(&surcharge).unwrap();
109        let parsed: RegionalSurcharge = serde_json::from_str(&json).unwrap();
110        assert_eq!(surcharge, parsed);
111    }
112
113    #[test]
114    fn test_bo4e_object_impl() {
115        assert_eq!(RegionalSurcharge::type_name_german(), "AufAbschlagRegional");
116        assert_eq!(RegionalSurcharge::type_name_english(), "RegionalSurcharge");
117    }
118}