Skip to main content

backbone_inventory/presentation/dto/
route_dto.rs

1//! Route DTOs (Data Transfer Objects)
2//!
3//! Generated by metaphor-schema. Do not edit manually.
4//!
5//! DTOs provide a clean separation between domain entities and API
6//! representations, with OpenAPI documentation support.
7
8use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10use chrono::{DateTime, Utc};
11
12#[cfg(feature = "openapi")]
13#[cfg(feature = "openapi")]
14use utoipa::ToSchema;
15
16use crate::domain::entity::Route;
17use crate::domain::entity::AuditMetadata;
18
19// =============================================================================
20// Create DTO
21// =============================================================================
22
23/// Request DTO for creating a new Route
24///
25/// Used in POST requests to create new entities.
26/// Excludes auto-generated fields (id, created_at, updated_at, deleted_at).
27#[derive(Debug, Clone, Deserialize)]
28#[cfg_attr(feature = "openapi", derive(ToSchema))]
29#[serde(rename_all = "camelCase")]
30pub struct CreateRouteDto {
31    #[cfg_attr(feature = "openapi", schema(example = "example"))]
32    pub name: String,
33    #[cfg_attr(feature = "openapi", schema(example = true))]
34    pub active: bool,
35    #[cfg_attr(feature = "openapi", schema(example = 42))]
36    pub sequence: i32,
37    #[cfg_attr(feature = "openapi", schema(example = true))]
38    #[serde(alias = "product_selectable")]
39    pub product_selectable: bool,
40    #[cfg_attr(feature = "openapi", schema(example = true))]
41    #[serde(alias = "product_categ_selectable")]
42    pub product_categ_selectable: bool,
43    #[cfg_attr(feature = "openapi", schema(example = true))]
44    #[serde(alias = "warehouse_selectable")]
45    pub warehouse_selectable: bool,
46}
47
48// =============================================================================
49// Update DTO
50// =============================================================================
51
52/// Request DTO for full update of a Route
53///
54/// Used in PUT requests for full entity replacement.
55/// All fields are required (except auto-generated ones).
56#[derive(Debug, Clone, Deserialize)]
57#[cfg_attr(feature = "openapi", derive(ToSchema))]
58#[serde(rename_all = "camelCase")]
59pub struct UpdateRouteDto {
60    #[cfg_attr(feature = "openapi", schema(example = "example"))]
61    pub name: String,
62    #[cfg_attr(feature = "openapi", schema(example = true))]
63    pub active: bool,
64    #[cfg_attr(feature = "openapi", schema(example = 42))]
65    pub sequence: i32,
66    #[cfg_attr(feature = "openapi", schema(example = true))]
67    #[serde(alias = "product_selectable")]
68    pub product_selectable: bool,
69    #[cfg_attr(feature = "openapi", schema(example = true))]
70    #[serde(alias = "product_categ_selectable")]
71    pub product_categ_selectable: bool,
72    #[cfg_attr(feature = "openapi", schema(example = true))]
73    #[serde(alias = "warehouse_selectable")]
74    pub warehouse_selectable: bool,
75}
76
77// =============================================================================
78// Patch DTO
79// =============================================================================
80
81/// Request DTO for partial update of a Route
82///
83/// Used in PATCH requests for partial updates.
84/// All fields are optional - only provided fields will be updated.
85#[derive(Debug, Clone, Default, Deserialize)]
86#[cfg_attr(feature = "openapi", derive(ToSchema))]
87#[serde(rename_all = "camelCase")]
88pub struct PatchRouteDto {
89    #[cfg_attr(feature = "openapi", schema(example = "example"))]
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub name: Option<String>,
92    #[cfg_attr(feature = "openapi", schema(example = true))]
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub active: Option<bool>,
95    #[cfg_attr(feature = "openapi", schema(example = 42))]
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub sequence: Option<i32>,
98    #[cfg_attr(feature = "openapi", schema(example = true))]
99    #[serde(skip_serializing_if = "Option::is_none", alias = "product_selectable")]
100    pub product_selectable: Option<bool>,
101    #[cfg_attr(feature = "openapi", schema(example = true))]
102    #[serde(skip_serializing_if = "Option::is_none", alias = "product_categ_selectable")]
103    pub product_categ_selectable: Option<bool>,
104    #[cfg_attr(feature = "openapi", schema(example = true))]
105    #[serde(skip_serializing_if = "Option::is_none", alias = "warehouse_selectable")]
106    pub warehouse_selectable: Option<bool>,
107}
108
109impl PatchRouteDto {
110    /// Check if any field is set
111    pub fn has_changes(&self) -> bool {
112        self.name.is_some() || self.active.is_some() || self.sequence.is_some() || self.product_selectable.is_some() || self.product_categ_selectable.is_some() || self.warehouse_selectable.is_some()
113    }
114}
115
116// =============================================================================
117// Response DTO
118// =============================================================================
119
120/// Response DTO for Route entity
121///
122/// Used in API responses for single entity.
123/// Includes all fields including metadata.
124#[derive(Debug, Clone, Serialize)]
125#[cfg_attr(feature = "openapi", derive(ToSchema))]
126#[serde(rename_all = "camelCase")]
127pub struct RouteResponseDto {
128    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
129    pub id: Uuid,
130    #[cfg_attr(feature = "openapi", schema(example = "example"))]
131    pub name: String,
132    #[cfg_attr(feature = "openapi", schema(example = true))]
133    pub active: bool,
134    #[cfg_attr(feature = "openapi", schema(example = 42))]
135    pub sequence: i32,
136    #[cfg_attr(feature = "openapi", schema(example = true))]
137    pub product_selectable: bool,
138    #[cfg_attr(feature = "openapi", schema(example = true))]
139    pub product_categ_selectable: bool,
140    #[cfg_attr(feature = "openapi", schema(example = true))]
141    pub warehouse_selectable: bool,
142    pub metadata: AuditMetadata,
143}
144
145// =============================================================================
146// List Response DTO
147// =============================================================================
148
149/// Paginated list response for Route entities
150///
151/// Used in API responses for list endpoints.
152/// Includes pagination metadata.
153#[derive(Debug, Clone, Serialize)]
154#[cfg_attr(feature = "openapi", derive(ToSchema))]
155#[serde(rename_all = "camelCase")]
156pub struct RouteListResponseDto {
157    /// List of items
158    pub items: Vec<RouteResponseDto>,
159    /// Total number of items (across all pages)
160    pub total: u64,
161    /// Current page number (1-indexed)
162    pub page: u32,
163    /// Number of items per page
164    pub per_page: u32,
165    /// Total number of pages
166    pub total_pages: u32,
167    /// Whether there is a next page
168    pub has_next: bool,
169    /// Whether there is a previous page
170    pub has_prev: bool,
171}
172
173impl RouteListResponseDto {
174    /// Create a new list response from items and pagination info
175    pub fn new(items: Vec<RouteResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
176        let total_pages = if per_page > 0 {
177            ((total as f64) / (per_page as f64)).ceil() as u32
178        } else {
179            0
180        };
181        Self {
182            items,
183            total,
184            page,
185            per_page,
186            total_pages,
187            has_next: page < total_pages,
188            has_prev: page > 1,
189        }
190    }
191}
192
193/// Summary DTO for list views (compact version)
194#[derive(Debug, Clone, Serialize)]
195#[cfg_attr(feature = "openapi", derive(ToSchema))]
196#[serde(rename_all = "camelCase")]
197pub struct RouteSummaryDto {
198    pub id: Uuid,
199    pub name: String,
200    pub active: bool,
201    pub sequence: i32,
202    pub created_at: Option<DateTime<Utc>>,
203}
204
205// =============================================================================
206// Conversions
207// =============================================================================
208
209impl From<Route> for RouteResponseDto {
210    fn from(entity: Route) -> Self {
211        Self {
212            id: entity.id,
213            name: entity.name,
214            active: entity.active,
215            sequence: entity.sequence,
216            product_selectable: entity.product_selectable,
217            product_categ_selectable: entity.product_categ_selectable,
218            warehouse_selectable: entity.warehouse_selectable,
219            metadata: entity.metadata,
220        }
221    }
222}
223
224impl From<Route> for RouteSummaryDto {
225    fn from(entity: Route) -> Self {
226        let created_at = backbone_core::PersistentEntity::created_at(&entity);
227        Self {
228            id: entity.id,
229            name: entity.name,
230            active: entity.active,
231            sequence: entity.sequence,
232            created_at,
233        }
234    }
235}
236
237impl From<CreateRouteDto> for Route {
238    fn from(dto: CreateRouteDto) -> Self {
239        Self {
240            id: Uuid::new_v4(),
241            name: dto.name,
242            active: dto.active,
243            sequence: dto.sequence,
244            product_selectable: dto.product_selectable,
245            product_categ_selectable: dto.product_categ_selectable,
246            warehouse_selectable: dto.warehouse_selectable,
247            metadata: AuditMetadata::default(),
248        }
249    }
250}
251
252impl From<&Route> for RouteResponseDto {
253    fn from(entity: &Route) -> Self {
254        Self {
255            id: entity.id.clone(),
256            name: entity.name.clone(),
257            active: entity.active.clone(),
258            sequence: entity.sequence.clone(),
259            product_selectable: entity.product_selectable.clone(),
260            product_categ_selectable: entity.product_categ_selectable.clone(),
261            warehouse_selectable: entity.warehouse_selectable.clone(),
262            metadata: entity.metadata.clone(),
263        }
264    }
265}
266
267impl backbone_core::FromCreateDto<CreateRouteDto> for Route {
268    fn from_create_dto(dto: CreateRouteDto) -> backbone_core::ServiceResult<Self> {
269        Ok(Route::from(dto))
270    }
271}
272
273impl backbone_core::ApplyUpdateDto<UpdateRouteDto> for Route {
274    fn apply_update(mut self, dto: UpdateRouteDto) -> backbone_core::ServiceResult<Self> {
275        self.name = dto.name;
276        self.active = dto.active;
277        self.sequence = dto.sequence;
278        self.product_selectable = dto.product_selectable;
279        self.product_categ_selectable = dto.product_categ_selectable;
280        self.warehouse_selectable = dto.warehouse_selectable;
281        Ok(self)
282    }
283}
284
285// =============================================================================
286// Custom DTOs
287// =============================================================================
288
289// Add custom DTOs specific to Route here.
290// This section will be preserved during regeneration.
291// >>> END CUSTOM DTOs
292