Skip to content

Commit 5d1dca5

Browse files
vahid-ahmadiclaude
andauthored
Expand National Insurance documentation page (#746) (#1699)
* Expand National Insurance docs page (#746) The existing page covered Classes 1, 2 and 4 and ended in two parameter charts. Round it out with: - Class 3 (voluntary) added to the modelling table now that ni_class_3 is exposed, - a "How PolicyEngine computes National Insurance liability" section that walks through the per-class variables and the household total, - a References block (SSCBA 1992, HMRC rates page, HMRC outturn stats). Also fix the chained boolean indexing in the rates chart cell, which was triggering a pandas UserWarning ("Boolean Series key will be reindexed"). * Correct national_insurance rollup in NI docs national_insurance sums ni_class_1_employee + ni_class_2 + ni_class_3 + ni_class_4 directly (Class 3 is included), not ni_employee + ni_self_employed. The separately-tracked item is the Class 1 employer charge, not Class 3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 005934a commit 5d1dca5

2 files changed

Lines changed: 26 additions & 16 deletions

File tree

changelog.d/746.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Expand the National Insurance documentation page with a per-class computation section, add Class 3 (voluntary) to the modelling table, link the underlying variables, and add a references section; also fix the boolean-chain warning in the rates chart.

docs/book/programs/gov/hmrc/national-insurance.ipynb

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -133,37 +133,45 @@
133133
"source": [
134134
"# @title\n",
135135
"import pandas as pd\n",
136-
"from tabulate import tabulate\n",
137136
"\n",
138137
"\n",
139138
"data = {\n",
140-
" \"Class\": [\"Class 1\", \"Class 2\", \"Class 4\"],\n",
139+
" \"Class\": [\"Class 1\", \"Class 2\", \"Class 3\", \"Class 4\"],\n",
141140
" \"Methodology & Basis\": [\n",
142141
" \"Based on employment income. \\n- Monthly and annual calculations.\",\n",
143142
" \"Based on self-employment income. \\n- Weekly flat rate.\",\n",
143+
" \"Voluntary contributions for those filling gaps in their NI record. \\n- Weekly flat rate.\",\n",
144144
" \"Derived from self-employment income minus Class 1 employee NI.\",\n",
145145
" ],\n",
146146
" \"Thresholds & Limits\": [\n",
147147
" \"Primary Threshold, Upper Earnings Limit\",\n",
148148
" \"Small Profits Threshold\",\n",
149+
" \"None (voluntary)\",\n",
149150
" \"Lower Profits Limit, Upper Profits Limit\",\n",
150151
" ],\n",
151152
" \"Rate Application\": [\n",
152153
" \"Main and Additional rates\",\n",
153154
" \"Flat rate\",\n",
155+
" \"Flat rate\",\n",
154156
" \"Main and Additional rates\",\n",
155157
" ],\n",
156158
" \"Reference\": [\n",
157159
" \"Social Security Contributions and Benefits Act 1992 s. 8\",\n",
158-
" \"Social Security and Benefits Act 1992 s. 11\",\n",
159-
" \"Social Security and Benefits Act 1992 s. 15\",\n",
160+
" \"Social Security Contributions and Benefits Act 1992 s. 11\",\n",
161+
" \"Social Security Contributions and Benefits Act 1992 s. 13\",\n",
162+
" \"Social Security Contributions and Benefits Act 1992 s. 15\",\n",
160163
" ],\n",
161164
"}\n",
162165
"\n",
163166
"df = pd.DataFrame(data)\n",
164167
"df"
165168
]
166169
},
170+
{
171+
"cell_type": "markdown",
172+
"metadata": {},
173+
"source": "## How PolicyEngine computes National Insurance liability\n\nFor each person, PolicyEngine computes NI contributions class-by-class:\n\n- **Class 1 employee** (`ni_class_1_employee`): the sum of `ni_class_1_employee_primary` (main rate on earnings between the Primary Threshold and the Upper Earnings Limit) and `ni_class_1_employee_additional` (additional rate on earnings above the UEL).\n- **Class 1 employer** (`ni_class_1_employer`): paid on earnings above the Secondary Threshold; surfaced through the `ni_employer` variable.\n- **Class 2** (`ni_class_2`): a flat weekly rate paid by the self-employed with profits above the Small Profits Threshold.\n- **Class 3** (`ni_class_3`): a voluntary flat weekly rate; the variable is exposed but defaults to zero unless explicitly set.\n- **Class 4** (`ni_class_4`): main rate between the Lower and Upper Profits Limits plus additional rate above the UPL, capped at the published Class 4 maximum.\n\nThe individual total `national_insurance` sums the four employee and self-employed components directly — `ni_class_1_employee + ni_class_2 + ni_class_3 + ni_class_4` — so voluntary Class 3 contributions are included in the household-side liability. The convenience aggregates `ni_employee` (Class 1 employee only) and `ni_self_employed` (Class 2 + Class 4) are also exposed for reporting. The Class 1 *employer* charge (`ni_class_1_employer`, surfaced as `ni_employer`) is an employer-side cost rather than part of the individual's `national_insurance`, so it is tracked separately and feeds the government revenue aggregates on its own.\n\nParameters live in `policyengine_uk/parameters/gov/hmrc/national_insurance/` and the per-class formulas in `policyengine_uk/variables/gov/hmrc/national_insurance/`."
174+
},
167175
{
168176
"cell_type": "markdown",
169177
"metadata": {
@@ -1529,16 +1537,6 @@
15291537
]
15301538
},
15311539
"outputs": [
1532-
{
1533-
"name": "stderr",
1534-
"output_type": "stream",
1535-
"text": [
1536-
"/var/folders/8f/pgfhysmd5ls3jnxb_5j7yy340000gn/T/ipykernel_41381/4247299465.py:2: UserWarning:\n",
1537-
"\n",
1538-
"Boolean Series key will be reindexed to match DataFrame index.\n",
1539-
"\n"
1540-
]
1541-
},
15421540
{
15431541
"data": {
15441542
"application/vnd.plotly.v1+json": {
@@ -2688,7 +2686,7 @@
26882686
],
26892687
"source": [
26902688
"fig = px.line(\n",
2691-
" df[df[\"Threshold\"] == False][df.Value < 1], # Don't plot the flat rate,\n",
2689+
" df[(df[\"Threshold\"] == False) & (df[\"Value\"] < 1)], # Don't plot the flat rate,\n",
26922690
" x=\"Instant\",\n",
26932691
" y=\"Value\",\n",
26942692
" color=\"Label\",\n",
@@ -2714,6 +2712,17 @@
27142712
"fig = format_fig(fig)\n",
27152713
"fig"
27162714
]
2715+
},
2716+
{
2717+
"cell_type": "markdown",
2718+
"metadata": {},
2719+
"source": [
2720+
"## References\n",
2721+
"\n",
2722+
"- [Social Security Contributions and Benefits Act 1992](https://www.legislation.gov.uk/ukpga/1992/4/contents) — primary statute defining each NI class.\n",
2723+
"- HMRC, [Rates and allowances: National Insurance contributions](https://www.gov.uk/government/publications/rates-and-allowances-national-insurance-contributions).\n",
2724+
"- HMRC, [National Insurance contributions outturn statistics](https://www.gov.uk/government/collections/income-tax-statistics-and-distributions)."
2725+
]
27172726
}
27182727
],
27192728
"metadata": {
@@ -2739,4 +2748,4 @@
27392748
},
27402749
"nbformat": 4,
27412750
"nbformat_minor": 0
2742-
}
2751+
}

0 commit comments

Comments
 (0)