koprogo_api/application/dto/
expense_dto.rs

1use crate::domain::entities::{ApprovalStatus, ExpenseCategory, PaymentStatus};
2use serde::{Deserialize, Serialize};
3use validator::Validate;
4
5// ========== Legacy DTOs (backward compatibility) ==========
6
7#[derive(Debug, Deserialize, Validate, Clone)]
8pub struct CreateExpenseDto {
9    #[serde(default)]
10    pub organization_id: String,
11    pub building_id: String,
12    pub category: ExpenseCategory,
13
14    #[validate(length(min = 1))]
15    pub description: String,
16
17    #[validate(range(min = 0.01))]
18    pub amount: f64,
19
20    pub expense_date: String,
21    pub supplier: Option<String>,
22    pub invoice_number: Option<String>,
23
24    /// Optional Belgian PCMN account code (e.g., "604001" for electricity)
25    /// Must reference an existing account in the organization's chart of accounts
26    #[validate(length(max = 40))]
27    pub account_code: Option<String>,
28}
29
30#[derive(Debug, Serialize)]
31pub struct ExpenseResponseDto {
32    pub id: String,
33    pub building_id: String,
34    pub category: ExpenseCategory,
35    pub description: String,
36    pub amount: f64,
37    pub expense_date: String,
38    pub payment_status: PaymentStatus,
39    pub approval_status: ApprovalStatus,
40    pub supplier: Option<String>,
41    pub invoice_number: Option<String>,
42    /// Belgian PCMN account code if linked to chart of accounts
43    pub account_code: Option<String>,
44    /// Contractor report reference for Works category (Issue #309)
45    pub contractor_report_id: Option<String>,
46}
47
48// ========== New Invoice DTOs (with VAT & Workflow) ==========
49
50/// Créer une facture brouillon avec gestion TVA
51#[derive(Debug, Deserialize, Validate, Clone)]
52pub struct CreateInvoiceDraftDto {
53    #[serde(default)]
54    pub organization_id: String,
55    pub building_id: String,
56    pub category: ExpenseCategory,
57
58    #[validate(length(min = 1))]
59    pub description: String,
60
61    #[validate(range(min = 0.01))]
62    pub amount_excl_vat: f64, // Montant HT
63
64    #[validate(range(min = 0.0, max = 100.0))]
65    pub vat_rate: f64, // Taux TVA (21.0 pour 21%)
66
67    pub invoice_date: String,     // ISO 8601
68    pub due_date: Option<String>, // ISO 8601
69    pub supplier: Option<String>,
70    pub invoice_number: Option<String>,
71}
72
73/// Modifier une facture brouillon ou rejetée
74#[derive(Debug, Deserialize, Validate, Clone)]
75pub struct UpdateInvoiceDraftDto {
76    #[validate(length(min = 1))]
77    pub description: Option<String>,
78
79    pub category: Option<ExpenseCategory>,
80
81    #[validate(range(min = 0.01))]
82    pub amount_excl_vat: Option<f64>,
83
84    #[validate(range(min = 0.0, max = 100.0))]
85    pub vat_rate: Option<f64>,
86
87    pub invoice_date: Option<String>,
88    pub due_date: Option<String>,
89    pub supplier: Option<String>,
90    pub invoice_number: Option<String>,
91}
92
93/// Soumettre une facture pour validation (Draft → PendingApproval)
94#[derive(Debug, Deserialize, Clone)]
95pub struct SubmitForApprovalDto {
96    // Empty body, action via PUT /invoices/:id/submit
97}
98
99/// Approuver une facture (PendingApproval → Approved)
100#[derive(Debug, Deserialize, Clone)]
101pub struct ApproveInvoiceDto {
102    pub approved_by_user_id: String, // User ID du syndic/admin
103}
104
105/// Rejeter une facture avec raison (PendingApproval → Rejected)
106#[derive(Debug, Deserialize, Validate, Clone)]
107pub struct RejectInvoiceDto {
108    pub rejected_by_user_id: String,
109
110    #[validate(length(min = 1))]
111    pub rejection_reason: String,
112}
113
114/// Créer une ligne de facture
115#[derive(Debug, Deserialize, Validate, Clone)]
116pub struct CreateInvoiceLineItemDto {
117    pub expense_id: String,
118
119    #[validate(length(min = 1))]
120    pub description: String,
121
122    #[validate(range(min = 0.01))]
123    pub quantity: f64,
124
125    #[validate(range(min = 0.0))]
126    pub unit_price: f64,
127
128    #[validate(range(min = 0.0, max = 100.0))]
129    pub vat_rate: f64,
130}
131
132// ========== Response DTOs ==========
133
134/// Response enrichie avec tous les champs invoice/workflow
135#[derive(Debug, Serialize, Clone)]
136pub struct InvoiceResponseDto {
137    pub id: String,
138    pub organization_id: String,
139    pub building_id: String,
140    pub category: ExpenseCategory,
141    pub description: String,
142
143    // Montants
144    pub amount: f64, // TTC (backward compatibility)
145    pub amount_excl_vat: Option<f64>,
146    pub vat_rate: Option<f64>,
147    pub vat_amount: Option<f64>,
148    pub amount_incl_vat: Option<f64>,
149
150    // Dates
151    pub expense_date: String,
152    pub invoice_date: Option<String>,
153    pub due_date: Option<String>,
154    pub paid_date: Option<String>,
155
156    // Workflow
157    pub approval_status: ApprovalStatus,
158    pub submitted_at: Option<String>,
159    pub approved_by: Option<String>,
160    pub approved_at: Option<String>,
161    pub rejection_reason: Option<String>,
162
163    // Payment
164    pub payment_status: PaymentStatus,
165    pub supplier: Option<String>,
166    pub invoice_number: Option<String>,
167
168    /// Contractor report reference for Works category (Issue #309)
169    pub contractor_report_id: Option<String>,
170
171    pub created_at: String,
172    pub updated_at: String,
173}
174
175/// Response pour une ligne de facture
176#[derive(Debug, Serialize)]
177pub struct InvoiceLineItemResponseDto {
178    pub id: String,
179    pub expense_id: String,
180    pub description: String,
181    pub quantity: f64,
182    pub unit_price: f64,
183    pub amount_excl_vat: f64,
184    pub vat_rate: f64,
185    pub vat_amount: f64,
186    pub amount_incl_vat: f64,
187    pub created_at: String,
188}
189
190/// Response pour une répartition de charge
191#[derive(Debug, Serialize)]
192pub struct ChargeDistributionResponseDto {
193    pub id: String,
194    pub expense_id: String,
195    pub unit_id: String,
196    pub owner_id: String,
197    pub quota_percentage: f64, // Sera converti en pourcentage côté client (0.25 → 25%)
198    pub amount_due: f64,
199    pub created_at: String,
200}
201
202/// Liste des factures en attente d'approbation (pour syndics)
203#[derive(Debug, Serialize)]
204pub struct PendingInvoicesListDto {
205    pub invoices: Vec<InvoiceResponseDto>,
206    pub count: usize,
207}