koprogo_api/domain/entities/
owner.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5/// Représente un copropriétaire
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub struct Owner {
8    pub id: Uuid,
9    pub organization_id: Uuid,
10    pub user_id: Option<Uuid>, // Optional link to user account (for portal access)
11    pub first_name: String,
12    pub last_name: String,
13    pub email: String,
14    pub phone: Option<String>,
15    pub address: String,
16    pub city: String,
17    pub postal_code: String,
18    pub country: String,
19    pub created_at: DateTime<Utc>,
20    pub updated_at: DateTime<Utc>,
21}
22
23impl Owner {
24    #[allow(clippy::too_many_arguments)]
25    pub fn new(
26        organization_id: Uuid,
27        first_name: String,
28        last_name: String,
29        email: String,
30        phone: Option<String>,
31        address: String,
32        city: String,
33        postal_code: String,
34        country: String,
35    ) -> Result<Self, String> {
36        if first_name.is_empty() {
37            return Err("First name cannot be empty".to_string());
38        }
39        if last_name.is_empty() {
40            return Err("Last name cannot be empty".to_string());
41        }
42        if !Self::is_valid_email(&email) {
43            return Err("Invalid email format".to_string());
44        }
45
46        let now = Utc::now();
47        Ok(Self {
48            id: Uuid::new_v4(),
49            organization_id,
50            user_id: None, // Set by admin later if needed
51            first_name,
52            last_name,
53            email,
54            phone,
55            address,
56            city,
57            postal_code,
58            country,
59            created_at: now,
60            updated_at: now,
61        })
62    }
63
64    fn is_valid_email(email: &str) -> bool {
65        email.contains('@') && email.contains('.')
66    }
67
68    pub fn full_name(&self) -> String {
69        format!("{} {}", self.first_name, self.last_name)
70    }
71
72    pub fn update_contact(&mut self, email: String, phone: Option<String>) -> Result<(), String> {
73        if !Self::is_valid_email(&email) {
74            return Err("Invalid email format".to_string());
75        }
76        self.email = email;
77        self.phone = phone;
78        self.updated_at = Utc::now();
79        Ok(())
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_create_owner_success() {
89        let org_id = Uuid::new_v4();
90        let owner = Owner::new(
91            org_id,
92            "Jean".to_string(),
93            "Dupont".to_string(),
94            "jean.dupont@example.com".to_string(),
95            Some("+33612345678".to_string()),
96            "123 Rue de la Paix".to_string(),
97            "Paris".to_string(),
98            "75001".to_string(),
99            "France".to_string(),
100        );
101
102        assert!(owner.is_ok());
103        let owner = owner.unwrap();
104        assert_eq!(owner.organization_id, org_id);
105        assert_eq!(owner.full_name(), "Jean Dupont");
106    }
107
108    #[test]
109    fn test_create_owner_invalid_email_fails() {
110        let org_id = Uuid::new_v4();
111        let owner = Owner::new(
112            org_id,
113            "Jean".to_string(),
114            "Dupont".to_string(),
115            "invalid-email".to_string(),
116            None,
117            "123 Rue de la Paix".to_string(),
118            "Paris".to_string(),
119            "75001".to_string(),
120            "France".to_string(),
121        );
122
123        assert!(owner.is_err());
124        assert_eq!(owner.unwrap_err(), "Invalid email format");
125    }
126
127    #[test]
128    fn test_update_contact() {
129        let org_id = Uuid::new_v4();
130        let mut owner = Owner::new(
131            org_id,
132            "Jean".to_string(),
133            "Dupont".to_string(),
134            "jean.dupont@example.com".to_string(),
135            None,
136            "123 Rue de la Paix".to_string(),
137            "Paris".to_string(),
138            "75001".to_string(),
139            "France".to_string(),
140        )
141        .unwrap();
142
143        let result = owner.update_contact(
144            "new.email@example.com".to_string(),
145            Some("+33699999999".to_string()),
146        );
147
148        assert!(result.is_ok());
149        assert_eq!(owner.email, "new.email@example.com");
150    }
151}