koprogo_api/domain/entities/
contract_evaluation.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use uuid::Uuid;
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct ContractEvaluation {
11 pub id: Uuid,
12 pub organization_id: Uuid,
13 pub service_provider_id: Uuid,
14 pub quote_id: Option<Uuid>,
15 pub ticket_id: Option<Uuid>,
16 pub evaluator_id: Uuid,
17 pub building_id: Uuid,
18 pub criteria: HashMap<String, u8>,
20 pub global_score: f64, pub comments: Option<String>,
22 pub would_recommend: bool,
23 pub is_legal_evaluation: bool, pub is_anonymous: bool,
25 pub created_at: DateTime<Utc>,
26}
27
28impl ContractEvaluation {
29 pub fn new(
30 organization_id: Uuid,
31 service_provider_id: Uuid,
32 evaluator_id: Uuid,
33 building_id: Uuid,
34 criteria: HashMap<String, u8>,
35 would_recommend: bool,
36 ) -> Result<Self, String> {
37 for (key, &val) in &criteria {
39 if val > 5 {
40 return Err(format!("Criteria '{}' must be 0-5, got {}", key, val));
41 }
42 }
43
44 let global = if criteria.is_empty() {
45 0.0
46 } else {
47 criteria.values().map(|&v| v as f64).sum::<f64>() / criteria.len() as f64
48 };
49
50 Ok(Self {
51 id: Uuid::new_v4(),
52 organization_id,
53 service_provider_id,
54 quote_id: None,
55 ticket_id: None,
56 evaluator_id,
57 building_id,
58 criteria,
59 global_score: global,
60 comments: None,
61 would_recommend,
62 is_legal_evaluation: false,
63 is_anonymous: false,
64 created_at: Utc::now(),
65 })
66 }
67
68 pub fn link_quote(&mut self, quote_id: Uuid) -> Result<(), String> {
70 self.quote_id = Some(quote_id);
71 Ok(())
72 }
73
74 pub fn link_ticket(&mut self, ticket_id: Uuid) -> Result<(), String> {
76 self.ticket_id = Some(ticket_id);
77 Ok(())
78 }
79
80 pub fn mark_as_legal_evaluation(&mut self) -> Result<(), String> {
82 self.is_legal_evaluation = true;
83 Ok(())
84 }
85
86 pub fn mark_as_anonymous(&mut self) -> Result<(), String> {
88 self.is_anonymous = true;
89 Ok(())
90 }
91
92 pub fn recalculate_global_score(&mut self) -> Result<(), String> {
94 self.global_score = if self.criteria.is_empty() {
95 0.0
96 } else {
97 self.criteria.values().map(|&v| v as f64).sum::<f64>() / self.criteria.len() as f64
98 };
99 Ok(())
100 }
101
102 pub fn set_comments(&mut self, comments: String) -> Result<(), String> {
104 if comments.is_empty() {
105 return Err("Comments cannot be empty".to_string());
106 }
107 self.comments = Some(comments);
108 Ok(())
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_contract_evaluation_new_success() {
118 let org_id = Uuid::new_v4();
119 let provider_id = Uuid::new_v4();
120 let evaluator_id = Uuid::new_v4();
121 let building_id = Uuid::new_v4();
122
123 let mut criteria = HashMap::new();
124 criteria.insert("qualite".to_string(), 5);
125 criteria.insert("delai".to_string(), 4);
126 criteria.insert("prix".to_string(), 3);
127
128 let eval = ContractEvaluation::new(
129 org_id,
130 provider_id,
131 evaluator_id,
132 building_id,
133 criteria,
134 true,
135 );
136
137 assert!(eval.is_ok());
138 let e = eval.unwrap();
139 assert_eq!(e.criteria.len(), 3);
140 assert!(e.global_score > 0.0);
141 assert!(e.would_recommend);
142 }
143
144 #[test]
145 fn test_contract_evaluation_invalid_criteria() {
146 let org_id = Uuid::new_v4();
147 let provider_id = Uuid::new_v4();
148 let evaluator_id = Uuid::new_v4();
149 let building_id = Uuid::new_v4();
150
151 let mut criteria = HashMap::new();
152 criteria.insert("qualite".to_string(), 6); let result = ContractEvaluation::new(
155 org_id,
156 provider_id,
157 evaluator_id,
158 building_id,
159 criteria,
160 true,
161 );
162
163 assert!(result.is_err());
164 }
165
166 #[test]
167 fn test_global_score_calculation() {
168 let org_id = Uuid::new_v4();
169 let provider_id = Uuid::new_v4();
170 let evaluator_id = Uuid::new_v4();
171 let building_id = Uuid::new_v4();
172
173 let mut criteria = HashMap::new();
174 criteria.insert("qualite".to_string(), 5);
175 criteria.insert("delai".to_string(), 3);
176
177 let eval = ContractEvaluation::new(
178 org_id,
179 provider_id,
180 evaluator_id,
181 building_id,
182 criteria,
183 true,
184 )
185 .unwrap();
186
187 assert_eq!(eval.global_score, 4.0);
189 }
190
191 #[test]
192 fn test_mark_legal_evaluation() {
193 let org_id = Uuid::new_v4();
194 let provider_id = Uuid::new_v4();
195 let evaluator_id = Uuid::new_v4();
196 let building_id = Uuid::new_v4();
197
198 let criteria = HashMap::new();
199 let mut eval = ContractEvaluation::new(
200 org_id,
201 provider_id,
202 evaluator_id,
203 building_id,
204 criteria,
205 true,
206 )
207 .unwrap();
208
209 assert!(!eval.is_legal_evaluation);
210 let _ = eval.mark_as_legal_evaluation();
211 assert!(eval.is_legal_evaluation);
212 }
213}