def __init__(self, tax_brackets_configuration): self.tax_brackets = [] for bracket in tax_brackets_configuration['brackets']: new_bracket = TaxBracket(bracket['income'], bracket['rate']) self.tax_brackets.append(new_bracket) self.top_marginal_bracket = TaxBracket( Decimal('Infinity'), tax_brackets_configuration['top_marginal_rate']) logging.info( f"Initialized with {len(tax_brackets_configuration['brackets'])} " \ f"brackets, top marginal rate of "\ f"{tax_brackets_configuration['top_marginal_rate']}" )
class TaxBracketCollection: def __init__(self, tax_brackets_configuration): self.tax_brackets = [] for bracket in tax_brackets_configuration['brackets']: new_bracket = TaxBracket(bracket['income'], bracket['rate']) self.tax_brackets.append(new_bracket) self.top_marginal_bracket = TaxBracket( Decimal('Infinity'), tax_brackets_configuration['top_marginal_rate']) logging.info( f"Initialized with {len(tax_brackets_configuration['brackets'])} " \ f"brackets, top marginal rate of "\ f"{tax_brackets_configuration['top_marginal_rate']}" ) def calculate_tax(self, income): if income < 0: raise Exception("Negative incomes are not supported") total_tax = 0 for bracket in self.tax_brackets: if income == 0: break taxable_in_bracket = min(income, bracket.income) total_tax += bracket.calculate_tax(taxable_in_bracket) income -= taxable_in_bracket if income > 0: total_tax += self.top_marginal_bracket.calculate_tax(income) return total_tax def effective_tax_rate(self, income): # We could improve performance here by saving / memoizing the value # of "calculate_tax" if we called it earlier, at the expense of making # TaxBracketCollection stateful. total_tax = self.calculate_tax(income) return format(total_tax / income, '.2f')
def test_calculate_tax_below_limit(self): bracket = TaxBracket(100000, 0.10) self.assertEqual(bracket.calculate_tax(3000), 300)
def test_init(self): bracket = TaxBracket(100000, 0.10) self.assertTrue(isinstance(bracket, TaxBracket))
def test_error_negative_rate(self): with self.assertRaises(Exception): bracket = TaxBracket(1, -0.10)
def test_error_negative_income(self): with self.assertRaises(Exception): bracket = TaxBracket(-1, 0.10)
def test_error_calculate_tax_beyond_limit(self): bracket = TaxBracket(100000, 0.10) with self.assertRaises(Exception): bracket.calculate_tax(200000)
def test_does_not_round_to_two_decimal_places(self): # Intentional decision not to round to two decimal places (ie. cents) # until the end. More description in utils.py. bracket = TaxBracket(100000, 0.19) self.assertEqual(bracket.calculate_tax(7.10), 1.349)