Skip to main content

backbone_inventory/presentation/dto/
package_dto.rs

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