Skip to main content

koprogo_api/application/dto/
work_report_dto.rs

1//! Work report DTOs — les montants utilisent `rust_decimal::Decimal` (ADR-0007/0008).
2//!
3//! Deux notes qui expliquent les attributs serde ci-dessous :
4//!
5//! 1. `validator` ne sait pas borner un `Decimal` (`#[validate(range(...))]`
6//!    n'accepte que des littéraux flottants). L'invariant « coût ≥ 0 » descend
7//!    donc dans le domaine — `WorkReport::new` / `WorkReport::set_cost` — où il
8//!    couvre tous les appelants et plus seulement la route HTTP.
9//!
10//! 2. Un `Decimal` nu sérialise en **chaîne** JSON (`"1500.00"`), là où le type
11//!    d'avant produisait un nombre (`1500.0`). `serde::float` /
12//!    `serde::float_option` préservent la représentation numérique : la
13//!    conversion ne provoque donc AUCUN drift de contrat API. Le `default` sur
14//!    les champs optionnels est indispensable : `#[serde(with = ...)]` fait
15//!    perdre le défaut implicite d'un `Option` absent, et un `cost` omis dans
16//!    une mise à jour partielle deviendrait un 400 « missing field ».
17
18use crate::domain::entities::{WarrantyType, WorkType};
19use rust_decimal::Decimal;
20use serde::{Deserialize, Serialize};
21use validator::Validate;
22
23#[derive(Debug, Deserialize, Validate, Clone)]
24pub struct CreateWorkReportDto {
25    pub organization_id: String,
26    pub building_id: String,
27
28    #[validate(length(min = 1, max = 255))]
29    pub title: String,
30
31    #[validate(length(min = 1))]
32    pub description: String,
33
34    pub work_type: WorkType,
35
36    #[validate(length(min = 1, max = 255))]
37    pub contractor_name: String,
38
39    #[validate(length(max = 255))]
40    pub contractor_contact: Option<String>,
41
42    pub work_date: String,               // ISO 8601 format
43    pub completion_date: Option<String>, // ISO 8601 format
44
45    #[serde(with = "rust_decimal::serde::float")]
46    pub cost: Decimal,
47
48    #[validate(length(max = 100))]
49    pub invoice_number: Option<String>,
50
51    pub notes: Option<String>,
52    pub warranty_type: WarrantyType,
53}
54
55#[derive(Debug, Deserialize, Validate, Clone)]
56pub struct UpdateWorkReportDto {
57    #[validate(length(min = 1, max = 255))]
58    pub title: Option<String>,
59
60    #[validate(length(min = 1))]
61    pub description: Option<String>,
62
63    pub work_type: Option<WorkType>,
64
65    #[validate(length(min = 1, max = 255))]
66    pub contractor_name: Option<String>,
67
68    #[validate(length(max = 255))]
69    pub contractor_contact: Option<String>,
70
71    pub work_date: Option<String>,
72    pub completion_date: Option<String>,
73
74    #[serde(default, with = "rust_decimal::serde::float_option")]
75    pub cost: Option<Decimal>,
76
77    #[validate(length(max = 100))]
78    pub invoice_number: Option<String>,
79
80    pub notes: Option<String>,
81    pub warranty_type: Option<WarrantyType>,
82}
83
84#[derive(Debug, Serialize)]
85pub struct WorkReportResponseDto {
86    pub id: String,
87    pub organization_id: String,
88    pub building_id: String,
89    pub title: String,
90    pub description: String,
91    pub work_type: WorkType,
92    pub contractor_name: String,
93    pub contractor_contact: Option<String>,
94    pub work_date: String,
95    pub completion_date: Option<String>,
96    #[serde(with = "rust_decimal::serde::float")]
97    pub cost: Decimal,
98    pub invoice_number: Option<String>,
99    pub photos: Vec<String>,
100    pub documents: Vec<String>,
101    pub notes: Option<String>,
102    pub warranty_type: WarrantyType,
103    pub warranty_expiry: String,
104    pub is_warranty_valid: bool,
105    pub warranty_days_remaining: i64,
106    pub created_at: String,
107    pub updated_at: String,
108}
109
110#[derive(Debug, Deserialize, Validate)]
111pub struct AddPhotoDto {
112    #[validate(length(min = 1))]
113    pub photo_path: String,
114}
115
116#[derive(Debug, Deserialize, Validate)]
117pub struct AddDocumentDto {
118    #[validate(length(min = 1))]
119    pub document_path: String,
120}
121
122#[derive(Debug, Serialize)]
123pub struct WorkReportListResponseDto {
124    pub work_reports: Vec<WorkReportResponseDto>,
125    pub total: i64,
126    pub page: i64,
127    pub page_size: i64,
128}
129
130#[derive(Debug, Serialize)]
131pub struct WarrantyStatusDto {
132    pub work_report_id: String,
133    pub title: String,
134    pub warranty_type: WarrantyType,
135    pub warranty_expiry: String,
136    pub is_valid: bool,
137    pub days_remaining: i64,
138}