backbone_inventory/presentation/dto/
route_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::Route;
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 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#[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#[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 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#[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#[derive(Debug, Clone, Serialize)]
154#[cfg_attr(feature = "openapi", derive(ToSchema))]
155#[serde(rename_all = "camelCase")]
156pub struct RouteListResponseDto {
157 pub items: Vec<RouteResponseDto>,
159 pub total: u64,
161 pub page: u32,
163 pub per_page: u32,
165 pub total_pages: u32,
167 pub has_next: bool,
169 pub has_prev: bool,
171}
172
173impl RouteListResponseDto {
174 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#[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
205impl 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