Skip to main content

koprogo_api/application/dto/
age_request_dto.rs

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