backbone_inventory/domain/entity/
putaway_rule.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use sqlx::FromRow;
4use uuid::Uuid;
5
6use super::PutawaySublocation;
7use super::AuditMetadata;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct PutawayRuleId(pub Uuid);
13
14impl PutawayRuleId {
15 pub fn new(id: Uuid) -> Self { Self(id) }
16 pub fn generate() -> Self { Self(Uuid::new_v4()) }
17 pub fn into_inner(self) -> Uuid { self.0 }
18}
19
20impl std::fmt::Display for PutawayRuleId {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(f, "{}", self.0)
23 }
24}
25
26impl std::str::FromStr for PutawayRuleId {
27 type Err = uuid::Error;
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 Ok(Self(Uuid::parse_str(s)?))
30 }
31}
32
33impl From<Uuid> for PutawayRuleId {
34 fn from(id: Uuid) -> Self { Self(id) }
35}
36
37impl From<PutawayRuleId> for Uuid {
38 fn from(id: PutawayRuleId) -> Self { id.0 }
39}
40
41impl AsRef<Uuid> for PutawayRuleId {
42 fn as_ref(&self) -> &Uuid { &self.0 }
43}
44
45impl std::ops::Deref for PutawayRuleId {
46 type Target = Uuid;
47 fn deref(&self) -> &Self::Target { &self.0 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
51pub struct PutawayRule {
52 pub id: Uuid,
53 pub sequence: i32,
54 pub location_in_id: Uuid,
55 pub location_out_id: Uuid,
56 pub item_id: Option<Uuid>,
57 pub category_id: Option<Uuid>,
58 pub package_type_id: Option<Uuid>,
59 pub storage_category_id: Option<Uuid>,
60 pub sublocation: PutawaySublocation,
61 pub active: bool,
62 #[serde(default)]
63 #[sqlx(json)]
64 pub metadata: AuditMetadata,
65}
66
67impl PutawayRule {
68 pub fn builder() -> PutawayRuleBuilder {
70 <PutawayRuleBuilder as Default>::default()
71 }
72
73 pub fn new(sequence: i32, location_in_id: Uuid, location_out_id: Uuid, sublocation: PutawaySublocation, active: bool) -> Self {
75 Self {
76 id: Uuid::new_v4(),
77 sequence,
78 location_in_id,
79 location_out_id,
80 item_id: None,
81 category_id: None,
82 package_type_id: None,
83 storage_category_id: None,
84 sublocation,
85 active,
86 metadata: AuditMetadata::default(),
87 }
88 }
89
90 pub fn id(&self) -> &Uuid {
92 &self.id
93 }
94
95 pub fn typed_id(&self) -> PutawayRuleId {
97 PutawayRuleId(self.id)
98 }
99
100 pub fn created_at(&self) -> Option<&DateTime<Utc>> {
102 self.metadata.created_at.as_ref()
103 }
104
105 pub fn updated_at(&self) -> Option<&DateTime<Utc>> {
107 self.metadata.updated_at.as_ref()
108 }
109
110 pub fn is_deleted(&self) -> bool {
112 self.metadata.deleted_at.is_some()
113 }
114
115 pub fn is_active(&self) -> bool {
117 self.metadata.deleted_at.is_none()
118 }
119
120 pub fn deleted_at(&self) -> Option<&DateTime<Utc>> {
122 self.metadata.deleted_at.as_ref()
123 }
124
125 pub fn created_by(&self) -> Option<&Uuid> {
127 self.metadata.created_by.as_ref()
128 }
129
130 pub fn updated_by(&self) -> Option<&Uuid> {
132 self.metadata.updated_by.as_ref()
133 }
134
135 pub fn deleted_by(&self) -> Option<&Uuid> {
137 self.metadata.deleted_by.as_ref()
138 }
139
140
141 pub fn with_item_id(mut self, value: Uuid) -> Self {
147 self.item_id = Some(value);
148 self
149 }
150
151 pub fn with_category_id(mut self, value: Uuid) -> Self {
153 self.category_id = Some(value);
154 self
155 }
156
157 pub fn with_package_type_id(mut self, value: Uuid) -> Self {
159 self.package_type_id = Some(value);
160 self
161 }
162
163 pub fn with_storage_category_id(mut self, value: Uuid) -> Self {
165 self.storage_category_id = Some(value);
166 self
167 }
168
169 pub fn apply_patch(&mut self, fields: std::collections::HashMap<String, serde_json::Value>) {
175 for (key, value) in fields {
176 match key.as_str() {
177 "sequence" => {
178 if let Ok(v) = serde_json::from_value(value) { self.sequence = v; }
179 }
180 "location_in_id" => {
181 if let Ok(v) = serde_json::from_value(value) { self.location_in_id = v; }
182 }
183 "location_out_id" => {
184 if let Ok(v) = serde_json::from_value(value) { self.location_out_id = v; }
185 }
186 "item_id" => {
187 if let Ok(v) = serde_json::from_value(value) { self.item_id = v; }
188 }
189 "category_id" => {
190 if let Ok(v) = serde_json::from_value(value) { self.category_id = v; }
191 }
192 "package_type_id" => {
193 if let Ok(v) = serde_json::from_value(value) { self.package_type_id = v; }
194 }
195 "storage_category_id" => {
196 if let Ok(v) = serde_json::from_value(value) { self.storage_category_id = v; }
197 }
198 "sublocation" => {
199 if let Ok(v) = serde_json::from_value(value) { self.sublocation = v; }
200 }
201 "active" => {
202 if let Ok(v) = serde_json::from_value(value) { self.active = v; }
203 }
204 _ => {} }
206 }
207 }
208
209}
210
211impl super::Entity for PutawayRule {
212 type Id = Uuid;
213
214 fn entity_id(&self) -> &Self::Id {
215 &self.id
216 }
217
218 fn entity_type() -> &'static str {
219 "PutawayRule"
220 }
221}
222
223impl backbone_core::PersistentEntity for PutawayRule {
224 fn entity_id(&self) -> String {
225 self.id.to_string()
226 }
227 fn set_entity_id(&mut self, id: String) {
228 if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
229 self.id = uuid;
230 }
231 }
232 fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
233 self.metadata.created_at
234 }
235 fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
236 self.metadata.created_at = Some(ts);
237 }
238 fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
239 self.metadata.updated_at
240 }
241 fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
242 self.metadata.updated_at = Some(ts);
243 }
244 fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
245 self.metadata.deleted_at
246 }
247 fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
248 self.metadata.deleted_at = ts;
249 }
250}
251
252impl backbone_orm::EntityRepoMeta for PutawayRule {
253 fn column_types() -> std::collections::HashMap<String, String> {
254 let mut m = std::collections::HashMap::new();
255 m.insert("id".to_string(), "uuid".to_string());
256 m.insert("location_in_id".to_string(), "uuid".to_string());
257 m.insert("location_out_id".to_string(), "uuid".to_string());
258 m.insert("item_id".to_string(), "uuid".to_string());
259 m.insert("category_id".to_string(), "uuid".to_string());
260 m.insert("package_type_id".to_string(), "uuid".to_string());
261 m.insert("storage_category_id".to_string(), "uuid".to_string());
262 m.insert("sublocation".to_string(), "putaway_sublocation".to_string());
263 m
264 }
265 fn search_fields() -> &'static [&'static str] {
266 &[]
267 }
268 fn relations() -> &'static [(&'static str, &'static str, &'static str)] {
269 &[("locationIn", "locations", "locationInId"), ("locationOut", "locations", "locationOutId"), ("packageType", "package_types", "packageTypeId"), ("storageCategory", "storage_categories", "storageCategoryId")]
270 }
271}
272
273#[derive(Debug, Clone, Default)]
278pub struct PutawayRuleBuilder {
279 sequence: Option<i32>,
280 location_in_id: Option<Uuid>,
281 location_out_id: Option<Uuid>,
282 item_id: Option<Uuid>,
283 category_id: Option<Uuid>,
284 package_type_id: Option<Uuid>,
285 storage_category_id: Option<Uuid>,
286 sublocation: Option<PutawaySublocation>,
287 active: Option<bool>,
288}
289
290impl PutawayRuleBuilder {
291 pub fn sequence(mut self, value: i32) -> Self {
293 self.sequence = Some(value);
294 self
295 }
296
297 pub fn location_in_id(mut self, value: Uuid) -> Self {
299 self.location_in_id = Some(value);
300 self
301 }
302
303 pub fn location_out_id(mut self, value: Uuid) -> Self {
305 self.location_out_id = Some(value);
306 self
307 }
308
309 pub fn item_id(mut self, value: Uuid) -> Self {
311 self.item_id = Some(value);
312 self
313 }
314
315 pub fn category_id(mut self, value: Uuid) -> Self {
317 self.category_id = Some(value);
318 self
319 }
320
321 pub fn package_type_id(mut self, value: Uuid) -> Self {
323 self.package_type_id = Some(value);
324 self
325 }
326
327 pub fn storage_category_id(mut self, value: Uuid) -> Self {
329 self.storage_category_id = Some(value);
330 self
331 }
332
333 pub fn sublocation(mut self, value: PutawaySublocation) -> Self {
335 self.sublocation = Some(value);
336 self
337 }
338
339 pub fn active(mut self, value: bool) -> Self {
341 self.active = Some(value);
342 self
343 }
344
345 pub fn build(self) -> Result<PutawayRule, String> {
349 let location_in_id = self.location_in_id.ok_or_else(|| "location_in_id is required".to_string())?;
350 let location_out_id = self.location_out_id.ok_or_else(|| "location_out_id is required".to_string())?;
351
352 Ok(PutawayRule {
353 id: Uuid::new_v4(),
354 sequence: self.sequence.unwrap_or(0),
355 location_in_id,
356 location_out_id,
357 item_id: self.item_id,
358 category_id: self.category_id,
359 package_type_id: self.package_type_id,
360 storage_category_id: self.storage_category_id,
361 sublocation: self.sublocation.unwrap_or_default(),
362 active: self.active.unwrap_or(true),
363 metadata: AuditMetadata::default(),
364 })
365 }
366}