koprogo_api/application/use_cases/
etat_date_use_cases.rs1use crate::application::dto::{
2 CreateEtatDateRequest, EtatDateResponse, EtatDateStatsResponse, PageRequest,
3 UpdateEtatDateAdditionalDataRequest, UpdateEtatDateFinancialRequest,
4};
5use crate::application::ports::{
6 BuildingRepository, EtatDateRepository, UnitOwnerRepository, UnitRepository,
7};
8use crate::domain::entities::{EtatDate, EtatDateStatus};
9use f64;
10use std::sync::Arc;
11use uuid::Uuid;
12
13pub struct EtatDateUseCases {
14 repository: Arc<dyn EtatDateRepository>,
15 unit_repository: Arc<dyn UnitRepository>,
16 building_repository: Arc<dyn BuildingRepository>,
17 unit_owner_repository: Arc<dyn UnitOwnerRepository>,
18}
19
20impl EtatDateUseCases {
21 pub fn new(
22 repository: Arc<dyn EtatDateRepository>,
23 unit_repository: Arc<dyn UnitRepository>,
24 building_repository: Arc<dyn BuildingRepository>,
25 unit_owner_repository: Arc<dyn UnitOwnerRepository>,
26 ) -> Self {
27 Self {
28 repository,
29 unit_repository,
30 building_repository,
31 unit_owner_repository,
32 }
33 }
34
35 pub async fn create_etat_date(
37 &self,
38 request: CreateEtatDateRequest,
39 ) -> Result<EtatDateResponse, String> {
40 let unit = self
42 .unit_repository
43 .find_by_id(request.unit_id)
44 .await?
45 .ok_or_else(|| "Unit not found".to_string())?;
46
47 let building = self
49 .building_repository
50 .find_by_id(request.building_id)
51 .await?
52 .ok_or_else(|| "Building not found".to_string())?;
53
54 let unit_owners = self
56 .unit_owner_repository
57 .find_current_owners_by_unit(request.unit_id)
58 .await?;
59
60 if unit_owners.is_empty() {
61 return Err("Unit has no active owners".to_string());
62 }
63
64 let total_quota: f64 = unit_owners.iter().map(|uo| uo.ownership_percentage).sum();
66
67 let ordinary_charges_quota = total_quota * 100.0; let extraordinary_charges_quota = ordinary_charges_quota;
71
72 let etat_date = EtatDate::new(
74 request.organization_id,
75 request.building_id,
76 request.unit_id,
77 request.reference_date,
78 request.language,
79 request.notary_name,
80 request.notary_email,
81 request.notary_phone,
82 building.name.clone(),
83 building.address.clone(),
84 unit.unit_number.clone(),
85 unit.floor.map(|f| f.to_string()),
86 Some(unit.surface_area),
87 ordinary_charges_quota,
88 extraordinary_charges_quota,
89 )?;
90
91 let created = self.repository.create(&etat_date).await?;
92 Ok(EtatDateResponse::from(created))
93 }
94
95 pub async fn get_etat_date(&self, id: Uuid) -> Result<Option<EtatDateResponse>, String> {
97 let etat_date = self.repository.find_by_id(id).await?;
98 Ok(etat_date.map(EtatDateResponse::from))
99 }
100
101 pub async fn get_by_reference_number(
103 &self,
104 reference_number: &str,
105 ) -> Result<Option<EtatDateResponse>, String> {
106 let etat_date = self
107 .repository
108 .find_by_reference_number(reference_number)
109 .await?;
110 Ok(etat_date.map(EtatDateResponse::from))
111 }
112
113 pub async fn list_by_unit(&self, unit_id: Uuid) -> Result<Vec<EtatDateResponse>, String> {
115 let etats = self.repository.find_by_unit(unit_id).await?;
116 Ok(etats.into_iter().map(EtatDateResponse::from).collect())
117 }
118
119 pub async fn list_by_building(
121 &self,
122 building_id: Uuid,
123 ) -> Result<Vec<EtatDateResponse>, String> {
124 let etats = self.repository.find_by_building(building_id).await?;
125 Ok(etats.into_iter().map(EtatDateResponse::from).collect())
126 }
127
128 pub async fn list_paginated(
130 &self,
131 page_request: &PageRequest,
132 organization_id: Option<Uuid>,
133 status: Option<EtatDateStatus>,
134 ) -> Result<(Vec<EtatDateResponse>, i64), String> {
135 let (etats, total) = self
136 .repository
137 .find_all_paginated(page_request, organization_id, status)
138 .await?;
139
140 let dtos = etats.into_iter().map(EtatDateResponse::from).collect();
141 Ok((dtos, total))
142 }
143
144 pub async fn mark_in_progress(&self, id: Uuid) -> Result<EtatDateResponse, String> {
146 let mut etat_date = self
147 .repository
148 .find_by_id(id)
149 .await?
150 .ok_or_else(|| "État daté not found".to_string())?;
151
152 etat_date.mark_in_progress()?;
153
154 let updated = self.repository.update(&etat_date).await?;
155 Ok(EtatDateResponse::from(updated))
156 }
157
158 pub async fn mark_generated(
160 &self,
161 id: Uuid,
162 pdf_file_path: String,
163 ) -> Result<EtatDateResponse, String> {
164 let mut etat_date = self
165 .repository
166 .find_by_id(id)
167 .await?
168 .ok_or_else(|| "État daté not found".to_string())?;
169
170 etat_date.mark_generated(pdf_file_path)?;
171
172 let updated = self.repository.update(&etat_date).await?;
173 Ok(EtatDateResponse::from(updated))
174 }
175
176 pub async fn mark_delivered(&self, id: Uuid) -> Result<EtatDateResponse, String> {
178 let mut etat_date = self
179 .repository
180 .find_by_id(id)
181 .await?
182 .ok_or_else(|| "État daté not found".to_string())?;
183
184 etat_date.mark_delivered()?;
185
186 let updated = self.repository.update(&etat_date).await?;
187 Ok(EtatDateResponse::from(updated))
188 }
189
190 pub async fn update_financial_data(
192 &self,
193 id: Uuid,
194 request: UpdateEtatDateFinancialRequest,
195 ) -> Result<EtatDateResponse, String> {
196 let mut etat_date = self
197 .repository
198 .find_by_id(id)
199 .await?
200 .ok_or_else(|| "État daté not found".to_string())?;
201
202 etat_date.update_financial_data(
203 request.owner_balance,
204 request.arrears_amount,
205 request.monthly_provision_amount,
206 request.total_balance,
207 request.approved_works_unpaid,
208 )?;
209
210 let updated = self.repository.update(&etat_date).await?;
211 Ok(EtatDateResponse::from(updated))
212 }
213
214 pub async fn update_additional_data(
216 &self,
217 id: Uuid,
218 request: UpdateEtatDateAdditionalDataRequest,
219 ) -> Result<EtatDateResponse, String> {
220 let mut etat_date = self
221 .repository
222 .find_by_id(id)
223 .await?
224 .ok_or_else(|| "État daté not found".to_string())?;
225
226 etat_date.update_additional_data(request.additional_data)?;
227
228 let updated = self.repository.update(&etat_date).await?;
229 Ok(EtatDateResponse::from(updated))
230 }
231
232 pub async fn list_overdue(
234 &self,
235 organization_id: Uuid,
236 ) -> Result<Vec<EtatDateResponse>, String> {
237 let etats = self.repository.find_overdue(organization_id).await?;
238 Ok(etats.into_iter().map(EtatDateResponse::from).collect())
239 }
240
241 pub async fn list_expired(
243 &self,
244 organization_id: Uuid,
245 ) -> Result<Vec<EtatDateResponse>, String> {
246 let etats = self.repository.find_expired(organization_id).await?;
247 Ok(etats.into_iter().map(EtatDateResponse::from).collect())
248 }
249
250 pub async fn delete_etat_date(&self, id: Uuid) -> Result<bool, String> {
252 self.repository.delete(id).await
253 }
254
255 pub async fn get_stats(&self, organization_id: Uuid) -> Result<EtatDateStatsResponse, String> {
257 self.repository.get_stats(organization_id).await
258 }
259}