Skip to main content

backbone_inventory/presentation/dto/
route_rule_dto.rs

1//! RouteRule 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::RouteRule;
17use crate::domain::entity::AuditMetadata;
18use crate::domain::entity::ProcureMethod;
19use crate::domain::entity::RuleAction;
20use crate::domain::entity::RuleAuto;
21
22// =============================================================================
23// Create DTO
24// =============================================================================
25
26/// Request DTO for creating a new RouteRule
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#[serde(rename_all = "camelCase")]
33pub struct CreateRouteRuleDto {
34    #[cfg_attr(feature = "openapi", schema(example = "example"))]
35    pub name: String,
36    #[cfg_attr(feature = "openapi", schema(example = true))]
37    pub active: bool,
38    #[cfg_attr(feature = "openapi", schema(example = 42))]
39    pub sequence: i32,
40    pub action: RuleAction,
41    pub auto: RuleAuto,
42    #[serde(alias = "procure_method")]
43    pub procure_method: ProcureMethod,
44    #[cfg_attr(feature = "openapi", schema(example = 42))]
45    pub delay: i32,
46    #[serde(default, skip_serializing_if = "Option::is_none", alias = "location_src_id")]
47    pub location_src_id: Option<Uuid>,
48    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
49    #[serde(alias = "location_dest_id")]
50    pub location_dest_id: Uuid,
51    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
52    #[serde(alias = "picking_type_id")]
53    pub picking_type_id: Uuid,
54    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
55    #[serde(alias = "route_id")]
56    pub route_id: Uuid,
57    #[serde(default, skip_serializing_if = "Option::is_none", alias = "warehouse_id")]
58    pub warehouse_id: Option<Uuid>,
59    #[cfg_attr(feature = "openapi", schema(example = true))]
60    #[serde(alias = "propagate_cancel")]
61    pub propagate_cancel: bool,
62}
63
64// =============================================================================
65// Update DTO
66// =============================================================================
67
68/// Request DTO for full update of a RouteRule
69///
70/// Used in PUT requests for full entity replacement.
71/// All fields are required (except auto-generated ones).
72#[derive(Debug, Clone, Deserialize)]
73#[cfg_attr(feature = "openapi", derive(ToSchema))]
74#[serde(rename_all = "camelCase")]
75pub struct UpdateRouteRuleDto {
76    #[cfg_attr(feature = "openapi", schema(example = "example"))]
77    pub name: String,
78    #[cfg_attr(feature = "openapi", schema(example = true))]
79    pub active: bool,
80    #[cfg_attr(feature = "openapi", schema(example = 42))]
81    pub sequence: i32,
82    pub action: RuleAction,
83    pub auto: RuleAuto,
84    #[serde(alias = "procure_method")]
85    pub procure_method: ProcureMethod,
86    #[cfg_attr(feature = "openapi", schema(example = 42))]
87    pub delay: i32,
88    #[serde(default, skip_serializing_if = "Option::is_none", alias = "location_src_id")]
89    pub location_src_id: Option<Uuid>,
90    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
91    #[serde(alias = "location_dest_id")]
92    pub location_dest_id: Uuid,
93    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
94    #[serde(alias = "picking_type_id")]
95    pub picking_type_id: Uuid,
96    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
97    #[serde(alias = "route_id")]
98    pub route_id: Uuid,
99    #[serde(default, skip_serializing_if = "Option::is_none", alias = "warehouse_id")]
100    pub warehouse_id: Option<Uuid>,
101    #[cfg_attr(feature = "openapi", schema(example = true))]
102    #[serde(alias = "propagate_cancel")]
103    pub propagate_cancel: bool,
104}
105
106// =============================================================================
107// Patch DTO
108// =============================================================================
109
110/// Request DTO for partial update of a RouteRule
111///
112/// Used in PATCH requests for partial updates.
113/// All fields are optional - only provided fields will be updated.
114#[derive(Debug, Clone, Default, Deserialize)]
115#[cfg_attr(feature = "openapi", derive(ToSchema))]
116#[serde(rename_all = "camelCase")]
117pub struct PatchRouteRuleDto {
118    #[cfg_attr(feature = "openapi", schema(example = "example"))]
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub name: Option<String>,
121    #[cfg_attr(feature = "openapi", schema(example = true))]
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub active: Option<bool>,
124    #[cfg_attr(feature = "openapi", schema(example = 42))]
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub sequence: Option<i32>,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub action: Option<RuleAction>,
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub auto: Option<RuleAuto>,
131    #[serde(skip_serializing_if = "Option::is_none", alias = "procure_method")]
132    pub procure_method: Option<ProcureMethod>,
133    #[cfg_attr(feature = "openapi", schema(example = 42))]
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub delay: Option<i32>,
136    #[serde(skip_serializing_if = "Option::is_none", alias = "location_src_id")]
137    pub location_src_id: Option<Uuid>,
138    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
139    #[serde(skip_serializing_if = "Option::is_none", alias = "location_dest_id")]
140    pub location_dest_id: Option<Uuid>,
141    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
142    #[serde(skip_serializing_if = "Option::is_none", alias = "picking_type_id")]
143    pub picking_type_id: Option<Uuid>,
144    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
145    #[serde(skip_serializing_if = "Option::is_none", alias = "route_id")]
146    pub route_id: Option<Uuid>,
147    #[serde(skip_serializing_if = "Option::is_none", alias = "warehouse_id")]
148    pub warehouse_id: Option<Uuid>,
149    #[cfg_attr(feature = "openapi", schema(example = true))]
150    #[serde(skip_serializing_if = "Option::is_none", alias = "propagate_cancel")]
151    pub propagate_cancel: Option<bool>,
152}
153
154impl PatchRouteRuleDto {
155    /// Check if any field is set
156    pub fn has_changes(&self) -> bool {
157        self.name.is_some() || self.active.is_some() || self.sequence.is_some() || self.action.is_some() || self.auto.is_some() || self.procure_method.is_some() || self.delay.is_some() || self.location_src_id.is_some() || self.location_dest_id.is_some() || self.picking_type_id.is_some() || self.route_id.is_some() || self.warehouse_id.is_some() || self.propagate_cancel.is_some()
158    }
159}
160
161// =============================================================================
162// Response DTO
163// =============================================================================
164
165/// Response DTO for RouteRule entity
166///
167/// Used in API responses for single entity.
168/// Includes all fields including metadata.
169#[derive(Debug, Clone, Serialize)]
170#[cfg_attr(feature = "openapi", derive(ToSchema))]
171#[serde(rename_all = "camelCase")]
172pub struct RouteRuleResponseDto {
173    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
174    pub id: Uuid,
175    #[cfg_attr(feature = "openapi", schema(example = "example"))]
176    pub name: String,
177    #[cfg_attr(feature = "openapi", schema(example = true))]
178    pub active: bool,
179    #[cfg_attr(feature = "openapi", schema(example = 42))]
180    pub sequence: i32,
181    pub action: RuleAction,
182    pub auto: RuleAuto,
183    pub procure_method: ProcureMethod,
184    #[cfg_attr(feature = "openapi", schema(example = 42))]
185    pub delay: i32,
186    pub location_src_id: Option<Uuid>,
187    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
188    pub location_dest_id: Uuid,
189    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
190    pub picking_type_id: Uuid,
191    #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
192    pub route_id: Uuid,
193    pub warehouse_id: Option<Uuid>,
194    #[cfg_attr(feature = "openapi", schema(example = true))]
195    pub propagate_cancel: bool,
196    pub metadata: AuditMetadata,
197}
198
199// =============================================================================
200// List Response DTO
201// =============================================================================
202
203/// Paginated list response for RouteRule entities
204///
205/// Used in API responses for list endpoints.
206/// Includes pagination metadata.
207#[derive(Debug, Clone, Serialize)]
208#[cfg_attr(feature = "openapi", derive(ToSchema))]
209#[serde(rename_all = "camelCase")]
210pub struct RouteRuleListResponseDto {
211    /// List of items
212    pub items: Vec<RouteRuleResponseDto>,
213    /// Total number of items (across all pages)
214    pub total: u64,
215    /// Current page number (1-indexed)
216    pub page: u32,
217    /// Number of items per page
218    pub per_page: u32,
219    /// Total number of pages
220    pub total_pages: u32,
221    /// Whether there is a next page
222    pub has_next: bool,
223    /// Whether there is a previous page
224    pub has_prev: bool,
225}
226
227impl RouteRuleListResponseDto {
228    /// Create a new list response from items and pagination info
229    pub fn new(items: Vec<RouteRuleResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
230        let total_pages = if per_page > 0 {
231            ((total as f64) / (per_page as f64)).ceil() as u32
232        } else {
233            0
234        };
235        Self {
236            items,
237            total,
238            page,
239            per_page,
240            total_pages,
241            has_next: page < total_pages,
242            has_prev: page > 1,
243        }
244    }
245}
246
247/// Summary DTO for list views (compact version)
248#[derive(Debug, Clone, Serialize)]
249#[cfg_attr(feature = "openapi", derive(ToSchema))]
250#[serde(rename_all = "camelCase")]
251pub struct RouteRuleSummaryDto {
252    pub id: Uuid,
253    pub name: String,
254    pub active: bool,
255    pub sequence: i32,
256    pub created_at: Option<DateTime<Utc>>,
257}
258
259// =============================================================================
260// Conversions
261// =============================================================================
262
263impl From<RouteRule> for RouteRuleResponseDto {
264    fn from(entity: RouteRule) -> Self {
265        Self {
266            id: entity.id,
267            name: entity.name,
268            active: entity.active,
269            sequence: entity.sequence,
270            action: entity.action,
271            auto: entity.auto,
272            procure_method: entity.procure_method,
273            delay: entity.delay,
274            location_src_id: entity.location_src_id,
275            location_dest_id: entity.location_dest_id,
276            picking_type_id: entity.picking_type_id,
277            route_id: entity.route_id,
278            warehouse_id: entity.warehouse_id,
279            propagate_cancel: entity.propagate_cancel,
280            metadata: entity.metadata,
281        }
282    }
283}
284
285impl From<RouteRule> for RouteRuleSummaryDto {
286    fn from(entity: RouteRule) -> Self {
287        let created_at = backbone_core::PersistentEntity::created_at(&entity);
288        Self {
289            id: entity.id,
290            name: entity.name,
291            active: entity.active,
292            sequence: entity.sequence,
293            created_at,
294        }
295    }
296}
297
298impl From<CreateRouteRuleDto> for RouteRule {
299    fn from(dto: CreateRouteRuleDto) -> Self {
300        Self {
301            id: Uuid::new_v4(),
302            name: dto.name,
303            active: dto.active,
304            sequence: dto.sequence,
305            action: dto.action,
306            auto: dto.auto,
307            procure_method: dto.procure_method,
308            delay: dto.delay,
309            location_src_id: dto.location_src_id,
310            location_dest_id: dto.location_dest_id,
311            picking_type_id: dto.picking_type_id,
312            route_id: dto.route_id,
313            warehouse_id: dto.warehouse_id,
314            propagate_cancel: dto.propagate_cancel,
315            metadata: AuditMetadata::default(),
316        }
317    }
318}
319
320impl From<&RouteRule> for RouteRuleResponseDto {
321    fn from(entity: &RouteRule) -> Self {
322        Self {
323            id: entity.id.clone(),
324            name: entity.name.clone(),
325            active: entity.active.clone(),
326            sequence: entity.sequence.clone(),
327            action: entity.action.clone(),
328            auto: entity.auto.clone(),
329            procure_method: entity.procure_method.clone(),
330            delay: entity.delay.clone(),
331            location_src_id: entity.location_src_id.clone(),
332            location_dest_id: entity.location_dest_id.clone(),
333            picking_type_id: entity.picking_type_id.clone(),
334            route_id: entity.route_id.clone(),
335            warehouse_id: entity.warehouse_id.clone(),
336            propagate_cancel: entity.propagate_cancel.clone(),
337            metadata: entity.metadata.clone(),
338        }
339    }
340}
341
342impl backbone_core::FromCreateDto<CreateRouteRuleDto> for RouteRule {
343    fn from_create_dto(dto: CreateRouteRuleDto) -> backbone_core::ServiceResult<Self> {
344        Ok(RouteRule::from(dto))
345    }
346}
347
348impl backbone_core::ApplyUpdateDto<UpdateRouteRuleDto> for RouteRule {
349    fn apply_update(mut self, dto: UpdateRouteRuleDto) -> backbone_core::ServiceResult<Self> {
350        self.name = dto.name;
351        self.active = dto.active;
352        self.sequence = dto.sequence;
353        self.action = dto.action;
354        self.auto = dto.auto;
355        self.procure_method = dto.procure_method;
356        self.delay = dto.delay;
357        self.location_src_id = dto.location_src_id;
358        self.location_dest_id = dto.location_dest_id;
359        self.picking_type_id = dto.picking_type_id;
360        self.route_id = dto.route_id;
361        self.warehouse_id = dto.warehouse_id;
362        self.propagate_cancel = dto.propagate_cancel;
363        Ok(self)
364    }
365}
366
367// =============================================================================
368// Custom DTOs
369// =============================================================================
370
371// Add custom DTOs specific to RouteRule here.
372// This section will be preserved during regeneration.
373// >>> END CUSTOM DTOs
374