Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import List
from .money_amount import money ← from money.amount ^1.0.0 · built alongside by fune
from .payroll_gross_to_net_types import Payslip, PayslipInput
from .payroll_income_tax import income_tax ← from payroll.income-tax ^1.0.0 · built alongside by fune
from .payroll_national_insurance import national_insurance ← from payroll.national-insurance ^1.0.0 · built alongside by fune
from .payroll_pension_auto_enrolment import pension_contributions ← from payroll.pension-auto-enrolment ^1.0.0 · built alongside by fune
from .payroll_student_loan import student_loan ← from payroll.student-loan ^1.0.0 · built alongside by fune
from .payroll_tax_period import tax_period ← from payroll.tax-period ^1.0.0 · built alongside by fune
def gross_to_net(input: PayslipInput) -> Payslip:
"""One period's payslip, in the order a UK payroll works it out.
The order matters because each deduction is taken from a different figure:
a net pay arrangement pension comes off pay before tax but not before
National Insurance; tax is on taxable pay to date; NI and student loans are
on this period's gross pay alone; relief at source pension comes off net pay.
"""
gross = input.gross
if gross.currency != "GBP":
raise ValueError("payroll amounts must be in GBP, received %s for gross" % (gross.currency,))
when = tax_period(input.pay_date, input.frequency)
pension_employee = 0
pension_employer = 0
before_tax = 0
if input.pension is not None:
pension = pension_contributions(gross, input.frequency, input.pension, input.pay_date)
pension_employee = pension.employee_deduction.minor
pension_employer = pension.employer.minor
if pension.deduct_before_tax:
before_tax = pension.employee_deduction.minor
taxable_pay = money(gross.minor - before_tax, "GBP")
tax = income_tax(input.tax_code, input.frequency, when.period, taxable_pay, input.previous_taxable_pay_to_date, input.previous_tax_to_date, input.pay_date)
ni = national_insurance(gross, input.ni_category, input.frequency, input.pay_date, None)
# An employee with more than one undergraduate plan repays once, against the
# lowest threshold, which is the largest of the per-plan deductions; a
# postgraduate loan is repaid alongside it.
undergraduate = 0
postgraduate = 0
seen: List[str] = []
for plan in input.student_loan_plans:
if plan in seen:
raise ValueError("student loan plan %s is listed twice" % (plan,))
seen.append(plan)
deduction = student_loan(gross, plan, input.frequency, input.pay_date).minor
if plan == "postgraduate":
postgraduate = deduction
elif deduction > undergraduate:
undergraduate = deduction
net = gross.minor - pension_employee - tax.tax.minor - ni.employee.minor - undergraduate - postgraduate
return Payslip(
gross=gross,
pension_employee=money(pension_employee, "GBP"),
pension_employer=money(pension_employer, "GBP"),
taxable_pay=taxable_pay,
tax=tax.tax,
employee_ni=ni.employee,
employer_ni=ni.employer,
student_loan=money(undergraduate, "GBP"),
postgraduate_loan=money(postgraduate, "GBP"),
net=money(net, "GBP"),
taxable_pay_to_date=tax.pay_to_date,
tax_to_date=tax.tax_to_date,
period=when.period,
tax_year=when.tax_year,
)