diff --git a/changelog.d/class4-maximum-steps.md b/changelog.d/class4-maximum-steps.md new file mode 100644 index 000000000..bbb140a6b --- /dev/null +++ b/changelog.d/class4-maximum-steps.md @@ -0,0 +1 @@ +- Apply the Class 4 National Insurance annual maximum's Step Six and Step Nine calculations from Regulation 100. diff --git a/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.yaml b/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.yaml index ca5693c7b..f1f8ea999 100644 --- a/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.yaml @@ -5,4 +5,4 @@ self_employment_income: 100_000 employment_income: 100_000 output: - ni_class_4_maximum: 48_661 \ No newline at end of file + ni_class_4_maximum: 3_083.22 diff --git a/policyengine_uk/tests/test_ni_class_4_maximum.py b/policyengine_uk/tests/test_ni_class_4_maximum.py index 108049c99..ae03d7c15 100644 --- a/policyengine_uk/tests/test_ni_class_4_maximum.py +++ b/policyengine_uk/tests/test_ni_class_4_maximum.py @@ -3,7 +3,7 @@ from policyengine_uk import Simulation -def test_class_4_annual_maximum_uses_current_main_rate_factor(): +def test_class_4_annual_maximum_applies_case_3_steps(): year = 2026 monthly_primary_class_1 = {f"{year}-{month:02d}": 500 for month in range(1, 13)} sim = Simulation( @@ -21,6 +21,29 @@ def test_class_4_annual_maximum_uses_current_main_rate_factor(): ) assert sim.calculate("ni_class_4_maximum", year)[0] == pytest.approx( - 46_484, + 1_748.60, abs=0.01, ) + assert sim.calculate("ni_class_4", year)[0] == pytest.approx(1_748.60, abs=0.01) + + +def test_class_4_annual_maximum_does_not_bind_without_class_1(): + year = 2026 + sim = Simulation( + situation={ + "people": { + "person": { + "age": {year: 40}, + "self_employment_income": {year: 60_000}, + } + }, + "benunits": {"benunit": {"members": ["person"]}}, + "households": {"household": {"members": ["person"]}}, + } + ) + + assert sim.calculate("ni_class_4_maximum", year)[0] == pytest.approx( + 2_456.60, + abs=0.01, + ) + assert sim.calculate("ni_class_4", year)[0] == pytest.approx(2_456.60, abs=0.01) diff --git a/policyengine_uk/variables/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.py b/policyengine_uk/variables/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.py index c7d44a059..a454a53ed 100644 --- a/policyengine_uk/variables/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.py +++ b/policyengine_uk/variables/gov/hmrc/national_insurance/class_4/ni_class_4_maximum.py @@ -20,22 +20,23 @@ def formula(person, period, parameters): step_3 = step_2 + 53 * ni.class_2.flat_rate class_2_contributions = person("ni_class_2", period) primary_class_1_contributions = person("ni_class_1_employee_primary", period) - step_4 = step_3 - class_2_contributions - primary_class_1_contributions + step_4_raw = step_3 - class_2_contributions - primary_class_1_contributions + step_4 = max_(step_4_raw, 0) class_4_main_contributions = person("ni_class_4_main", period) other_aggregate_contributions = ( primary_class_1_contributions + class_2_contributions + class_4_main_contributions ) - case_1 = (step_4 >= 0) & (step_4 > other_aggregate_contributions) - case_2 = (step_4 >= 0) & (step_4 <= other_aggregate_contributions) - case_3 = step_4 < 0 + case_1 = (step_4_raw >= 0) & (step_4_raw > other_aggregate_contributions) + case_2 = (step_4_raw >= 0) & (step_4_raw <= other_aggregate_contributions) + case_3 = step_4_raw < 0 step_5 = step_4 / main_rate profits = person("self_employment_income", period) - step_6 = lpl - min_(upl, profits) + step_6 = min_(upl, profits) - lpl step_7 = max_(0, step_6 - step_5) step_8 = step_7 * add_rate - step_9 = max_(0, profits - upl) + step_9 = max_(0, profits - upl) * add_rate return select( [