koprogo_api/application/dto/
public_dto.rs

1use crate::domain::entities::Building;
2use serde::{Deserialize, Serialize};
3
4/// Public syndic information response (no authentication required)
5/// Belgian legal requirement: syndics must publicly display contact information
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct PublicSyndicInfoResponse {
8    // Building information (public)
9    pub building_name: String,
10    pub building_address: String,
11    pub building_city: String,
12    pub building_postal_code: String,
13    pub building_country: String,
14    pub slug: String,
15
16    // Syndic contact information (public per Belgian law)
17    pub syndic_name: Option<String>,
18    pub syndic_email: Option<String>,
19    pub syndic_phone: Option<String>,
20    pub syndic_address: Option<String>,
21    pub syndic_office_hours: Option<String>,
22    pub syndic_emergency_contact: Option<String>,
23
24    // Metadata
25    pub has_syndic_info: bool,
26}
27
28impl From<Building> for PublicSyndicInfoResponse {
29    fn from(building: Building) -> Self {
30        let has_syndic_info = building.has_public_syndic_info();
31
32        Self {
33            building_name: building.name,
34            building_address: building.address,
35            building_city: building.city,
36            building_postal_code: building.postal_code,
37            building_country: building.country,
38            slug: building.slug.unwrap_or_default(),
39            syndic_name: building.syndic_name,
40            syndic_email: building.syndic_email,
41            syndic_phone: building.syndic_phone,
42            syndic_address: building.syndic_address,
43            syndic_office_hours: building.syndic_office_hours,
44            syndic_emergency_contact: building.syndic_emergency_contact,
45            has_syndic_info,
46        }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use uuid::Uuid;
54
55    #[test]
56    fn test_public_syndic_info_conversion() {
57        let building = Building::new(
58            Uuid::new_v4(),
59            "Résidence Les Jardins".to_string(),
60            "123 Rue de la Paix".to_string(),
61            "Brussels".to_string(),
62            "1000".to_string(),
63            "Belgium".to_string(),
64            50,
65            1000,
66            Some(1985),
67        )
68        .unwrap();
69
70        let response = PublicSyndicInfoResponse::from(building);
71
72        assert_eq!(response.building_name, "Résidence Les Jardins");
73        assert_eq!(response.building_city, "Brussels");
74        assert_eq!(response.slug, "residence-les-jardins-brussels");
75        assert!(!response.has_syndic_info); // No syndic info yet
76    }
77
78    #[test]
79    fn test_public_syndic_info_with_syndic() {
80        let mut building = Building::new(
81            Uuid::new_v4(),
82            "Résidence Les Jardins".to_string(),
83            "123 Rue de la Paix".to_string(),
84            "Brussels".to_string(),
85            "1000".to_string(),
86            "Belgium".to_string(),
87            50,
88            1000,
89            Some(1985),
90        )
91        .unwrap();
92
93        building.update_syndic_info(
94            Some("Syndic ASBL".to_string()),
95            Some("contact@syndic.be".to_string()),
96            Some("+32 2 123 4567".to_string()),
97            Some("Avenue Louise 123, 1000 Brussels".to_string()),
98            Some("Mon-Fri 9h-17h".to_string()),
99            Some("+32 475 123 456".to_string()),
100        );
101
102        let response = PublicSyndicInfoResponse::from(building);
103
104        assert!(response.has_syndic_info);
105        assert_eq!(response.syndic_name, Some("Syndic ASBL".to_string()));
106        assert_eq!(response.syndic_email, Some("contact@syndic.be".to_string()));
107        assert_eq!(response.syndic_phone, Some("+32 2 123 4567".to_string()));
108    }
109}