1pub const PERSONAL_ALLOWANCE: f64 = 12_570.0; pub const BASIC_LIMIT: f64 = 50_270.0; pub const HIGHER_LIMIT: f64 = 125_140.0; pub const PA_TAPER_START: f64 = 100_000.0; pub const NI_PRIMARY_THRESHOLD: f64 = 12_570.0;
31pub const NI_UPPER_LIMIT: f64 = 50_270.0;
32pub const NI_MAIN_RATE: f64 = 0.08; pub const NI_UPPER_RATE: f64 = 0.02; pub fn personal_allowance(gross: f64) -> f64 {
37 if gross <= PA_TAPER_START { return PERSONAL_ALLOWANCE; }
38 let reduced = PERSONAL_ALLOWANCE - (gross - PA_TAPER_START) / 2.0;
39 reduced.max(0.0)
40}
41
42pub fn income_tax(gross: f64) -> f64 {
44 let pa = personal_allowance(gross);
45 let taxable = (gross - pa).max(0.0);
46 if taxable <= 0.0 { return 0.0; }
47 let basic_width = (BASIC_LIMIT - PERSONAL_ALLOWANCE).max(0.0);
48 let higher_width = (HIGHER_LIMIT - BASIC_LIMIT).max(0.0);
49 let mut tax = 0.0;
50 let mut remaining = taxable;
51 let b = remaining.min(basic_width); tax += 0.20 * b; remaining -= b;
53 if remaining > 0.0 { let h = remaining.min(higher_width); tax += 0.40 * h; remaining -= h; }
54 if remaining > 0.0 { tax += 0.45 * remaining; }
55 tax
56}
57
58pub fn national_insurance(earnings: f64) -> f64 {
60 if earnings <= NI_PRIMARY_THRESHOLD { return 0.0; }
61 let main_band = (earnings.min(NI_UPPER_LIMIT) - NI_PRIMARY_THRESHOLD).max(0.0);
62 let upper = (earnings - NI_UPPER_LIMIT).max(0.0);
63 NI_MAIN_RATE * main_band + NI_UPPER_RATE * upper
64}
65
66pub fn take_home(gross: f64) -> (f64, f64, f64) {
68 let t = income_tax(gross);
69 let n = national_insurance(gross);
70 (gross - t - n, t, n)
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 #[test]
77 fn basic_rate_only() {
78 let t = income_tax(40_000.0);
80 assert!((t - 0.20 * 27_430.0).abs() < 1e-6);
81 }
82 #[test]
83 fn nil_allowance_at_125140() {
84 assert!(personal_allowance(125_140.0).abs() < 1e-6);
85 }
86 #[test]
87 fn ni_main_band() {
88 let n = national_insurance(50_000.0);
90 assert!((n - 0.08 * (50_000.0 - 12_570.0)).abs() < 1e-6);
91 }
92 #[test]
93 fn ni_upper_rate() {
94 let n = national_insurance(60_000.0);
96 let expect = 0.08 * (50_270.0 - 12_570.0) + 0.02 * (60_000.0 - 50_270.0);
97 assert!((n - expect).abs() < 1e-6);
98 }
99 #[test]
100 fn take_home_decreases_with_tax() {
101 let (net, _, _) = take_home(50_000.0);
102 assert!(net < 50_000.0);
103 }
104}