koprogo_api/infrastructure/web/handlers/
etat_date_handlers.rs1use crate::application::dto::{
2 CreateEtatDateRequest, PageRequest, PageResponse, UpdateEtatDateAdditionalDataRequest,
3 UpdateEtatDateFinancialRequest,
4};
5use crate::domain::entities::EtatDateStatus;
6use crate::infrastructure::audit::{AuditEventType, AuditLogEntry};
7use crate::infrastructure::web::{AppState, AuthenticatedUser};
8use actix_web::{delete, get, post, put, web, HttpResponse, Responder};
9use uuid::Uuid;
10
11#[post("/etats-dates")]
13pub async fn create_etat_date(
14 state: web::Data<AppState>,
15 user: AuthenticatedUser,
16 mut request: web::Json<CreateEtatDateRequest>,
17) -> impl Responder {
18 let organization_id = match user.require_organization() {
20 Ok(org_id) => org_id,
21 Err(e) => {
22 return HttpResponse::Unauthorized().json(serde_json::json!({
23 "error": e.to_string()
24 }))
25 }
26 };
27 request.organization_id = organization_id;
28
29 match state
30 .etat_date_use_cases
31 .create_etat_date(request.into_inner())
32 .await
33 {
34 Ok(etat_date) => {
35 AuditLogEntry::new(
36 AuditEventType::EtatDateCreated,
37 Some(user.user_id),
38 Some(organization_id),
39 )
40 .with_resource("EtatDate", etat_date.id)
41 .log();
42
43 HttpResponse::Created().json(etat_date)
44 }
45 Err(err) => {
46 AuditLogEntry::new(
47 AuditEventType::EtatDateCreated,
48 Some(user.user_id),
49 Some(organization_id),
50 )
51 .with_error(err.clone())
52 .log();
53
54 HttpResponse::BadRequest().json(serde_json::json!({
55 "error": err
56 }))
57 }
58 }
59}
60
61#[get("/etats-dates/{id}")]
63pub async fn get_etat_date(state: web::Data<AppState>, id: web::Path<Uuid>) -> impl Responder {
64 match state.etat_date_use_cases.get_etat_date(*id).await {
65 Ok(Some(etat_date)) => HttpResponse::Ok().json(etat_date),
66 Ok(None) => HttpResponse::NotFound().json(serde_json::json!({
67 "error": "État daté not found"
68 })),
69 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
70 "error": err
71 })),
72 }
73}
74
75#[get("/etats-dates/reference/{reference_number}")]
77pub async fn get_by_reference_number(
78 state: web::Data<AppState>,
79 reference_number: web::Path<String>,
80) -> impl Responder {
81 match state
82 .etat_date_use_cases
83 .get_by_reference_number(&reference_number)
84 .await
85 {
86 Ok(Some(etat_date)) => HttpResponse::Ok().json(etat_date),
87 Ok(None) => HttpResponse::NotFound().json(serde_json::json!({
88 "error": "État daté not found"
89 })),
90 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
91 "error": err
92 })),
93 }
94}
95
96#[get("/etats-dates")]
98pub async fn list_etats_dates(
99 state: web::Data<AppState>,
100 user: AuthenticatedUser,
101 page_request: web::Query<PageRequest>,
102 status_filter: web::Query<Option<String>>,
103) -> impl Responder {
104 let organization_id = user.organization_id;
105
106 let status = status_filter.0.as_ref().and_then(|s| match s.as_str() {
108 "requested" => Some(EtatDateStatus::Requested),
109 "in_progress" => Some(EtatDateStatus::InProgress),
110 "generated" => Some(EtatDateStatus::Generated),
111 "delivered" => Some(EtatDateStatus::Delivered),
112 "expired" => Some(EtatDateStatus::Expired),
113 _ => None,
114 });
115
116 match state
117 .etat_date_use_cases
118 .list_paginated(&page_request, organization_id, status)
119 .await
120 {
121 Ok((etats, total)) => {
122 let response =
123 PageResponse::new(etats, page_request.page, page_request.per_page, total);
124 HttpResponse::Ok().json(response)
125 }
126 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
127 "error": err
128 })),
129 }
130}
131
132#[get("/units/{unit_id}/etats-dates")]
134pub async fn list_etats_dates_by_unit(
135 state: web::Data<AppState>,
136 unit_id: web::Path<Uuid>,
137) -> impl Responder {
138 match state.etat_date_use_cases.list_by_unit(*unit_id).await {
139 Ok(etats) => HttpResponse::Ok().json(etats),
140 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
141 "error": err
142 })),
143 }
144}
145
146#[get("/buildings/{building_id}/etats-dates")]
148pub async fn list_etats_dates_by_building(
149 state: web::Data<AppState>,
150 building_id: web::Path<Uuid>,
151) -> impl Responder {
152 match state
153 .etat_date_use_cases
154 .list_by_building(*building_id)
155 .await
156 {
157 Ok(etats) => HttpResponse::Ok().json(etats),
158 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
159 "error": err
160 })),
161 }
162}
163
164#[put("/etats-dates/{id}/mark-in-progress")]
166pub async fn mark_in_progress(
167 state: web::Data<AppState>,
168 user: AuthenticatedUser,
169 id: web::Path<Uuid>,
170) -> impl Responder {
171 match state.etat_date_use_cases.mark_in_progress(*id).await {
172 Ok(etat_date) => {
173 AuditLogEntry::new(
174 AuditEventType::EtatDateInProgress,
175 Some(user.user_id),
176 user.organization_id,
177 )
178 .with_resource("EtatDate", etat_date.id)
179 .log();
180
181 HttpResponse::Ok().json(etat_date)
182 }
183 Err(err) => HttpResponse::BadRequest().json(serde_json::json!({
184 "error": err
185 })),
186 }
187}
188
189#[put("/etats-dates/{id}/mark-generated")]
191pub async fn mark_generated(
192 state: web::Data<AppState>,
193 user: AuthenticatedUser,
194 id: web::Path<Uuid>,
195 pdf_path: web::Json<serde_json::Value>,
196) -> impl Responder {
197 let pdf_file_path = match pdf_path.get("pdf_file_path") {
198 Some(serde_json::Value::String(path)) => path.clone(),
199 _ => {
200 return HttpResponse::BadRequest().json(serde_json::json!({
201 "error": "pdf_file_path is required as a string"
202 }))
203 }
204 };
205
206 match state
207 .etat_date_use_cases
208 .mark_generated(*id, pdf_file_path)
209 .await
210 {
211 Ok(etat_date) => {
212 AuditLogEntry::new(
213 AuditEventType::EtatDateGenerated,
214 Some(user.user_id),
215 user.organization_id,
216 )
217 .with_resource("EtatDate", etat_date.id)
218 .log();
219
220 HttpResponse::Ok().json(etat_date)
221 }
222 Err(err) => HttpResponse::BadRequest().json(serde_json::json!({
223 "error": err
224 })),
225 }
226}
227
228#[put("/etats-dates/{id}/mark-delivered")]
230pub async fn mark_delivered(
231 state: web::Data<AppState>,
232 user: AuthenticatedUser,
233 id: web::Path<Uuid>,
234) -> impl Responder {
235 match state.etat_date_use_cases.mark_delivered(*id).await {
236 Ok(etat_date) => {
237 AuditLogEntry::new(
238 AuditEventType::EtatDateDelivered,
239 Some(user.user_id),
240 user.organization_id,
241 )
242 .with_resource("EtatDate", etat_date.id)
243 .log();
244
245 HttpResponse::Ok().json(etat_date)
246 }
247 Err(err) => HttpResponse::BadRequest().json(serde_json::json!({
248 "error": err
249 })),
250 }
251}
252
253#[put("/etats-dates/{id}/financial")]
255pub async fn update_financial_data(
256 state: web::Data<AppState>,
257 user: AuthenticatedUser,
258 id: web::Path<Uuid>,
259 request: web::Json<UpdateEtatDateFinancialRequest>,
260) -> impl Responder {
261 match state
262 .etat_date_use_cases
263 .update_financial_data(*id, request.into_inner())
264 .await
265 {
266 Ok(etat_date) => {
267 AuditLogEntry::new(
268 AuditEventType::EtatDateFinancialUpdate,
269 Some(user.user_id),
270 user.organization_id,
271 )
272 .with_resource("EtatDate", etat_date.id)
273 .log();
274
275 HttpResponse::Ok().json(etat_date)
276 }
277 Err(err) => HttpResponse::BadRequest().json(serde_json::json!({
278 "error": err
279 })),
280 }
281}
282
283#[put("/etats-dates/{id}/additional-data")]
285pub async fn update_additional_data(
286 state: web::Data<AppState>,
287 user: AuthenticatedUser,
288 id: web::Path<Uuid>,
289 request: web::Json<UpdateEtatDateAdditionalDataRequest>,
290) -> impl Responder {
291 match state
292 .etat_date_use_cases
293 .update_additional_data(*id, request.into_inner())
294 .await
295 {
296 Ok(etat_date) => {
297 AuditLogEntry::new(
298 AuditEventType::EtatDateAdditionalDataUpdate,
299 Some(user.user_id),
300 user.organization_id,
301 )
302 .with_resource("EtatDate", etat_date.id)
303 .log();
304
305 HttpResponse::Ok().json(etat_date)
306 }
307 Err(err) => HttpResponse::BadRequest().json(serde_json::json!({
308 "error": err
309 })),
310 }
311}
312
313#[get("/etats-dates/overdue")]
315pub async fn list_overdue(state: web::Data<AppState>, user: AuthenticatedUser) -> impl Responder {
316 let organization_id = match user.require_organization() {
317 Ok(org_id) => org_id,
318 Err(e) => {
319 return HttpResponse::Unauthorized().json(serde_json::json!({
320 "error": e.to_string()
321 }))
322 }
323 };
324
325 match state
326 .etat_date_use_cases
327 .list_overdue(organization_id)
328 .await
329 {
330 Ok(etats) => HttpResponse::Ok().json(etats),
331 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
332 "error": err
333 })),
334 }
335}
336
337#[get("/etats-dates/expired")]
339pub async fn list_expired(state: web::Data<AppState>, user: AuthenticatedUser) -> impl Responder {
340 let organization_id = match user.require_organization() {
341 Ok(org_id) => org_id,
342 Err(e) => {
343 return HttpResponse::Unauthorized().json(serde_json::json!({
344 "error": e.to_string()
345 }))
346 }
347 };
348
349 match state
350 .etat_date_use_cases
351 .list_expired(organization_id)
352 .await
353 {
354 Ok(etats) => HttpResponse::Ok().json(etats),
355 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
356 "error": err
357 })),
358 }
359}
360
361#[get("/etats-dates/stats")]
363pub async fn get_stats(state: web::Data<AppState>, user: AuthenticatedUser) -> impl Responder {
364 let organization_id = match user.require_organization() {
365 Ok(org_id) => org_id,
366 Err(e) => {
367 return HttpResponse::Unauthorized().json(serde_json::json!({
368 "error": e.to_string()
369 }))
370 }
371 };
372
373 match state.etat_date_use_cases.get_stats(organization_id).await {
374 Ok(stats) => HttpResponse::Ok().json(stats),
375 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
376 "error": err
377 })),
378 }
379}
380
381#[delete("/etats-dates/{id}")]
383pub async fn delete_etat_date(
384 state: web::Data<AppState>,
385 user: AuthenticatedUser,
386 id: web::Path<Uuid>,
387) -> impl Responder {
388 match state.etat_date_use_cases.delete_etat_date(*id).await {
389 Ok(true) => {
390 AuditLogEntry::new(
391 AuditEventType::EtatDateDeleted,
392 Some(user.user_id),
393 user.organization_id,
394 )
395 .with_resource("EtatDate", *id)
396 .log();
397
398 HttpResponse::NoContent().finish()
399 }
400 Ok(false) => HttpResponse::NotFound().json(serde_json::json!({
401 "error": "État daté not found"
402 })),
403 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
404 "error": err
405 })),
406 }
407}