Skip to main content

backbone_pos/presentation/dto/
pos_table_dto.rs

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