1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::com::{ContractConditions, ContractPart, TimePeriod};
7use crate::enums::{ContractStatus, ContractType, Division};
8use crate::traits::{Bo4eMeta, Bo4eObject};
9
10#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
29#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
30#[cfg_attr(feature = "json-schema", schemars(rename = "Vertrag"))]
31#[serde(rename_all = "camelCase")]
32pub struct Contract {
33 #[serde(flatten)]
35 pub meta: Bo4eMeta,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragsnummer"))]
40 pub contract_number: Option<String>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 #[cfg_attr(feature = "json-schema", schemars(rename = "beschreibung"))]
45 pub description: Option<String>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragsart"))]
50 pub contract_type: Option<ContractType>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragsstatus"))]
55 pub status: Option<ContractStatus>,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
59 #[cfg_attr(feature = "json-schema", schemars(rename = "sparte"))]
60 pub division: Option<Division>,
61
62 #[serde(skip_serializing_if = "Option::is_none")]
64 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragsbeginn"))]
65 pub contract_start: Option<DateTime<Utc>>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
69 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragsende"))]
70 pub contract_end: Option<DateTime<Utc>>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 #[cfg_attr(feature = "json-schema", schemars(rename = "unterzeichnungsdatum"))]
75 pub signing_date: Option<DateTime<Utc>>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 #[cfg_attr(feature = "json-schema", schemars(rename = "gueltigkeitszeitraum"))]
80 pub validity_period: Option<TimePeriod>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragskonditionen"))]
85 pub conditions: Option<ContractConditions>,
86
87 #[serde(default, skip_serializing_if = "Vec::is_empty")]
89 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragsteile"))]
90 pub parts: Vec<ContractPart>,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 #[cfg_attr(feature = "json-schema", schemars(rename = "vertragspartner"))]
95 pub contract_partner: Option<Box<super::BusinessPartner>>,
96}
97
98impl Bo4eObject for Contract {
99 fn type_name_german() -> &'static str {
100 "Vertrag"
101 }
102
103 fn type_name_english() -> &'static str {
104 "Contract"
105 }
106
107 fn meta(&self) -> &Bo4eMeta {
108 &self.meta
109 }
110
111 fn meta_mut(&mut self) -> &mut Bo4eMeta {
112 &mut self.meta
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_supply_contract() {
122 let contract = Contract {
123 contract_number: Some("V-2024-001".to_string()),
124 contract_type: Some(ContractType::EnergySupplyContract),
125 status: Some(ContractStatus::Active),
126 division: Some(Division::Electricity),
127 ..Default::default()
128 };
129
130 assert_eq!(contract.status, Some(ContractStatus::Active));
131 }
132
133 #[test]
134 fn test_serialize() {
135 let contract = Contract {
136 meta: Bo4eMeta::with_type("Vertrag"),
137 contract_number: Some("V-123".to_string()),
138 ..Default::default()
139 };
140
141 let json = serde_json::to_string(&contract).unwrap();
142 assert!(json.contains(r#""contractNumber":"V-123""#));
143 }
144
145 #[test]
146 fn test_roundtrip() {
147 let contract = Contract {
148 meta: Bo4eMeta::with_type("Vertrag"),
149 contract_number: Some("V-123".to_string()),
150 description: Some("Test contract".to_string()),
151 contract_type: Some(ContractType::EnergySupplyContract),
152 status: Some(ContractStatus::Active),
153 division: Some(Division::Electricity),
154 ..Default::default()
155 };
156
157 let json = serde_json::to_string(&contract).unwrap();
158 let parsed: Contract = serde_json::from_str(&json).unwrap();
159 assert_eq!(contract, parsed);
160 }
161
162 #[test]
163 fn test_bo4e_object_impl() {
164 assert_eq!(Contract::type_name_german(), "Vertrag");
165 assert_eq!(Contract::type_name_english(), "Contract");
166 }
167}