Skip to main content

koprogo_api/application/dto/
contractor_report_dto.rs

1use crate::domain::entities::contractor_report::{ContractorReport, ReplacedPart};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6/// Création d'un rapport par le corps de métier (via magic link ou syndic)
7#[derive(Debug, Deserialize, utoipa::ToSchema)]
8pub struct CreateContractorReportDto {
9    pub building_id: Uuid,
10    pub contractor_name: String,
11    pub ticket_id: Option<Uuid>,
12    pub quote_id: Option<Uuid>,
13    pub contractor_user_id: Option<Uuid>,
14}
15
16/// Mise à jour du brouillon (photos, pièces, compte-rendu)
17///
18/// `ToSchema` est requis depuis la fusion du 2026-09-15 : `magic_link_handlers`
19/// expose ce DTO dans un `#[utoipa::path]`, et utoipa exige alors qu'il sache
20/// se décrire. Les deux branches étaient justes séparément — l'une ajoutait le
21/// handler, l'autre le DTO — et leur rencontre a produit l'incohérence. C'est
22/// le genre de défaut qu'aucune des deux revues n'aurait pu voir.
23#[derive(Debug, Deserialize, utoipa::ToSchema)]
24pub struct UpdateContractorReportDto {
25    pub work_date: Option<DateTime<Utc>>,
26    pub compte_rendu: Option<String>,
27    pub photos_before: Option<Vec<Uuid>>,
28    pub photos_after: Option<Vec<Uuid>>,
29    pub parts_replaced: Option<Vec<ReplacedPartDto>>,
30}
31
32#[derive(Debug, Deserialize, Serialize, utoipa::ToSchema)]
33pub struct ReplacedPartDto {
34    pub name: String,
35    pub reference: Option<String>,
36    pub quantity: u32,
37    pub photo_document_id: Option<Uuid>,
38}
39
40impl From<ReplacedPartDto> for ReplacedPart {
41    fn from(d: ReplacedPartDto) -> Self {
42        ReplacedPart {
43            name: d.name,
44            reference: d.reference,
45            quantity: d.quantity,
46            photo_document_id: d.photo_document_id,
47        }
48    }
49}
50
51impl From<&ReplacedPart> for ReplacedPartDto {
52    fn from(p: &ReplacedPart) -> Self {
53        ReplacedPartDto {
54            name: p.name.clone(),
55            reference: p.reference.clone(),
56            quantity: p.quantity,
57            photo_document_id: p.photo_document_id,
58        }
59    }
60}
61
62/// Demande de corrections par le CdC
63#[derive(Debug, Deserialize, utoipa::ToSchema)]
64pub struct RequestCorrectionsDto {
65    pub comments: String,
66}
67
68/// Rejet par le CdC
69#[derive(Debug, Deserialize, utoipa::ToSchema)]
70pub struct RejectReportDto {
71    pub comments: String,
72}
73
74/// Génération du magic link (syndic → corps de métier)
75#[derive(Debug, Deserialize, utoipa::ToSchema)]
76pub struct GenerateMagicLinkDto {
77    pub report_id: Uuid,
78}
79
80/// Réponse magic link
81#[derive(Debug, Serialize)]
82pub struct MagicLinkResponseDto {
83    pub magic_link: String,
84    pub expires_at: DateTime<Utc>,
85}
86
87/// Réponse complète d'un rapport de travaux
88#[derive(Debug, Serialize)]
89pub struct ContractorReportResponseDto {
90    pub id: Uuid,
91    pub organization_id: Uuid,
92    pub building_id: Uuid,
93    pub ticket_id: Option<Uuid>,
94    pub quote_id: Option<Uuid>,
95    pub contractor_user_id: Option<Uuid>,
96    pub contractor_name: String,
97    pub work_date: Option<DateTime<Utc>>,
98    pub compte_rendu: Option<String>,
99    pub photos_before: Vec<Uuid>,
100    pub photos_after: Vec<Uuid>,
101    pub parts_replaced: Vec<ReplacedPartDto>,
102    pub status: String,
103    pub submitted_at: Option<DateTime<Utc>>,
104    pub validated_at: Option<DateTime<Utc>>,
105    pub validated_by: Option<Uuid>,
106    pub review_comments: Option<String>,
107    pub created_at: DateTime<Utc>,
108    pub updated_at: DateTime<Utc>,
109}
110
111impl From<&ContractorReport> for ContractorReportResponseDto {
112    fn from(r: &ContractorReport) -> Self {
113        ContractorReportResponseDto {
114            id: r.id,
115            organization_id: r.organization_id,
116            building_id: r.building_id,
117            ticket_id: r.ticket_id,
118            quote_id: r.quote_id,
119            contractor_user_id: r.contractor_user_id,
120            contractor_name: r.contractor_name.clone(),
121            work_date: r.work_date,
122            compte_rendu: r.compte_rendu.clone(),
123            photos_before: r.photos_before.clone(),
124            photos_after: r.photos_after.clone(),
125            parts_replaced: r.parts_replaced.iter().map(ReplacedPartDto::from).collect(),
126            status: r.status.to_db_str().to_string(),
127            submitted_at: r.submitted_at,
128            validated_at: r.validated_at,
129            validated_by: r.validated_by,
130            review_comments: r.review_comments.clone(),
131            created_at: r.created_at,
132            updated_at: r.updated_at,
133        }
134    }
135}