backbone_payroll/domain/entity/
salary_structure.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use sqlx::FromRow;
4use uuid::Uuid;
5
6use super::SalaryStructureStatus;
7use super::AuditMetadata;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(transparent)]
12pub struct SalaryStructureId(pub Uuid);
13
14impl SalaryStructureId {
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 SalaryStructureId {
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 SalaryStructureId {
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 SalaryStructureId {
34 fn from(id: Uuid) -> Self { Self(id) }
35}
36
37impl From<SalaryStructureId> for Uuid {
38 fn from(id: SalaryStructureId) -> Self { id.0 }
39}
40
41impl AsRef<Uuid> for SalaryStructureId {
42 fn as_ref(&self) -> &Uuid { &self.0 }
43}
44
45impl std::ops::Deref for SalaryStructureId {
46 type Target = Uuid;
47 fn deref(&self) -> &Self::Target { &self.0 }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
51pub struct SalaryStructure {
52 pub id: Uuid,
53 pub name: String,
54 pub status: SalaryStructureStatus,
55 #[serde(default)]
56 #[sqlx(json)]
57 pub metadata: AuditMetadata,
58}
59
60impl SalaryStructure {
61 pub fn builder() -> SalaryStructureBuilder {
63 <SalaryStructureBuilder as Default>::default()
64 }
65
66 pub fn new(name: String, status: SalaryStructureStatus) -> Self {
68 Self {
69 id: Uuid::new_v4(),
70 name,
71 status,
72 metadata: AuditMetadata::default(),
73 }
74 }
75
76 pub fn id(&self) -> &Uuid {
78 &self.id
79 }
80
81 pub fn typed_id(&self) -> SalaryStructureId {
83 SalaryStructureId(self.id)
84 }
85
86 pub fn created_at(&self) -> Option<&DateTime<Utc>> {
88 self.metadata.created_at.as_ref()
89 }
90
91 pub fn updated_at(&self) -> Option<&DateTime<Utc>> {
93 self.metadata.updated_at.as_ref()
94 }
95
96 pub fn is_deleted(&self) -> bool {
98 self.metadata.deleted_at.is_some()
99 }
100
101 pub fn is_active(&self) -> bool {
103 self.metadata.deleted_at.is_none()
104 }
105
106 pub fn deleted_at(&self) -> Option<&DateTime<Utc>> {
108 self.metadata.deleted_at.as_ref()
109 }
110
111 pub fn created_by(&self) -> Option<&Uuid> {
113 self.metadata.created_by.as_ref()
114 }
115
116 pub fn updated_by(&self) -> Option<&Uuid> {
118 self.metadata.updated_by.as_ref()
119 }
120
121 pub fn deleted_by(&self) -> Option<&Uuid> {
123 self.metadata.deleted_by.as_ref()
124 }
125
126 pub fn status(&self) -> &SalaryStructureStatus {
128 &self.status
129 }
130
131
132 pub fn apply_patch(&mut self, fields: std::collections::HashMap<String, serde_json::Value>) {
138 for (key, value) in fields {
139 match key.as_str() {
140 "name" => {
141 if let Ok(v) = serde_json::from_value(value) { self.name = v; }
142 }
143 "status" => {
144 if let Ok(v) = serde_json::from_value(value) { self.status = v; }
145 }
146 _ => {} }
148 }
149 }
150
151 }
154
155impl super::Entity for SalaryStructure {
156 type Id = Uuid;
157
158 fn entity_id(&self) -> &Self::Id {
159 &self.id
160 }
161
162 fn entity_type() -> &'static str {
163 "SalaryStructure"
164 }
165}
166
167impl backbone_core::PersistentEntity for SalaryStructure {
168 fn entity_id(&self) -> String {
169 self.id.to_string()
170 }
171 fn set_entity_id(&mut self, id: String) {
172 if let Ok(uuid) = uuid::Uuid::parse_str(&id) {
173 self.id = uuid;
174 }
175 }
176 fn created_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
177 self.metadata.created_at
178 }
179 fn set_created_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
180 self.metadata.created_at = Some(ts);
181 }
182 fn updated_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
183 self.metadata.updated_at
184 }
185 fn set_updated_at(&mut self, ts: chrono::DateTime<chrono::Utc>) {
186 self.metadata.updated_at = Some(ts);
187 }
188 fn deleted_at(&self) -> Option<chrono::DateTime<chrono::Utc>> {
189 self.metadata.deleted_at
190 }
191 fn set_deleted_at(&mut self, ts: Option<chrono::DateTime<chrono::Utc>>) {
192 self.metadata.deleted_at = ts;
193 }
194}
195
196impl backbone_orm::EntityRepoMeta for SalaryStructure {
197 fn column_types() -> std::collections::HashMap<String, String> {
198 let mut m = std::collections::HashMap::new();
199 m.insert("id".to_string(), "uuid".to_string());
200 m.insert("status".to_string(), "salary_structure_status".to_string());
201 m
202 }
203 fn search_fields() -> &'static [&'static str] {
204 &["name"]
205 }
206}
207
208#[derive(Debug, Clone, Default)]
213pub struct SalaryStructureBuilder {
214 name: Option<String>,
215 status: Option<SalaryStructureStatus>,
216}
217
218impl SalaryStructureBuilder {
219 pub fn name(mut self, value: String) -> Self {
221 self.name = Some(value);
222 self
223 }
224
225 pub fn status(mut self, value: SalaryStructureStatus) -> Self {
227 self.status = Some(value);
228 self
229 }
230
231 pub fn build(self) -> Result<SalaryStructure, String> {
235 let name = self.name.ok_or_else(|| "name is required".to_string())?;
236
237 Ok(SalaryStructure {
238 id: Uuid::new_v4(),
239 name,
240 status: self.status.unwrap_or_default(),
241 metadata: AuditMetadata::default(),
242 })
243 }
244}