backbone_inventory/presentation/dto/
package_dto.rs1use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10use chrono::{DateTime, Utc, NaiveDate};
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::Package;
20use crate::domain::entity::AuditMetadata;
21
22#[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 CreatePackageDto {
35 #[cfg_attr(feature = "validation", validate(length(max = 150)))]
36 #[cfg_attr(feature = "openapi", schema(example = "example"))]
37 pub name: String,
38 #[cfg_attr(feature = "validation", validate(length(max = 1000)))]
39 #[cfg_attr(feature = "openapi", schema(example = "example"))]
40 #[serde(alias = "complete_name")]
41 pub complete_name: String,
42 #[serde(default, skip_serializing_if = "Option::is_none", alias = "location_id")]
43 pub location_id: Option<Uuid>,
44 #[serde(default, skip_serializing_if = "Option::is_none", alias = "parent_package_id")]
45 pub parent_package_id: Option<Uuid>,
46 #[cfg_attr(feature = "validation", validate(length(max = 1000)))]
47 #[cfg_attr(feature = "openapi", schema(example = "example"))]
48 #[serde(alias = "parent_path")]
49 pub parent_path: String,
50 #[serde(default, skip_serializing_if = "Option::is_none", alias = "pack_date")]
51 pub pack_date: Option<NaiveDate>,
52 #[serde(default, skip_serializing_if = "Option::is_none", alias = "package_type_id")]
53 pub package_type_id: Option<Uuid>,
54}
55
56#[derive(Debug, Clone, Deserialize)]
65#[cfg_attr(feature = "openapi", derive(ToSchema))]
66#[cfg_attr(feature = "validation", derive(Validate))]
67#[serde(rename_all = "camelCase")]
68pub struct UpdatePackageDto {
69 #[cfg_attr(feature = "validation", validate(length(max = 150)))]
70 #[cfg_attr(feature = "openapi", schema(example = "example"))]
71 pub name: String,
72 #[cfg_attr(feature = "validation", validate(length(max = 1000)))]
73 #[cfg_attr(feature = "openapi", schema(example = "example"))]
74 #[serde(alias = "complete_name")]
75 pub complete_name: String,
76 #[serde(default, skip_serializing_if = "Option::is_none", alias = "location_id")]
77 pub location_id: Option<Uuid>,
78 #[serde(default, skip_serializing_if = "Option::is_none", alias = "parent_package_id")]
79 pub parent_package_id: Option<Uuid>,
80 #[cfg_attr(feature = "validation", validate(length(max = 1000)))]
81 #[cfg_attr(feature = "openapi", schema(example = "example"))]
82 #[serde(alias = "parent_path")]
83 pub parent_path: String,
84 #[serde(default, skip_serializing_if = "Option::is_none", alias = "pack_date")]
85 pub pack_date: Option<NaiveDate>,
86 #[serde(default, skip_serializing_if = "Option::is_none", alias = "package_type_id")]
87 pub package_type_id: Option<Uuid>,
88}
89
90#[derive(Debug, Clone, Default, Deserialize)]
99#[cfg_attr(feature = "openapi", derive(ToSchema))]
100#[cfg_attr(feature = "validation", derive(Validate))]
101#[serde(rename_all = "camelCase")]
102pub struct PatchPackageDto {
103 #[cfg_attr(feature = "validation", validate(length(max = 150)))]
104 #[cfg_attr(feature = "openapi", schema(example = "example"))]
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub name: Option<String>,
107 #[cfg_attr(feature = "validation", validate(length(max = 1000)))]
108 #[cfg_attr(feature = "openapi", schema(example = "example"))]
109 #[serde(skip_serializing_if = "Option::is_none", alias = "complete_name")]
110 pub complete_name: Option<String>,
111 #[serde(skip_serializing_if = "Option::is_none", alias = "location_id")]
112 pub location_id: Option<Uuid>,
113 #[serde(skip_serializing_if = "Option::is_none", alias = "parent_package_id")]
114 pub parent_package_id: Option<Uuid>,
115 #[cfg_attr(feature = "validation", validate(length(max = 1000)))]
116 #[cfg_attr(feature = "openapi", schema(example = "example"))]
117 #[serde(skip_serializing_if = "Option::is_none", alias = "parent_path")]
118 pub parent_path: Option<String>,
119 #[serde(skip_serializing_if = "Option::is_none", alias = "pack_date")]
120 pub pack_date: Option<NaiveDate>,
121 #[serde(skip_serializing_if = "Option::is_none", alias = "package_type_id")]
122 pub package_type_id: Option<Uuid>,
123}
124
125impl PatchPackageDto {
126 pub fn has_changes(&self) -> bool {
128 self.name.is_some() || self.complete_name.is_some() || self.location_id.is_some() || self.parent_package_id.is_some() || self.parent_path.is_some() || self.pack_date.is_some() || self.package_type_id.is_some()
129 }
130}
131
132#[derive(Debug, Clone, Serialize)]
141#[cfg_attr(feature = "openapi", derive(ToSchema))]
142#[serde(rename_all = "camelCase")]
143pub struct PackageResponseDto {
144 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
145 pub id: Uuid,
146 #[cfg_attr(feature = "openapi", schema(example = "example"))]
147 pub name: String,
148 #[cfg_attr(feature = "openapi", schema(example = "example"))]
149 pub complete_name: String,
150 pub location_id: Option<Uuid>,
151 pub parent_package_id: Option<Uuid>,
152 #[cfg_attr(feature = "openapi", schema(example = "example"))]
153 pub parent_path: String,
154 pub pack_date: Option<NaiveDate>,
155 pub package_type_id: Option<Uuid>,
156 pub metadata: AuditMetadata,
157}
158
159#[derive(Debug, Clone, Serialize)]
168#[cfg_attr(feature = "openapi", derive(ToSchema))]
169#[serde(rename_all = "camelCase")]
170pub struct PackageListResponseDto {
171 pub items: Vec<PackageResponseDto>,
173 pub total: u64,
175 pub page: u32,
177 pub per_page: u32,
179 pub total_pages: u32,
181 pub has_next: bool,
183 pub has_prev: bool,
185}
186
187impl PackageListResponseDto {
188 pub fn new(items: Vec<PackageResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
190 let total_pages = if per_page > 0 {
191 ((total as f64) / (per_page as f64)).ceil() as u32
192 } else {
193 0
194 };
195 Self {
196 items,
197 total,
198 page,
199 per_page,
200 total_pages,
201 has_next: page < total_pages,
202 has_prev: page > 1,
203 }
204 }
205}
206
207#[derive(Debug, Clone, Serialize)]
209#[cfg_attr(feature = "openapi", derive(ToSchema))]
210#[serde(rename_all = "camelCase")]
211pub struct PackageSummaryDto {
212 pub id: Uuid,
213 pub name: String,
214 pub complete_name: String,
215 pub location_id: Option<Uuid>,
216 pub created_at: Option<DateTime<Utc>>,
217}
218
219impl From<Package> for PackageResponseDto {
224 fn from(entity: Package) -> Self {
225 Self {
226 id: entity.id,
227 name: entity.name,
228 complete_name: entity.complete_name,
229 location_id: entity.location_id,
230 parent_package_id: entity.parent_package_id,
231 parent_path: entity.parent_path,
232 pack_date: entity.pack_date,
233 package_type_id: entity.package_type_id,
234 metadata: entity.metadata,
235 }
236 }
237}
238
239impl From<Package> for PackageSummaryDto {
240 fn from(entity: Package) -> Self {
241 let created_at = backbone_core::PersistentEntity::created_at(&entity);
242 Self {
243 id: entity.id,
244 name: entity.name,
245 complete_name: entity.complete_name,
246 location_id: entity.location_id,
247 created_at,
248 }
249 }
250}
251
252impl From<CreatePackageDto> for Package {
253 fn from(dto: CreatePackageDto) -> Self {
254 Self {
255 id: Uuid::new_v4(),
256 name: dto.name,
257 complete_name: dto.complete_name,
258 location_id: dto.location_id,
259 parent_package_id: dto.parent_package_id,
260 parent_path: dto.parent_path,
261 pack_date: dto.pack_date,
262 package_type_id: dto.package_type_id,
263 metadata: AuditMetadata::default(),
264 }
265 }
266}
267
268impl From<&Package> for PackageResponseDto {
269 fn from(entity: &Package) -> Self {
270 Self {
271 id: entity.id.clone(),
272 name: entity.name.clone(),
273 complete_name: entity.complete_name.clone(),
274 location_id: entity.location_id.clone(),
275 parent_package_id: entity.parent_package_id.clone(),
276 parent_path: entity.parent_path.clone(),
277 pack_date: entity.pack_date.clone(),
278 package_type_id: entity.package_type_id.clone(),
279 metadata: entity.metadata.clone(),
280 }
281 }
282}
283
284impl backbone_core::FromCreateDto<CreatePackageDto> for Package {
285 fn from_create_dto(dto: CreatePackageDto) -> backbone_core::ServiceResult<Self> {
286 Ok(Package::from(dto))
287 }
288}
289
290impl backbone_core::ApplyUpdateDto<UpdatePackageDto> for Package {
291 fn apply_update(mut self, dto: UpdatePackageDto) -> backbone_core::ServiceResult<Self> {
292 self.name = dto.name;
293 self.complete_name = dto.complete_name;
294 self.location_id = dto.location_id;
295 self.parent_package_id = dto.parent_package_id;
296 self.parent_path = dto.parent_path;
297 self.pack_date = dto.pack_date;
298 self.package_type_id = dto.package_type_id;
299 Ok(self)
300 }
301}
302
303