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