Skip to main content

backbone_accounting/domain/entity/
printed_check.rs

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