Skip to main content

paycheck_utils/
deductions.rs

1//! Module for handling paycheck deductions.
2//! Defines structures and functions for managing pre-tax and post-tax deductions.
3
4/// Pre-tax deductions are applied before federal tax calculations.
5///
6#[derive(Debug)]
7pub enum PreTaxDeduction {
8    Medical(Option<f32>),
9    Dental(Option<f32>),
10    Vision(Option<f32>),
11    Traditional401K(Option<f32>),
12    HSA(Option<f32>),
13    FSA(Option<f32>),
14}
15
16/// Post-tax deductions are applied after federal tax calculations
17#[derive(Debug)]
18pub enum PostTaxDeduction {
19    Roth401K(Option<f32>),
20    VoluntaryLife(Option<f32>),
21    VoluntaryADD(Option<f32>),
22    VoluntarySTD(Option<f32>),
23    VoluntaryLTD(Option<f32>),
24    WageGarnishment(Option<f32>), // e.g., child support, alimony
25}
26
27/// Struct to manage a collection of pre-tax deductions
28#[derive(Default, Debug)]
29pub struct PreTaxDeductions {
30    pretax_deductions: Vec<PreTaxDeduction>,
31}
32
33/// Struct to manage a collection of post-tax deductions
34#[derive(Default, Debug)]
35pub struct PostTaxDeductions {
36    posttax_deductions: Vec<PostTaxDeduction>,
37}
38
39impl PreTaxDeductions {
40    /// Create a new collection of pre-tax deductions
41    pub fn new(deductions: Vec<PreTaxDeduction>) -> Self {
42        PreTaxDeductions {
43            pretax_deductions: deductions,
44        }
45    }
46    /// Add multiple pre-tax deductions to the collection
47    pub fn add_pretax_deductions(&mut self, deductions: Vec<PreTaxDeduction>) {
48        self.pretax_deductions.extend(deductions);
49    }
50
51    /// Get a reference to the list of pre-tax deductions
52    pub fn get_pretax_deductions(&self) -> &Vec<PreTaxDeduction> {
53        &self.pretax_deductions
54    }
55
56    /// Calculate the total amount of pre-tax deductions
57    pub fn total_pretax_deductions(&self) -> f32 {
58        self.pretax_deductions
59            .iter()
60            .fold(0.0, |acc, deduction| match deduction {
61                PreTaxDeduction::Medical(amount)
62                | PreTaxDeduction::Dental(amount)
63                | PreTaxDeduction::Vision(amount)
64                | PreTaxDeduction::Traditional401K(amount)
65                | PreTaxDeduction::HSA(amount)
66                | PreTaxDeduction::FSA(amount) => acc + amount.unwrap_or(0.0),
67            })
68    }
69}
70
71impl PostTaxDeductions {
72    /// Create a new collection of post-tax deductions
73    pub fn new(deductions: Vec<PostTaxDeduction>) -> Self {
74        PostTaxDeductions {
75            posttax_deductions: deductions,
76        }
77    }
78
79    /// Add multiple post-tax deductions to the collection
80    pub fn add_posttax_deductions(&mut self, deductions: Vec<PostTaxDeduction>) {
81        self.posttax_deductions.extend(deductions);
82    }
83
84    /// Get a reference to the list of post-tax deductions
85    pub fn get_posttax_deductions(&self) -> &Vec<PostTaxDeduction> {
86        &self.posttax_deductions
87    }
88
89    /// Calculate the total amount of post-tax deductions
90    pub fn total_posttax_deductions(&self) -> f32 {
91        self.posttax_deductions
92            .iter()
93            .fold(0.0, |acc, deduction| match deduction {
94                PostTaxDeduction::Roth401K(amount)
95                | PostTaxDeduction::VoluntaryLife(amount)
96                | PostTaxDeduction::VoluntaryADD(amount)
97                | PostTaxDeduction::VoluntarySTD(amount)
98                | PostTaxDeduction::VoluntaryLTD(amount)
99                | PostTaxDeduction::WageGarnishment(amount) => acc + amount.unwrap_or(0.0),
100            })
101    }
102}
103
104// UNIT TESTS FOR DEDUCTIONS MODULE
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use PostTaxDeduction::*;
110    use PreTaxDeduction::*;
111    #[test]
112    fn test_total_pretax_deductions() {
113        let deductions = PreTaxDeductions::new(vec![
114            Medical(Some(150.0)),
115            Dental(Some(50.0)),
116            Traditional401K(Some(200.0)),
117        ]);
118        let total = deductions.total_pretax_deductions();
119        assert_eq!(total, 400.0);
120    }
121    #[test]
122    fn test_get_pretax_deductions() {
123        let deductions = PreTaxDeductions::new(vec![
124            Medical(Some(150.0)),
125            Dental(Some(50.0)),
126            Traditional401K(Some(200.0)),
127        ]);
128        let pretax_list = deductions.get_pretax_deductions();
129        assert_eq!(pretax_list.len(), 3);
130    }
131    #[test]
132    fn test_add_pretax_deductions() {
133        let mut deductions = PreTaxDeductions::new(vec![Medical(Some(150.0))]);
134        deductions.add_pretax_deductions(vec![Dental(Some(50.0)), Traditional401K(Some(200.0))]);
135        let total = deductions.total_pretax_deductions();
136        assert_eq!(total, 400.0);
137    }
138    #[test]
139    fn test_total_posttax_deductions() {
140        let deductions = PostTaxDeductions::new(vec![
141            VoluntaryLife(Some(30.0)),
142            VoluntarySTD(Some(22.0)),
143            VoluntaryLTD(Some(34.0)),
144            WageGarnishment(Some(600.0)),
145        ]);
146        let total = deductions.total_posttax_deductions();
147        assert_eq!(total, 686.0);
148    }
149    #[test]
150    fn test_get_posttax_deductions() {
151        let deductions = PostTaxDeductions::new(vec![
152            VoluntaryLife(Some(30.0)),
153            VoluntarySTD(Some(22.0)),
154            VoluntaryLTD(Some(34.0)),
155            WageGarnishment(Some(600.0)),
156        ]);
157        let posttax_list = deductions.get_posttax_deductions();
158        assert_eq!(posttax_list.len(), 4);
159    }
160    #[test]
161    fn test_add_posttax_deductions() {
162        let mut deductions = PostTaxDeductions::new(vec![VoluntaryLife(Some(30.0))]);
163        deductions.add_posttax_deductions(vec![
164            VoluntarySTD(Some(22.0)),
165            VoluntaryLTD(Some(34.0)),
166            WageGarnishment(Some(600.0)),
167        ]);
168        let total = deductions.total_posttax_deductions();
169        assert_eq!(total, 686.0);
170    }
171}