koprogo_api/domain/services/
expense_calculator.rs1use crate::domain::entities::{Expense, Unit};
2
3pub struct ExpenseCalculator;
5
6impl ExpenseCalculator {
7 pub fn calculate_unit_share(expense: &Expense, unit: &Unit) -> f64 {
9 expense.amount * (unit.quota / 1000.0)
10 }
11
12 pub fn calculate_total_expenses(expenses: &[Expense]) -> f64 {
14 expenses.iter().map(|e| e.amount).sum()
15 }
16
17 pub fn calculate_paid_expenses(expenses: &[Expense]) -> f64 {
19 expenses
20 .iter()
21 .filter(|e| e.is_paid())
22 .map(|e| e.amount)
23 .sum()
24 }
25
26 pub fn calculate_unpaid_expenses(expenses: &[Expense]) -> f64 {
28 expenses
29 .iter()
30 .filter(|e| !e.is_paid())
31 .map(|e| e.amount)
32 .sum()
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39 use crate::domain::entities::{ExpenseCategory, UnitType};
40 use chrono::Utc;
41 use uuid::Uuid;
42
43 #[test]
44 fn test_calculate_unit_share() {
45 let org_id = Uuid::new_v4();
46 let building_id = Uuid::new_v4();
47
48 let expense = Expense::new(
49 org_id,
50 building_id,
51 ExpenseCategory::Maintenance,
52 "Test".to_string(),
53 1000.0,
54 Utc::now(),
55 None,
56 None,
57 )
58 .unwrap();
59
60 let unit = Unit::new(
61 org_id,
62 building_id,
63 "A101".to_string(),
64 UnitType::Apartment,
65 Some(1),
66 75.0,
67 50.0, )
69 .unwrap();
70
71 let share = ExpenseCalculator::calculate_unit_share(&expense, &unit);
72 assert_eq!(share, 50.0); }
74
75 #[test]
76 fn test_calculate_total_expenses() {
77 let org_id = Uuid::new_v4();
78 let building_id = Uuid::new_v4();
79
80 let expenses = vec![
81 Expense::new(
82 org_id,
83 building_id,
84 ExpenseCategory::Maintenance,
85 "Test 1".to_string(),
86 100.0,
87 Utc::now(),
88 None,
89 None,
90 )
91 .unwrap(),
92 Expense::new(
93 org_id,
94 building_id,
95 ExpenseCategory::Repairs,
96 "Test 2".to_string(),
97 200.0,
98 Utc::now(),
99 None,
100 None,
101 )
102 .unwrap(),
103 ];
104
105 let total = ExpenseCalculator::calculate_total_expenses(&expenses);
106 assert_eq!(total, 300.0);
107 }
108
109 #[test]
110 fn test_calculate_paid_and_unpaid() {
111 let org_id = Uuid::new_v4();
112 let building_id = Uuid::new_v4();
113
114 let mut expense1 = Expense::new(
115 org_id,
116 building_id,
117 ExpenseCategory::Maintenance,
118 "Test 1".to_string(),
119 100.0,
120 Utc::now(),
121 None,
122 None,
123 )
124 .unwrap();
125 expense1.mark_as_paid();
126
127 let expense2 = Expense::new(
128 org_id,
129 building_id,
130 ExpenseCategory::Repairs,
131 "Test 2".to_string(),
132 200.0,
133 Utc::now(),
134 None,
135 None,
136 )
137 .unwrap();
138
139 let expenses = vec![expense1, expense2];
140
141 let paid = ExpenseCalculator::calculate_paid_expenses(&expenses);
142 let unpaid = ExpenseCalculator::calculate_unpaid_expenses(&expenses);
143
144 assert_eq!(paid, 100.0);
145 assert_eq!(unpaid, 200.0);
146 }
147}