backbone_pos/presentation/dto/
pos_table_dto.rs1use 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#[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#[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#[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 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#[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#[derive(Debug, Clone, Serialize)]
133#[cfg_attr(feature = "openapi", derive(ToSchema))]
134#[serde(rename_all = "camelCase")]
135pub struct PosTableListResponseDto {
136 pub items: Vec<PosTableResponseDto>,
138 pub total: u64,
140 pub page: u32,
142 pub per_page: u32,
144 pub total_pages: u32,
146 pub has_next: bool,
148 pub has_prev: bool,
150}
151
152impl PosTableListResponseDto {
153 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#[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
184impl 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