Functional Weave
Code in Python

payroll.gross-to-net@1.0.1

impl/python.py

3,098 bytes · the Python implementation · view raw

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,
    )