backbone_banking/domain/entity/
bank_clearance.rs1use chrono::{DateTime, Utc, NaiveDate};
2use serde::{Deserialize, Serialize};
3use sqlx::FromRow;
4use uuid::Uuid;
5use rust_decimal::Decimal;
6
7use super::MatchedSourceType;
8use super::MatchMethod;
9use super::AuditMetadata;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct BankClearanceId(pub Uuid);
15
16impl BankClearanceId {
17 pub fn new(id: Uuid) -> Self { Self(id) }
18 pub fn generate() -> Self { Self(Uuid::new_v4()) }
19 pub fn into_inner(self) -> Uuid { self.0 }
20}
21
22impl std::fmt::Display for BankClearanceId {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(f, "{}", self.0)
25 }
26}
27
28impl std::str::FromStr for BankClearanceId {
29 type Err = uuid::Error;
30 fn from_str(s: &str) -> Result<Self, Self::Err> {
31 Ok(Self(Uuid::parse_str(s)?))
32 }
33}
34
35impl From<Uuid> for BankClearanceId {
36 fn from(id: Uuid) -> Self { Self(id) }
37}
38
39impl From<BankClearanceId> for Uuid {
40 fn from(id: BankClearanceId) -> Self { id.0 }
41}
42
43impl AsRef<Uuid> for BankClearanceId {
44 fn as_ref(&self) -> &Uuid { &self.0 }
45}
46
47impl std::ops::Deref for BankClearanceId {
48 type Target = Uuid;
49 fn deref(&self) -> &Self::Target { &self.0 }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
53pub struct BankClearance {
54 pub id: Uuid,
55 pub bank_transaction_id: Uuid,
56 pub matched_source_type: MatchedSourceType,
57 pub matched_source_id: Uuid,
58 pub matched_amount: Decimal,
59 pub match_method: MatchMethod,
60 pub clearance_date: NaiveDate,
61 pub accounting_post_id: Option<Uuid>,
62 pub journal_id: Option<Uuid>,
63 #[serde(default)]
64 #[sqlx(json)]
65 pub metadata: AuditMetadata,
66}
67
68impl BankClearance {
69 pub fn builder() -> BankClearanceBuilder {
71 <BankClearanceBuilder as Default>::default()
72 }
73
74 pub fn new(bank_transaction_id: Uuid, matched_source_type: MatchedSourceType, matched_source_id: Uuid, matched_amount: Decimal, match_method: MatchMethod, clearance_date: NaiveDate) -> Self {
76 Self {
77 id: Uuid::new_v4(),
78 bank_transaction_id,
79 matched_source_type,
80 matched_source_id,
81 matched_amount,
82 match_method,
83 clearance_date,
84 accounting_post_id: None,
85 journal_id: None,
86 metadata: AuditMetadata::default(),
87 }
88 }
89
90 pub fn id(&self) -> &Uuid {
92 &self.id
93 }
94
95 pub fn typed_id(&self) -> BankClearanceId {
97 BankClearanceId(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_accounting_post_id(mut self, value: Uuid) -> Self {
147 self.accounting_post_id = Some(value);
148 self
149 }
150
151 pub fn with_journal_id(mut self, value: Uuid) -> Self {
153 self.journal_id = Some(value);
154 self
155 }
156
157 pub fn apply_patch(&mut self, fields: std::collections::HashMap<String, serde_json::Value>) {
163 for (key, value) in fields {
164 match key.as_str() {
165 "bank_transaction_id" => {
166 if let Ok(v) = serde_json::from_value(value) { self.bank_transaction_id = v; }
167 }
168 "matched_source_type" => {
169 if let Ok(v) = serde_json::from_value(value) { self.matched_source_type = v; }
170 }
171 "matched_source_id" => {
172 if let Ok(v) = serde_json::from_value(value) { self.matched_source_id = v; }
173 }
174 "matched_amount" => {
175 if let Ok(v) = serde_json::from_value(value) { self.matched_amount = v; }
176 }
177 "match_method" => {
178 if let Ok(v) = serde_json::from_value(value) { self.match_method = v; }
179 }
180 "clearance_date" => {
181 if let Ok(v) = serde_json::from_value(value) { self.clearance_date = v; }
182 }
183 "accounting_post_id" => {
184 if let Ok(v) = serde_json::from_value(value) { self.accounting_post_id = v; }
185 }
186 "journal_id" => {
187 if let Ok(v) = serde_json::from_value(value) { self.journal_id = v; }
188 }
189 _ => {} }
191 }
192 }
193
194}
195
196impl super::Entity for BankClearance {
197 type Id = Uuid;
198
199 fn entity_id(&self) -> &Self::Id {
200 &self.id
201 }
202
203 fn entity_type() -> &'static str {
204 "BankClearance"
205 }
206}
207
208impl backbone_core::PersistentEntity for BankClearance {
209 fn entity_id(&self) -> String {
210 self.id.to_string()
211 }
212 fn set_entity_id(&mut self, id: String) {
213 if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
214 self.id = uuid;
215 }
216 }
217 fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
218 self.metadata.created_at
219 }
220 fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
221 self.metadata.created_at = Some(ts);
222 }
223 fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
224 self.metadata.updated_at
225 }
226 fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
227 self.metadata.updated_at = Some(ts);
228 }
229 fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
230 self.metadata.deleted_at
231 }
232 fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
233 self.metadata.deleted_at = ts;
234 }
235}
236
237impl backbone_orm::EntityRepoMeta for BankClearance {
238 fn column_types() -> std::collections::HashMap<String, String> {
239 let mut m = std::collections::HashMap::new();
240 m.insert("id".to_string(), "uuid".to_string());
241 m.insert("bank_transaction_id".to_string(), "uuid".to_string());
242 m.insert("matched_source_id".to_string(), "uuid".to_string());
243 m.insert("accounting_post_id".to_string(), "uuid".to_string());
244 m.insert("journal_id".to_string(), "uuid".to_string());
245 m.insert("matched_source_type".to_string(), "matched_source_type".to_string());
246 m.insert("match_method".to_string(), "match_method".to_string());
247 m.insert("clearance_date".to_string(), "date".to_string());
248 m
249 }
250 fn search_fields() -> &'static [&'static str] {
251 &[]
252 }
253 fn relations() -> &'static [(&'static str, &'static str, &'static str)] {
254 &[("bankTransaction", "bank_transactions", "bankTransactionId")]
255 }
256}
257
258#[derive(Debug, Clone, Default)]
263pub struct BankClearanceBuilder {
264 bank_transaction_id: Option<Uuid>,
265 matched_source_type: Option<MatchedSourceType>,
266 matched_source_id: Option<Uuid>,
267 matched_amount: Option<Decimal>,
268 match_method: Option<MatchMethod>,
269 clearance_date: Option<NaiveDate>,
270 accounting_post_id: Option<Uuid>,
271 journal_id: Option<Uuid>,
272}
273
274impl BankClearanceBuilder {
275 pub fn bank_transaction_id(mut self, value: Uuid) -> Self {
277 self.bank_transaction_id = Some(value);
278 self
279 }
280
281 pub fn matched_source_type(mut self, value: MatchedSourceType) -> Self {
283 self.matched_source_type = Some(value);
284 self
285 }
286
287 pub fn matched_source_id(mut self, value: Uuid) -> Self {
289 self.matched_source_id = Some(value);
290 self
291 }
292
293 pub fn matched_amount(mut self, value: Decimal) -> Self {
295 self.matched_amount = Some(value);
296 self
297 }
298
299 pub fn match_method(mut self, value: MatchMethod) -> Self {
301 self.match_method = Some(value);
302 self
303 }
304
305 pub fn clearance_date(mut self, value: NaiveDate) -> Self {
307 self.clearance_date = Some(value);
308 self
309 }
310
311 pub fn accounting_post_id(mut self, value: Uuid) -> Self {
313 self.accounting_post_id = Some(value);
314 self
315 }
316
317 pub fn journal_id(mut self, value: Uuid) -> Self {
319 self.journal_id = Some(value);
320 self
321 }
322
323 pub fn build(self) -> Result<BankClearance, String> {
327 let bank_transaction_id = self.bank_transaction_id.ok_or_else(|| "bank_transaction_id is required".to_string())?;
328 let matched_source_type = self.matched_source_type.ok_or_else(|| "matched_source_type is required".to_string())?;
329 let matched_source_id = self.matched_source_id.ok_or_else(|| "matched_source_id is required".to_string())?;
330 let matched_amount = self.matched_amount.ok_or_else(|| "matched_amount is required".to_string())?;
331 let clearance_date = self.clearance_date.ok_or_else(|| "clearance_date is required".to_string())?;
332
333 Ok(BankClearance {
334 id: Uuid::new_v4(),
335 bank_transaction_id,
336 matched_source_type,
337 matched_source_id,
338 matched_amount,
339 match_method: self.match_method.unwrap_or_default(),
340 clearance_date,
341 accounting_post_id: self.accounting_post_id,
342 journal_id: self.journal_id,
343 metadata: AuditMetadata::default(),
344 })
345 }
346}