Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d2be9c2
Let employers deduct less than the permitted state payroll premium
MaxGhenis Oct 19, 2026
f160968
Seed small-employer and capped-wage workers in the deduction share in…
MaxGhenis Oct 19, 2026
8ec5126
Address review r1: docstrings, Oregon line, employer-level coverage
MaxGhenis Oct 19, 2026
727ebcb
Scope the Rev. Rul. 2025-4 note to the state paid leave funds
MaxGhenis Oct 19, 2026
156453f
Model the Minnesota Paid Leave employer premium
MaxGhenis Oct 19, 2026
75ec5a5
Merge remote-tracking branch 'upstream/payroll-employer-deduction-sha…
MaxGhenis Oct 19, 2026
5e55446
Test that Minnesota's derived employee portion follows the parameters
MaxGhenis Oct 19, 2026
33b1f90
Merge main into payroll-employer-deduction-share
MaxGhenis Oct 19, 2026
3698893
Merge branch 'main' into payroll-employer-deduction-share
MaxGhenis Oct 19, 2026
f2f4314
Address review r1: wage limit source, float32 boundary, employee cap
MaxGhenis Oct 19, 2026
f5b8ec2
Keep pre-2015 Minnesota calculations working; compare the wage at flo…
MaxGhenis Oct 20, 2026
c1c6da1
Merge remote-tracking branch 'upstream/payroll-employer-deduction-sha…
MaxGhenis Oct 20, 2026
b0596ab
Address review r2: statutory sentinels, half-up limit rounding, wording
MaxGhenis Oct 20, 2026
a19c04c
Address review r3: sentinel comment, pin half-up limit rounding
MaxGhenis Oct 20, 2026
bfab0c9
Answer review of Minnesota employer paid leave premium
claude Nov 2, 2026
eef658a
State the unit of the subd. 5c(b) estimate
MaxGhenis Nov 2, 2026
2c662e9
Merge main into mn-employer-paid-leave-premium
MaxGhenis Nov 9, 2026
780a23e
Record Minnesota Paid Leave's small employer source conflicts and pin…
MaxGhenis Nov 9, 2026
e3966ea
Capture Minnesota's Paid Leave small employer sources and reword thei…
MaxGhenis Nov 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/mn-employer-paid-leave-premium.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Model the Minnesota Paid Leave employer premium, including the small employer rate and test (Minn. Stat. 268B.14, subds. 5a-5c), and include it in employer payroll taxes.
1 change: 1 addition & 0 deletions changelog.d/mn-employer-paid-leave-premium.removed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove the Minnesota Paid Leave `employee_rate` parameter. The model now derives the employee portion from `rate`, `employer_minimum_share` and the `small_employer` shares, so reforms that set `employee_rate` must set those instead.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: Minnesota sets this minimum share of the premium that employers pay under the Paid Leave program.
values:
# Earlier years read the 2026 value; the zero rate keeps every amount at 0
# before 2026 unless a reform sets an earlier rate.
0000-01-01: 0.5
2026-01-01: 0.5

metadata:
period: year
unit: /1
label: Minnesota Paid Leave employer minimum premium share
reference:
- title: Minnesota Statutes Section 268B.14, subdivision 3
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.3
- title: Minnesota Paid Leave, Premium rate and contributions ("employers can collect up to 0.44% from employees")
href: https://pl.mn.gov/resources/calculators/premium-rate-and-contributions
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
description: Minnesota sets this premium rate on taxable wages for an employer in both the family and medical benefit programs under the Paid Leave program.
values:
0000-01-01: 0
# Statutory 0.7% (subd. 6), adjusted by the commissioner under subd. 7.
2026-01-01: 0.0088
2027-01-01: 0.0088

metadata:
period: year
unit: /1
label: Minnesota Paid Leave premium rate
reference:
- title: Minnesota Statutes Section 268B.14, subdivisions 1, 6 and 7
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.1
- title: Minnesota DEED confirms Paid Leave premium rate
href: https://mn.gov/deed/newscenter/press-releases/?id=1045-670064
- title: Minnesota Paid Leave, Premium rate and contributions ("For 2026 and 2027, the Paid Leave premium rate is 0.88%")
href: https://pl.mn.gov/resources/calculators/premium-rate-and-contributions
- title: Minnesota DEED, Paid Leave premium rate unchanged for 2027 (July 31, 2026)
href: https://content.govdelivery.com/accounts/MNDEED/bulletins/422fdf7
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: Minnesota sets this minimum share of the full premium rate that small employers pay under the Paid Leave program.
values:
# Earlier years read the 2026 value; the zero rate keeps every amount at 0
# before 2026 unless a reform sets an earlier rate.
0000-01-01: 0.25
2026-01-01: 0.25

metadata:
period: year
unit: /1
label: Minnesota Paid Leave small employer minimum premium share
reference:
- title: Minnesota Statutes Section 268B.14, subdivision 5a(b)(1)
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.5a
- title: Minnesota DEED, Paid Leave small employer premium rate designation ("Like large employers, small employers can deduct up to 0.44% of wages")
href: https://mn.gov/deed/assets/paid-leave-small-employer-premium-rate-designation-acc_tcm1045-716947.pdf#page=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: Minnesota limits the small employer premium rate to employers whose average wage is at most this multiple of the state's average wage in covered employment under the Paid Leave program.
values:
# Earlier years read the 2026 value; the zero rate keeps every amount at 0
# before 2026 unless a reform sets an earlier rate.
0000-01-01: 1.5
2026-01-01: 1.5

metadata:
period: year
unit: /1
label: Minnesota Paid Leave small employer average wage limit ratio
reference:
- title: Minnesota Statutes Section 268B.14, subdivision 5a(a)(2)
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.5a
- title: Minnesota DEED, Paid Leave small employer premium rate designation
href: https://mn.gov/deed/assets/paid-leave-small-employer-premium-rate-designation-acc_tcm1045-716947.pdf#page=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: Minnesota limits the small employer premium rate to employers with at most this many employees under the Paid Leave program.
values:
# Earlier years read the 2026 value; the zero rate keeps every amount at 0
# before 2026 unless a reform sets an earlier rate.
0000-01-01: 30
2026-01-01: 30

metadata:
period: year
unit: person
label: Minnesota Paid Leave small employer maximum employees
reference:
- title: Minnesota Statutes Section 268B.14, subdivisions 5a(a)(1) and 5b
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.5a
- title: Minnesota DEED, Paid Leave small employer premium rate designation
href: https://mn.gov/deed/assets/paid-leave-small-employer-premium-rate-designation-acc_tcm1045-716947.pdf#page=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
description: Minnesota sets the small employer premium rate at this share of the full premium rate under the Paid Leave program.
values:
# Earlier years read the 2026 value; the zero rate keeps every amount at 0
# before 2026 unless a reform sets an earlier rate.
0000-01-01: 0.75
2026-01-01: 0.75

metadata:
period: year
unit: /1
label: Minnesota Paid Leave small employer premium rate share
reference:
- title: Minnesota Statutes Section 268B.14, subdivision 5a(b)
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.5a
- title: Minnesota Paid Leave, Premium rate and contributions ("The Paid Leave small employer rate is 0.66%")
href: https://pl.mn.gov/resources/calculators/premium-rate-and-contributions
- title: Minnesota DEED, Paid Leave small employer premium rate designation
href: https://mn.gov/deed/assets/paid-leave-small-employer-premium-rate-designation-acc_tcm1045-716947.pdf#page=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
description: Minnesota uses this statewide average annual wage in covered employment for the small employer wage test under the Paid Leave program.
values:
# Earlier years read the 2026 value; the zero rate keeps every amount at 0
# before 2026 unless a reform sets an earlier rate.
0000-01-01: 73_989
# Statewide average annual wage for 2025 ("$73,989 per year"), applied to
# 2026 premiums, whose basis period is October 2024 to September 2025.
2026-01-01: 73_989
# No Department of Employment and Economic Development figure for 2027
# premiums as of 2026-10-20, so the 2026 value carries forward; update it
# when the department issues 2027 small employer designations.

metadata:
period: year
unit: currency-USD
label: Minnesota Paid Leave state average annual wage
reference:
- title: Minnesota Statutes Section 268B.14, subdivisions 5a(a)(2) and 5b(a)
href: https://www.revisor.mn.gov/statutes/cite/268B.14#stat.268B.14.5a
- title: Minnesota DEED, Paid Leave small employer premium rate designation, Key Terms ("The Statewide Average Annual Wage for 2025 was $73,989 per year")
href: https://mn.gov/deed/assets/paid-leave-small-employer-premium-rate-designation-acc_tcm1045-716947.pdf#page=2
156 changes: 156 additions & 0 deletions policyengine_us/tests/core/test_payroll_contributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ def calculate(sim: Simulation, variable: str) -> float:
pytest.param(
"ME", "employer_total_me_paid_leave_taxable_wages", 4_000, id="ME"
),
pytest.param(
"MN", "employer_total_mn_paid_leave_taxable_wages", 4_000, id="MN"
),
pytest.param(
"OR", "employer_total_or_paid_leave_taxable_wages", 4_000, id="OR"
),
Expand Down Expand Up @@ -131,6 +134,7 @@ def make_employer_total_simulation(
employer_total_dc_paid_leave_taxable_wages: float = WAGES,
employer_total_ma_paid_leave_taxable_wages: float = WAGES,
employer_total_me_paid_leave_taxable_wages: float = WAGES,
employer_total_mn_paid_leave_taxable_wages: float = WAGES,
employer_total_or_paid_leave_taxable_wages: float = WAGES,
employer_total_vt_child_care_contribution_wages: float = WAGES,
employer_total_wa_paid_leave_taxable_wages: float = WAGES,
Expand Down Expand Up @@ -182,6 +186,9 @@ def make_employer_total_simulation(
"employer_total_me_paid_leave_taxable_wages": {
PERIOD: employer_total_me_paid_leave_taxable_wages
},
"employer_total_mn_paid_leave_taxable_wages": {
PERIOD: employer_total_mn_paid_leave_taxable_wages
},
"employer_total_or_paid_leave_taxable_wages": {
PERIOD: employer_total_or_paid_leave_taxable_wages
},
Expand Down Expand Up @@ -508,6 +515,14 @@ def test_employee_payroll_tax_zero_when_payroll_tax_abolished():
},
id="ME",
),
pytest.param(
"MN",
{
"mn_employer_paid_leave_contribution": 440,
"mn_employer_additional_state_payroll_tax": 440,
},
id="MN",
),
pytest.param(
"OR",
{
Expand Down Expand Up @@ -592,6 +607,143 @@ def test_small_employer_thresholds_zero_employer_paid_leave_share(
assert calculate(sim, variable) == 0


@pytest.mark.parametrize(
("small_employer_minimum", "small_employee", "small_employer"),
[
# A small employer minimum above the 75% small employer premium
# leaves employees nothing ("the remaining portion, if any").
pytest.param(0.8, 0, 750, id="employee-floor"),
# A negative minimum can't make employees pay more than the premium.
pytest.param(-0.1, 750, 0, id="employee-cap"),
],
)
def test_minnesota_paid_leave_shares_follow_the_parameters(
small_employer_minimum: float, small_employee: float, small_employer: float
):
# The employee portion is derived from the rate and the employer minimums
# (Minn. Stat. 268B.14, subds. 3 and 5a(b)), so a reform of either reaches
# both sides.
paid_leave = "gov.states.mn.tax.payroll.paid_leave"
reform = Reform.from_dict(
{
f"{paid_leave}.rate": {
"2025-01-01.2025-12-31": 0.01,
"2026-01-01.2026-12-31": 0.01,
},
f"{paid_leave}.employer_minimum_share": {"2026-01-01.2026-12-31": 0.6},
f"{paid_leave}.small_employer.employer_minimum_share": {
"2026-01-01.2026-12-31": small_employer_minimum
},
},
country_id="us",
)
people = {
name: {
"age": {PERIOD: 30},
"employment_income": {"2025": WAGES, PERIOD: WAGES},
"employer_headcount": {"2025": headcount, PERIOD: headcount},
"employer_total_mn_paid_leave_taxable_wages": {PERIOD: WAGES},
}
for name, headcount in (("large", 100), ("small", 30))
}
sim = Simulation(
tax_benefit_system=CountryTaxBenefitSystem(reform=(reform,)),
situation={
"people": people,
"households": {
"household": {
"members": list(people),
"state_code": {"2025": "MN", PERIOD: "MN"},
}
},
"tax_units": {"tax_unit": {"members": list(people)}},
"spm_units": {"spm_unit": {"members": list(people)}},
"families": {"family": {"members": list(people)}},
"marital_units": {
f"{name}_marital_unit": {"members": [name]} for name in people
},
},
)

# Large: 1% premium, 40% of it deductible. Small: 75% * 1% premium.
assert sim.calculate("mn_paid_leave_premium", PERIOD) == pytest.approx([1_000, 750])
assert sim.calculate(
"mn_employee_paid_leave_contribution", PERIOD
) == pytest.approx([400, small_employee])
assert sim.calculate(
"mn_employer_paid_leave_contribution", PERIOD
) == pytest.approx([600, small_employer])
# The employer-level path reads the same derived rates.
assert sim.calculate(
"employer_total_additional_state_payroll_tax", PERIOD
) == pytest.approx([600, small_employer])
# In 2025 the reform sets only the rate, so the shares keep their
# statutory values: the employer pays 1% - 0.5% = 0.5% of wages, or for
# a small employer 0.75% - (0.75% - 0.25%) = 0.25%.
assert sim.calculate("mn_paid_leave_premium", "2025") == pytest.approx([1_000, 750])
assert sim.calculate(
"mn_employer_paid_leave_contribution", "2025"
) == pytest.approx([500, 250])


def test_minnesota_small_employer_wage_limit_rounds_half_up():
# 150% * $73,991 / 4 = $27,746.625, which rounds half up to $27,746.63
# (half to even would give $27,746.62). In 2027, 150% * $73,989.02 / 4 =
# $27,745.8825, which rounds to $27,745.88 (rounding up would give
# $27,745.89).
reform = Reform.from_dict(
{
"gov.states.mn.tax.payroll.paid_leave.small_employer.state_average_annual_wage": {
"2026-01-01.2026-12-31": 73_991,
"2027-01-01.2027-12-31": 73_989.02,
},
},
country_id="us",
)
people = {
name: {
"age": {PERIOD: 30},
"employment_income": {PERIOD: WAGES},
"employer_headcount": {PERIOD: 10, "2027": 10},
"mn_paid_leave_employer_average_quarterly_wage": {
PERIOD: average_wage_2026,
"2027": average_wage_2027,
},
}
for name, average_wage_2026, average_wage_2027 in (
("at_limit", 27_746.63, 27_745.88),
("above", 27_746.64, 27_745.89),
)
}
sim = Simulation(
tax_benefit_system=CountryTaxBenefitSystem(reform=(reform,)),
situation={
"people": people,
"households": {
"household": {
"members": list(people),
"state_code": {PERIOD: "MN", "2027": "MN"},
}
},
"tax_units": {"tax_unit": {"members": list(people)}},
"spm_units": {"spm_unit": {"members": list(people)}},
"families": {"family": {"members": list(people)}},
"marital_units": {
f"{name}_marital_unit": {"members": [name]} for name in people
},
},
)

assert sim.calculate("mn_paid_leave_small_employer", PERIOD).tolist() == [
True,
False,
]
assert sim.calculate("mn_paid_leave_small_employer", "2027").tolist() == [
True,
False,
]


@pytest.mark.parametrize(
("state_code", "expected"),
[
Expand Down Expand Up @@ -637,6 +789,7 @@ def test_small_employer_thresholds_zero_employer_paid_leave_share(
{
"mn_paid_leave_taxable_wages": 7_000,
"mn_employee_paid_leave_contribution": 30.8,
"mn_employer_paid_leave_contribution": 30.8,
},
id="MN",
),
Expand Down Expand Up @@ -962,6 +1115,7 @@ def test_new_york_mctmt_employer_tax(
pytest.param("DE", 100, WAGES, 9_000, 400, id="DE"),
pytest.param("MA", 100, WAGES, 9_000, 420, id="MA"),
pytest.param("ME", 100, WAGES, 9_000, 500, id="ME"),
pytest.param("MN", 100, WAGES, 9_000, 440, id="MN"),
pytest.param("OR", 100, WAGES, 9_000, 400, id="OR"),
pytest.param("RI", 100, WAGES, 29_200, 61.32, id="RI"),
pytest.param("VT", 100, WAGES, 9_000, 330, id="VT"),
Expand Down Expand Up @@ -996,6 +1150,7 @@ def test_employer_total_additional_state_payroll_tax(
pytest.param("DE", 20, id="DE"),
pytest.param("MA", 29.4, id="MA"),
pytest.param("ME", 35, id="ME"),
pytest.param("MN", 30.8, id="MN"),
pytest.param("OR", 28, id="OR"),
pytest.param("RI", 8.4, id="RI"),
pytest.param("VT", 13.2, id="VT"),
Expand All @@ -1014,6 +1169,7 @@ def test_employer_total_additional_state_payroll_tax_uses_state_specific_wage_ba
employer_total_dc_paid_leave_taxable_wages=7_000,
employer_total_ma_paid_leave_taxable_wages=7_000,
employer_total_me_paid_leave_taxable_wages=7_000,
employer_total_mn_paid_leave_taxable_wages=7_000,
employer_total_or_paid_leave_taxable_wages=7_000,
employer_total_vt_child_care_contribution_wages=4_000,
employer_total_wa_paid_leave_taxable_wages=7_000,
Expand Down
Loading
Loading