koprogo_api/application/dto/
age_request_dto.rs

1use crate::domain::entities::age_request::{AgeRequest, AgeRequestCosignatory, AgeRequestStatus};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// Créer une nouvelle demande d'AGE
7#[derive(Debug, Deserialize)]
8pub struct CreateAgeRequestDto {
9    pub building_id: Uuid,
10    pub title: String,
11    pub description: Option<String>,
12}
13
14/// Ajouter un cosignataire
15#[derive(Debug, Deserialize)]
16pub struct AddCosignatoryDto {
17    pub owner_id: Uuid,
18    /// Quote-part du copropriétaire (0.0 à 1.0)
19    pub shares_pct: f64,
20}
21
22/// Réponse du syndic (accept ou reject)
23#[derive(Debug, Deserialize)]
24pub struct SyndicResponseDto {
25    pub accepted: bool,
26    /// Obligatoire si accepted = false
27    pub notes: Option<String>,
28}
29
30/// DTO cosignataire dans la réponse
31#[derive(Debug, Serialize, Clone)]
32pub struct AgeRequestCosignatoryDto {
33    pub id: Uuid,
34    pub owner_id: Uuid,
35    pub shares_pct: f64,
36    pub signed_at: DateTime<Utc>,
37}
38
39impl From<&AgeRequestCosignatory> for AgeRequestCosignatoryDto {
40    fn from(c: &AgeRequestCosignatory) -> Self {
41        Self {
42            id: c.id,
43            owner_id: c.owner_id,
44            shares_pct: c.shares_pct,
45            signed_at: c.signed_at,
46        }
47    }
48}
49
50/// Réponse complète d'une demande d'AGE
51#[derive(Debug, Serialize, Clone)]
52pub struct AgeRequestResponseDto {
53    pub id: Uuid,
54    pub organization_id: Uuid,
55    pub building_id: Uuid,
56    pub title: String,
57    pub description: Option<String>,
58    pub status: String,
59    pub created_by: Uuid,
60    pub cosignatories: Vec<AgeRequestCosignatoryDto>,
61    pub total_shares_pct: f64,
62    pub threshold_pct: f64,
63    pub threshold_reached: bool,
64    pub threshold_reached_at: Option<DateTime<Utc>>,
65    pub submitted_to_syndic_at: Option<DateTime<Utc>>,
66    pub syndic_deadline_at: Option<DateTime<Utc>>,
67    pub syndic_response_at: Option<DateTime<Utc>>,
68    pub syndic_notes: Option<String>,
69    pub auto_convocation_triggered: bool,
70    pub meeting_id: Option<Uuid>,
71    pub concertation_poll_id: Option<Uuid>,
72    /// Pourcentage manquant pour atteindre le seuil (0.0 si déjà atteint)
73    pub shares_pct_missing: f64,
74    /// Le délai syndic est-il dépassé ?
75    pub is_deadline_expired: bool,
76    pub created_at: DateTime<Utc>,
77    pub updated_at: DateTime<Utc>,
78}
79
80impl From<&AgeRequest> for AgeRequestResponseDto {
81    fn from(r: &AgeRequest) -> Self {
82        Self {
83            id: r.id,
84            organization_id: r.organization_id,
85            building_id: r.building_id,
86            title: r.title.clone(),
87            description: r.description.clone(),
88            status: r.status.to_db_str().to_string(),
89            created_by: r.created_by,
90            cosignatories: r
91                .cosignatories
92                .iter()
93                .map(AgeRequestCosignatoryDto::from)
94                .collect(),
95            total_shares_pct: r.total_shares_pct,
96            threshold_pct: r.threshold_pct,
97            threshold_reached: r.threshold_reached,
98            threshold_reached_at: r.threshold_reached_at,
99            submitted_to_syndic_at: r.submitted_to_syndic_at,
100            syndic_deadline_at: r.syndic_deadline_at,
101            syndic_response_at: r.syndic_response_at,
102            syndic_notes: r.syndic_notes.clone(),
103            auto_convocation_triggered: r.auto_convocation_triggered,
104            meeting_id: r.meeting_id,
105            concertation_poll_id: r.concertation_poll_id,
106            shares_pct_missing: r.shares_pct_missing(),
107            is_deadline_expired: r.is_deadline_expired(),
108            created_at: r.created_at,
109            updated_at: r.updated_at,
110        }
111    }
112}
113
114impl From<AgeRequestStatus> for String {
115    fn from(s: AgeRequestStatus) -> Self {
116        s.to_db_str().to_string()
117    }
118}