koprogo_api/domain/entities/
meeting.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub enum MeetingType {
8 Ordinary, Extraordinary, }
11
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub enum MeetingStatus {
15 Scheduled,
16 Completed,
17 Cancelled,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
22pub struct Meeting {
23 pub id: Uuid,
24 pub organization_id: Uuid,
25 pub building_id: Uuid,
26 pub meeting_type: MeetingType,
27 pub title: String,
28 pub description: Option<String>,
29 pub scheduled_date: DateTime<Utc>,
30 pub location: String,
31 pub status: MeetingStatus,
32 pub agenda: Vec<String>,
33 pub attendees_count: Option<i32>,
34 pub created_at: DateTime<Utc>,
35 pub updated_at: DateTime<Utc>,
36}
37
38impl Meeting {
39 pub fn new(
40 organization_id: Uuid,
41 building_id: Uuid,
42 meeting_type: MeetingType,
43 title: String,
44 description: Option<String>,
45 scheduled_date: DateTime<Utc>,
46 location: String,
47 ) -> Result<Self, String> {
48 if title.is_empty() {
49 return Err("Title cannot be empty".to_string());
50 }
51 if location.is_empty() {
52 return Err("Location cannot be empty".to_string());
53 }
54
55 let now = Utc::now();
56 Ok(Self {
57 id: Uuid::new_v4(),
58 organization_id,
59 building_id,
60 meeting_type,
61 title,
62 description,
63 scheduled_date,
64 location,
65 status: MeetingStatus::Scheduled,
66 agenda: Vec::new(),
67 attendees_count: None,
68 created_at: now,
69 updated_at: now,
70 })
71 }
72
73 pub fn add_agenda_item(&mut self, item: String) -> Result<(), String> {
74 if item.is_empty() {
75 return Err("Agenda item cannot be empty".to_string());
76 }
77 self.agenda.push(item);
78 self.updated_at = Utc::now();
79 Ok(())
80 }
81
82 pub fn complete(&mut self, attendees_count: i32) {
83 self.status = MeetingStatus::Completed;
84 self.attendees_count = Some(attendees_count);
85 self.updated_at = Utc::now();
86 }
87
88 pub fn cancel(&mut self) {
89 self.status = MeetingStatus::Cancelled;
90 self.updated_at = Utc::now();
91 }
92
93 pub fn is_upcoming(&self) -> bool {
94 self.status == MeetingStatus::Scheduled && self.scheduled_date > Utc::now()
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use chrono::Duration;
102
103 #[test]
104 fn test_create_meeting_success() {
105 let org_id = Uuid::new_v4();
106 let building_id = Uuid::new_v4();
107 let future_date = Utc::now() + Duration::days(30);
108
109 let meeting = Meeting::new(
110 org_id,
111 building_id,
112 MeetingType::Ordinary,
113 "AGO 2024".to_string(),
114 Some("Assemblée générale ordinaire annuelle".to_string()),
115 future_date,
116 "Salle des fêtes".to_string(),
117 );
118
119 assert!(meeting.is_ok());
120 let meeting = meeting.unwrap();
121 assert_eq!(meeting.organization_id, org_id);
122 assert_eq!(meeting.status, MeetingStatus::Scheduled);
123 assert!(meeting.is_upcoming());
124 }
125
126 #[test]
127 fn test_add_agenda_item() {
128 let org_id = Uuid::new_v4();
129 let building_id = Uuid::new_v4();
130 let future_date = Utc::now() + Duration::days(30);
131
132 let mut meeting = Meeting::new(
133 org_id,
134 building_id,
135 MeetingType::Ordinary,
136 "AGO 2024".to_string(),
137 None,
138 future_date,
139 "Salle des fêtes".to_string(),
140 )
141 .unwrap();
142
143 let result = meeting.add_agenda_item("Approbation des comptes".to_string());
144 assert!(result.is_ok());
145 assert_eq!(meeting.agenda.len(), 1);
146 }
147
148 #[test]
149 fn test_complete_meeting() {
150 let org_id = Uuid::new_v4();
151 let building_id = Uuid::new_v4();
152 let future_date = Utc::now() + Duration::days(30);
153
154 let mut meeting = Meeting::new(
155 org_id,
156 building_id,
157 MeetingType::Ordinary,
158 "AGO 2024".to_string(),
159 None,
160 future_date,
161 "Salle des fêtes".to_string(),
162 )
163 .unwrap();
164
165 meeting.complete(45);
166 assert_eq!(meeting.status, MeetingStatus::Completed);
167 assert_eq!(meeting.attendees_count, Some(45));
168 assert!(!meeting.is_upcoming());
169 }
170}