diff --git a/changelog.d/mn-employer-paid-leave-premium.added.md b/changelog.d/mn-employer-paid-leave-premium.added.md new file mode 100644 index 00000000000..5a1c2f0017c --- /dev/null +++ b/changelog.d/mn-employer-paid-leave-premium.added.md @@ -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. diff --git a/changelog.d/mn-employer-paid-leave-premium.removed.md b/changelog.d/mn-employer-paid-leave-premium.removed.md new file mode 100644 index 00000000000..c4788dcf90f --- /dev/null +++ b/changelog.d/mn-employer-paid-leave-premium.removed.md @@ -0,0 +1 @@ +Remove the Minnesota Paid Leave `employee_rate` parameter, which is now derived from `rate` and `employer_minimum_share`; reforms that set it must set those instead. diff --git a/changelog.d/payroll-employer-deduction-share.added.md b/changelog.d/payroll-employer-deduction-share.added.md new file mode 100644 index 00000000000..a556609c27a --- /dev/null +++ b/changelog.d/payroll-employer-deduction-share.added.md @@ -0,0 +1 @@ +Add `employer_state_payroll_premium_deduction_share`, the share of the permitted employee premium an employer deducts for Colorado FAMLI, Delaware Paid Leave, Maine and Massachusetts PFML, Minnesota Paid Leave, New York PFL and DBL, the Vermont Child Care Contribution and Washington PFML (default 1, the current full-share assumption), with the employer paying any part it does not deduct; apply Massachusetts' 2027 swap of the family and medical deduction caps and rates (Acts 2026 c. 101); and cite Conn. Gen. Stat. 31-49g(b)(1) for Connecticut's paid leave rate. diff --git a/policyengine_us/parameters/gov/states/ct/tax/payroll/paid_leave/employee_rate.yaml b/policyengine_us/parameters/gov/states/ct/tax/payroll/paid_leave/employee_rate.yaml index 6685da4dc7b..c28f33f86ba 100644 --- a/policyengine_us/parameters/gov/states/ct/tax/payroll/paid_leave/employee_rate.yaml +++ b/policyengine_us/parameters/gov/states/ct/tax/payroll/paid_leave/employee_rate.yaml @@ -7,7 +7,7 @@ metadata: unit: /1 label: Connecticut employee paid leave rate reference: - - title: Connecticut General Statutes Section 31-49e - href: https://www.cga.ct.gov/current/pub/chap_557.htm + - title: Connecticut General Statutes Section 31-49g(b)(1) + href: https://www.cga.ct.gov/current/pub/chap_557.htm#sec_31-49g - title: Connecticut Paid Leave - Remit Contributions href: https://www.ctpaidleave.org/remit-contributions diff --git a/policyengine_us/parameters/gov/states/de/tax/payroll/paid_leave/employee_share.yaml b/policyengine_us/parameters/gov/states/de/tax/payroll/paid_leave/employee_share.yaml index d30df3634d2..9961fdb19e2 100644 --- a/policyengine_us/parameters/gov/states/de/tax/payroll/paid_leave/employee_share.yaml +++ b/policyengine_us/parameters/gov/states/de/tax/payroll/paid_leave/employee_share.yaml @@ -1,4 +1,4 @@ -description: Default employee share of Delaware paid leave contributions. +description: Largest share of each Delaware Paid Leave contribution an employer may deduct from wages. values: 0000-01-01: 0 2025-01-01: 0.5 diff --git a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_employee_share.yaml b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_employee_share.yaml new file mode 100644 index 00000000000..8db687296dd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_employee_share.yaml @@ -0,0 +1,22 @@ +description: Largest share of the Massachusetts PFML family leave contribution an employer may deduct from wages. +values: + 0000-01-01: 0 + 2024-01-01: 1 + # Acts 2026 c. 101 s. 26 strikes "100" in s. 6(c)(2), (d) and (e)(2) and inserts "40". + 2027-01-01: 0.4 + +metadata: + period: year + unit: /1 + label: Massachusetts PFML family employee share + reference: + - title: Massachusetts General Laws Chapter 175M Section 6 + href: https://malegislature.gov/Laws/GeneralLaws/PartI/TitleXXII/Chapter175M/Section6 + - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator (2026 and 2027 sections, updated October 1, 2026) + href: https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator + - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2024 section (archived May 26, 2024) + href: https://web.archive.org/web/20240526092717/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator + - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2025 & 2026 section (archived December 8, 2025) + href: https://web.archive.org/web/20251208080415/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator + - title: Acts of 2026, Chapter 101, Sections 25, 26, 43 and 45 + href: https://malegislature.gov/Laws/SessionLaws/Acts/2026/Chapter101 diff --git a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_rate.yaml b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_rate.yaml index 7c5733a58fb..be8f9a9dc3d 100644 --- a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_rate.yaml +++ b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/family_rate.yaml @@ -2,6 +2,8 @@ description: Massachusetts PFML family leave contribution rate. values: 0000-01-01: 0 2024-01-01: 0.0018 + # DFML's 2027 rates swap with the deduction caps (Acts 2026 c. 101 s. 43(a)), leaving the employee and employer totals unchanged. + 2027-01-01: 0.007 metadata: period: year @@ -10,9 +12,11 @@ metadata: reference: - title: Massachusetts General Laws Chapter 175M Section 6 href: https://malegislature.gov/Laws/GeneralLaws/PartI/TitleXXII/Chapter175M/Section6 - - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator + - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator (2026 and 2027 sections, updated October 1, 2026) href: https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2024 section (archived May 26, 2024) href: https://web.archive.org/web/20240526092717/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2025 & 2026 section (archived December 8, 2025) href: https://web.archive.org/web/20251208080415/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator + - title: Acts of 2026, Chapter 101, Sections 25, 26, 43 and 45 + href: https://malegislature.gov/Laws/SessionLaws/Acts/2026/Chapter101 diff --git a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_employee_share.yaml b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_employee_share.yaml index 8025a24fd77..fed95485b78 100644 --- a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_employee_share.yaml +++ b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_employee_share.yaml @@ -1,7 +1,9 @@ -description: Employee share of the Massachusetts PFML medical leave contribution. +description: Largest share of the Massachusetts PFML medical leave contribution an employer may deduct from wages. values: 0000-01-01: 0 2024-01-01: 0.4 + # Acts 2026 c. 101 s. 25 strikes "40" in s. 6(c)(1), (d) and (e)(1) and inserts "100". + 2027-01-01: 1 metadata: period: year @@ -10,9 +12,11 @@ metadata: reference: - title: Massachusetts General Laws Chapter 175M Section 6 href: https://malegislature.gov/Laws/GeneralLaws/PartI/TitleXXII/Chapter175M/Section6 - - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator + - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator (2026 and 2027 sections, updated October 1, 2026) href: https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2024 section (archived May 26, 2024) href: https://web.archive.org/web/20240526092717/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2025 & 2026 section (archived December 8, 2025) href: https://web.archive.org/web/20251208080415/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator + - title: Acts of 2026, Chapter 101, Sections 25, 26, 43 and 45 + href: https://malegislature.gov/Laws/SessionLaws/Acts/2026/Chapter101 diff --git a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_rate.yaml b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_rate.yaml index 9d8fef45424..daf955cbd03 100644 --- a/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_rate.yaml +++ b/policyengine_us/parameters/gov/states/ma/tax/payroll/paid_leave/medical_rate.yaml @@ -2,6 +2,8 @@ description: Massachusetts PFML medical leave contribution rate. values: 0000-01-01: 0 2024-01-01: 0.007 + # DFML's 2027 rates swap with the deduction caps (Acts 2026 c. 101 s. 43(a)), leaving the employee and employer totals unchanged. + 2027-01-01: 0.0018 metadata: period: year @@ -10,9 +12,11 @@ metadata: reference: - title: Massachusetts General Laws Chapter 175M Section 6 href: https://malegislature.gov/Laws/GeneralLaws/PartI/TitleXXII/Chapter175M/Section6 - - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator + - title: Massachusetts Paid Family and Medical Leave employer contribution rates and calculator (2026 and 2027 sections, updated October 1, 2026) href: https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2024 section (archived May 26, 2024) href: https://web.archive.org/web/20240526092717/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator - title: Massachusetts Paid Family and Medical Leave employer contribution rates, 2025 & 2026 section (archived December 8, 2025) href: https://web.archive.org/web/20251208080415/https://www.mass.gov/info-details/paid-family-and-medical-leave-employer-contribution-rates-and-calculator + - title: Acts of 2026, Chapter 101, Sections 25, 26, 43 and 45 + href: https://malegislature.gov/Laws/SessionLaws/Acts/2026/Chapter101 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/employee_rate.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/employee_rate.yaml deleted file mode 100644 index a9d643c601a..00000000000 --- a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/employee_rate.yaml +++ /dev/null @@ -1,14 +0,0 @@ -description: Employee-side Minnesota Paid Leave contribution rate. -values: - 0000-01-01: 0 - 2026-01-01: 0.0044 - -metadata: - period: year - unit: /1 - label: Minnesota Paid Leave employee rate - reference: - - title: Minnesota DEED confirms Paid Leave premium rate - href: https://mn.gov/deed/newscenter/press-releases/?id=1045-670064 - - title: Minnesota Statutes Section 268B.14 - href: https://www.revisor.mn.gov/statutes/cite/268B.14 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/employer_minimum_share.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/employer_minimum_share.yaml new file mode 100644 index 00000000000..c776058b3eb --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/employer_minimum_share.yaml @@ -0,0 +1,16 @@ +description: Minnesota requires employers to pay at least this share of the Paid Leave premium; employees pay the remaining portion, if any, through a wage deduction. +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 + - 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 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/rate.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/rate.yaml new file mode 100644 index 00000000000..bdcf95010de --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/rate.yaml @@ -0,0 +1,20 @@ +description: Minnesota charges this Paid Leave premium rate on taxable wages for an employer participating in both the family and medical benefit programs. +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 + - 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 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/employer_minimum_share.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/employer_minimum_share.yaml new file mode 100644 index 00000000000..49d11a9a8d9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/employer_minimum_share.yaml @@ -0,0 +1,16 @@ +description: Minnesota requires small employers to pay at least this share of the full Paid Leave premium rate; employees pay the remaining portion of the small employer premium, if any, through a wage deduction. +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 + - 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 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/max_average_wage_ratio.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/max_average_wage_ratio.yaml new file mode 100644 index 00000000000..60e12ccb753 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/max_average_wage_ratio.yaml @@ -0,0 +1,16 @@ +description: Minnesota limits the Paid Leave small employer premium rate to employers whose average wage is at most this multiple of the state's average wage in covered employment for the basis period. +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 + - 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 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/max_headcount.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/max_headcount.yaml new file mode 100644 index 00000000000..ef96776fbd4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/max_headcount.yaml @@ -0,0 +1,16 @@ +description: Minnesota limits the Paid Leave small employer premium rate to employers with at most this many employees. +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 + - 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 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/rate_share.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/rate_share.yaml new file mode 100644 index 00000000000..139fd33a798 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/rate_share.yaml @@ -0,0 +1,18 @@ +description: Minnesota charges small employers this share of the full Paid Leave premium rate. +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 + - 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 diff --git a/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/state_average_annual_wage.yaml b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/state_average_annual_wage.yaml new file mode 100644 index 00000000000..8e8610ee00c --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/tax/payroll/paid_leave/small_employer/state_average_annual_wage.yaml @@ -0,0 +1,18 @@ +description: Minnesota compares a small employer's average wage with this statewide average annual wage in covered employment, which the Department of Employment and Economic Development calculates each year and applies to the Paid Leave basis period. +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 + +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 + - 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 diff --git a/policyengine_us/tests/core/test_payroll_contributions.py b/policyengine_us/tests/core/test_payroll_contributions.py index 6939b040785..55e773ae5b2 100644 --- a/policyengine_us/tests/core/test_payroll_contributions.py +++ b/policyengine_us/tests/core/test_payroll_contributions.py @@ -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" ), @@ -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, @@ -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 }, @@ -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", { @@ -592,6 +607,109 @@ 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": {"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": {PERIOD: WAGES}, + "employer_headcount": {PERIOD: headcount}, + } + 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": {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]) + + +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). + 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 + }, + }, + country_id="us", + ) + people = { + name: { + "age": {PERIOD: 30}, + "employment_income": {PERIOD: WAGES}, + "employer_headcount": {PERIOD: 10}, + "mn_paid_leave_employer_average_quarterly_wage": {PERIOD: average_wage}, + } + for name, average_wage in (("at_limit", 27_746.63), ("above", 27_746.64)) + } + sim = Simulation( + tax_benefit_system=CountryTaxBenefitSystem(reform=(reform,)), + situation={ + "people": people, + "households": { + "household": {"members": list(people), "state_code": {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 + }, + }, + ) + + assert sim.calculate("mn_paid_leave_small_employer", PERIOD).tolist() == [ + True, + False, + ] + + @pytest.mark.parametrize( ("state_code", "expected"), [ @@ -637,6 +755,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", ), @@ -962,6 +1081,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"), @@ -996,6 +1116,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"), @@ -1014,6 +1135,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, diff --git a/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py b/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py new file mode 100644 index 00000000000..c0de1ec3b42 --- /dev/null +++ b/policyengine_us/tests/core/test_state_payroll_premium_deduction_share_invariants.py @@ -0,0 +1,298 @@ +"""Invariants for the employer's deduction of state payroll premiums. + +Some state programs put the premium on the employer and let it deduct up to a +share from wages without requiring it: Colorado FAMLI, Delaware Paid Leave, +Maine and Massachusetts PFML, Minnesota Paid Leave, New York PFL and DBL, the +Vermont Child Care Contribution and Washington PFML. +`employer_state_payroll_premium_deduction_share` says how much of the +permitted employee share the employer deducts (default 1); the employer pays +the rest. Hypothesis draws workers in those states, in states whose +contributions are mandatory withholding, and in a state with neither, with any +wages, employer size, share and (for Minnesota's small employer test) employer +average wage, and runs each worker three times in one simulation: with two +drawn shares and with the input left at its default. For every worker, in 2026 +and 2027: + +1. The employee amount of the optional programs is the clipped share times the + amount at the default, so the default is the full permitted share and a + share outside 0 to 1 acts as the nearer bound. +2. The mandatory components of `employee_state_payroll_tax` do not depend on + the share. +3. Where the employer side is modeled (CO, DE, MA, ME, MN, VT, WA), employee + plus employer premium does not depend on the share: the employer pays + exactly what it does not deduct. The New York employer cost is not + modeled, so its employer amount is zero at any share. +4. A larger share never lowers the employee amount or raises the employer + amount. +5. With employer-level wage totals equal to the worker's own wages, capped at + the Social Security base where the worker's are and at Minnesota's rounded + base for Minnesota (a one-worker employer), + `employer_total_additional_state_payroll_tax` equals + `employer_additional_state_payroll_tax` in every modeled state: the + employer-level path and the per-worker path agree at any share and + employer size. +6. Massachusetts' 2027 swap of the family and medical deduction caps, paired + with DFML's swap of the two rates (Acts 2026 c. 101 ss. 25, 26, 43(a)), + leaves each worker's employee and employer amounts where they were in + 2026, for wages under both years' wage bases. +7. Minnesota matches the statute computed independently here: the premium is + 0.88% of taxable wages, or 0.66% for a small employer (30 or fewer + employees and an average quarterly wage of at most $27,745.88); employee + plus employer amounts equal it at any share; and the employer pays its + minimum (half the premium, or 0.22% of wages for a small employer) plus + the part of the rest it does not deduct (Minn. Stat. 268B.14, subds. 1, + 3 and 5a). + +Amounts are compared to float32 precision, within a cent. + +Why Python: the YAML cases pin one share and employer size each; this checks +every program at once against drawn shares, sizes and wages, including +boundary employer sizes and shares outside 0 to 1, in one vectorized +simulation per example. +""" + +import numpy as np +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation +from policyengine_us.system import system + +YEARS = (2026, 2027) +OPTIONAL_STATES = ("CO", "DE", "MA", "ME", "MN", "NY", "VT", "WA") +MANDATORY_STATES = ("CA", "CT", "NJ", "OR", "PA", "RI") +EMPLOYER_MODELED_STATES = ("CO", "DE", "MA", "ME", "MN", "VT", "WA") +OPTIONAL_EMPLOYEE_VARIABLES = ( + "co_employee_famli_contribution", + "de_employee_paid_leave_contribution", + "ma_employee_paid_leave_contribution", + "me_employee_paid_leave_contribution", + "mn_employee_paid_leave_contribution", + "ny_employee_paid_family_leave_contribution", + "ny_employee_disability_benefits_contribution", + "vt_employee_child_care_contribution", + "wa_employee_paid_leave_contribution", +) +# Below the 2026 Social Security wage base, so every program's wage base is +# the worker's wages in both years. +UNCAPPED_WAGES = 184_500 +SOCIAL_SECURITY_CAP = { + year: system.parameters(f"{year}-01-01").gov.irs.payroll.social_security.cap + for year in YEARS +} +# Minn. Stat. 268B.01, subd. 43: the Social Security base rounded to the +# nearest $1,000. +MN_TAXABLE_WAGE_BASE = { + year: 1_000 * np.floor(SOCIAL_SECURITY_CAP[year] / 1_000 + 0.5) for year in YEARS +} +# Minnesota Paid Leave, from the statute and DEED, independent of the +# parameter files: 0.88% in 2026 and 2027 (subd. 7); employer minimum 50% +# (subd. 3); small employers 75% of the rate with an employer minimum of 25% +# of the full rate (subd. 5a(b)), if 30 or fewer employees and an average +# quarterly wage of at most $27,745.88 (subd. 5a(a); DEED's 2026 designation: +# 150% of the $73,989 statewide average annual wage, per quarter). +MN_RATE = 0.0088 +MN_SMALL_MAX_HEADCOUNT = 30 +MN_SMALL_MAX_AVERAGE_QUARTERLY_WAGE = 27_745.88 +COPIES = 3 # drawn share a, drawn share b, input left at its default +# The model computes in float32: compare to that precision, never past a cent. +CENT = 0.01 +TOLERANCE = dict(rtol=1e-6, atol=CENT) + +share = st.one_of( + st.sampled_from([0.0, 0.25, 0.5, 1.0, -0.5, 1.5]), + st.floats(-0.5, 1.5, allow_nan=False), +) +# Whole cents, as DEED states wages: the model holds the input in float32, +# which can't tell sub-cent amounts around the limit apart. +average_quarterly_wage = st.one_of( + st.sampled_from([0.0, 27_745.88, 27_745.89, 40_000.0]), + st.integers(0, 6_000_000).map(lambda cents: cents / 100), +) +workers = st.tuples( + st.sampled_from(OPTIONAL_STATES + MANDATORY_STATES + ("TX",)), + st.integers(0, 300_000), # employment_income + st.sampled_from([1, 9, 10, 14, 15, 20, 24, 25, 30, 31, 49, 50, 100]), + share, + share, + average_quarterly_wage, # Minnesota small employer test only +) + + +def simulate(rows): + people, households = {}, {} + groups = {"tax_units": {}, "spm_units": {}, "families": {}, "marital_units": {}} + index = 0 + for state, wages, headcount, share_a, share_b, average_wage in rows: + for share_value in (share_a, share_b, None): + person = f"person_{index}" + people[person] = { + "age": {year: 30 for year in YEARS}, + "employment_income": {year: wages for year in YEARS}, + "employer_headcount": {year: headcount for year in YEARS}, + "employer_total_taxable_earnings_for_social_security": { + year: min(wages, SOCIAL_SECURITY_CAP[year]) for year in YEARS + }, + "employer_total_mn_paid_leave_taxable_wages": { + year: min(wages, MN_TAXABLE_WAGE_BASE[year]) for year in YEARS + }, + "mn_paid_leave_employer_average_quarterly_wage": { + year: average_wage for year in YEARS + }, + "employer_total_payroll_tax_gross_wages": { + year: wages for year in YEARS + }, + } + if share_value is not None: + people[person]["employer_state_payroll_premium_deduction_share"] = { + year: share_value for year in YEARS + } + households[f"household_{index}"] = { + "members": [person], + "state_code": {year: state for year in YEARS}, + } + for name in groups: + groups[name][f"{name}_{index}"] = {"members": [person]} + index += 1 + return Simulation(situation={"people": people, "households": households, **groups}) + + +def by_copy(simulation, variable, year): + return np.asarray(simulation.calculate(variable, year)).reshape(-1, COPIES) + + +@settings( + max_examples=8, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +@given( + st.lists(workers, min_size=4, max_size=30).map( + # Every optional state gets a worker at a large employer below every + # wage base, and one at a 9-employee employer (below the CO, MA, ME + # and WA size thresholds; DE does not cover it; a Minnesota small + # employer) above every wage base and New York's PFL maximum; + # Delaware also gets a 12-employee employer (parental leave only). + # Minnesota also gets employers at 30 and 31 employees and one of 10 + # employees whose average wage fails the small employer test. Shares + # lie strictly between 0 and 1 or above 1, so each program's + # properties compare positive amounts, small-employer rules and + # capped amounts. + lambda rows: ( + [(state, 60_000, 100, 0.5, 0.0, 0.0) for state in OPTIONAL_STATES] + + [(state, 250_000, 9, 0.3, 1.2, 0.0) for state in OPTIONAL_STATES] + + [("DE", 250_000, 12, 0.3, 1.2, 0.0)] + + [ + ("MN", 60_000, 30, 0.5, 0.0, 27_745.88), + ("MN", 60_000, 31, 0.5, 0.0, 0.0), + ("MN", 60_000, 10, 0.5, 0.0, 27_745.89), + ] + + rows + ) + ) +) +def test_state_payroll_premium_deduction_share_invariants(rows): + simulation = simulate(rows) + states = np.array([row[0] for row in rows]) + wages = np.array([row[1] for row in rows]) + headcounts = np.array([row[2] for row in rows]) + shares = np.clip(np.array([[row[3], row[4], 1.0] for row in rows]), 0, 1) + average_wages = np.array([row[5] for row in rows]) + modeled = np.isin(states, EMPLOYER_MODELED_STATES) + unmodeled = states == "NY" + mn = states == "MN" + mn_small = (headcounts <= MN_SMALL_MAX_HEADCOUNT) & ( + average_wages <= MN_SMALL_MAX_AVERAGE_QUARTERLY_WAGE + ) + assert mn_small[mn].any() and (~mn_small[mn]).any() + uncapped = wages <= UNCAPPED_WAGES + optional_by_year = {} + employer_by_year = {} + for year in YEARS: + optional = sum( + by_copy(simulation, variable, year) + for variable in OPTIONAL_EMPLOYEE_VARIABLES + ) + total = by_copy(simulation, "employee_state_payroll_tax", year) + employer = by_copy(simulation, "employer_additional_state_payroll_tax", year) + employer_total = by_copy( + simulation, "employer_total_additional_state_payroll_tax", year + ) + default = optional[:, [2]] + assert (default > 0).any(), "no worker with a positive optional premium" + # Property 1. + np.testing.assert_allclose(optional, shares * default, **TOLERANCE) + # Property 2. + mandatory = total - optional + np.testing.assert_allclose( + mandatory, mandatory[:, [2]] * np.ones((1, COPIES)), **TOLERANCE + ) + # Property 3. + remitted = optional + employer + np.testing.assert_allclose( + remitted[modeled], + remitted[modeled][:, [2]] * np.ones((1, COPIES)), + **TOLERANCE, + ) + assert (employer[unmodeled] == 0).all() + # Property 4. + for low, high in ((0, 1), (1, 0)): + lower = shares[:, low] <= shares[:, high] + assert (optional[lower, low] <= optional[lower, high] + CENT).all() + assert (employer[lower, low] >= employer[lower, high] - CENT).all() + # Property 5. + same_path = modeled + np.testing.assert_allclose( + employer_total[same_path], employer[same_path], **TOLERANCE + ) + # Property 7. + mn_wages = np.minimum(np.maximum(wages, 0), MN_TAXABLE_WAGE_BASE[year]) + mn_premium = MN_RATE * np.where(mn_small, 0.75, 1) * mn_wages + mn_minimum = np.where(mn_small, 0.25 * MN_RATE * mn_wages, 0.5 * mn_premium) + mn_employee = by_copy(simulation, "mn_employee_paid_leave_contribution", year) + mn_employer = by_copy(simulation, "mn_employer_paid_leave_contribution", year) + np.testing.assert_allclose( + by_copy(simulation, "mn_paid_leave_premium", year)[mn], + mn_premium[mn][:, None] * np.ones((1, COPIES)), + **TOLERANCE, + ) + np.testing.assert_allclose( + (mn_employee + mn_employer)[mn], + mn_premium[mn][:, None] * np.ones((1, COPIES)), + **TOLERANCE, + ) + np.testing.assert_allclose( + mn_employer[mn], + (mn_minimum[:, None] + (1 - shares) * (mn_premium - mn_minimum)[:, None])[ + mn + ], + **TOLERANCE, + ) + optional_by_year[year] = optional + employer_by_year[year] = employer + # Property 6. + ma = (states == "MA") & uncapped + assert ma.any() + np.testing.assert_allclose( + optional_by_year[2027][ma], optional_by_year[2026][ma], **TOLERANCE + ) + np.testing.assert_allclose( + employer_by_year[2027][ma], employer_by_year[2026][ma], **TOLERANCE + ) + + +def test_massachusetts_2027_swaps_deduction_caps_and_rates(): + """Pins the four 2027 values: properties 1-6 hold whether they swap or not.""" + p = system.parameters.gov.states.ma.tax.payroll.paid_leave + # 2026: 100% of the 0.18% family rate and 40% of the 0.70% medical rate. + assert p.family_rate("2026-01-01") == 0.0018 + assert p.family_employee_share("2026-01-01") == 1 + assert p.medical_rate("2026-01-01") == 0.007 + assert p.medical_employee_share("2026-01-01") == 0.4 + # 2027 (Acts 2026 c. 101 ss. 25-26; DFML 2027 rates): 40% of the 0.70% + # family rate and 100% of the 0.18% medical rate. + assert p.family_rate("2027-01-01") == 0.007 + assert p.family_employee_share("2027-01-01") == 0.4 + assert p.medical_rate("2027-01-01") == 0.0018 + assert p.medical_employee_share("2027-01-01") == 1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.yaml index 87456ff12a8..2580f52d02d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.yaml @@ -61,3 +61,48 @@ ma_employer_paid_leave_contribution: 0 # The employee share does not depend on employer size. ma_employee_paid_leave_contribution: 276.00 + +- name: Massachusetts PFML 2026 keeps the 100% family and 40% medical deduction caps. + period: 2026 + input: + employment_income: 100_000 + state_code: MA + output: + # Acts 2026 c. 101 swaps the caps from 2027 (s. 43(a); DFML). Applying the + # swap to 2026 rates would give 40% * 0.18% + 0.70% = 0.772%, or 772. + # 0.18% + 40% * 0.70% = 0.46%; 0.46% * 100,000 = 460. + ma_employee_paid_leave_contribution: 460 + # 60% * 0.70% * 100,000 = 420. + ma_employer_paid_leave_contribution: 420 + +- name: Massachusetts PFML 2027 swaps the caps and the rates, leaving the employee share at 0.46%. + period: 2027 + input: + employment_income: 100_000 + state_code: MA + output: + # 40% * 0.70% family + 100% * 0.18% medical = 0.28% + 0.18% = 0.46%. + ma_employee_paid_leave_contribution: 460 + # 60% * 0.70% family = 0.42%; nothing of medical. + ma_employer_paid_leave_contribution: 420 + +- name: Massachusetts PFML 2027 small employer remits only the 0.46% it may deduct. + period: 2027 + input: + employment_income: 100_000 + employer_headcount: 24 + state_code: MA + output: + ma_employee_paid_leave_contribution: 460 + ma_employer_paid_leave_contribution: 0 + +- name: Massachusetts PFML 2027 employer pays the part of the employee share it does not deduct. + period: 2027 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: MA + output: + ma_employee_paid_leave_contribution: 230 + # 420 + 230 = 650. + ma_employer_paid_leave_contribution: 650 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/tax/payroll/paid_leave/mn_employer_paid_leave_contribution.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/payroll/paid_leave/mn_employer_paid_leave_contribution.yaml new file mode 100644 index 00000000000..d8ea540e219 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/tax/payroll/paid_leave/mn_employer_paid_leave_contribution.yaml @@ -0,0 +1,279 @@ +# Minnesota Paid Leave premium, employer and employee sides (Minn. Stat. +# 268B.14). 2026 and 2027 premium rate 0.88% (DEED, subd. 7); the employer +# pays at least 50% (subd. 3). A small employer under subd. 5a (30 or fewer +# employees, average quarterly wage at most 150% * $73,989 / 4 = $27,745.875, +# which DEED's 2026 designation gives as $27,745.88) pays 75% of the rate, +# 0.66%, of which the employer pays at least 25% of the full rate, 0.22%. +# Employees pay at most 0.88% - 0.44% = 0.66% - 0.22% = 0.44% of taxable +# wages. Taxable wages are capped at the Social Security base rounded to the +# nearest $1,000 (268B.01, subd. 43): $184,500 rounds to $185,000 in 2026. + +- name: A large employer that deducts the full permitted share pays half the premium. + period: 2026 + input: + employment_income: 100_000 + state_code: MN + output: + mn_paid_leave_small_employer: false + mn_paid_leave_premium_rate: 0.0088 + mn_paid_leave_permitted_employee_rate: 0.0044 + # 0.88% * 100,000 = 880. + mn_paid_leave_premium: 880 + # 0.44% * 100,000 = 440. + mn_employee_paid_leave_contribution: 440 + # 880 - 440 = 440. + mn_employer_paid_leave_contribution: 440 + mn_employer_additional_state_payroll_tax: 440 + employer_additional_state_payroll_tax: 440 + +- name: A large employer that deducts half the permitted share pays the rest. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: MN + output: + mn_paid_leave_premium: 880 + # 0.5 * 440 = 220. + mn_employee_paid_leave_contribution: 220 + # 880 - 220 = 660. + mn_employer_paid_leave_contribution: 660 + +- name: A large employer that deducts nothing pays the whole premium. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0 + state_code: MN + output: + mn_employee_paid_leave_contribution: 0 + mn_employer_paid_leave_contribution: 880 + +- name: A small employer pays 75% of the rate, of which employees may pay the same 0.44%. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 30 + state_code: MN + output: + mn_paid_leave_small_employer: true + # 75% * 0.88% = 0.66%. + mn_paid_leave_premium_rate: 0.0066 + # (75% - 25%) * 0.88% = 0.44%. + mn_paid_leave_permitted_employee_rate: 0.0044 + # 0.66% * 100,000 = 660. + mn_paid_leave_premium: 660 + mn_employee_paid_leave_contribution: 440 + # 660 - 440 = 220, the 25% * 0.88% = 0.22% minimum. + mn_employer_paid_leave_contribution: 220 + employer_additional_state_payroll_tax: 220 + +- name: A small employer that deducts half the permitted share pays the rest. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 30 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: MN + output: + mn_employee_paid_leave_contribution: 220 + # 660 - 220 = 440. + mn_employer_paid_leave_contribution: 440 + +- name: A small employer that deducts nothing pays the whole small employer premium. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 30 + employer_state_payroll_premium_deduction_share: 0 + state_code: MN + output: + mn_employee_paid_leave_contribution: 0 + mn_employer_paid_leave_contribution: 660 + +- name: An employer with 31 employees is not a small employer. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 31 + state_code: MN + output: + mn_paid_leave_small_employer: false + mn_paid_leave_premium: 880 + mn_employer_paid_leave_contribution: 440 + +- name: An average quarterly wage equal to the limit meets the small employer wage test. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 10 + mn_paid_leave_employer_average_quarterly_wage: 27_745.88 + state_code: MN + output: + mn_paid_leave_small_employer: true + mn_paid_leave_premium: 660 + mn_employer_paid_leave_contribution: 220 + +- name: An average quarterly wage above the limit fails the small employer wage test. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 10 + mn_paid_leave_employer_average_quarterly_wage: 27_745.89 + state_code: MN + output: + mn_paid_leave_small_employer: false + mn_paid_leave_premium: 880 + mn_employer_paid_leave_contribution: 440 + +- name: An average quarterly wage a fraction of a cent above the limit fails the wage test. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 10 + mn_paid_leave_employer_average_quarterly_wage: 27_745.885 + state_code: MN + output: + mn_paid_leave_small_employer: false + mn_paid_leave_premium: 880 + +- name: Wages above the rounded Social Security base are capped at 185,000. + period: 2026 + input: + employment_income: 250_000 + state_code: MN + output: + mn_paid_leave_taxable_wages: 185_000 + # 0.88% * 185,000 = 1,628. + mn_paid_leave_premium: 1_628 + # 0.44% * 185,000 = 814. + mn_employee_paid_leave_contribution: 814 + mn_employer_paid_leave_contribution: 814 + +- name: A small employer's capped premium leaves the employer a quarter of the full rate. + period: 2026 + input: + employment_income: 250_000 + employer_headcount: 9 + state_code: MN + output: + # 0.66% * 185,000 = 1,221. + mn_paid_leave_premium: 1_221 + mn_employee_paid_leave_contribution: 814 + # 1,221 - 814 = 407 = 0.22% * 185,000. + mn_employer_paid_leave_contribution: 407 + +- name: Small wages keep fractional cents. + period: 2026 + input: + employment_income: 8_000 + state_code: MN + output: + # 0.88% * 8,000 = 70.40; 0.44% * 8,000 = 35.20. + mn_paid_leave_premium: 70.4 + mn_employee_paid_leave_contribution: 35.2 + mn_employer_paid_leave_contribution: 35.2 + +- name: Negative employment income owes no premium. + period: 2026 + input: + employment_income: -5_000 + state_code: MN + output: + mn_paid_leave_premium: 0 + mn_employee_paid_leave_contribution: 0 + mn_employer_paid_leave_contribution: 0 + +- name: The employer premium flows into employer state and total payroll taxes. + period: 2026 + input: + employment_income: 100_000 + state_code: MN + output: + mn_employer_paid_leave_contribution: 440 + # Unemployment insurance: 0.9% default rate * the 42,000 wage base = 378. + employer_state_unemployment_tax: 378 + # 378 + 440 = 818. + employer_state_payroll_tax: 818 + # Social Security 6.2% * 100,000 = 6,200; Medicare 1.45% * 100,000 = + # 1,450; FUTA 0.6% * 7,000 = 42; 6,200 + 1,450 + 42 + 818 = 8,510. + employer_payroll_tax: 8_510 + +- name: The 2027 premium rate is unchanged at 0.88%. + period: 2027 + input: + employment_income: 100_000 + state_code: MN + output: + mn_paid_leave_premium: 880 + mn_employee_paid_leave_contribution: 440 + mn_employer_paid_leave_contribution: 440 + +- name: No premium is due before 2026. + period: 2025 + input: + employment_income: 100_000 + employer_headcount: 9 + state_code: MN + output: + mn_paid_leave_premium: 0 + mn_employee_paid_leave_contribution: 0 + mn_employer_paid_leave_contribution: 0 + mn_employer_additional_state_payroll_tax: 0 + +- name: Years before the 2015 parameter backdating still compute. + period: 2014 + input: + employment_income: 100_000 + employer_headcount: 9 + state_code: MN + output: + mn_paid_leave_premium: 0 + mn_employer_paid_leave_contribution: 0 + employer_additional_state_payroll_tax: 0 + +- name: Workers outside Minnesota owe no Minnesota premium. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 9 + state_code: WI + output: + mn_paid_leave_premium: 0 + mn_employer_paid_leave_contribution: 0 + employer_additional_state_payroll_tax: 0 + +- name: Employer-level premium for a large employer that deducts the full permitted share. + period: 2026 + input: + employer_headcount: 100 + employer_total_taxable_earnings_for_social_security: 1_000_000 + state_code: MN + output: + employer_total_mn_paid_leave_taxable_wages: 1_000_000 + # (0.88% - 0.44%) * 1,000,000 = 4,400. + employer_total_additional_state_payroll_tax: 4_400 + +- name: Employer-level premium for a small employer that deducts a quarter of the permitted share. + period: 2026 + input: + employer_headcount: 20 + employer_state_payroll_premium_deduction_share: 0.25 + employer_total_taxable_earnings_for_social_security: 1_000_000 + state_code: MN + output: + # (0.66% - 0.25 * 0.44%) * 1,000,000 = 6,600 - 1,100 = 5,500. + employer_total_additional_state_payroll_tax: 5_500 + +- name: Employer-level wages can be set at Minnesota's rounded base. + period: 2026 + input: + employer_headcount: 100 + employer_total_taxable_earnings_for_social_security: 369_000 + # Two workers at Minnesota's 185,000 base, not the 184,500 Social + # Security base. + employer_total_mn_paid_leave_taxable_wages: 370_000 + state_code: MN + output: + # 0.44% * 370,000 = 1,628. + employer_total_additional_state_payroll_tax: 1_628 diff --git a/policyengine_us/tests/policy/baseline/gov/states/tax/payroll/state_payroll_premium_deduction_share.yaml b/policyengine_us/tests/policy/baseline/gov/states/tax/payroll/state_payroll_premium_deduction_share.yaml new file mode 100644 index 00000000000..528c90d7b06 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/tax/payroll/state_payroll_premium_deduction_share.yaml @@ -0,0 +1,241 @@ +# The employer deducts a share of the largest employee premium the law lets it +# deduct; it pays the rest. Wages are 100,000, below every 2026 wage base. + +- name: The deduction share defaults to the full permitted share. + period: 2026 + input: + employment_income: 100_000 + state_code: CO + output: + employer_state_payroll_premium_deduction_share: 1 + state_payroll_premium_deduction_share: 1 + # 0.44% * 100,000 = 440. + co_employee_famli_contribution: 440 + co_employer_famli_contribution: 440 + +- name: The deduction share is held between 0 and 1. + period: 2026 + input: + people: + over: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 1.5 + under: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: -0.5 + tax_units: + over_unit: + members: [over] + under_unit: + members: [under] + households: + over_household: + members: [over] + state_code: CO + under_household: + members: [under] + state_code: CO + output: + state_payroll_premium_deduction_share: [1, 0] + co_employee_famli_contribution: [440, 0] + # 0.44% + 0.44% = 0.88% when the employer deducts nothing. + co_employer_famli_contribution: [440, 880] + +- name: Colorado FAMLI employer pays the half of the employee share it does not deduct. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: CO + output: + # 0.5 * 0.44% * 100,000 = 220. + co_employee_famli_contribution: 220 + co_employee_state_payroll_tax: 220 + employee_state_payroll_tax: 220 + # 0.44% * 100,000 + 220 = 660. + co_employer_famli_contribution: 660 + co_employer_additional_state_payroll_tax: 660 + +- name: Colorado FAMLI employer with fewer than 10 employees still pays the employee share it does not deduct. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 9 + employer_state_payroll_premium_deduction_share: 0.25 + state_code: CO + output: + # 0.25 * 0.44% * 100,000 = 110. + co_employee_famli_contribution: 110 + # No employer half; 0.75 * 440 = 330 of the 0.44% it must remit. + co_employer_famli_contribution: 330 + +- name: Massachusetts PFML employer pays the part of the 0.46% employee share it does not deduct. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: MA + output: + # 0.5 * (0.18% family + 40% * 0.70% medical) * 100,000 = 0.5 * 460 = 230. + ma_employee_paid_leave_contribution: 230 + employee_state_payroll_tax: 230 + # 60% * 0.70% * 100,000 = 420, plus the 230 not deducted. + ma_employer_paid_leave_contribution: 650 + +- name: Massachusetts PFML small employer that deducts nothing remits the 0.46% itself. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 24 + employer_state_payroll_premium_deduction_share: 0 + state_code: MA + output: + ma_employee_paid_leave_contribution: 0 + ma_employer_paid_leave_contribution: 460 + +- name: Maine PFML employer pays the part of the employee half it does not deduct. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: ME + output: + # 0.5 * 0.5% * 100,000 = 250. + me_employee_paid_leave_contribution: 250 + # 0.5% * 100,000 + 250 = 750. + me_employer_paid_leave_contribution: 750 + +- name: Maine PFML employer with fewer than 15 employees remits the half it does not deduct. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 14 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: ME + output: + me_employee_paid_leave_contribution: 250 + # No employer half; it must still remit 0.5%, of which it deducted 250. + me_employer_paid_leave_contribution: 250 + +- name: Delaware Paid Leave employer pays the part of the employee half it does not deduct. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: DE + output: + # 0.5 * 50% * (0.40% + 0.08% + 0.32%) * 100,000 = 0.25 * 800 = 200. + de_employee_paid_leave_contribution: 200 + # 800 - 200 = 600. + de_employer_paid_leave_contribution: 600 + +- name: Delaware Paid Leave employer with 10 to 24 employees that deducts nothing pays the parental rate itself. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 20 + employer_state_payroll_premium_deduction_share: 0 + state_code: DE + output: + de_employee_paid_leave_contribution: 0 + # 0.32% * 100,000 = 320. + de_employer_paid_leave_contribution: 320 + +- name: Vermont employer pays the part of the permitted quarter it does not withhold. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: VT + output: + # 0.5 * 0.11% * 100,000 = 55. + vt_employee_child_care_contribution: 55 + # 0.33% * 100,000 + 55 = 385. + vt_employer_child_care_contribution: 385 + +- name: Washington PFML employer pays the part of the employee share it does not deduct; WA Cares does not change. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: WA + output: + # 0.5 * 1.13% * (1 - 0.2857) * 100,000 = 0.5 * 807.159 = 403.5795. + wa_employee_paid_leave_contribution: 403.5795 + # WA Cares is mandatory withholding: 0.58% * 100,000 = 580. + wa_employee_long_term_care_contribution: 580 + wa_employee_state_payroll_tax: 983.5795 + # 1.13% * 0.2857 * 100,000 = 322.841, plus 403.5795 not deducted. + wa_employer_paid_leave_contribution: 726.4205 + +- name: Washington PFML employer with fewer than 50 employees that deducts nothing pays the employee share. + period: 2026 + input: + employment_income: 100_000 + employer_headcount: 49 + employer_state_payroll_premium_deduction_share: 0 + state_code: WA + output: + wa_employee_paid_leave_contribution: 0 + # 1.13% * (1 - 0.2857) * 100,000 = 807.159. + wa_employer_paid_leave_contribution: 807.159 + +- name: Minnesota Paid Leave employer pays the premium the employee share leaves. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: MN + output: + # 0.5 * 0.44% * 100,000 = 220. + mn_employee_paid_leave_contribution: 220 + employee_state_payroll_tax: 220 + # 0.88% * 100,000 - 220 = 660. + mn_employer_paid_leave_contribution: 660 + +- name: New York PFL and DBL scale the capped permitted contribution. + period: 2026 + input: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0.5 + state_code: NY + output: + # 0.432% * 100,000 = 432 exceeds the 411.91 maximum; 0.5 * 411.91 = 205.955. + ny_employee_paid_family_leave_contribution: 205.955 + # 0.5% * 100,000 = 500 exceeds 52 weeks * 0.60 = 31.20; 0.5 * 31.20 = 15.60. + ny_employee_disability_benefits_contribution: 15.6 + ny_employee_state_payroll_tax: 221.555 + +- name: Mandatory employee withholding does not depend on the deduction share. + period: 2026 + input: + people: + ca_worker: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0 + ct_worker: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0 + pa_worker: + employment_income: 100_000 + employer_state_payroll_premium_deduction_share: 0 + tax_units: + ca_unit: + members: [ca_worker] + ct_unit: + members: [ct_worker] + pa_unit: + members: [pa_worker] + households: + ca_household: + members: [ca_worker] + state_code: CA + ct_household: + members: [ct_worker] + state_code: CT + pa_household: + members: [pa_worker] + state_code: PA + output: + # CA SDI 1.3%, CT Paid Leave 0.5%, PA UC 0.07%, each of 100,000. + employee_state_payroll_tax: [1_300, 500, 70] diff --git a/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employee_famli_contribution.py b/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employee_famli_contribution.py index c29f79b3e52..23fb43677bb 100644 --- a/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employee_famli_contribution.py +++ b/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employee_famli_contribution.py @@ -5,11 +5,21 @@ class co_employee_famli_contribution(Variable): value_type = float entity = Person label = "Colorado employee FAMLI contribution" - documentation = "Employee-side Colorado FAMLI payroll contribution." + documentation = ( + "Employee-side Colorado FAMLI premium. The employer remits the premium " + "and may deduct up to half of it from wages (C.R.S. 8-13.3-507(5)); " + "this is that permitted share times state_payroll_premium_deduction_share." + ) definition_period = YEAR unit = USD defined_for = StateCode.CO + reference = ( + "https://olls.info/crs/crs2025-title-08.pdf#page=222", + # PDF pages 7-8 + "https://www.sos.state.co.us/CCR/GenerateRulePdf.do?ruleVersionId=12341&fileName=7%20CCR%201107-1#page=7", + ) def formula(person, period, parameters): rate = parameters(period).gov.states.co.tax.payroll.famli.employee_rate - return rate * person("co_famli_taxable_wages", period) + permitted = rate * person("co_famli_taxable_wages", period) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employer_famli_contribution.py b/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employer_famli_contribution.py index c29f2f349a5..08ad3b5628f 100644 --- a/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employer_famli_contribution.py +++ b/policyengine_us/variables/gov/states/co/tax/payroll/famli/co_employer_famli_contribution.py @@ -5,13 +5,25 @@ class co_employer_famli_contribution(Variable): value_type = float entity = Person label = "Colorado employer FAMLI contribution" - documentation = "Employer-side Colorado FAMLI payroll contribution." + documentation = ( + "Employer-side Colorado FAMLI premium: the employer half for employers " + "with 10 or more employees, plus the part of the permitted employee " + "half the employer does not deduct, which it is treated as electing " + "to pay (7 CCR 1107-1 s. 1.4(6)(A))." + ) definition_period = YEAR unit = USD defined_for = StateCode.CO + reference = ( + "https://olls.info/crs/crs2025-title-08.pdf#page=222", + # PDF pages 7-8 + "https://www.sos.state.co.us/CCR/GenerateRulePdf.do?ruleVersionId=12341&fileName=7%20CCR%201107-1#page=7", + ) def formula(person, period, parameters): p = parameters(period).gov.states.co.tax.payroll.famli liable = person("employer_headcount", period) >= p.employer_headcount_threshold taxable_wages = person("co_famli_taxable_wages", period) - return where(liable, p.employer_rate * taxable_wages, 0) + employer_share = where(liable, p.employer_rate * taxable_wages, 0) + undeducted = 1 - person("state_payroll_premium_deduction_share", period) + return employer_share + undeducted * p.employee_rate * taxable_wages diff --git a/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employee_paid_leave_contribution.py b/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employee_paid_leave_contribution.py index aec23942ac6..e567136436e 100644 --- a/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employee_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employee_paid_leave_contribution.py @@ -6,18 +6,22 @@ class de_employee_paid_leave_contribution(Variable): entity = Person label = "Delaware employee paid leave contribution" documentation = ( - "Employee-side Delaware paid leave contribution, assuming the employer " - "withholds the maximum permitted employee share." + "Employee-side Delaware Paid Leave contribution. The employer remits " + "the contribution and may deduct up to half of it from wages " + "(19 Del. C. s. 3705(d)-(g)); this is that permitted share times " + "state_payroll_premium_deduction_share." ) definition_period = YEAR unit = USD defined_for = StateCode.DE + reference = "https://delcode.delaware.gov/title19/c037/index.html" def formula(person, period, parameters): p = parameters(period).gov.states.de.tax.payroll.paid_leave taxable_wages = person("taxable_earnings_for_social_security", period) - return ( + permitted = ( person("de_paid_leave_contribution_rate", period) * p.employee_share * taxable_wages ) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employer_paid_leave_contribution.py b/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employer_paid_leave_contribution.py index 5ac4a6fce66..7036b6741d0 100644 --- a/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employer_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/de/tax/payroll/paid_leave/de_employer_paid_leave_contribution.py @@ -6,18 +6,24 @@ class de_employer_paid_leave_contribution(Variable): entity = Person label = "Delaware employer paid leave contribution" documentation = ( - "Employer-side Delaware paid leave contribution, assuming the employer " - "contributes only the minimum required share." + "Employer-side Delaware Paid Leave contribution: the half the " + "employer may not deduct, plus the part of the permitted employee " + "half it does not deduct, for which it remains liable " + "(19 Del. C. s. 3705(g))." ) definition_period = YEAR unit = USD defined_for = StateCode.DE + reference = "https://delcode.delaware.gov/title19/c037/index.html" def formula(person, period, parameters): p = parameters(period).gov.states.de.tax.payroll.paid_leave taxable_wages = person("taxable_earnings_for_social_security", period) + deducted = p.employee_share * person( + "state_payroll_premium_deduction_share", period + ) return ( person("de_paid_leave_contribution_rate", period) - * (1 - p.employee_share) + * (1 - deducted) * taxable_wages ) diff --git a/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.py b/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.py index 4b8a8f0fa76..d1d5c2f78ec 100644 --- a/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employee_paid_leave_contribution.py @@ -6,14 +6,25 @@ class ma_employee_paid_leave_contribution(Variable): entity = Person label = "Massachusetts employee paid leave contribution" documentation = ( - "Employee-side Massachusetts Paid Family and Medical Leave contribution, " - "assuming the employer withholds the maximum permitted employee share." + "Employee-side Massachusetts Paid Family and Medical Leave " + "contribution. The employer remits the contribution and may deduct up " + "to a capped share of the family and the medical contribution from " + "wages (M.G.L. c. 175M s. 6(c)-(d)); this is that permitted share " + "times state_payroll_premium_deduction_share." ) definition_period = YEAR unit = USD defined_for = StateCode.MA + reference = ( + "https://malegislature.gov/Laws/GeneralLaws/PartI/TitleXXII/Chapter175M/Section6", + "https://malegislature.gov/Laws/SessionLaws/Acts/2026/Chapter101", + ) def formula(person, period, parameters): p = parameters(period).gov.states.ma.tax.payroll.paid_leave - rate = p.family_rate + p.medical_rate * p.medical_employee_share - return rate * person("ma_paid_leave_taxable_wages", period) + rate = ( + p.family_rate * p.family_employee_share + + p.medical_rate * p.medical_employee_share + ) + permitted = rate * person("ma_paid_leave_taxable_wages", period) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employer_paid_leave_contribution.py b/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employer_paid_leave_contribution.py index e2cc2236580..b88c5450ecc 100644 --- a/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employer_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/ma/tax/payroll/paid_leave/ma_employer_paid_leave_contribution.py @@ -6,16 +6,33 @@ class ma_employer_paid_leave_contribution(Variable): entity = Person label = "Massachusetts employer paid leave contribution" documentation = ( - "Employer-side Massachusetts Paid Family and Medical Leave contribution, " - "using employer headcount as a proxy for covered individuals." + "Employer-side Massachusetts Paid Family and Medical Leave " + "contribution: the part of each contribution the employer may not " + "deduct, for employers with 25 or more covered individuals (employer " + "headcount is the proxy), plus the part of the permitted employee " + "share the employer does not deduct, which it must still remit " + "(458 CMR 2.05(5))." ) definition_period = YEAR unit = USD defined_for = StateCode.MA + reference = ( + "https://malegislature.gov/Laws/GeneralLaws/PartI/TitleXXII/Chapter175M/Section6", + "https://malegislature.gov/Laws/SessionLaws/Acts/2026/Chapter101", + "https://www.mass.gov/doc/458-cmr-2-family-and-medical-leave/download#page=12", + ) def formula(person, period, parameters): p = parameters(period).gov.states.ma.tax.payroll.paid_leave liable = person("employer_headcount", period) >= p.employer_headcount_threshold - rate = p.medical_rate * (1 - p.medical_employee_share) + employer_rate = p.family_rate * ( + 1 - p.family_employee_share + ) + p.medical_rate * (1 - p.medical_employee_share) + employee_rate = ( + p.family_rate * p.family_employee_share + + p.medical_rate * p.medical_employee_share + ) taxable_wages = person("ma_paid_leave_taxable_wages", period) - return where(liable, rate * taxable_wages, 0) + employer_share = where(liable, employer_rate * taxable_wages, 0) + undeducted = 1 - person("state_payroll_premium_deduction_share", period) + return employer_share + undeducted * employee_rate * taxable_wages diff --git a/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employee_paid_leave_contribution.py b/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employee_paid_leave_contribution.py index 874ba8d8f9c..736206e9457 100644 --- a/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employee_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employee_paid_leave_contribution.py @@ -6,13 +6,17 @@ class me_employee_paid_leave_contribution(Variable): entity = Person label = "Maine employee paid leave contribution" documentation = ( - "Employee-side Maine paid leave contribution, assuming the employer " - "withholds the maximum permitted employee share." + "Employee-side Maine Paid Family and Medical Leave premium. The " + "employer remits the premium and may deduct up to half of it from " + "wages (26 M.R.S. s. 850-F(5)); this is that permitted share times " + "state_payroll_premium_deduction_share." ) definition_period = YEAR unit = USD defined_for = StateCode.ME + reference = "https://legislature.maine.gov/legis/statutes/26/title26sec850-F.html" def formula(person, period, parameters): rate = parameters(period).gov.states.me.tax.payroll.paid_leave.employee_rate - return rate * person("me_paid_leave_taxable_wages", period) + permitted = rate * person("me_paid_leave_taxable_wages", period) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employer_paid_leave_contribution.py b/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employer_paid_leave_contribution.py index 98e57db2fd2..c1ac657a992 100644 --- a/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employer_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/me/tax/payroll/paid_leave/me_employer_paid_leave_contribution.py @@ -6,15 +6,21 @@ class me_employer_paid_leave_contribution(Variable): entity = Person label = "Maine employer paid leave contribution" documentation = ( - "Employer-side Maine paid leave contribution, using employer headcount " - "as a proxy for covered employee count." + "Employer-side Maine Paid Family and Medical Leave premium: the " + "employer half for employers with 15 or more employees (employer " + "headcount is the proxy), plus the part of the permitted employee " + "half the employer does not deduct, which every employer must still " + "remit (26 M.R.S. s. 850-F(5))." ) definition_period = YEAR unit = USD defined_for = StateCode.ME + reference = "https://legislature.maine.gov/legis/statutes/26/title26sec850-F.html" def formula(person, period, parameters): p = parameters(period).gov.states.me.tax.payroll.paid_leave liable = person("employer_headcount", period) >= p.employer_headcount_threshold taxable_wages = person("me_paid_leave_taxable_wages", period) - return where(liable, p.employer_rate * taxable_wages, 0) + employer_share = where(liable, p.employer_rate * taxable_wages, 0) + undeducted = 1 - person("state_payroll_premium_deduction_share", period) + return employer_share + undeducted * p.employee_rate * taxable_wages diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/mn_employer_additional_state_payroll_tax.py b/policyengine_us/variables/gov/states/mn/tax/payroll/mn_employer_additional_state_payroll_tax.py new file mode 100644 index 00000000000..f073e239871 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/mn_employer_additional_state_payroll_tax.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class mn_employer_additional_state_payroll_tax(Variable): + value_type = float + entity = Person + label = "Minnesota employer additional state payroll tax" + documentation = "Employer-side Minnesota Paid Leave premium." + definition_period = YEAR + unit = USD + defined_for = StateCode.MN + adds = ["mn_employer_paid_leave_contribution"] diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employee_paid_leave_contribution.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employee_paid_leave_contribution.py index 74f346285ee..fc3f4b36cf7 100644 --- a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employee_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employee_paid_leave_contribution.py @@ -6,13 +6,21 @@ class mn_employee_paid_leave_contribution(Variable): entity = Person label = "Minnesota employee paid leave contribution" documentation = ( - "Employee-side Minnesota Paid Leave contribution, assuming the employer " - "withholds the maximum permitted employee share." + "Employee-side Minnesota Paid Leave premium. The premium is payable " + "by the employer, which must pay at least half (a small employer " + "under subd. 5a, at least a quarter of the full rate); employees pay " + "by wage deduction only the part the employer does not pay (Minn. " + "Stat. 268B.14, subds. 1, 3 and 5a). This is the largest such part, " + "mn_paid_leave_permitted_employee_rate times taxable wages, times " + "state_payroll_premium_deduction_share. The employer pays the rest " + "of the premium (mn_employer_paid_leave_contribution)." ) definition_period = YEAR unit = USD defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/268B.14" def formula(person, period, parameters): - rate = parameters(period).gov.states.mn.tax.payroll.paid_leave.employee_rate - return rate * person("mn_paid_leave_taxable_wages", period) + rate = person("mn_paid_leave_permitted_employee_rate", period) + permitted = rate * person("mn_paid_leave_taxable_wages", period) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employer_paid_leave_contribution.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employer_paid_leave_contribution.py new file mode 100644 index 00000000000..9dc1402c42a --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_employer_paid_leave_contribution.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class mn_employer_paid_leave_contribution(Variable): + value_type = float + entity = Person + label = "Minnesota employer paid leave contribution" + documentation = ( + "Employer-side Minnesota Paid Leave premium: the premium the employer " + "owes on the person's taxable wages (Minn. Stat. 268B.14, subd. 1) " + "less the employee wage deduction (subds. 3 and 5a). That is at " + "least the employer's minimum, half the premium or for a small " + "employer a quarter of the full rate, plus any part of the permitted " + "employee portion the employer does not deduct." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/268B.14" + + def formula(person, period, parameters): + return person("mn_paid_leave_premium", period) - person( + "mn_employee_paid_leave_contribution", period + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_employer_average_quarterly_wage.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_employer_average_quarterly_wage.py new file mode 100644 index 00000000000..f3ef0014bd6 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_employer_average_quarterly_wage.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class mn_paid_leave_employer_average_quarterly_wage(Variable): + value_type = float + entity = Person + label = "Minnesota Paid Leave employer average quarterly wage" + documentation = ( + "Average wage of the person's employer as Minnesota Paid Leave " + "measures it for the small employer premium rate: the employer's " + "covered wages in its highest-paid quarter of the basis period (the " + "four quarters ending September 30 of the prior year) divided by its " + "highest quarterly employee count in that period; the two may come " + "from different quarters (Minn. Stat. 268B.14, subds. 5b(a) and " + "5c(a)). An employer not covered for the whole basis period uses its " + "own estimates instead (subd. 5c(b)). The default of 0 treats the " + "employer as meeting the wage test, so employer_headcount alone " + "decides whether the small employer rate applies." + ) + unit = USD + definition_period = YEAR + reference = "https://www.revisor.mn.gov/statutes/cite/268B.14" diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_permitted_employee_rate.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_permitted_employee_rate.py new file mode 100644 index 00000000000..48d472c265e --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_permitted_employee_rate.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class mn_paid_leave_permitted_employee_rate(Variable): + value_type = float + entity = Person + label = "Minnesota Paid Leave permitted employee premium rate" + documentation = ( + "Largest share of the person's taxable wages the employer may deduct " + "for Minnesota Paid Leave: the premium rate less the employer's " + "minimum. The employer pays at least half the premium (Minn. Stat. " + "268B.14, subd. 3), or for a small employer eligible under subd. 5a, " + "at least 25 percent of the full rate out of a premium of 75 percent " + "of it (subd. 5a(b)); employees pay the remaining portion, if any." + ) + definition_period = YEAR + unit = "/1" + defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/268B.14" + + def formula(person, period, parameters): + p = parameters(period).gov.states.mn.tax.payroll.paid_leave + small = person("mn_paid_leave_small_employer", period) + premium_share_of_full_rate = where(small, p.small_employer.rate_share, 1) + employer_minimum_share_of_full_rate = where( + small, + p.small_employer.employer_minimum_share, + p.employer_minimum_share, + ) + # Employees pay the remaining portion, if any, which is never more + # than the premium itself. + employee_share_of_full_rate = clip( + premium_share_of_full_rate - employer_minimum_share_of_full_rate, + 0, + premium_share_of_full_rate, + ) + return p.rate * employee_share_of_full_rate diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_premium.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_premium.py new file mode 100644 index 00000000000..583930617b9 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_premium.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class mn_paid_leave_premium(Variable): + value_type = float + entity = Person + label = "Minnesota Paid Leave premium" + documentation = ( + "Minnesota Paid Leave premium on the person's taxable wages, which " + "accrues to and is payable by the employer (Minn. Stat. 268B.14, " + "subd. 1). The employer pays it less the employee wage deduction." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/268B.14" + + def formula(person, period, parameters): + return person("mn_paid_leave_premium_rate", period) * person( + "mn_paid_leave_taxable_wages", period + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_premium_rate.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_premium_rate.py new file mode 100644 index 00000000000..0c0a4ede280 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_premium_rate.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class mn_paid_leave_premium_rate(Variable): + value_type = float + entity = Person + label = "Minnesota Paid Leave premium rate" + documentation = ( + "Minnesota Paid Leave premium rate on the person's taxable wages: the " + "annual premium rate, or 75 percent of it for a small employer " + "eligible under subd. 5a (Minn. Stat. 268B.14, subds. 5a(b), 6 and " + "7). Assumes the employer participates in both the family and " + "medical benefit programs; approved private plans (subds. 1 and 6, " + "section 268B.10) are not modeled." + ) + definition_period = YEAR + unit = "/1" + defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/268B.14" + + def formula(person, period, parameters): + p = parameters(period).gov.states.mn.tax.payroll.paid_leave + small = person("mn_paid_leave_small_employer", period) + return p.rate * where(small, p.small_employer.rate_share, 1) diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_small_employer.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_small_employer.py new file mode 100644 index 00000000000..8b776d183a1 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_small_employer.py @@ -0,0 +1,44 @@ +from policyengine_us.model_api import * + + +class mn_paid_leave_small_employer(Variable): + value_type = bool + entity = Person + label = "Minnesota Paid Leave small employer" + documentation = ( + "Whether the person's employer qualifies for the Minnesota Paid Leave " + "small employer premium rate: 30 or fewer employees, and an average " + "wage at most 150 percent of the state's average wage in covered " + "employment for the basis period (Minn. Stat. 268B.14, subd. 5a(a)). " + "employer_headcount stands in for the employer's highest quarterly " + "employee count in the basis period (subd. 5b), and " + "mn_paid_leave_employer_average_quarterly_wage for its average wage " + "(subd. 5c). The limit is a quarterly amount, which DEED states to " + "the cent: 150 percent of $73,989 / 4 is $27,745.875 for 2026, which " + "DEED gives as $27,745.88. DEED's " + "further condition that the employer filed every wage detail report " + "in the basis period is not modeled." + ) + definition_period = YEAR + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/268B.14", + "https://mn.gov/deed/assets/paid-leave-small-employer-premium-rate-designation-acc_tcm1045-716947.pdf#page=1", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.mn.tax.payroll.paid_leave.small_employer + headcount = person("employer_headcount", period) + average_wage = person("mn_paid_leave_employer_average_quarterly_wage", period) + quarterly_state_average = p.state_average_annual_wage / 4 + # DEED states the limit to the cent: $27,745.875 for 2026 becomes + # $27,745.88. Round half up, as for the taxable wage base. + max_average_wage = ( + np.floor(100 * p.max_average_wage_ratio * quarterly_state_average + 0.5) + / 100 + ) + # Inputs are held in float32: compare at that precision, so an input + # of exactly the published limit meets it. + return (headcount <= p.max_headcount) & ( + average_wage <= np.float32(max_average_wage) + ) diff --git a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_taxable_wages.py b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_taxable_wages.py index 03112c1cd04..8fc38110961 100644 --- a/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_taxable_wages.py +++ b/policyengine_us/variables/gov/states/mn/tax/payroll/paid_leave/mn_paid_leave_taxable_wages.py @@ -18,3 +18,26 @@ def formula(person, period, parameters): social_security_cap = parameters(period).gov.irs.payroll.social_security.cap taxable_wage_base = 1_000 * np.floor(social_security_cap / 1_000 + 0.5) return min_(max_(0, person("employment_income", period)), taxable_wage_base) + + +class employer_total_mn_paid_leave_taxable_wages(Variable): + value_type = float + entity = Person + label = "Employer total Minnesota Paid Leave taxable wages" + documentation = ( + "Aggregate employer wages subject to Minnesota Paid Leave premiums " + "for employer-only payroll tax calculations. Defaults to " + "employer_total_taxable_earnings_for_social_security, which caps each " + "worker's wages at the Social Security wage base. Minnesota caps them " + "at that base rounded to the nearest $1,000 (Minn. Stat. 268B.01, " + "subd. 43): $185,000 against $184,500 in 2026. The two bases differ " + "by at most $500, so the default is off by at most $500 per worker " + "paid above the lower one; set this input to use Minnesota's base." + ) + definition_period = YEAR + unit = USD + defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/268B.01" + + def formula(person, period, parameters): + return person("employer_total_taxable_earnings_for_social_security", period) diff --git a/policyengine_us/variables/gov/states/ny/tax/payroll/disability_benefits/ny_employee_disability_benefits_contribution.py b/policyengine_us/variables/gov/states/ny/tax/payroll/disability_benefits/ny_employee_disability_benefits_contribution.py index c4154ab4e3c..608d52a4e74 100644 --- a/policyengine_us/variables/gov/states/ny/tax/payroll/disability_benefits/ny_employee_disability_benefits_contribution.py +++ b/policyengine_us/variables/gov/states/ny/tax/payroll/disability_benefits/ny_employee_disability_benefits_contribution.py @@ -6,16 +6,27 @@ class ny_employee_disability_benefits_contribution(Variable): entity = Person label = "New York employee disability benefits contribution" documentation = ( - "Employee-side New York Disability Benefits withholding, annualized " - "from the statutory weekly cap." + "Employee-side New York Disability Benefits contribution. The " + "employer is authorized, not required, to collect it by payroll " + "deduction, up to 0.5 percent of wages and 60 cents a week, and pays " + "the cost beyond what it collects (Workers' Compensation Law " + "ss. 209(3)(a), (4) and 210(1)); this is that permitted amount, " + "annualized from the weekly cap, times " + "state_payroll_premium_deduction_share. The employer's cost of " + "coverage is not modeled." ) definition_period = YEAR unit = USD defined_for = StateCode.NY + reference = ( + "https://www.nysenate.gov/legislation/laws/WKC/209", + "https://www.nysenate.gov/legislation/laws/WKC/210", + ) def formula(person, period, parameters): p = parameters(period).gov.states.ny.tax.payroll.disability_benefits uncapped = p.employee_rate * person( "ny_disability_benefits_taxable_wages", period ) - return min_(uncapped, p.annual_max_contribution) + permitted = min_(uncapped, p.annual_max_contribution) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/ny/tax/payroll/paid_family_leave/ny_employee_paid_family_leave_contribution.py b/policyengine_us/variables/gov/states/ny/tax/payroll/paid_family_leave/ny_employee_paid_family_leave_contribution.py index 6691dff1f8d..9b7fb67e980 100644 --- a/policyengine_us/variables/gov/states/ny/tax/payroll/paid_family_leave/ny_employee_paid_family_leave_contribution.py +++ b/policyengine_us/variables/gov/states/ny/tax/payroll/paid_family_leave/ny_employee_paid_family_leave_contribution.py @@ -5,14 +5,23 @@ class ny_employee_paid_family_leave_contribution(Variable): value_type = float entity = Person label = "New York employee paid family leave contribution" - documentation = "Employee-side New York Paid Family Leave contribution." + documentation = ( + "Employee-side New York Paid Family Leave contribution. The employer " + "is authorized, not required, to collect it by payroll deduction up " + "to the rate and annual maximum the Department of Financial Services " + "sets (Workers' Compensation Law s. 209(3)(b), (4)); this is that " + "permitted amount times state_payroll_premium_deduction_share. The " + "employer's cost of coverage is not modeled." + ) definition_period = YEAR unit = USD defined_for = StateCode.NY + reference = "https://www.nysenate.gov/legislation/laws/WKC/209" def formula(person, period, parameters): p = parameters(period).gov.states.ny.tax.payroll.paid_family_leave uncapped = p.employee_rate * person( "ny_paid_family_leave_taxable_wages", period ) - return min_(uncapped, p.annual_max_contribution) + permitted = min_(uncapped, p.annual_max_contribution) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py b/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py index 7956a031799..686c8339ec8 100644 --- a/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py +++ b/policyengine_us/variables/gov/states/tax/payroll/employee_state_payroll_tax.py @@ -23,8 +23,33 @@ class employee_state_payroll_tax(Variable): entity = TaxUnit label = "Employee state payroll taxes and contributions" documentation = ( - "Employee-side mandatory state payroll taxes and payroll-funded " - "contributions, aggregated from jurisdiction-specific rules." + "Employee-side state payroll taxes and payroll-funded contributions, " + "aggregated from jurisdiction-specific rules. Most components are " + "contributions the statute puts on the worker and requires the " + "employer to withhold: California SDI, Connecticut Paid Leave, New " + "Jersey TDI, FLI, UI and workforce contributions, Paid Leave Oregon " + "and the Oregon statewide transit tax, Pennsylvania UC, Rhode Island " + "TDI and WA Cares. In the rest, the law caps what the employer may " + "deduct from wages and leaves it to decide how much of that to " + "deduct: Colorado FAMLI, Delaware Paid Leave, Maine and Massachusetts " + "Paid Family and Medical Leave, Minnesota Paid Leave and the Vermont " + "Child Care Contribution, whose premium the statute puts on the " + "employer; New York Paid Family Leave and Disability Benefits, which " + "the employer is authorized but not required to collect; and " + "Washington Paid Family and Medical Leave, whose employee share the " + "employer may deduct up to and may pay in any part. For those, the " + "employee amount is the permitted share times " + "employer_state_payroll_premium_deduction_share, which defaults to 1, " + "the full permitted share, and the employer-side variables carry any " + "part the employer does not deduct, except in New York, whose " + "employer cost is not modeled. Not modeled: an employer's " + "election to pay a required employee contribution as a benefit (Paid " + "Leave Oregon, ORS 657B.150(5)) or voluntary payment of other " + "mandatory contributions, and, for the state paid family and medical " + "leave funds (Colorado, Delaware, Maine, Massachusetts, Minnesota and " + "Washington), the federal treatment of an employer's payment of the " + "employee share as the employee's wages (Rev. Rul. 2025-4; Notice " + "2026-6)." ) definition_period = YEAR unit = USD diff --git a/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py b/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py index 0f81b0058e2..c4fd5cc40cf 100644 --- a/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py +++ b/policyengine_us/variables/gov/states/tax/payroll/employer_additional_state_payroll_tax.py @@ -7,6 +7,7 @@ "de_employer_additional_state_payroll_tax", "ma_employer_additional_state_payroll_tax", "me_employer_additional_state_payroll_tax", + "mn_employer_additional_state_payroll_tax", "or_employer_additional_state_payroll_tax", "ri_employer_additional_state_payroll_tax", "vt_employer_additional_state_payroll_tax", @@ -19,8 +20,11 @@ class employer_additional_state_payroll_tax(Variable): entity = Person label = "Employer additional state payroll taxes and contributions" documentation = ( - "Employer-side mandatory state payroll taxes and payroll-funded " - "contributions other than state unemployment insurance." + "Employer-side state payroll taxes and payroll-funded contributions " + "other than state unemployment insurance, including any part of a " + "permitted employee premium the employer does not deduct " + "(employer_state_payroll_premium_deduction_share). The New York PFL " + "and DBL employer costs are not modeled." ) definition_period = YEAR unit = USD diff --git a/policyengine_us/variables/gov/states/tax/payroll/employer_total_additional_state_payroll_tax.py b/policyengine_us/variables/gov/states/tax/payroll/employer_total_additional_state_payroll_tax.py index 13102382f5a..0966b78fc32 100644 --- a/policyengine_us/variables/gov/states/tax/payroll/employer_total_additional_state_payroll_tax.py +++ b/policyengine_us/variables/gov/states/tax/payroll/employer_total_additional_state_payroll_tax.py @@ -7,7 +7,11 @@ class employer_total_additional_state_payroll_tax(Variable): label = "Employer total additional state payroll taxes and contributions" documentation = ( "Employer-level state payroll taxes and contributions other than " - "state unemployment insurance, from aggregate employer inputs." + "state unemployment insurance, from aggregate employer inputs. For " + "programs where the law caps the employer's deduction from wages and " + "the employer pays what it does not deduct, it applies the person's " + "state_payroll_premium_deduction_share to the whole payroll, as if " + "the employer deducts the same share for everyone." ) definition_period = YEAR unit = USD @@ -18,6 +22,9 @@ def formula(person, period, parameters): ss_taxable = person( "employer_total_taxable_earnings_for_social_security", period ) + # Where the law caps the employer's deduction from wages, the employer + # pays the part of the permitted employee share it does not deduct. + deducted = person("state_payroll_premium_deduction_share", period) state_ui_taxable = person( "employer_total_taxable_earnings_for_state_unemployment_tax", period ) @@ -30,11 +37,14 @@ def formula(person, period, parameters): ) co_p = parameters(period).gov.states.co.tax.payroll.famli - co = where( - headcount >= co_p.employer_headcount_threshold, - co_p.employer_rate - * person("employer_total_co_famli_taxable_wages", period), - 0, + co_wages = person("employer_total_co_famli_taxable_wages", period) + co = ( + where( + headcount >= co_p.employer_headcount_threshold, + co_p.employer_rate * co_wages, + 0, + ) + + (1 - deducted) * co_p.employee_rate * co_wages ) dc = parameters( @@ -55,25 +65,45 @@ def formula(person, period, parameters): [0, de_p.parental_rate], default=de_full_coverage_rate, ) - de = de_contribution_rate * (1 - de_p.employee_share) * ss_taxable + de = de_contribution_rate * (1 - de_p.employee_share * deducted) * ss_taxable ma_p = parameters(period).gov.states.ma.tax.payroll.paid_leave - ma = where( - headcount >= ma_p.employer_headcount_threshold, - ma_p.medical_rate - * (1 - ma_p.medical_employee_share) - * person("employer_total_ma_paid_leave_taxable_wages", period), - 0, + ma_wages = person("employer_total_ma_paid_leave_taxable_wages", period) + ma_employer_rate = ma_p.family_rate * ( + 1 - ma_p.family_employee_share + ) + ma_p.medical_rate * (1 - ma_p.medical_employee_share) + ma_employee_rate = ( + ma_p.family_rate * ma_p.family_employee_share + + ma_p.medical_rate * ma_p.medical_employee_share + ) + ma = ( + where( + headcount >= ma_p.employer_headcount_threshold, + ma_employer_rate * ma_wages, + 0, + ) + + (1 - deducted) * ma_employee_rate * ma_wages ) me_p = parameters(period).gov.states.me.tax.payroll.paid_leave - me = where( - headcount >= me_p.employer_headcount_threshold, - me_p.employer_rate - * person("employer_total_me_paid_leave_taxable_wages", period), - 0, + me_wages = person("employer_total_me_paid_leave_taxable_wages", period) + me = ( + where( + headcount >= me_p.employer_headcount_threshold, + me_p.employer_rate * me_wages, + 0, + ) + + (1 - deducted) * me_p.employee_rate * me_wages ) + # The premium and permitted employee rates depend on the small + # employer test (Minn. Stat. 268B.14, subd. 5a), which reads the same + # employer inputs as the per-worker path. + mn = ( + person("mn_paid_leave_premium_rate", period) + - deducted * person("mn_paid_leave_permitted_employee_rate", period) + ) * person("employer_total_mn_paid_leave_taxable_wages", period) + or_p = parameters(period).gov.states["or"].tax.payroll.paid_leave or_tax = where( headcount >= or_p.employer_headcount_threshold, @@ -89,19 +119,20 @@ def formula(person, period, parameters): * state_ui_taxable ) - vt = parameters( - period - ).gov.states.vt.tax.payroll.child_care.employer_rate * person( + vt_p = parameters(period).gov.states.vt.tax.payroll.child_care + vt = (vt_p.employer_rate + (1 - deducted) * vt_p.employee_rate) * person( "employer_total_vt_child_care_contribution_wages", period ) wa_p = parameters(period).gov.states.wa.tax.payroll.paid_leave - wa = where( - headcount >= wa_p.employer_headcount_threshold, - wa_p.total_rate - * wa_p.employer_share - * person("employer_total_wa_paid_leave_taxable_wages", period), - 0, + wa_wages = person("employer_total_wa_paid_leave_taxable_wages", period) + wa = ( + where( + headcount >= wa_p.employer_headcount_threshold, + wa_p.total_rate * wa_p.employer_share * wa_wages, + 0, + ) + + (1 - deducted) * wa_p.total_rate * (1 - wa_p.employer_share) * wa_wages ) return select( @@ -112,11 +143,12 @@ def formula(person, period, parameters): state_code == StateCode.DE, state_code == StateCode.MA, state_code == StateCode.ME, + state_code == StateCode.MN, state_code == StateCode.OR, state_code == StateCode.RI, state_code == StateCode.VT, state_code == StateCode.WA, ], - [ca, co, dc, de, ma, me, or_tax, ri, vt, wa], + [ca, co, dc, de, ma, me, mn, or_tax, ri, vt, wa], default=0, ) diff --git a/policyengine_us/variables/gov/states/tax/payroll/state_payroll_premium_deduction_share.py b/policyengine_us/variables/gov/states/tax/payroll/state_payroll_premium_deduction_share.py new file mode 100644 index 00000000000..9abd4cbe95f --- /dev/null +++ b/policyengine_us/variables/gov/states/tax/payroll/state_payroll_premium_deduction_share.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class state_payroll_premium_deduction_share(Variable): + value_type = float + entity = Person + label = "State payroll premium deduction share" + documentation = ( + "Share of the permitted employee premium deducted from wages, for " + "state programs where the law caps the employer's deduction and " + "leaves the amount to the employer. It is " + "employer_state_payroll_premium_deduction_share held between 0 and 1: " + "an employer may not deduct more than the permitted share, and " + "deducting less than nothing has no meaning." + ) + unit = "/1" + definition_period = YEAR + + def formula(person, period, parameters): + share = person("employer_state_payroll_premium_deduction_share", period) + return clip(share, 0, 1) diff --git a/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employee_child_care_contribution.py b/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employee_child_care_contribution.py index 1014e8ca0f3..dd92530afe7 100644 --- a/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employee_child_care_contribution.py +++ b/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employee_child_care_contribution.py @@ -6,13 +6,17 @@ class vt_employee_child_care_contribution(Variable): entity = Person label = "Vermont employee child care contribution" documentation = ( - "Employee-side Vermont Child Care Contribution, assuming the employer " - "withholds the maximum permitted employee share." + "Employee-side Vermont Child Care Contribution. The employer pays the " + "contribution and may withhold up to a quarter of it from wages " + "(32 V.S.A. s. 10553(a)(1)); this is that permitted share times " + "state_payroll_premium_deduction_share." ) definition_period = YEAR unit = USD defined_for = StateCode.VT + reference = "https://legislature.vermont.gov/statutes/section/32/246/10553" def formula(person, period, parameters): rate = parameters(period).gov.states.vt.tax.payroll.child_care.employee_rate - return rate * person("vt_child_care_contribution_wages", period) + permitted = rate * person("vt_child_care_contribution_wages", period) + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employer_child_care_contribution.py b/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employer_child_care_contribution.py index f5aca0696d1..026d417832b 100644 --- a/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employer_child_care_contribution.py +++ b/policyengine_us/variables/gov/states/vt/tax/payroll/child_care/vt_employer_child_care_contribution.py @@ -6,13 +6,18 @@ class vt_employer_child_care_contribution(Variable): entity = Person label = "Vermont employer child care contribution" documentation = ( - "Employer-side Vermont Child Care Contribution, assuming the employer " - "contributes only the minimum required employer share." + "Employer-side Vermont Child Care Contribution: the three quarters the " + "employer may not withhold, plus the part of the permitted employee " + "quarter it does not withhold, for which it is responsible " + "(32 V.S.A. s. 10553(c)(2))." ) definition_period = YEAR unit = USD defined_for = StateCode.VT + reference = "https://legislature.vermont.gov/statutes/section/32/246/10553" def formula(person, period, parameters): - rate = parameters(period).gov.states.vt.tax.payroll.child_care.employer_rate - return rate * person("vt_child_care_contribution_wages", period) + p = parameters(period).gov.states.vt.tax.payroll.child_care + wages = person("vt_child_care_contribution_wages", period) + undeducted = 1 - person("state_payroll_premium_deduction_share", period) + return (p.employer_rate + undeducted * p.employee_rate) * wages diff --git a/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employee_paid_leave_contribution.py b/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employee_paid_leave_contribution.py index b0b2c6b1c67..a77513c9c91 100644 --- a/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employee_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employee_paid_leave_contribution.py @@ -6,13 +6,25 @@ class wa_employee_paid_leave_contribution(Variable): entity = Person label = "Washington employee paid leave contribution" documentation = ( - "Employee-side Washington Paid Family and Medical Leave contribution." + "Employee-side Washington Paid Family and Medical Leave premium. The " + "employer collects and remits the premium, may deduct up to the " + "employee share from wages, and may elect to pay all or any portion " + "of it (RCW 50A.10.030(3), (7)); this is that permitted share times " + "state_payroll_premium_deduction_share. Unlike Paid Leave Oregon, " + "whose employer must deduct a fixed 60 percent (ORS 657B.150(2)(b)), " + "the deduction itself is permissive and capped, and a deduction not " + "taken is the employer's (WAC 192-510-065(2))." ) definition_period = YEAR unit = USD defined_for = StateCode.WA + reference = ( + "https://app.leg.wa.gov/RCW/default.aspx?cite=50A.10.030", + "https://app.leg.wa.gov/WAC/default.aspx?cite=192-510-065", + ) def formula(person, period, parameters): p = parameters(period).gov.states.wa.tax.payroll.paid_leave taxable_wages = person("wa_paid_leave_taxable_wages", period) - return p.total_rate * (1 - p.employer_share) * taxable_wages + permitted = p.total_rate * (1 - p.employer_share) * taxable_wages + return permitted * person("state_payroll_premium_deduction_share", period) diff --git a/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employer_paid_leave_contribution.py b/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employer_paid_leave_contribution.py index f4e26d381fb..d57d3c2873d 100644 --- a/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employer_paid_leave_contribution.py +++ b/policyengine_us/variables/gov/states/wa/tax/payroll/paid_leave/wa_employer_paid_leave_contribution.py @@ -6,14 +6,29 @@ class wa_employer_paid_leave_contribution(Variable): entity = Person label = "Washington employer paid leave contribution" documentation = ( - "Employer-side Washington Paid Family and Medical Leave contribution." + "Employer-side Washington Paid Family and Medical Leave premium: the " + "employer portion for employers with 50 or more employees (employer " + "headcount is the proxy), plus the part of the permitted employee " + "share the employer does not deduct, which it is treated as electing " + "to pay (WAC 192-510-065(2))." ) definition_period = YEAR unit = USD defined_for = StateCode.WA + reference = ( + "https://app.leg.wa.gov/RCW/default.aspx?cite=50A.10.030", + "https://app.leg.wa.gov/WAC/default.aspx?cite=192-510-065", + ) def formula(person, period, parameters): p = parameters(period).gov.states.wa.tax.payroll.paid_leave liable = person("employer_headcount", period) >= p.employer_headcount_threshold taxable_wages = person("wa_paid_leave_taxable_wages", period) - return where(liable, p.total_rate * p.employer_share * taxable_wages, 0) + employer_share = where( + liable, p.total_rate * p.employer_share * taxable_wages, 0 + ) + undeducted = 1 - person("state_payroll_premium_deduction_share", period) + return ( + employer_share + + undeducted * p.total_rate * (1 - p.employer_share) * taxable_wages + ) diff --git a/policyengine_us/variables/input/employer_payroll.py b/policyengine_us/variables/input/employer_payroll.py index 4aff703de14..9a6c72a1023 100644 --- a/policyengine_us/variables/input/employer_payroll.py +++ b/policyengine_us/variables/input/employer_payroll.py @@ -21,12 +21,40 @@ class employer_headcount(Variable): label = "Employer headcount" documentation = ( "Employer employee count used as a proxy for size-based payroll " - "contribution rules, including paid leave and similar programs." + "contribution rules, including paid leave and similar programs. For " + "Minnesota Paid Leave's small employer rate it stands in for the " + "employer's highest quarterly employee count in the basis period " + "(Minn. Stat. 268B.14, subd. 5b)." ) definition_period = YEAR default_value = 100 +class employer_state_payroll_premium_deduction_share(Variable): + value_type = float + entity = Person + label = "Employer state payroll premium deduction share" + documentation = ( + "Share of the largest employee premium the law lets the employer " + "deduct from wages that the employer actually deducts, for state " + "programs where the law caps the deduction and leaves the amount to " + "the employer: Colorado FAMLI, Delaware Paid Leave, Maine and " + "Massachusetts Paid Family and Medical Leave, Minnesota Paid Leave, " + "New York Paid Family Leave and Disability Benefits, the Vermont " + "Child Care Contribution and Washington Paid Family and Medical " + "Leave. 1, the default, deducts the full permitted share; 0 deducts " + "nothing. The employer pays any part it does not deduct, which the " + "employer-side variables carry except in New York, whose employer " + "cost is not modeled. For the state paid family and medical leave " + "funds, the federal treatment of that payment as the employee's wages " + "(Rev. Rul. 2025-4; Notice 2026-6) is not modeled. " + "Values outside 0 to 1 are treated as the nearer bound." + ) + unit = "/1" + definition_period = YEAR + default_value = 1 + + class employer_quarterly_payroll_expense_override(Variable): value_type = float entity = Person