Skip to main content

backbone_inventory/domain/entity/
landed_cost_adjustment_line.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use sqlx::FromRow;
4use uuid::Uuid;
5use rust_decimal::Decimal;
6use super::AuditMetadata;
7
8/// Strongly-typed ID for LandedCostAdjustmentLine
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(transparent)]
11pub struct LandedCostAdjustmentLineId(pub Uuid);
12
13impl LandedCostAdjustmentLineId {
14    pub fn new(id: Uuid) -> Self { Self(id) }
15    pub fn generate() -> Self { Self(Uuid::new_v4()) }
16    pub fn into_inner(self) -> Uuid { self.0 }
17}
18
19impl std::fmt::Display for LandedCostAdjustmentLineId {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        write!(f, "{}", self.0)
22    }
23}
24
25impl std::str::FromStr for LandedCostAdjustmentLineId {
26    type Err = uuid::Error;
27    fn from_str(s: &str) -> Result<Self, Self::Err> {
28        Ok(Self(Uuid::parse_str(s)?))
29    }
30}
31
32impl From<Uuid> for LandedCostAdjustmentLineId {
33    fn from(id: Uuid) -> Self { Self(id) }
34}
35
36impl From<LandedCostAdjustmentLineId> for Uuid {
37    fn from(id: LandedCostAdjustmentLineId) -> Self { id.0 }
38}
39
40impl AsRef<Uuid> for LandedCostAdjustmentLineId {
41    fn as_ref(&self) -> &Uuid { &self.0 }
42}
43
44impl std::ops::Deref for LandedCostAdjustmentLineId {
45    type Target = Uuid;
46    fn deref(&self) -> &Self::Target { &self.0 }
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
50pub struct LandedCostAdjustmentLine {
51    pub id: Uuid,
52    pub lc_id: Uuid,
53    pub move_line_id: Uuid,
54    pub cost_line_id: Uuid,
55    pub share: Decimal,
56    pub additional_landed_cost: Decimal,
57    pub remaining_qty: Decimal,
58    #[serde(default)]
59    #[sqlx(json)]
60    pub metadata: AuditMetadata,
61}
62
63impl LandedCostAdjustmentLine {
64    /// Create a builder for LandedCostAdjustmentLine
65    pub fn builder() -> LandedCostAdjustmentLineBuilder {
66        <LandedCostAdjustmentLineBuilder as Default>::default()
67    }
68
69    /// Create a new LandedCostAdjustmentLine with required fields
70    pub fn new(lc_id: Uuid, move_line_id: Uuid, cost_line_id: Uuid, share: Decimal, additional_landed_cost: Decimal, remaining_qty: Decimal) -> Self {
71        Self {
72            id: Uuid::new_v4(),
73            lc_id,
74            move_line_id,
75            cost_line_id,
76            share,
77            additional_landed_cost,
78            remaining_qty,
79            metadata: AuditMetadata::default(),
80        }
81    }
82
83    /// Get the entity's unique identifier
84    pub fn id(&self) -> &Uuid {
85        &self.id
86    }
87
88    /// Get a strongly-typed ID for this entity
89    pub fn typed_id(&self) -> LandedCostAdjustmentLineId {
90        LandedCostAdjustmentLineId(self.id)
91    }
92
93    /// Get when this entity was created
94    pub fn created_at(&self) -> Option<&DateTime<Utc>> {
95        self.metadata.created_at.as_ref()
96    }
97
98    /// Get when this entity was last updated
99    pub fn updated_at(&self) -> Option<&DateTime<Utc>> {
100        self.metadata.updated_at.as_ref()
101    }
102
103    /// Check if this entity is soft deleted
104    pub fn is_deleted(&self) -> bool {
105        self.metadata.deleted_at.is_some()
106    }
107
108    /// Check if this entity is active (not deleted)
109    pub fn is_active(&self) -> bool {
110        self.metadata.deleted_at.is_none()
111    }
112
113    /// Get when this entity was deleted
114    pub fn deleted_at(&self) -> Option<&DateTime<Utc>> {
115        self.metadata.deleted_at.as_ref()
116    }
117
118    /// Get who created this entity
119    pub fn created_by(&self) -> Option<&Uuid> {
120        self.metadata.created_by.as_ref()
121    }
122
123    /// Get who last updated this entity
124    pub fn updated_by(&self) -> Option<&Uuid> {
125        self.metadata.updated_by.as_ref()
126    }
127
128    /// Get who deleted this entity
129    pub fn deleted_by(&self) -> Option<&Uuid> {
130        self.metadata.deleted_by.as_ref()
131    }
132
133
134    // ==========================================================
135    // Partial Update
136    // ==========================================================
137
138    /// Apply partial updates from a map of field name to JSON value
139    pub fn apply_patch(&mut self, fields: std::collections::HashMap<String, serde_json::Value>) {
140        for (key, value) in fields {
141            match key.as_str() {
142                "lc_id" => {
143                    if let Ok(v) = serde_json::from_value(value) { self.lc_id = v; }
144                }
145                "move_line_id" => {
146                    if let Ok(v) = serde_json::from_value(value) { self.move_line_id = v; }
147                }
148                "cost_line_id" => {
149                    if let Ok(v) = serde_json::from_value(value) { self.cost_line_id = v; }
150                }
151                "share" => {
152                    if let Ok(v) = serde_json::from_value(value) { self.share = v; }
153                }
154                "additional_landed_cost" => {
155                    if let Ok(v) = serde_json::from_value(value) { self.additional_landed_cost = v; }
156                }
157                "remaining_qty" => {
158                    if let Ok(v) = serde_json::from_value(value) { self.remaining_qty = v; }
159                }
160                _ => {} // ignore unknown fields
161            }
162        }
163    }
164
165}
166
167impl super::Entity for LandedCostAdjustmentLine {
168    type Id = Uuid;
169
170    fn entity_id(&self) -> &Self::Id {
171        &self.id
172    }
173
174    fn entity_type() -> &'static str {
175        "LandedCostAdjustmentLine"
176    }
177}
178
179impl backbone_core::PersistentEntity for LandedCostAdjustmentLine {
180    fn entity_id(&self) -> String {
181        self.id.to_string()
182    }
183    fn set_entity_id(&mut self, id: String) {
184        if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
185            self.id = uuid;
186        }
187    }
188    fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
189        self.metadata.created_at
190    }
191    fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
192        self.metadata.created_at = Some(ts);
193    }
194    fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
195        self.metadata.updated_at
196    }
197    fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
198        self.metadata.updated_at = Some(ts);
199    }
200    fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
201        self.metadata.deleted_at
202    }
203    fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
204        self.metadata.deleted_at = ts;
205    }
206}
207
208impl backbone_orm::EntityRepoMeta for LandedCostAdjustmentLine {
209    fn column_types() -> std::collections::HashMap<String, String> {
210        let mut m = std::collections::HashMap::new();
211        m.insert("id".to_string(), "uuid".to_string());
212        m.insert("lc_id".to_string(), "uuid".to_string());
213        m.insert("move_line_id".to_string(), "uuid".to_string());
214        m.insert("cost_line_id".to_string(), "uuid".to_string());
215        m
216    }
217    fn search_fields() -> &'static [&'static str] {
218        &[]
219    }
220    fn relations() -> &'static [(&'static str, &'static str, &'static str)] {
221        &[("lc", "landed_costs", "lcId")]
222    }
223}
224
225/// Builder for LandedCostAdjustmentLine entity
226///
227/// Provides a fluent API for constructing LandedCostAdjustmentLine instances.
228/// System fields (id, metadata, timestamps) are auto-initialized.
229#[derive(Debug, Clone, Default)]
230pub struct LandedCostAdjustmentLineBuilder {
231    lc_id: Option<Uuid>,
232    move_line_id: Option<Uuid>,
233    cost_line_id: Option<Uuid>,
234    share: Option<Decimal>,
235    additional_landed_cost: Option<Decimal>,
236    remaining_qty: Option<Decimal>,
237}
238
239impl LandedCostAdjustmentLineBuilder {
240    /// Set the lc_id field (required)
241    pub fn lc_id(mut self, value: Uuid) -> Self {
242        self.lc_id = Some(value);
243        self
244    }
245
246    /// Set the move_line_id field (required)
247    pub fn move_line_id(mut self, value: Uuid) -> Self {
248        self.move_line_id = Some(value);
249        self
250    }
251
252    /// Set the cost_line_id field (required)
253    pub fn cost_line_id(mut self, value: Uuid) -> Self {
254        self.cost_line_id = Some(value);
255        self
256    }
257
258    /// Set the share field (required)
259    pub fn share(mut self, value: Decimal) -> Self {
260        self.share = Some(value);
261        self
262    }
263
264    /// Set the additional_landed_cost field (default: `Decimal::from(0)`)
265    pub fn additional_landed_cost(mut self, value: Decimal) -> Self {
266        self.additional_landed_cost = Some(value);
267        self
268    }
269
270    /// Set the remaining_qty field (default: `Decimal::from(0)`)
271    pub fn remaining_qty(mut self, value: Decimal) -> Self {
272        self.remaining_qty = Some(value);
273        self
274    }
275
276    /// Build the LandedCostAdjustmentLine entity
277    ///
278    /// Returns Err if any required field without a default is missing.
279    pub fn build(self) -> Result<LandedCostAdjustmentLine, String> {
280        let lc_id = self.lc_id.ok_or_else(|| "lc_id is required".to_string())?;
281        let move_line_id = self.move_line_id.ok_or_else(|| "move_line_id is required".to_string())?;
282        let cost_line_id = self.cost_line_id.ok_or_else(|| "cost_line_id is required".to_string())?;
283        let share = self.share.ok_or_else(|| "share is required".to_string())?;
284
285        Ok(LandedCostAdjustmentLine {
286            id: Uuid::new_v4(),
287            lc_id,
288            move_line_id,
289            cost_line_id,
290            share,
291            additional_landed_cost: self.additional_landed_cost.unwrap_or(Decimal::from(0)),
292            remaining_qty: self.remaining_qty.unwrap_or(Decimal::from(0)),
293            metadata: AuditMetadata::default(),
294        })
295    }
296}