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