diff --git a/changelog.d/ok-ui.added.md b/changelog.d/ok-ui.added.md new file mode 100644 index 00000000000..619d7d92233 --- /dev/null +++ b/changelog.d/ok-ui.added.md @@ -0,0 +1,2 @@ +Add Oklahoma Unemployment Insurance. +The Oklahoma taxable wage base is now dated 2022-2026, which corrects ok_employer_state_unemployment_tax in four of five years. diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml new file mode 100644 index 00000000000..b1dadd9bd04 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_taxable_wages.yaml @@ -0,0 +1,14 @@ +description: Oklahoma sets the minimum taxable base period wages at this amount for monetary eligibility under the Unemployment Insurance program. + +values: + 1980-07-01: 1_500 + +metadata: + unit: currency-USD + period: year + label: Oklahoma UI minimum taxable base period wages + reference: + - title: 40 O.S. §2-207(A)(1) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: 40 O.S. §2-207 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml new file mode 100644 index 00000000000..9f38530fbd2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/eligibility/min_total_wages_multiplier.yaml @@ -0,0 +1,14 @@ +description: Oklahoma uses this multiple of high quarter wages as the minimum total base period wages for monetary eligibility under the Unemployment Insurance program. + +values: + 1980-07-01: 1.5 + +metadata: + unit: /1 + period: year + label: Oklahoma UI minimum total wages multiplier + reference: + - title: 40 O.S. §2-207(A)(2) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: 40 O.S. §2-207 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml new file mode 100644 index 00000000000..cb39cde8a79 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/index.yaml @@ -0,0 +1,4 @@ +metadata: + propagate_metadata_to_children: true + economy: false + household: true diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml new file mode 100644 index 00000000000..d53f84fff0f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/base_period_wages_share.yaml @@ -0,0 +1,26 @@ +description: Oklahoma limits unemployment compensation benefits to this share of base period wages under the Unemployment Insurance program. + +values: + # 40 O.S. §2-106(3) base-period-wages percentages: (a) 50%, (b) 47.5%, + # (c) 45%, (d) 42.5%, (e) 40%, keyed to the conditional factor in place. + # 2022-2025 reflect condition "e" (40%); 2026 reflects condition "b" (47.5%). + 2022-01-01: 0.4 + 2026-01-01: 0.475 + +metadata: + unit: /1 + period: year + label: Oklahoma UI maximum benefit base period wages share + reference: + - title: 40 O.S. §2-106(3) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=53 + - title: 40 O.S. §2-106 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 + - title: OESC Important Numbers for 2026 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml new file mode 100644 index 00000000000..2cf413b22a0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_amount.yaml @@ -0,0 +1,34 @@ +description: Oklahoma limits unemployment compensation benefits to this amount within a benefit year under the Unemployment Insurance program. + +values: + # 40 O.S. §2-106(2) defines the statutory cap as a conditional-factor + # percentage of the state's average annual wage. From 2023 onward the + # OESC-published values below are the 16 x maximum-WBA proxies OESC + # publishes rather than the statutory %-of-average-annual-wage figure; this + # parameter never binds after 2023 because the 16-week duration cap on WBA + # is the lesser amount. + 2022-01-01: 9_900 + 2023-01-01: 7_888 + 2024-01-01: 8_304 + 2025-01-01: 8_656 + 2026-01-01: 10_384 + +metadata: + unit: currency-USD + period: year + label: Oklahoma UI maximum benefit amount + reference: + - title: 40 O.S. §2-106(2) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=52 + - title: 40 O.S. §2-106 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 + - title: Oklahoma Unemployment Insurance Tax Rates by Industry, Size, and County (2022 column) + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=6 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 + - title: OESC Important Numbers for 2026 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml new file mode 100644 index 00000000000..f8fc4141db8 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/mba/max_weeks.yaml @@ -0,0 +1,29 @@ +description: Oklahoma limits unemployment compensation benefits to this number of weeks within a benefit year under the Unemployment Insurance program. + +values: + # 40 O.S. §2-106(1) sets the times-WBA multiplier for the benefit-year cap; + # the 2023-01-01 key rests on §2-106(1)(b). §1-231 (Laws 2022, c. 287 / + # HB 1933) sets the duration floor at 16 weeks, escalating +2 weeks per + # 15,000-claim increment up to 20 weeks, and up to 26 weeks if continued + # claims exceed 40,000. That escalator is operative but does not bind here: + # the 13-week continued-claim averages (roughly 10,266 in 2025 and 11,393 in + # 2026) sit below the first 15,000-claim increment, so 16 weeks remains the + # applicable duration. + 1980-07-01: 26 + 2023-01-01: 16 + +metadata: + unit: week + period: year + label: Oklahoma UI maximum benefit weeks + reference: + - title: 40 O.S. §1-231 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=48 + - title: 40 O.S. §1-231 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=492632 + - title: 40 O.S. §2-106(1) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=52 + - title: 40 O.S. §2-106 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77166 + - title: Oklahoma House Bill 1933 (Laws 2022, c. 287) + href: https://www.oklegislature.gov/cf_pdf/2021-22%20ENR/hB/HB1933%20ENR.PDF diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml new file mode 100644 index 00000000000..e62162ce4f4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/partial/disregard.yaml @@ -0,0 +1,14 @@ +description: Oklahoma disregards this amount of weekly earnings before reducing the partial weekly benefit under the Unemployment Insurance program. + +values: + 1994-07-01: 100 + +metadata: + unit: currency-USD + period: week + label: Oklahoma UI partial benefit earnings disregard + reference: + - title: 40 O.S. §2-105 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51 + - title: 40 O.S. §2-105 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77165 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml new file mode 100644 index 00000000000..bb72053e0eb --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/divisor.yaml @@ -0,0 +1,14 @@ +description: Oklahoma uses this divisor on taxable high quarter wages to compute the weekly benefit amount under the Unemployment Insurance program. + +values: + 1980-07-01: 23 + +metadata: + unit: /1 + period: year + label: Oklahoma UI weekly benefit divisor + reference: + - title: 40 O.S. §2-104(A) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + - title: 40 O.S. §2-104 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml new file mode 100644 index 00000000000..65589dee88d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/max_amount.yaml @@ -0,0 +1,30 @@ +description: Oklahoma sets the maximum weekly benefit amount at this amount under the Unemployment Insurance program. + +values: + 2022-01-01: 476 + 2023-01-01: 493 + 2024-01-01: 519 + 2025-01-01: 541 + 2026-01-01: 649 + +metadata: + unit: currency-USD + period: week + label: Oklahoma UI maximum weekly benefit amount + reference: + - title: 40 O.S. §2-104(B) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + - title: 40 O.S. §2-104 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 + - title: Oklahoma Unemployment Insurance Tax Rates by Industry, Size, and County (2022 column) + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=6 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: OESC Important Numbers for 2025 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2025.pdf#page=1 + - title: OESC Claimant Handbook OES-339 + href: https://oklahoma.gov/content/dam/ok/en/oesc/documents/forms/OES-339.pdf#page=4 + - title: OESC Important Numbers for 2026 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml new file mode 100644 index 00000000000..ba5fe00aab0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/oesc/unemployment_insurance/wba/min_amount.yaml @@ -0,0 +1,14 @@ +description: Oklahoma sets the minimum weekly benefit amount at this amount under the Unemployment Insurance program. + +values: + 1980-07-01: 16 + +metadata: + unit: currency-USD + period: week + label: Oklahoma UI minimum weekly benefit amount + reference: + - title: 40 O.S. §2-104(A) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50 + - title: 40 O.S. §2-104 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77164 diff --git a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml index aeec506fd45..6db22f2bea2 100644 --- a/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml +++ b/policyengine_us/parameters/gov/states/ok/tax/payroll/unemployment/taxable_wage_base.yaml @@ -1,15 +1,46 @@ -description: Employer-side unemployment insurance taxable wage base for Oklahoma. +description: Oklahoma sets the annual unemployment insurance taxable wage base at this amount under the Unemployment Insurance program. + values: + # 40 O.S. §1-223 sets the taxable wage base as a conditional-factor share of + # the state's average annual wage. The pre-Laws-2025 ladder ran 40 / 42.5 / + # 45 / 47.5 / 50% across factors A-D; conditional factor "D" applies for + # 2022-2025 and factor "A" for 2026. The Laws 2025 ladder (effective + # Nov. 1, 2025) resets these shares, which is why the 2026 base falls below + # the 2025 base rather than rising. Values below are the OESC-published + # taxable wage bases, so no recomputation from the ladder is required. 0000-01-01: 27_000 + 2022-01-01: 24_800 + 2023-01-01: 25_700 + 2024-01-01: 27_000 + 2025-01-01: 28_200 + 2026-01-01: 25_000 metadata: period: year unit: currency-USD label: Oklahoma unemployment taxable wage base reference: - - title: Oklahoma Statutes Title 40 Section 1-223 - href: https://oksenate.gov/sites/default/files/2022-05/os40.pdf#page=32 - - title: Oklahoma Employment Security Commission important numbers for 2026 + - title: 40 O.S. §1-201(48) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23 + - title: 40 O.S. §1-201 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77132 + - title: 40 O.S. §1-223 + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44 + - title: 40 O.S. §1-223 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77157 + - title: 40 O.S. §2-207(B) + href: https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56 + - title: 40 O.S. §2-207 + href: https://www.oscn.net/applications/oscn/DeliverDocument.asp?CiteID=77177 + - title: Oklahoma Unemployment Insurance Tax Rates by Industry, Size, and County (2022 column) + href: https://www.oklahoma.gov/content/dam/ok/en/oesc/documents/labor-market/publications/special-reports/oklahoma-ui-tax-rates-industry-size-county-2021.pdf#page=6 + - title: OESC Important Numbers for 2023 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2023.pdf#page=1 + - title: OESC Important Numbers for 2024 + href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Important-Numbers-2024.pdf#page=1 + - title: Oklahoma OMES 2025 Rates and Maximums for FICA and Unemployment + href: https://oklahoma.gov/content/dam/ok/en/omes/documents/2025RatesMaximumsFICAUnemployment.pdf#page=1 + - title: Oklahoma Employment Security Commission Important Numbers for 2026 href: https://oklahoma.gov/content/dam/ok/en/oesc/images/misc/Employer-Improtant-Numbers-2026.pdf#page=1 - title: Tax Measures of State Unemployment Insurance Tax Systems, CY 2024 href: https://oui.doleta.gov/unemploy/pdf/sigmeasures/sigmeasuitaxsys24.pdf#page=46 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 24928d7e4e9..0e5559ecd6a 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1471,6 +1471,17 @@ programs: variable: ny_drive_clean_rebate parameter_prefix: gov.states.ny.nyserda.drive_clean + - id: ok_ui + name: Oklahoma UI + full_name: Oklahoma Unemployment Insurance + category: Benefits + agency: Oklahoma Employment Security Commission + status: complete + coverage: OK + variable: ok_ui + parameter_prefix: gov.states.ok.oesc.unemployment_insurance + verified_years: "2022-2026" + - id: ut_ui name: Utah UI full_name: Utah Unemployment Insurance diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml new file mode 100644 index 00000000000..c776e6375d4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/integration.yaml @@ -0,0 +1,215 @@ +# Integration tests for Oklahoma Unemployment Insurance (OK UI). +# End-to-end scenarios checking ok_ui together with intermediate variables. +# References: 40 O.S. §§1-202, 1-218, 1-223, 1-231, 2-102, 2-104, 2-105, 2-106, 2-207; +# OESC Claimant Handbook OES-339; OESC Important Numbers 2024/2025/2026. + +- name: Case 1, eligible single claimant with mid-range wages in 2024. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_high_quarter_total_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $11,500 >= $1,500 (ok); total $35,000 >= 1.5 * $11,500 = $17,250 -> passes. + ok_ui_meets_high_quarter_test: true + ok_ui_monetarily_eligible: true + # WBA: floor($11,500 / 23) = $500; within 2024 [$16, $519] -> $500. + ok_ui_weekly_benefit_rate: 500 + # Earnings $0 -> full WBA paid. + ok_ui_weekly_payable: 500 + # 2024 max_weeks = 16 (post-2023); MBA = $500 * 16 = $8,000. + ok_ui_maximum_benefit_amount: 8_000 + # Annual: min($500 * 16, $8,000) = $8,000. + ok_ui: 8_000 + +- name: Case 2, ineligible claimant - wages too low in 2024. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ok_ui_high_quarter_taxable_wages: 5_000 + ok_ui_high_quarter_total_wages: 5_000 + ok_ui_base_period_taxable_wages: 500 + ok_ui_base_period_total_wages: 5_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 12 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $500 < $1,500 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: total $5,000 < $27,000 (2024 wage base) -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 + +- name: Case 3, high earner in 2025 capped at $541 max WBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + ok_ui_high_quarter_taxable_wages: 30_000 + ok_ui_high_quarter_total_wages: 30_000 + ok_ui_base_period_taxable_wages: 30_000 + ok_ui_base_period_total_wages: 90_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $30,000 >= $1,500; total $90,000 >= 1.5 * $30,000 = $45,000 -> passes. + ok_ui_monetarily_eligible: true + # WBA: floor($30,000 / 23) = floor($1,304.35) = $1,304; clamped to $541 (2025 max). + ok_ui_weekly_benefit_rate: 541 + ok_ui_weekly_payable: 541 + # MBA = $541 * 16 = $8,656. + ok_ui_maximum_benefit_amount: 8_656 + # Annual: min($541 * 16, $8,656) = $8,656. + ok_ui: 8_656 + +- name: Case 4, partial benefit week - claimant works part-time. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + # HQW $9,200 -> WBA = $400. + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_high_quarter_total_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 200 + weeks_unemployed: 10 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $9,200 >= $1,500; total $30,000 >= 1.5 * $9,200 = $13,800 -> passes. + ok_ui_monetarily_eligible: true + # WBA: floor($9,200 / 23) = $400; within 2025 [$16, $541] -> $400. + ok_ui_weekly_benefit_rate: 400 + # Earnings offset: max(0, $200 - $100) = $100. + # Partial: max(0, $400 - $100) = $300. + ok_ui_weekly_payable: 300 + # MBA = $400 * 16 = $6,400. + ok_ui_maximum_benefit_amount: 6_400 + # Annual: min($300 * 10, $6,400) = min($3,000, $6,400) = $3,000. + ok_ui: 3_000 + +- name: Case 5, pre-2023 regime - 26-week max_weeks doubles MBA. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + # HQW $6,900 -> WBA = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_high_quarter_total_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 26 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $6,900 >= $1,500; total $20,700 >= 1.5 * $6,900 = $10,350 -> passes. + ok_ui_monetarily_eligible: true + # WBA: floor($6,900 / 23) = $300. + ok_ui_weekly_benefit_rate: 300 + ok_ui_weekly_payable: 300 + # Pre-2023 max_weeks = 26; MBA = $300 * 26 = $7,800. + ok_ui_maximum_benefit_amount: 7_800 + # Annual: min($300 * 26, $7,800) = $7,800. + ok_ui: 7_800 + +- name: Case 6, Test B prong - low taxable but high total wages in 2025. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_500 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $2,000 >= $1,500 (ok); total $28,500 < 1.5 * $20,000 = $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: taxable $2,000 > $0 (ok); total $28,500 >= $28,200 (2025 wage base) -> passes. + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + # WBA: floor($20,000 / 23) = floor($869.57) = $869; clamped to $541 (2025 max). + ok_ui_weekly_benefit_rate: 541 + ok_ui_weekly_payable: 541 + # MBA = $541 * 16 = $8,656. + ok_ui_maximum_benefit_amount: 8_656 + # Annual: min($541 * 16, $8,656) = $8,656. + ok_ui: 8_656 + +- name: Case 7, out-of-state claimant - state gate yields zero benefit. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: TX + output: + people: + person1: + # state_code TX != OK -> defined_for = StateCode.OK gate -> $0. + # Note: intermediate variables (eligibility, WBA, etc.) may still + # compute, but the top-level ok_ui is gated to OK households only. + ok_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml new file mode 100644 index 00000000000..1cb30f16ab1 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui.yaml @@ -0,0 +1,417 @@ +# Tests for Oklahoma UI annual benefit (top-level variable). +# Annual benefit = min(partial_weekly_benefit * weeks_unemployed, MBA). +# Gated by ok_ui_monetarily_eligible (defined_for) and StateCode.OK. +# Reference: 40 O.S. §2-105, §2-106. + +- name: Case 1, eligible claimant - 10 weeks unemployed yields partial of MBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> WBA = $400 (within 2025 [$16, $541] range). + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 10 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $9,200 >= $1,500 AND total $30,000 >= 1.5 * $9,200 = $13,800 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 400 + ok_ui_weekly_payable: 400 + # MBA = $400 * 16 weeks = $6,400. + ok_ui_maximum_benefit_amount: 6_400 + # Annual = min($400 * 10, $6,400) = min($4,000, $6,400) = $4,000. + ok_ui: 4_000 + +- name: Case 2, eligible claimant - weeks exceed max_weeks - capped at MBA. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 20 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 400 + ok_ui_maximum_benefit_amount: 6_400 + # Annual = min($400 * 20, $6,400) = min($8,000, $6,400) = $6,400 (capped at MBA). + ok_ui: 6_400 + +- name: Case 3, monetarily ineligible - zero benefit regardless of weeks. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_000 + ok_ui_base_period_total_wages: 12_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $1,000 < $1,500 -> fails. + # Test B: total $12,000 < $28,200 (2025 wage base) -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 + +# --- End-to-end edge cases redistributed from edge_cases.yaml. --- + +- name: Case 4, all wages zero - both tests fail, no benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_base_period_taxable_wages: 0 + ok_ui_base_period_total_wages: 0 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $0 < $1,500 -> fails. Test B: $0 not > 0 -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0. + ok_ui: 0 + +- name: Case 5, eligible but zero weeks unemployed - annual benefit zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 0 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # WBA: floor($9,200 / 23) = $400. + ok_ui_weekly_benefit_rate: 400 + # MBA = $400 * 16 = $6,400 (defined regardless of weeks worked). + ok_ui_maximum_benefit_amount: 6_400 + # Annual: min($400 * 0, $6,400) = $0. + ok_ui: 0 + +- name: Case 6, non-OK state with otherwise eligible inputs - benefit zeroed. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: TX + output: + people: + person1: + # state_code TX: StateCode.OK gate on upstream variables and the + # ok_ui_monetarily_eligible defined_for cascade returns $0. + ok_ui: 0 + +- name: Case 7, OK state with same inputs as Case 6 - benefit positive. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_500 + ok_ui_base_period_taxable_wages: 11_500 + ok_ui_base_period_total_wages: 35_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # WBA: floor($11,500 / 23) = $500; within 2024 [$16, $519] -> $500. + ok_ui_weekly_benefit_rate: 500 + # MBA = $500 * 16 = $8,000; annual = min($500 * 16, $8,000) = $8,000. + ok_ui: 8_000 + +- name: Case 8, base-period wages share caps annual benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 434 + # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. + ok_ui_maximum_benefit_amount: 6_000 + ok_ui: 6_000 + +# --- Item 18(e): share-cap-derived MBA binds ok_ui even though weeks < 16. --- + +- name: Case 9, share cap binds annual benefit at 14 weeks (< 16). + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 14 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: total $15,000 >= 1.5 * $10,000 = $15,000 -> passes. + ok_ui_monetarily_eligible: true + # WBR: floor($10,000 / 23) = $434. + ok_ui_weekly_benefit_rate: 434 + # MBA = lesser of $434 * 16 = $6,944, statewide $8,656, and + # 40% * $15,000 = $6,000 -> share cap binds at $6,000. + ok_ui_maximum_benefit_amount: 6_000 + # Annual: min($434 * 14 = $6,076, $6,000) = $6,000 -> share-derived MBA + # binds despite only 14 weeks (< 16 max_weeks). + ok_ui: 6_000 + +# --- Item 19: negative base-period wages -> ok_ui $0 (monetary gate fails; the +# max_(..., 0) guard also prevents a negative MBA). --- + +- name: Case 10, negative base-period total wages - no benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: -5_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: total -$5,000 < 1.5 * $9,200 = $13,800 -> fails. + # Test B: total -$5,000 < $28,200 -> fails. + ok_ui_monetarily_eligible: false + # defined_for gate -> $0 (guard also keeps MBA >= 0). + ok_ui: 0 + +# --- C3 (end-to-end): statewide max_amount $9,900 binds ok_ui in 2022 under the +# 26-week regime, where WBR*26 overshoots the cap. --- + +- name: Case 11, 2022 - statewide max_amount caps annual benefit at $9,900. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $476 (2022 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 26 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $20,000 >= $1,500; total $100,000 >= 1.5 * $20,000 = $30,000 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 476 + # MBA = min(min($476 * 26 = $12,376, $9,900 max_amount), 0.4 * $100,000 = $40,000) = $9,900. + ok_ui_maximum_benefit_amount: 9_900 + # Annual: min($476 * 26 = $12,376, $9,900) = $9,900 (statewide max_amount binds). + ok_ui: 9_900 + +# --- C4: end-to-end year coverage for 2023 and 2026 (publishes verified_years +# 2022-2026). --- + +- name: Case 12, 2023 - first 16-week year yields ok_ui $4,800. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300 (within 2023 [$16, $493]). + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_high_quarter_total_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 50_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $6,900 >= $1,500; total $50,000 >= 1.5 * $6,900 = $10,350 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 300 + # MBA = min(min($300 * 16 = $4,800, $7,888 max_amount), 0.4 * $50,000 = $20,000) = $4,800. + ok_ui_maximum_benefit_amount: 4_800 + # Annual: min($300 * 16 = $4,800, $4,800) = $4,800. + ok_ui: 4_800 + +- name: Case 13, 2026 - 16 x max WBA equals max_amount, ok_ui $10,384. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $649 (2026 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 16 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $20,000 >= $1,500; total $100,000 >= 1.5 * $20,000 = $30,000 -> passes. + ok_ui_monetarily_eligible: true + ok_ui_weekly_benefit_rate: 649 + # MBA = min(min($649 * 16 = $10,384, $10,384 max_amount), 0.475 * $100,000 = $47,500) = $10,384. + # ($649 * 16 ties the $10,384 max_amount because max_amount is published as 16 x max WBA.) + ok_ui_maximum_benefit_amount: 10_384 + # Annual: min($649 * 16 = $10,384, $10,384) = $10,384. + ok_ui: 10_384 + +# --- A3/A9 hardening: minimum WBA floor and negative-weeks guard. --- + +- name: Case 14, zero high-quarter taxable wages - WBR floored at statutory $16 minimum. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW taxable $0 -> floor($0 / 23) = $0 -> floored up to the $16 minimum. + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_high_quarter_total_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: 10 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $1,500 >= $1,500; total $30,000 >= 1.5 * $1,000 = $1,500 -> passes. + ok_ui_monetarily_eligible: true + # max(floor($0 / 23), $16) = $16 (statutory minimum floor). + ok_ui_weekly_benefit_rate: 16 + # Annual: min($16 * 10 = $160, MBA $256) = $160. + ok_ui: 160 + +- name: Case 15, negative weeks unemployed - guarded to zero benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_high_quarter_total_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 0 + weeks_unemployed: -5 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_monetarily_eligible: true + # max(-5, 0) = 0 weeks; annual = min($400 * 0, $6,400) = $0 (not negative). + ok_ui: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml new file mode 100644 index 00000000000..60e6db334a3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.yaml @@ -0,0 +1,268 @@ +# Tests for Oklahoma UI maximum benefit amount (40 O.S. §2-106). +# MBA = min(WBA * max_weeks, statewide max benefit amount, base-period wages share cap). +# max_weeks: 26 before 2023-01-01, 16 from 2023-01-01. +# Reference: 40 O.S. §2-106; HB 1933 (2022). + +- name: Case 1, 2024 - WBA $400 yields MBA $6,400 over 16 weeks. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> floor($9,200 / 23) = $400 (within 2024 [$16, $519] range). + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # 2024 max_weeks = 16; MBA = $400 * 16 = $6,400. + ok_ui_maximum_benefit_amount: 6_400 + +- name: Case 2, pre-2023 - WBA $300 yields MBA $7,800 over 26 weeks. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # Pre-2023 max_weeks = 26; MBA = $300 * 26 = $7,800. + ok_ui_maximum_benefit_amount: 7_800 + +- name: Case 3, 2025 - base-period wages share caps marginal Test A claimant. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $10,000 -> floor($10,000 / 23) = $434. + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 434 + # Lesser of $434 * 16 = $6,944, statewide $8,656, and 40% * $15,000 = $6,000. + ok_ui_maximum_benefit_amount: 6_000 + +# --- max_weeks transition cases redistributed from edge_cases.yaml (§2-106). --- + +- name: Case 4, year 2022 - pre-2023 max_weeks of 26. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 2022: min(min($300 * 26 = $7,800, $9,900 max_amount), 0.4 * $20,700 = $8,280) = $7,800. + ok_ui_maximum_benefit_amount: 7_800 + +- name: Case 5, year 2024 - post-2023 max_weeks of 16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # Same HQW as Case 4 to isolate the max_weeks change. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 20_700 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 2024: min(min($300 * 16 = $4,800, $8,304 max_amount), 0.4 * $20,700 = $8,280) = $4,800. + ok_ui_maximum_benefit_amount: 4_800 + +# --- Item 17: 2022 base-period-wages-share (0.4) binding band. Confirms the +# restored 2022=0.4 share can be the binding cap under the 26-week regime. --- + +- name: Case 6, 2022 - 0.4 share binds under the 26-week regime. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 12_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # 26-week product $300 * 26 = $7,800 < $9,900 max_amount, but + # 0.4 * $12,000 = $4,800 share cap is the lesser -> MBA $4,800. + ok_ui_maximum_benefit_amount: 4_800 + +# --- Item 18(c): 2025 statewide max_amount binding vs the share cap. --- + +- name: Case 7, 2025 - statewide max amount binds against a large share cap. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $541 (2025 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 541 + # min(min($541 * 16 = $8,656, $8,656 max_amount), 0.4 * $100,000 = $40,000) = $8,656. + ok_ui_maximum_benefit_amount: 8_656 + +# --- Item 18(d): 2026 share of 0.475 binding. --- + +- name: Case 8, 2026 - 0.475 share cap binds. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $10,000 -> floor($10,000 / 23) = $434 (within 2026 [$16, $649]). + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 10_000 + ok_ui_base_period_total_wages: 12_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 434 + # min(min($434 * 16 = $6,944, $10,384 max_amount), 0.475 * $12,000 = $5,700) = $5,700. + ok_ui_maximum_benefit_amount: 5_700 + +# --- Item 18(f): 2023 16-week seam (first year at 16 weeks, share not binding). --- + +- name: Case 9, 2023 - first year at 16 weeks with non-binding share cap. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $6,900 -> floor($6,900 / 23) = $300. + ok_ui_high_quarter_taxable_wages: 6_900 + ok_ui_base_period_taxable_wages: 6_900 + ok_ui_base_period_total_wages: 50_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 300 + # min(min($300 * 16 = $4,800, $7,888 max_amount), 0.4 * $50,000 = $20,000) = $4,800. + # Contrast Case 4 (2022, 26 weeks) -> $7,800: confirms the 16-week seam. + ok_ui_maximum_benefit_amount: 4_800 + +# --- Item 19: negative base-period wages exercise the max_(..., 0) guard so the +# share cap cannot drive MBA below zero. --- + +- name: Case 10, negative base-period total wages - share cap guarded to zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> WBA $400 (positive), but negative base-period total wages. + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: -5_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Guard: max(-$5,000, 0) = $0; share cap = 0.4 * $0 = $0. + # min(min($400 * 16 = $6,400, $8,656), $0) = $0 (not negative). + ok_ui_maximum_benefit_amount: 0 + +# --- C3: statewide max_amount ($9,900) actually BINDS in 2022 under the 26-week +# regime. Because the 2023-2026 max_amount values are published as 16 x maximum +# WBA, WBR*max_weeks can never exceed max_amount once max_weeks = 16, so +# max_amount is structurally unfalsifiable after 2022. 2022 is the only year the +# suite can demonstrate it binding, since 26 weeks lets WBR*max_weeks overshoot. --- + +- name: Case 11, 2022 - statewide max_amount $9,900 binds under the 26-week regime. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $20,000 -> floor($20,000 / 23) = $869 -> clamped to $476 (2022 max WBA). + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 20_000 + ok_ui_base_period_total_wages: 100_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 476 + # 26-week product $476 * 26 = $12,376 exceeds the $9,900 max_amount, and + # the share cap 0.4 * $100,000 = $40,000 is larger still, so the + # statewide $9,900 max_amount is the binding constraint. + ok_ui_maximum_benefit_amount: 9_900 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml new file mode 100644 index 00000000000..8b5c4e316bc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.yaml @@ -0,0 +1,106 @@ +# Tests for Oklahoma UI monetary eligibility Test B (40 O.S. §2-207(B)). +# Both conditions must be met: +# 1. Base-period taxable wages > 0. +# 2. Total base-period wages >= annual taxable wage base for the claim year. +# 2025 taxable wage base = $28,200 (gov.states.ok.tax.payroll.unemployment.taxable_wage_base). +# Reference: 40 O.S. §2-207(B); 40 O.S. §1-223. + +- name: Case 1, both prongs pass with minimal taxable and total at wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 7_050 + ok_ui_base_period_taxable_wages: 1 + ok_ui_base_period_total_wages: 28_200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1 > $0 (passes prong 1). + # Total $28,200 >= $28,200 (2025 wage base) -> passes prong 2. + ok_ui_meets_alternate_wages_test: true + +- name: Case 2, fails taxable wages prong - zero taxable wages. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 0 + ok_ui_base_period_taxable_wages: 0 + ok_ui_base_period_total_wages: 50_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $0 is not > $0 -> fails prong 1. + ok_ui_meets_alternate_wages_test: false + +- name: Case 3, fails total-wages prong by one dollar below 2025 wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 7_000 + ok_ui_base_period_taxable_wages: 1_000 + ok_ui_base_period_total_wages: 28_199 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1,000 > 0 (passes prong 1). + # Total $28,199 < $28,200 (2025 wage base) -> fails prong 2. + ok_ui_meets_alternate_wages_test: false + +# --- Item 18(a): 2026 taxable wage base = $25,000; Test B step at that boundary. +# Test A cannot rescue (total < 1.5 x HQW), isolating the Test B threshold. --- + +- name: Case 4, 2026 total wages exactly at $25,000 wage base - passes Test B. + period: 2026 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 25_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $2,000 > $0 AND total $25,000 >= $25,000 (2026 wage base) -> passes (>=). + ok_ui_meets_alternate_wages_test: true + +- name: Case 5, 2026 total wages one dollar below $25,000 wage base - fails Test B. + period: 2026 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 24_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Total $24,999 < $25,000 (2026 wage base) -> fails prong 2. + ok_ui_meets_alternate_wages_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml new file mode 100644 index 00000000000..5a2b5197af5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.yaml @@ -0,0 +1,116 @@ +# Tests for Oklahoma UI monetary eligibility Test A (40 O.S. §2-207(A)). +# Both conditions must be met: +# 1. Base-period taxable wages >= $1,500. +# 2. Total base-period wages >= 1.5 x high-quarter total wages. +# Reference: 40 O.S. §2-207(A). + +- name: Case 1, both prongs pass with margin. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1,500 >= $1,500 (passes prong 1). + # Total $15,000 >= 1.5 * $10,000 = $15,000 (passes prong 2). + ok_ui_meets_high_quarter_test: true + +- name: Case 2, fails taxable wages floor by one dollar. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_499 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $1,499 < $1,500 -> fails prong 1. + ok_ui_meets_high_quarter_test: false + +- name: Case 3, fails 1.5x high-quarter multiplier by one dollar. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 14_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable $2,000 >= $1,500 (passes prong 1). + # Total $14,999 < 1.5 * $10,000 = $15,000 -> fails prong 2. + ok_ui_meets_high_quarter_test: false + +- name: Case 4, boundary - taxable exactly at floor and total exactly at 1.5 x HQW. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Taxable exactly $1,500 (passes prong 1; >= test). + # Total exactly $15,000 = 1.5 * $10,000 (passes prong 2; >= test). + ok_ui_meets_high_quarter_test: true + +# --- C1 regression guard: prong 2 must multiply TOTAL high-quarter wages, not +# the taxable-capped figure (§2-207(A)(2) uses bare "wages"). This case is in +# the divergence zone where high-quarter taxable wages are capped BELOW total +# high-quarter wages, so the old (taxable) reference and the new (total) +# reference give OPPOSITE eligibility results. It fails if C1 is reverted. --- + +- name: Case 5, divergence zone - taxable HQW capped below total HQW flips prong 2. + period: 2024 + input: + people: + person1: + age: 35 + # Total high-quarter wages $20,000; taxable high-quarter wages capped + # at $10,000 (below total). Old code multiplied the $10,000 taxable + # figure; correct code multiplies the $20,000 total figure. + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 25_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Prong 1: taxable $2,000 >= $1,500 -> passes. + # Prong 2 (NEW, total): $25,000 < 1.5 * $20,000 = $30,000 -> FAILS. + # Prong 2 (OLD, taxable): $25,000 >= 1.5 * $10,000 = $15,000 -> would PASS. + # Correct result is false; a revert to taxable wages would return true. + ok_ui_meets_high_quarter_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml new file mode 100644 index 00000000000..e012bf9ede1 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.yaml @@ -0,0 +1,220 @@ +# Tests for Oklahoma UI overall monetary eligibility (40 O.S. §2-207). +# Eligible if Test A OR Test B passes: +# Test A (§2-207(A)): taxable >= $1,500 AND total >= 1.5 x HQW. +# Test B (§2-207(B)): taxable > 0 AND total >= annual taxable wage base. +# Reference: 40 O.S. §2-207. + +- name: Case 1, Test A passes alone (Test B fails on total below wage base). + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 20_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $5,000 >= $1,500 AND $20,000 >= 1.5 * $10,000 = $15,000 -> passes. + # Test B: total $20,000 < $27,000 (2024 wage base) -> fails. + # Overall: A OR B = true. + ok_ui_meets_high_quarter_test: true + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: true + +- name: Case 2, Test B passes alone (Test A fails on 1.5x prong). + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $2,000 >= $1,500 (ok); total $28,500 < 1.5 * $20,000 = $30,000 -> fails. + # Test B: taxable $2,000 > $0 (ok); total $28,500 >= $28,200 (2025 wage base) -> passes. + # Overall: A OR B = true. + ok_ui_meets_high_quarter_test: false + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + +- name: Case 3, both tests fail. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 1_000 + ok_ui_base_period_total_wages: 12_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: taxable $1,000 < $1,500 -> fails. + # Test B: total $12,000 < $28,200 (2025 wage base) -> fails. + # Overall: A OR B = false. + ok_ui_meets_high_quarter_test: false + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +# --- Boundary cases redistributed from edge_cases.yaml (Test A/Test B seams) --- +# These assert the two component tests plus the overall aggregator, all of which +# this file covers. + +- name: Case 1, Test A taxable wages exactly at $1,500 threshold. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_high_quarter_total_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 1_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A taxable prong: $1,500 >= $1,500 -> passes (>= operator). + # Test A multiplier prong: $1,500 >= 1.5 * $1,000 = $1,500 -> passes (>=). + # Test A: both prongs pass. + ok_ui_meets_high_quarter_test: true + # Test B: total $1,500 < $27,000 (2024 wage base) -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: true + +- name: Case 2, Test A taxable wages one dollar below threshold. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 1_000 + ok_ui_high_quarter_total_wages: 1_000 + ok_ui_base_period_taxable_wages: 1_499 + ok_ui_base_period_total_wages: 1_500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A taxable prong: $1,499 < $1,500 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: $1,499 > 0 but total $1,500 < $27,000 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +- name: Case 3, Test A total wages exactly at 1.5x HQW boundary. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 15_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A multiplier prong: $15,000 >= 1.5 * $10,000 = $15,000 -> passes (>= operator). + # Test A taxable prong: $5,000 >= $1,500 -> passes. + ok_ui_meets_high_quarter_test: true + ok_ui_monetarily_eligible: true + +- name: Case 4, Test A total wages one dollar below 1.5x HQW boundary. + period: 2024 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + ok_ui_high_quarter_total_wages: 10_000 + ok_ui_base_period_taxable_wages: 5_000 + ok_ui_base_period_total_wages: 14_999 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A multiplier prong: $14,999 < 1.5 * $10,000 = $15,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: total $14,999 < $27,000 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false + +- name: Case 5, Test B total wages exactly at 2025 taxable wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $28,200 < 1.5 * $20,000 = $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: taxable $2,000 > $0 AND $28,200 >= $28,200 (2025 wage base) -> passes (>=). + ok_ui_meets_alternate_wages_test: true + ok_ui_monetarily_eligible: true + +- name: Case 6, Test B total wages one dollar below 2025 taxable wage base. + period: 2025 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 20_000 + ok_ui_high_quarter_total_wages: 20_000 + ok_ui_base_period_taxable_wages: 2_000 + ok_ui_base_period_total_wages: 28_199 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # Test A: $28,199 < $30,000 -> fails. + ok_ui_meets_high_quarter_test: false + # Test B: $28,199 < $28,200 -> fails. + ok_ui_meets_alternate_wages_test: false + ok_ui_monetarily_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml new file mode 100644 index 00000000000..ba477007cdc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.yaml @@ -0,0 +1,284 @@ +# Tests for Oklahoma UI weekly benefit amount (40 O.S. §2-104(A), §2-102). +# Formula: WBA = clamp(floor(HQW_taxable / 23), [min=$16, max=annual_cap]). +# Annual max WBA: 2022=$476, 2023=$493, 2024=$519, 2025=$541, 2026=$649. +# Min WBA $16 has been the statutory floor since 1980. +# Reference: 40 O.S. §2-104(A), §2-102; OESC Important Numbers. + +- name: Case 1, handbook example - HQW $14,000 in 2024 clamped to max $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 14_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($14,000 / 23) = floor($608.69) = $608. + # $608 > $519 (2024 max) -> clamped to $519. + # Matches OES-339 page 4 worked example. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 2, low HQW lifted to statutory minimum $16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 200 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($200 / 23) = floor($8.70) = $8. + # $8 < $16 -> lifted to $16 minimum. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 3, mid HQW within 2025 range. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($10,000 / 23) = floor($434.78) = $434. + # $16 <= $434 <= $541 (2025 max) -> WBA = $434. + ok_ui_weekly_benefit_rate: 434 + +- name: Case 4, mid HQW within 2026 range. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 10_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($10,000 / 23) = $434. + # $16 <= $434 <= $649 (2026 max) -> WBA = $434. + ok_ui_weekly_benefit_rate: 434 + +- name: Case 5, high HQW clamped to 2026 maximum. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ok_ui_high_quarter_taxable_wages: 20_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($20,000 / 23) = floor($869.57) = $869. + # $869 > $649 (2026 max) -> clamped to $649. + ok_ui_weekly_benefit_rate: 649 + +- name: Case 6, high HQW clamped to 2022 maximum. + period: 2022 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ok_ui_high_quarter_taxable_wages: 20_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($20,000 / 23) = floor($869.57) = $869. + # $869 > $476 (2022 max) -> clamped to $476. + ok_ui_weekly_benefit_rate: 476 + +# --- WBA clamp boundaries redistributed from edge_cases.yaml (min $16 floor, +# annual max ceiling; §2-104(A)). --- + +- name: Case 7, WBA below minimum - HQW $367 clamped up to $16 floor. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 367 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 2_250 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($367 / 23) = floor($15.957) = $15 -> below $16 minimum -> clamped to $16. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 8, WBA exactly at minimum - HQW $368 yields $16. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 368 + ok_ui_base_period_taxable_wages: 1_500 + ok_ui_base_period_total_wages: 2_250 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($368 / 23) = floor($16.0) = $16 -> exactly at minimum. + ok_ui_weekly_benefit_rate: 16 + +- name: Case 9, WBA exactly at 2024 maximum - HQW $11,937 yields $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_937 + ok_ui_base_period_taxable_wages: 11_937 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # 519 * 23 = $11,937 exactly; floor($11,937 / 23) = $519. + # 2024 max is $519 -> no clamp needed, exactly at boundary. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 10, WBA still at 2024 max - HQW $11,938 yields $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_938 + ok_ui_base_period_taxable_wages: 11_938 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($11,938 / 23) = floor($519.043) = $519 -> at 2024 max, no clamp. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 11, WBA clamped down at 2024 max - HQW $11,960 yields $520 raw, clamped to $519. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 11_960 + ok_ui_base_period_taxable_wages: 11_960 + ok_ui_base_period_total_wages: 30_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # 520 * 23 = $11,960 exactly; floor($11,960 / 23) = $520. + # $520 > $519 (2024 max) -> clamped down to $519. + ok_ui_weekly_benefit_rate: 519 + +- name: Case 12, very high HQW clamped to 2025 max $541. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 100_000 + ok_ui_base_period_taxable_wages: 100_000 + ok_ui_base_period_total_wages: 300_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($100,000 / 23) = floor($4,347.83) = $4,347 -> far above $541 (2025 max) -> clamped to $541. + ok_ui_weekly_benefit_rate: 541 + +# --- WBA annual-max clamp seams (item 18b) and negative-HQW floor (item 19). --- + +- name: Case 13, very high HQW clamped to 2023 max $493. + period: 2023 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 100_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor($100,000 / 23) = $4,347 -> above $493 (2023 max) -> clamped to $493. + ok_ui_weekly_benefit_rate: 493 + +- name: Case 14, negative HQW lifted to $16 statutory floor. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: -1_000 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + # floor(-$1,000 / 23) = floor(-$43.48) = -$44; max(-$44, $16) = $16; + # min($16, $541) = $16. The $16 min_amount floor absorbs negative HQW. + ok_ui_weekly_benefit_rate: 16 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml new file mode 100644 index 00000000000..1075f0c5ea7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.yaml @@ -0,0 +1,189 @@ +# Tests for Oklahoma UI partial weekly benefit (40 O.S. §2-105). +# Formula: weekly_payable = max(0, WBA - max(0, weekly_earnings - $100)). +# The first $100 of weekly earnings is disregarded; every dollar above $100 +# reduces WBA dollar-for-dollar; result is floored at $0. +# Reference: 40 O.S. §2-105. + +- name: Case 1, weekly earnings below disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # HQW $9,200 -> floor($9,200 / 23) = $400 WBA (within 2025 range). + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 50 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $50 < $100 disregard -> earnings_offset = max(0, 50 - 100) = $0. + # Payable = max(0, $400 - $0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 2, weekly earnings exactly at disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 100 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $100 = $100 disregard -> earnings_offset = max(0, 100 - 100) = $0. + # Payable = max(0, $400 - $0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 3, weekly earnings above disregard - dollar-for-dollar reduction. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 150 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $150 > $100 -> earnings_offset = $150 - $100 = $50. + # Payable = max(0, $400 - $50) = $350. + ok_ui_weekly_payable: 350 + +- name: Case 4, weekly earnings so high payable would be negative - floored at zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 600 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # Earnings $600 > $100 -> earnings_offset = $600 - $100 = $500. + # Raw payable = $400 - $500 = -$100; max(0, -$100) = $0. + ok_ui_weekly_payable: 0 + +# --- Disregard boundaries redistributed from edge_cases.yaml (§2-105). All use +# 2025 HQW $9,200 -> WBA $400. --- + +- name: Case 5, weekly earnings exactly at $100 disregard - full WBA paid. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 100 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $100 - $100) = $0; payable = max(0, $400 - 0) = $400. + ok_ui_weekly_payable: 400 + +- name: Case 6, weekly earnings one dollar above disregard - WBA reduced by $1. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 101 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $101 - $100) = $1; payable = max(0, $400 - $1) = $399. + ok_ui_weekly_payable: 399 + +- name: Case 7, weekly earnings exactly at WBA + disregard - payable zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 500 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $500 - $100) = $400; payable = max(0, $400 - $400) = $0. + ok_ui_weekly_payable: 0 + +- name: Case 8, weekly earnings above WBA + disregard - payable floored at zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + ok_ui_high_quarter_taxable_wages: 9_200 + ok_ui_base_period_taxable_wages: 9_200 + ok_ui_base_period_total_wages: 30_000 + ok_ui_gross_weekly_earnings: 501 + households: + household: + members: [person1] + state_code: OK + output: + people: + person1: + ok_ui_weekly_benefit_rate: 400 + # earnings_reduction = max(0, $501 - $100) = $401; raw payable = $400 - $401 = -$1 -> max(0, -1) = $0. + ok_ui_weekly_payable: 0 diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py new file mode 100644 index 00000000000..3251f6492f8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui.py @@ -0,0 +1,50 @@ +from policyengine_us.model_api import * + + +class ok_ui(Variable): + """Annual Oklahoma Unemployment Insurance benefit. Implements the + monetary eligibility tests (§ 2-207), weekly benefit rate (§ 2-104), + partial benefit subtraction (§ 2-105), and benefit duration cap + (§ 2-106 / § 1-231). + + Not modeled: § 1-202.1 alternative and extended base periods; § 2-104(B) + max-WBA percentage derivation by fund condition (only the resulting + maximum dollar amount is parameterized); § 2-106(2) statutory + %-of-average-annual-wage benefit-year cap (OESC-published proxy used + instead); § 1-217(B)(2) 15% wage/hour-loss unemployment prong; § 1-231 + 16-to-26-week claim-volume duration escalation above the 16-week floor; + § 2-107 portion-of-a-week proration; § 2-108 approved training waiver; + § 2-202 / § 2-205.1 able-available-seeking-work; § 2-206 one-week waiting + period; § 2-208 alien-status rules; § 2-109 10x WBA requalification; all + § 2-404 through § 2-422 disqualifications. + """ + + value_type = float + entity = Person + label = "Oklahoma unemployment insurance" + documentation = ( + "Annual Oklahoma Unemployment Insurance benefit. Not modeled: the " + "§ 2-106(2) statutory percentage-of-average-annual-wage benefit-year " + "cap (an OESC-published proxy is used); the § 1-231 claim-volume " + "duration escalation above the 16-week floor (up to 20 or 26 weeks); " + "the § 1-217(B)(2) 15% wage/hour-loss partial-unemployment prong; the " + "§ 2-206 one-week waiting period; the § 1-202.1 alternative and " + "extended base periods; and the § 2-404 through " + "§ 2-422 nonmonetary disqualifications, waiting week, and " + "able-available-seeking-work requirements." + ) + unit = USD + definition_period = YEAR + defined_for = "ok_ui_monetarily_eligible" + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", + ) + + def formula(person, period, parameters): + weekly_payable = person("ok_ui_weekly_payable", period) + maximum_benefit_amount = person("ok_ui_maximum_benefit_amount", period) + # Guard against negative weeks so the benefit cannot go below zero. + weeks_unemployed = max_(person("weeks_unemployed", period), 0) + annual_benefit = weekly_payable * weeks_unemployed + return min_(annual_benefit, maximum_benefit_amount) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py new file mode 100644 index 00000000000..8a2a77bbb8a --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_taxable_wages.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ok_ui_base_period_taxable_wages(Variable): + """Sum of taxable wages across all four quarters of the base period, each + capped at the Oklahoma taxable wage base. Per 40 O.S. § 1-201(48) the + taxable-wage cap applies per CALENDAR YEAR, not per quarter, per 40 O.S. + § 1-223 and § 1-201(4). Used in the monetary-eligibility tests in + § 2-207(A) and § 2-207(B). PolicyEngine cannot derive quarterly wages from + annual data, so this is a direct input rather than a computed value; + populate via test fixtures or reform. Defaults to zero, so it is inert in + microsimulation until supplied. + """ + + value_type = float + entity = Person + label = "Oklahoma UI base period taxable wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + # 40 O.S. §1-201(48) — Taxable wages / base period definitions + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23", + # 40 O.S. §1-223 — Taxable wage base + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=44", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py new file mode 100644 index 00000000000..99750a0b6f7 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_base_period_total_wages.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class ok_ui_base_period_total_wages(Variable): + """Sum of total (uncapped) gross wages across all four quarters of the + base period, per 40 O.S. § 1-218 (wages definition), § 1-201(4) (base + period definition), and § 2-207 (where "total wages" is used). Used in + the monetary-eligibility tests in § 2-207(A) and § 2-207(B). PolicyEngine + cannot derive quarterly wages from annual data, so this is a direct input + rather than a computed value; populate via test fixtures or reform. + Defaults to zero, so it is inert in microsimulation until supplied. + """ + + value_type = float + entity = Person + label = "Oklahoma UI base period total wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + # 40 O.S. §1-201(4) — Base period definition + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=20", + # 40 O.S. §1-218 — Wages definition + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=42", + # 40 O.S. §2-207 — Total wages used in monetary-eligibility tests + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py new file mode 100644 index 00000000000..bc6095b88c4 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_gross_weekly_earnings.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ok_ui_gross_weekly_earnings(Variable): + """Gross earnings during a week of partial unemployment, used to compute + the partial weekly benefit reduction per 40 O.S. § 2-105. Stored at the + annual definition period but holds an average WEEKLY figure; populate via + test fixtures or reform. Defaults to zero, so it is inert in + microsimulation until supplied. + """ + + value_type = float + entity = Person + label = "Oklahoma UI average weekly earnings" + documentation = ( + "Stored at the annual definition period but holds an average WEEKLY " + "figure, populated via test fixtures or reform." + ) + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py new file mode 100644 index 00000000000..aec03181519 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_taxable_wages.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ok_ui_high_quarter_taxable_wages(Variable): + """Wages paid in the claimant's highest base-period quarter, capped at the + Oklahoma taxable wage base. Per 40 O.S. § 1-201(48) the taxable-wage cap + applies per CALENDAR YEAR, not per quarter; test fixtures should supply + the already-capped high-quarter figure. Used as the input to the weekly + benefit amount formula per 40 O.S. § 2-104(A). PolicyEngine cannot derive + quarterly wages from annual data, so this is a direct input rather than a + computed value; populate via test fixtures or reform. Defaults to zero, so + it is inert in microsimulation until supplied. + """ + + value_type = float + entity = Person + label = "Oklahoma UI high quarter taxable wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + # 40 O.S. §1-201(48) — per-calendar-year taxable-wage cap + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=23", + # 40 O.S. §2-104(A) — weekly benefit amount input + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py new file mode 100644 index 00000000000..035488db66c --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_high_quarter_total_wages.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class ok_ui_high_quarter_total_wages(Variable): + """Total (uncapped) gross wages paid in the claimant's highest base-period + quarter, per 40 O.S. § 2-207(A)(2), which applies the 1.5x multiplier to + the claimant's total high-quarter wages rather than the taxable-capped + figure. PolicyEngine cannot derive quarterly wages from annual data, so + this is a direct input rather than a computed value; populate via test + fixtures or reform. Defaults to zero, so it is inert in microsimulation + until supplied. + """ + + value_type = float + entity = Person + label = "Oklahoma UI high quarter total wages" + unit = USD + definition_period = YEAR + default_value = 0 + defined_for = StateCode.OK + reference = ( + # 40 O.S. §2-207(A)(2) — total high-quarter wages used in the 1.5x test + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py new file mode 100644 index 00000000000..4b6a6ca45bc --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_maximum_benefit_amount.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ok_ui_maximum_benefit_amount(Variable): + value_type = float + entity = Person + label = "Oklahoma UI maximum benefit amount" + unit = USD + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=52", + ) + + def formula(person, period, parameters): + # § 2-106 caps benefits in a benefit year at the lesser of the + # duration cap, the statewide maximum benefit amount, and the + # applicable share of base-period wages. + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.mba + weekly_benefit_rate = person("ok_ui_weekly_benefit_rate", period) + # Guard against negative base-period wages so the share-of-wages cap + # cannot drive the maximum benefit amount below zero. + base_period_total_wages = max_( + person("ok_ui_base_period_total_wages", period), 0 + ) + return min_( + min_(weekly_benefit_rate * p.max_weeks, p.max_amount), + base_period_total_wages * p.base_period_wages_share, + ) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py new file mode 100644 index 00000000000..c4e30b7ce6f --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_alternate_wages_test.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ok_ui_meets_alternate_wages_test(Variable): + value_type = bool + entity = Person + label = "Meets the Oklahoma UI alternate monetary eligibility test" + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", + ) + + def formula(person, period, parameters): + base_period_taxable_wages = person("ok_ui_base_period_taxable_wages", period) + base_period_total_wages = person("ok_ui_base_period_total_wages", period) + taxable_wage_base = parameters( + period + ).gov.states.ok.tax.payroll.unemployment.taxable_wage_base + has_taxable_wages = base_period_taxable_wages > 0 + meets_wage_base = base_period_total_wages >= taxable_wage_base + return has_taxable_wages & meets_wage_base diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py new file mode 100644 index 00000000000..bab4e2aeff8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_meets_high_quarter_test.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class ok_ui_meets_high_quarter_test(Variable): + """Oklahoma UI high-quarter monetary eligibility test (§ 2-207(A)). + + Prong 1 (§ 2-207(A)(1)) requires base-period taxable wages of at least the + statutory minimum. Prong 2 (§ 2-207(A)(2)) requires total base-period + wages of at least 1.5x the claimant's total high-quarter wages; the statute + uses total (uncapped) wages, not the taxable-capped figure. + """ + + value_type = bool + entity = Person + label = "Meets the Oklahoma UI high-quarter monetary eligibility test" + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.eligibility + base_period_taxable_wages = person("ok_ui_base_period_taxable_wages", period) + base_period_total_wages = person("ok_ui_base_period_total_wages", period) + high_quarter_total_wages = person("ok_ui_high_quarter_total_wages", period) + meets_taxable_minimum = base_period_taxable_wages >= p.min_taxable_wages + meets_multiplier = base_period_total_wages >= ( + p.min_total_wages_multiplier * high_quarter_total_wages + ) + return meets_taxable_minimum & meets_multiplier diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py new file mode 100644 index 00000000000..0e931a3566f --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_monetarily_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ok_ui_monetarily_eligible(Variable): + value_type = bool + entity = Person + label = "Monetarily eligible for Oklahoma Unemployment Insurance" + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=56", + ) + + def formula(person, period, parameters): + high_quarter = person("ok_ui_meets_high_quarter_test", period) + alternate = person("ok_ui_meets_alternate_wages_test", period) + return high_quarter | alternate diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py new file mode 100644 index 00000000000..f15b4cbdb48 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_benefit_rate.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ok_ui_weekly_benefit_rate(Variable): + value_type = float + entity = Person + label = "Oklahoma UI weekly benefit rate" + unit = USD + definition_period = YEAR + defined_for = StateCode.OK + reference = ( + # 40 O.S. §2-104 — weekly benefit amount + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=50", + # 40 O.S. §2-102 — rounding down to the next lower whole dollar + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=49", + ) + + def formula(person, period, parameters): + # § 2-104(A): WBA = floor(high quarter taxable wages / divisor), + # clamped to the statutory minimum and the annual maximum set under + # § 2-104(B). § 2-102 specifies that fractional results are rounded + # down to the next lower whole dollar. + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.wba + high_quarter_taxable_wages = person("ok_ui_high_quarter_taxable_wages", period) + raw_weekly_benefit_rate = np.floor(high_quarter_taxable_wages / p.divisor) + return min_(max_(raw_weekly_benefit_rate, p.min_amount), p.max_amount) diff --git a/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py new file mode 100644 index 00000000000..43d76589d8e --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/oesc/unemployment_insurance/ok_ui_weekly_payable.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ok_ui_weekly_payable(Variable): + value_type = float + entity = Person + label = "Oklahoma UI weekly payable amount" + unit = USD + definition_period = YEAR + defined_for = "ok_ui_monetarily_eligible" + reference = ( + "https://www.oklegislature.gov/OK_Statutes/CompleteTitles/os40.pdf#page=51", + ) + + def formula(person, period, parameters): + # § 2-105: weekly payable amount = WBR minus the portion of weekly + # earnings that exceeds the statutory earnings disregard, floored at + # zero. + p = parameters(period).gov.states.ok.oesc.unemployment_insurance.partial + weekly_benefit_rate = person("ok_ui_weekly_benefit_rate", period) + gross_weekly_earnings = person("ok_ui_gross_weekly_earnings", period) + earnings_reduction = max_(gross_weekly_earnings - p.disregard, 0) + return max_(weekly_benefit_rate - earnings_reduction, 0)