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
16use crate::domain::entity::Package;
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 CreatePackageDto {
31 #[cfg_attr(feature = "openapi", schema(example = "example"))]
32 pub name: String,
33 #[cfg_attr(feature = "openapi", schema(example = "example"))]
34 #[serde(alias = "complete_name")]
35 pub complete_name: String,
36 #[serde(default, skip_serializing_if = "Option::is_none", alias = "location_id")]
37 pub location_id: Option<Uuid>,
38 #[serde(default, skip_serializing_if = "Option::is_none", alias = "parent_package_id")]
39 pub parent_package_id: Option<Uuid>,
40 #[cfg_attr(feature = "openapi", schema(example = "example"))]
41 #[serde(alias = "parent_path")]
42 pub parent_path: String,
43 #[serde(default, skip_serializing_if = "Option::is_none", alias = "pack_date")]
44 pub pack_date: Option<NaiveDate>,
45 #[serde(default, skip_serializing_if = "Option::is_none", alias = "package_type_id")]
46 pub package_type_id: Option<Uuid>,
47}
48
49#[derive(Debug, Clone, Deserialize)]
58#[cfg_attr(feature = "openapi", derive(ToSchema))]
59#[serde(rename_all = "camelCase")]
60pub struct UpdatePackageDto {
61 #[cfg_attr(feature = "openapi", schema(example = "example"))]
62 pub name: String,
63 #[cfg_attr(feature = "openapi", schema(example = "example"))]
64 #[serde(alias = "complete_name")]
65 pub complete_name: String,
66 #[serde(default, skip_serializing_if = "Option::is_none", alias = "location_id")]
67 pub location_id: Option<Uuid>,
68 #[serde(default, skip_serializing_if = "Option::is_none", alias = "parent_package_id")]
69 pub parent_package_id: Option<Uuid>,
70 #[cfg_attr(feature = "openapi", schema(example = "example"))]
71 #[serde(alias = "parent_path")]
72 pub parent_path: String,
73 #[serde(default, skip_serializing_if = "Option::is_none", alias = "pack_date")]
74 pub pack_date: Option<NaiveDate>,
75 #[serde(default, skip_serializing_if = "Option::is_none", alias = "package_type_id")]
76 pub package_type_id: Option<Uuid>,
77}
78
79#[derive(Debug, Clone, Default, Deserialize)]
88#[cfg_attr(feature = "openapi", derive(ToSchema))]
89#[serde(rename_all = "camelCase")]
90pub struct PatchPackageDto {
91 #[cfg_attr(feature = "openapi", schema(example = "example"))]
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub name: Option<String>,
94 #[cfg_attr(feature = "openapi", schema(example = "example"))]
95 #[serde(skip_serializing_if = "Option::is_none", alias = "complete_name")]
96 pub complete_name: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none", alias = "location_id")]
98 pub location_id: Option<Uuid>,
99 #[serde(skip_serializing_if = "Option::is_none", alias = "parent_package_id")]
100 pub parent_package_id: Option<Uuid>,
101 #[cfg_attr(feature = "openapi", schema(example = "example"))]
102 #[serde(skip_serializing_if = "Option::is_none", alias = "parent_path")]
103 pub parent_path: Option<String>,
104 #[serde(skip_serializing_if = "Option::is_none", alias = "pack_date")]
105 pub pack_date: Option<NaiveDate>,
106 #[serde(skip_serializing_if = "Option::is_none", alias = "package_type_id")]
107 pub package_type_id: Option<Uuid>,
108}
109
110impl PatchPackageDto {
111 pub fn has_changes(&self) -> bool {
113 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()
114 }
115}
116
117#[derive(Debug, Clone, Serialize)]
126#[cfg_attr(feature = "openapi", derive(ToSchema))]
127#[serde(rename_all = "camelCase")]
128pub struct PackageResponseDto {
129 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
130 pub id: Uuid,
131 #[cfg_attr(feature = "openapi", schema(example = "example"))]
132 pub name: String,
133 #[cfg_attr(feature = "openapi", schema(example = "example"))]
134 pub complete_name: String,
135 pub location_id: Option<Uuid>,
136 pub parent_package_id: Option<Uuid>,
137 #[cfg_attr(feature = "openapi", schema(example = "example"))]
138 pub parent_path: String,
139 pub pack_date: Option<NaiveDate>,
140 pub package_type_id: Option<Uuid>,
141 pub metadata: AuditMetadata,
142}
143
144#[derive(Debug, Clone, Serialize)]
153#[cfg_attr(feature = "openapi", derive(ToSchema))]
154#[serde(rename_all = "camelCase")]
155pub struct PackageListResponseDto {
156 pub items: Vec<PackageResponseDto>,
158 pub total: u64,
160 pub page: u32,
162 pub per_page: u32,
164 pub total_pages: u32,
166 pub has_next: bool,
168 pub has_prev: bool,
170}
171
172impl PackageListResponseDto {
173 pub fn new(items: Vec<PackageResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
175 let total_pages = if per_page > 0 {
176 ((total as f64) / (per_page as f64)).ceil() as u32
177 } else {
178 0
179 };
180 Self {
181 items,
182 total,
183 page,
184 per_page,
185 total_pages,
186 has_next: page < total_pages,
187 has_prev: page > 1,
188 }
189 }
190}
191
192#[derive(Debug, Clone, Serialize)]
194#[cfg_attr(feature = "openapi", derive(ToSchema))]
195#[serde(rename_all = "camelCase")]
196pub struct PackageSummaryDto {
197 pub id: Uuid,
198 pub name: String,
199 pub complete_name: String,
200 pub location_id: Option<Uuid>,
201 pub created_at: Option<DateTime<Utc>>,
202}
203
204impl From<Package> for PackageResponseDto {
209 fn from(entity: Package) -> Self {
210 Self {
211 id: entity.id,
212 name: entity.name,
213 complete_name: entity.complete_name,
214 location_id: entity.location_id,
215 parent_package_id: entity.parent_package_id,
216 parent_path: entity.parent_path,
217 pack_date: entity.pack_date,
218 package_type_id: entity.package_type_id,
219 metadata: entity.metadata,
220 }
221 }
222}
223
224impl From<Package> for PackageSummaryDto {
225 fn from(entity: Package) -> Self {
226 let created_at = backbone_core::PersistentEntity::created_at(&entity);
227 Self {
228 id: entity.id,
229 name: entity.name,
230 complete_name: entity.complete_name,
231 location_id: entity.location_id,
232 created_at,
233 }
234 }
235}
236
237impl From<CreatePackageDto> for Package {
238 fn from(dto: CreatePackageDto) -> Self {
239 Self {
240 id: Uuid::new_v4(),
241 name: dto.name,
242 complete_name: dto.complete_name,
243 location_id: dto.location_id,
244 parent_package_id: dto.parent_package_id,
245 parent_path: dto.parent_path,
246 pack_date: dto.pack_date,
247 package_type_id: dto.package_type_id,
248 metadata: AuditMetadata::default(),
249 }
250 }
251}
252
253impl From<&Package> for PackageResponseDto {
254 fn from(entity: &Package) -> Self {
255 Self {
256 id: entity.id.clone(),
257 name: entity.name.clone(),
258 complete_name: entity.complete_name.clone(),
259 location_id: entity.location_id.clone(),
260 parent_package_id: entity.parent_package_id.clone(),
261 parent_path: entity.parent_path.clone(),
262 pack_date: entity.pack_date.clone(),
263 package_type_id: entity.package_type_id.clone(),
264 metadata: entity.metadata.clone(),
265 }
266 }
267}
268
269impl backbone_core::FromCreateDto<CreatePackageDto> for Package {
270 fn from_create_dto(dto: CreatePackageDto) -> backbone_core::ServiceResult<Self> {
271 Ok(Package::from(dto))
272 }
273}
274
275impl backbone_core::ApplyUpdateDto<UpdatePackageDto> for Package {
276 fn apply_update(mut self, dto: UpdatePackageDto) -> backbone_core::ServiceResult<Self> {
277 self.name = dto.name;
278 self.complete_name = dto.complete_name;
279 self.location_id = dto.location_id;
280 self.parent_package_id = dto.parent_package_id;
281 self.parent_path = dto.parent_path;
282 self.pack_date = dto.pack_date;
283 self.package_type_id = dto.package_type_id;
284 Ok(self)
285 }
286}
287
288