koprogo_api/domain/entities/
unit.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5/// Type de lot (appartement, cave, parking, etc.)
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub enum UnitType {
8    Apartment,
9    Parking,
10    Cellar,
11    Commercial,
12    Other,
13}
14
15/// Représente un lot dans la copropriété
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
17pub struct Unit {
18    pub id: Uuid,
19    pub organization_id: Uuid,
20    pub building_id: Uuid,
21    pub unit_number: String,
22    pub unit_type: UnitType,
23    pub floor: Option<i32>,
24    pub surface_area: f64, // en m²
25    pub quota: f64,        // Quote-part en millièmes
26    pub owner_id: Option<Uuid>,
27    pub created_at: DateTime<Utc>,
28    pub updated_at: DateTime<Utc>,
29}
30
31impl Unit {
32    pub fn new(
33        organization_id: Uuid,
34        building_id: Uuid,
35        unit_number: String,
36        unit_type: UnitType,
37        floor: Option<i32>,
38        surface_area: f64,
39        quota: f64,
40    ) -> Result<Self, String> {
41        if unit_number.is_empty() {
42            return Err("Unit number cannot be empty".to_string());
43        }
44        if surface_area <= 0.0 {
45            return Err("Surface area must be greater than 0".to_string());
46        }
47        if quota <= 0.0 || quota > 1000.0 {
48            return Err("Quota must be between 0 and 1000".to_string());
49        }
50
51        let now = Utc::now();
52        Ok(Self {
53            id: Uuid::new_v4(),
54            organization_id,
55            building_id,
56            unit_number,
57            unit_type,
58            floor,
59            surface_area,
60            quota,
61            owner_id: None,
62            created_at: now,
63            updated_at: now,
64        })
65    }
66
67    pub fn assign_owner(&mut self, owner_id: Uuid) {
68        self.owner_id = Some(owner_id);
69        self.updated_at = Utc::now();
70    }
71
72    pub fn remove_owner(&mut self) {
73        self.owner_id = None;
74        self.updated_at = Utc::now();
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_create_unit_success() {
84        let org_id = Uuid::new_v4();
85        let building_id = Uuid::new_v4();
86        let unit = Unit::new(
87            org_id,
88            building_id,
89            "A101".to_string(),
90            UnitType::Apartment,
91            Some(1),
92            75.5,
93            50.0,
94        );
95
96        assert!(unit.is_ok());
97        let unit = unit.unwrap();
98        assert_eq!(unit.organization_id, org_id);
99        assert_eq!(unit.unit_number, "A101");
100        assert_eq!(unit.surface_area, 75.5);
101    }
102
103    #[test]
104    fn test_create_unit_invalid_surface_fails() {
105        let org_id = Uuid::new_v4();
106        let building_id = Uuid::new_v4();
107        let unit = Unit::new(
108            org_id,
109            building_id,
110            "A101".to_string(),
111            UnitType::Apartment,
112            Some(1),
113            0.0,
114            50.0,
115        );
116
117        assert!(unit.is_err());
118    }
119
120    #[test]
121    fn test_assign_owner() {
122        let org_id = Uuid::new_v4();
123        let building_id = Uuid::new_v4();
124        let mut unit = Unit::new(
125            org_id,
126            building_id,
127            "A101".to_string(),
128            UnitType::Apartment,
129            Some(1),
130            75.5,
131            50.0,
132        )
133        .unwrap();
134
135        let owner_id = Uuid::new_v4();
136        unit.assign_owner(owner_id);
137
138        assert_eq!(unit.owner_id, Some(owner_id));
139    }
140}