Skip to content

Salary sacrifice NI measures charge the whole amount returned at one rate #2361

Open

Description

@MaxGhenis

salary_sacrifice_pension_ni_employee multiplies the whole amount returned to employment income (salary_sacrifice_returned_to_income) by one rate: the main rate if employment_income is at or below the upper earnings limit, otherwise the additional rate. salary_sacrifice_pension_ni_employer multiplies it by the employer rate.

Neither equals the change in the Class 1 liability the model computes (ni_class_1_employee, ni_class_1_employer) when the amount returned enters earnings:

  • An amount that straddles the upper earnings limit is charged entirely at the additional rate. With 2025 thresholds and a £2,000 cap, pay of £48,000 with £6,000 sacrificed returns £4,000 and takes earnings to £52,000. The liability rises by £216.20 (8% up to £50,269.96, 2% above it); the variable reports £80.
  • An amount below, or straddling, the primary threshold (employee) or the secondary threshold (employer) is charged in full. Pay of £1,500 with £5,000 sacrificed gives earnings of £4,500, below the £5,000 secondary threshold: the employer liability is £0 and the variable reports £450.
  • The age conditions are ignored. The employee variable charges people under 16 or over State Pension age (ni_liable), and the employer variable charges under-16s (ni_class_1_secondary_liable).
  • The employee variable compares employment_income with the limit, not Class 1 earnings (ni_class_1_income, which also includes statutory sick, maternity and paternity pay).

Both are reporting measures. No tax total reads them: the amount returned is already in employment_income, so ni_class_1_employee and ni_class_1_employer charge it.

Found by the independent specification of the tax-head partition written for #2235 (its defect 7).

Fix: make each variable the complete Class 1 liability on earnings less the liability on the same earnings without the amount returned, with YAML cases and a property test of that identity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions