FAQ | This is a LIVE service | Changelog

Apparent error in oncost calculation

This came about from me trying to understand by matching a simple result with HR's online calculator. To repeat run the salaries-commitments container:

cd $DEVOPS_HOME/research-dashboard/salaries-commitments
docker-compose run commitments python3

Then using HR's online calculator select:

  • Scheme: USS (exchange)
  • Period: 1st August 2019
  • Grades: Grade 8

.. and select the Salary, NIC, and Total for Scale point 052 (you will see these value are plugged in below). Then run the following in the console:

import ucamstaffoncosts
import salaries
from datetime import date

# target oncost etc retrieved from HR's online calculator
uss_exchange_grade_8_point_52_salary=45361
uss_exchange_grade_8_point_52_nic=4518
uss_exchange_grade_8_point_52_oncost=58930

# we calculate for a small time period (31 days) to avoid going into a different table
start=date(2019, 8, 1)
until=date(2019, 9, 1)
proportion_of_year=(until - start).days / 365

# note that NIC won't kick in for this small period (31 days)
print(f'Expected oncosts: {(uss_exchange_grade_8_point_52_oncost - uss_exchange_grade_8_point_52_nic) * proportion_of_year}')

grade, point, table = salaries.grade_and_point_for_staff_member(
    {'GRADE': 'Grade 8', 'POINT_VALUE_FTE': uss_exchange_grade_8_point_52_salary}
)

_, commitment, explanations = ucamstaffoncosts.employment_expenditure_and_commitments(
    start_date=start, 
    from_date=start, 
    until_date=until, 
    next_anniversary_date=until,
    initial_grade=grade, 
    initial_point=point,
    occupancy=1,
    scheme=ucamstaffoncosts.Scheme.USS_EXCHANGE,
    scale_table=table,
)

print(f'Actual oncosts: {commitment}')

You will see that the values differ by about £13. If we look at the explanations we will see that this is due mainly to the salary:

print(f'Expected salary: {uss_exchange_grade_8_point_52_salary * proportion_of_year}')

from ucamstaffoncosts.util import pprinttable
def print_explanations(explanations, from_date):
     running_commitment = 0
     for explanation in explanations:
         print('=' * 60)
         print('TAX YEAR: {}/{}'.format(explanation.tax_year, explanation.tax_year+1))
         print('\nSalaries\n--------\n')
         pprinttable(explanation.salaries)
         print('\nCosts\n-----')
         if explanation.cost.tax_year != explanation.tax_year:
             print('(approximated using tax tables for {})'.format(explanation.cost.tax_year))
         print('\n')
         pprinttable([explanation.cost])
         print('\nSalary for year: {}'.format(explanation.salary))
         print('Salary earned after {}: {}'.format(from_date, explanation.salary_to_come))
         print('Expenditure until {}: {}'.format(from_date, explanation.expenditure))
         print('Commitment from {}: {}'.format(from_date, explanation.commitment))
         running_commitment += explanation.commitment
         print('Running total commitment: {}'.format(running_commitment))
         print('\n')

print_explanations(explanations, start)

This shows a £10 difference (assumption: the remain £3 comes from amplification of the original error)

Edited by Mike Bamford