stateset_embedded/
fixed_assets.rs1use chrono::NaiveDate;
17use rust_decimal::Decimal;
18use stateset_core::{
19 CreateFixedAsset, DepreciationSchedule, FixedAsset, FixedAssetFilter, Result, UpdateFixedAsset,
20};
21use stateset_db::{Database, DatabaseCapability};
22use std::sync::Arc;
23use uuid::Uuid;
24
25#[cfg(feature = "events")]
26use crate::events::EventSystem;
27#[cfg(feature = "events")]
28use chrono::Utc;
29#[cfg(feature = "events")]
30use stateset_core::CommerceEvent;
31
32pub struct FixedAssets {
34 db: Arc<dyn Database>,
35 #[cfg(feature = "events")]
36 event_system: Arc<EventSystem>,
37}
38
39impl std::fmt::Debug for FixedAssets {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("FixedAssets").finish_non_exhaustive()
42 }
43}
44
45impl FixedAssets {
46 #[cfg(feature = "events")]
47 pub(crate) fn new(db: Arc<dyn Database>, event_system: Arc<EventSystem>) -> Self {
48 Self { db, event_system }
49 }
50
51 #[cfg(not(feature = "events"))]
52 pub(crate) fn new(db: Arc<dyn Database>) -> Self {
53 Self { db }
54 }
55
56 #[cfg(feature = "events")]
57 fn emit(&self, event: CommerceEvent) {
58 self.event_system.emit(event);
59 }
60
61 #[must_use]
63 pub fn is_supported(&self) -> bool {
64 self.db.supports_capability(DatabaseCapability::FixedAssets)
65 }
66
67 fn ensure(&self) -> Result<()> {
68 self.db.ensure_capability(DatabaseCapability::FixedAssets)
69 }
70
71 pub fn create(&self, input: CreateFixedAsset) -> Result<FixedAsset> {
73 self.ensure()?;
74 self.db.fixed_assets().create(input)
75 }
76
77 pub fn get(&self, id: Uuid) -> Result<Option<FixedAsset>> {
79 self.ensure()?;
80 self.db.fixed_assets().get(id)
81 }
82
83 pub fn list(&self, filter: FixedAssetFilter) -> Result<Vec<FixedAsset>> {
85 self.ensure()?;
86 self.db.fixed_assets().list(filter)
87 }
88
89 pub fn update(&self, id: Uuid, input: UpdateFixedAsset) -> Result<FixedAsset> {
91 self.ensure()?;
92 self.db.fixed_assets().update(id, input)
93 }
94
95 pub fn place_in_service(&self, id: Uuid, date: NaiveDate) -> Result<FixedAsset> {
97 self.ensure()?;
98 let asset = self.db.fixed_assets().place_in_service(id, date)?;
99 #[cfg(feature = "events")]
100 self.emit(CommerceEvent::FixedAssetPlacedInService {
101 asset_id: asset.id,
102 asset_number: asset.asset_number.clone(),
103 in_service_date: asset.in_service_date.unwrap_or(date),
104 acquisition_cost: asset.acquisition_cost,
105 timestamp: Utc::now(),
106 });
107 Ok(asset)
108 }
109
110 pub fn dispose(
112 &self,
113 id: Uuid,
114 date: NaiveDate,
115 proceeds: Decimal,
116 notes: Option<String>,
117 ) -> Result<FixedAsset> {
118 self.ensure()?;
119 let asset = self.db.fixed_assets().dispose(id, date, proceeds, notes)?;
120 #[cfg(feature = "events")]
121 self.emit(CommerceEvent::FixedAssetDisposed {
122 asset_id: asset.id,
123 asset_number: asset.asset_number.clone(),
124 disposal_date: asset.disposal.as_ref().map_or(date, |d| d.disposal_date),
125 proceeds,
126 gain_loss: asset.disposal.as_ref().map_or(rust_decimal::Decimal::ZERO, |d| d.gain_loss),
127 timestamp: Utc::now(),
128 });
129 Ok(asset)
130 }
131
132 pub fn write_off(
134 &self,
135 id: Uuid,
136 date: NaiveDate,
137 notes: Option<String>,
138 ) -> Result<FixedAsset> {
139 self.ensure()?;
140 let asset = self.db.fixed_assets().write_off(id, date, notes)?;
141 #[cfg(feature = "events")]
142 self.emit(CommerceEvent::FixedAssetWrittenOff {
143 asset_id: asset.id,
144 asset_number: asset.asset_number.clone(),
145 write_off_date: asset.disposal.as_ref().map_or(date, |d| d.disposal_date),
146 loss: asset
147 .disposal
148 .as_ref()
149 .map_or(rust_decimal::Decimal::ZERO, |d| d.gain_loss.abs()),
150 timestamp: Utc::now(),
151 });
152 Ok(asset)
153 }
154
155 pub fn generate_schedule(&self, id: Uuid) -> Result<DepreciationSchedule> {
157 self.ensure()?;
158 self.db.fixed_assets().generate_schedule(id)
159 }
160
161 pub fn get_schedule(&self, id: Uuid) -> Result<Option<DepreciationSchedule>> {
163 self.ensure()?;
164 self.db.fixed_assets().get_schedule(id)
165 }
166
167 pub fn post_depreciation(&self, id: Uuid, periods: u32) -> Result<FixedAsset> {
175 self.ensure()?;
176 #[cfg(feature = "events")]
177 let previous_accumulated = self
178 .db
179 .fixed_assets()
180 .get(id)?
181 .map(|a| a.accumulated_depreciation)
182 .unwrap_or(rust_decimal::Decimal::ZERO);
183 let asset = self.db.fixed_assets().post_depreciation(id, periods)?;
184 #[cfg(feature = "events")]
185 self.emit(CommerceEvent::DepreciationPosted {
186 asset_id: asset.id,
187 asset_number: asset.asset_number.clone(),
188 periods,
189 amount: asset.accumulated_depreciation - previous_accumulated,
190 accumulated_depreciation: asset.accumulated_depreciation,
191 timestamp: Utc::now(),
192 });
193 Ok(asset)
194 }
195}