diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..291ae3f0256 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - Added Oklahoma TANF (Temporary Assistance for Needy Families) program diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/benefit/minimum_benefit.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/benefit/minimum_benefit.yaml new file mode 100644 index 00000000000..cf6c8658eea --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/benefit/minimum_benefit.yaml @@ -0,0 +1,12 @@ +description: Oklahoma provides this amount as the minimum benefit under the Temporary Assistance for Needy Families program. + +values: + 2021-01-01: 10 + +metadata: + unit: currency-USD + period: month + label: Oklahoma TANF minimum benefit + reference: + - title: OAC 340:10-3-59(c) - Minimum Payment + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-59 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/benefit/payment_standard.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/benefit/payment_standard.yaml new file mode 100644 index 00000000000..c1cafedda4e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/benefit/payment_standard.yaml @@ -0,0 +1,55 @@ +description: Oklahoma provides this amount as the payment standard under the Temporary Assistance for Needy Families program. + +metadata: + amount_unit: currency-USD + period: month + label: Oklahoma TANF payment standard + type: single_amount + threshold_unit: person + reference: + - title: OAC 340:10-3-59(a) - Payment Standard + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-59 + - title: OKDHS Appendix C-1 Schedule IX-A + href: https://www.okdhslive.org/popups/IncomeStandardsPopup.aspx + +# NOTE: Oklahoma has two payment standard schedules: + # - "Adult only or adults and children" - IMPLEMENTED + # - "Children only" - NOT IMPLEMENTED + # This parameter uses the adult/adults+children schedule from Schedule IX-A. +brackets: + - threshold: + 2021-01-01: 1 + amount: + 2021-01-01: 180 + - threshold: + 2021-01-01: 2 + amount: + 2021-01-01: 225 + - threshold: + 2021-01-01: 3 + amount: + 2021-01-01: 292 + - threshold: + 2021-01-01: 4 + amount: + 2021-01-01: 361 + - threshold: + 2021-01-01: 5 + amount: + 2021-01-01: 422 + - threshold: + 2021-01-01: 6 + amount: + 2021-01-01: 483 + - threshold: + 2021-01-01: 7 + amount: + 2021-01-01: 544 + - threshold: + 2021-01-01: 8 + amount: + 2021-01-01: 598 + - threshold: + 2021-01-01: 9 + amount: + 2021-01-01: 650 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/deductions/dependent_care.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/deductions/dependent_care.yaml new file mode 100644 index 00000000000..93551a03f7e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/deductions/dependent_care.yaml @@ -0,0 +1,21 @@ +description: Oklahoma deducts this amount of dependent care expenses under the Temporary Assistance for Needy Families program. + +metadata: + period: month + label: Oklahoma TANF dependent care deduction + type: single_amount + threshold_unit: year + amount_unit: currency-USD + reference: + - title: OAC 340:10-3-33(b) - Dependent Care Expense Deduction + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-33 + +brackets: + - threshold: + 2021-01-01: 0 + amount: + 2021-01-01: 200 + - threshold: + 2021-01-01: 2 + amount: + 2021-01-01: 175 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/deductions/work_expense.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/deductions/work_expense.yaml new file mode 100644 index 00000000000..acf59534bd0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/deductions/work_expense.yaml @@ -0,0 +1,21 @@ +description: Oklahoma deducts this amount of work-related expenses under the Temporary Assistance for Needy Families program. + +metadata: + period: month + label: Oklahoma TANF work expense deduction + type: single_amount + threshold_unit: hour + amount_unit: currency-USD + reference: + - title: OAC 340:10-3-33(1) - Work-Related Expense Deduction + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-33 + +brackets: + - threshold: + 2021-01-01: 0 + amount: + 2021-01-01: 120 + - threshold: + 2021-01-01: 30 + amount: + 2021-01-01: 240 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/disregard/cap.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/disregard/cap.yaml new file mode 100644 index 00000000000..4ca791cbe3f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/disregard/cap.yaml @@ -0,0 +1,12 @@ +description: Oklahoma limits gross earned income to this amount for the earned income disregard under the Temporary Assistance for Needy Families program. + +values: + 2010-07-01: 2_064 + +metadata: + unit: currency-USD + period: month + label: Oklahoma TANF earned income disregard cap + reference: + - title: OAC 340:10-3-31.1(a) - Earned Income Disregard Eligibility + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-31.1 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/disregard/rate.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/disregard/rate.yaml new file mode 100644 index 00000000000..4afc50c8c06 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/disregard/rate.yaml @@ -0,0 +1,12 @@ +description: Oklahoma excludes this share of earnings from countable income under the Temporary Assistance for Needy Families program. + +values: + 2021-01-01: 0.5 + +metadata: + unit: /1 + period: month + label: Oklahoma TANF earned income disregard rate + reference: + - title: OAC 340:10-3-31.1(2) - 50% Earned Income Disregard + href: https://oklahoma.gov/okdhs/library/policy/current/oac-340/chapter-10/subchapter-3/parts-3/earned-income-disregard.html diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/gross_income_limit_rate.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/gross_income_limit_rate.yaml new file mode 100644 index 00000000000..b1269c62870 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/gross_income_limit_rate.yaml @@ -0,0 +1,14 @@ +description: Oklahoma limits gross income to this share of the State Standard of Need under the Temporary Assistance for Needy Families program. + +values: + 2021-01-01: 1.85 + +metadata: + unit: /1 + period: month + label: Oklahoma TANF gross income limit rate + reference: + - title: OAC 340:10-3-27(a) - Gross Income Limit + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-27 + - title: OKDHS Appendix C-1 Schedule IX-A + href: https://www.okdhslive.org/popups/IncomeStandardsPopup.aspx diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/need_standard.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/need_standard.yaml new file mode 100644 index 00000000000..1d5113e9b96 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/income/need_standard.yaml @@ -0,0 +1,55 @@ +description: Oklahoma sets this amount as the State Standard of Need under the Temporary Assistance for Needy Families program. + +metadata: + amount_unit: currency-USD + period: month + label: Oklahoma TANF State Standard of Need + type: single_amount + threshold_unit: person + reference: + - title: OAC 340:10-3-27 - State Standard of Need + href: https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-27 + - title: OKDHS Appendix C-1 Schedule IX-A + href: https://www.okdhslive.org/popups/IncomeStandardsPopup.aspx + +# NOTE: Oklahoma has two need standard schedules: + # - "Adult only or adults and children" - IMPLEMENTED + # - "Children only" - NOT IMPLEMENTED + # This parameter uses the adult/adults+children schedule from Schedule IX-A. +brackets: + - threshold: + 2021-01-01: 1 + amount: + 2021-01-01: 398 + - threshold: + 2021-01-01: 2 + amount: + 2021-01-01: 499 + - threshold: + 2021-01-01: 3 + amount: + 2021-01-01: 645 + - threshold: + 2021-01-01: 4 + amount: + 2021-01-01: 798 + - threshold: + 2021-01-01: 5 + amount: + 2021-01-01: 933 + - threshold: + 2021-01-01: 6 + amount: + 2021-01-01: 1068 + - threshold: + 2021-01-01: 7 + amount: + 2021-01-01: 1203 + - threshold: + 2021-01-01: 8 + amount: + 2021-01-01: 1323 + - threshold: + 2021-01-01: 9 + amount: + 2021-01-01: 1436 diff --git a/policyengine_us/parameters/gov/states/ok/dhs/tanf/resources/limit.yaml b/policyengine_us/parameters/gov/states/ok/dhs/tanf/resources/limit.yaml new file mode 100644 index 00000000000..bbdff9d481e --- /dev/null +++ b/policyengine_us/parameters/gov/states/ok/dhs/tanf/resources/limit.yaml @@ -0,0 +1,12 @@ +description: Oklahoma limits resources to this amount under the Temporary Assistance for Needy Families program. + +values: + 2021-01-01: 1_000 + +metadata: + unit: currency-USD + period: month + label: Oklahoma TANF resource limit + reference: + - title: OAC 340:10-3-5(a) - Maximum Countable Reserve + href: https://www.law.cornell.edu/regulations/oklahoma/Okla-Admin-Code-SS-340-10-3-5 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/integration.yaml new file mode 100644 index 00000000000..b9271dc4959 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/integration.yaml @@ -0,0 +1,292 @@ +# Integration tests for Oklahoma TANF - full pipeline testing +# Tests realistic family scenarios with complete eligibility and benefit calculations +# OAC 340:10: https://www.law.cornell.edu/regulations/oklahoma/title-340/chapter-10 +# Note: Work expense based on hours: $120 (<30 hrs), $240 (30+ hrs) +# Note: Minimum benefit is $10 - benefits below this are not issued + +- name: Scenario 1 - Single parent with 2 children, no income - full benefit + # Family of 3, no income, receives full payment standard + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 30 + employment_income_before_lsr: 0 + person2: + age: 5 + is_in_k12_school: true + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: OK + output: + # Family size: 3 + # Gross earned income: $0 + # Countable income: $0 + # Payment standard (family of 3): $292 + # Benefit: $292 - $0 = $292 (>= $10 minimum) + is_person_demographic_tanf_eligible: [false, true, true] + ok_tanf_eligible: true + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 0 + ok_tanf: 292 + +- name: Scenario 2 - Family of 3 with $700 monthly earnings (part-time) + # Standard earned income calculation with $120 work expense (<30 hrs) + # Benefits below $10 are not issued + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 28 + employment_income_before_lsr: 8_400 # $700/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + person2: + age: 4 + is_in_k12_school: true + person3: + age: 2 + spm_units: + spm_unit: + members: [person1, person2, person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: OK + output: + # Family size: 3 + # Monthly gross earned income: $700 + # Work expense deduction: $120 (<30 hrs) + # After work expense: $700 - $120 = $580 + # 50% disregard: $580 * 0.50 = $290 + # Countable earned income: $290 + # Payment standard (family of 3): $292 + # Calculated benefit: $292 - $290 = $2 + # But $2 < $10 minimum, so no payment issued + is_person_demographic_tanf_eligible: [false, true, true] + ok_tanf_eligible: true + ok_tanf_countable_income: 290 + ok_tanf_payment_standard: 292 + ok_tanf: 0 + +- name: Scenario 3 - Single parent with one child, $500 monthly earnings (part-time) + # Family of 2, uses $120 work expense (<30 hrs) + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 35 + employment_income_before_lsr: 6_000 # $500/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + person2: + age: 10 + is_in_k12_school: true + spm_units: + spm_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OK + output: + # Family size: 2 + # Monthly gross earned income: $500 + # Work expense deduction: $120 (<30 hrs) + # After work expense: $500 - $120 = $380 + # 50% disregard: $380 * 0.50 = $190 + # Countable earned income: $190 + # Payment standard (family of 2): $225 + # Benefit: $225 - $190 = $35 (>= $10 minimum) + is_person_demographic_tanf_eligible: [false, true] + ok_tanf_eligible: true + ok_tanf_countable_income: 190 + ok_tanf_payment_standard: 225 + ok_tanf: 35 + +- name: Scenario 4 - Family of 4 ineligible due to high gross income + # Gross income exceeds 185% of State Standard of Need + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 18_000 # $1,500/month - exceeds $1,476 limit + weekly_hours_worked_before_lsr: 40 + person2: + age: 38 + person3: + age: 12 + is_in_k12_school: true + person4: + age: 8 + is_in_k12_school: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: OK + output: + # Family size: 4 + # Monthly gross income: $1,500 + # Max gross income limit (185% of $798): $1,476 + # Income exceeds limit, ineligible + is_person_demographic_tanf_eligible: [false, false, true, true] + ok_tanf_income_eligible: false + ok_tanf_eligible: false + ok_tanf: 0 + +- name: Scenario 5 - Family just below income threshold, eligible but no benefit + # Gross income just under 185% limit, but countable exceeds payment standard + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 32 + employment_income_before_lsr: 14_280 # $1,190/month - just under $1,193 limit + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + person2: + age: 7 + is_in_k12_school: true + person3: + age: 5 + is_in_k12_school: true + spm_units: + spm_unit: + members: [person1, person2, person3] + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: OK + output: + # Family size: 3 + # Monthly gross income: $1,190 + # Max gross income limit (185% of $645): $1,193 + # Just under limit, eligible + # Work expense: $120 (<30 hrs) + # After work expense: $1,190 - $120 = $1,070 + # 50% disregard: $1,070 * 0.50 = $535 + # Countable earned income: $535 + # Payment standard: $292 + # Benefit: max($292 - $535, 0) = $0 (eligible but no payment) + is_person_demographic_tanf_eligible: [false, true, true] + ok_tanf_income_eligible: true + ok_tanf_eligible: true + ok_tanf_countable_income: 535 + ok_tanf: 0 + +- name: Scenario 6 - Combined earned and unearned income (part-time) + # Tests handling of both income types + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 29 + employment_income_before_lsr: 4_800 # $400/month earned + child_support_received: 1_200 # $100/month unearned + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + person2: + age: 4 + is_in_k12_school: true + spm_units: + spm_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: OK + output: + # Family size: 2 + # Monthly gross earned: $400, unearned: $100 + # Total gross: $500 (under $923 limit) + # Work expense: $120 (<30 hrs) + # After work expense: $400 - $120 = $280 + # 50% disregard: $280 * 0.50 = $140 + # Countable earned: $140 + # Countable income: $140 + $100 = $240 + # Payment standard (family of 2): $225 + # Benefit: max($225 - $240, 0) = $0 (eligible but no payment) + is_person_demographic_tanf_eligible: [false, true] + ok_tanf_eligible: true + ok_tanf_countable_income: 240 + ok_tanf_payment_standard: 225 + ok_tanf: 0 + +- name: Scenario 7 - Large family of 5, partial benefit (part-time) + # Tests larger family size payment standard + period: 2024-01 + absolute_error_margin: 0.5 + input: + people: + person1: + age: 38 + employment_income_before_lsr: 9_600 # $800/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + person2: + age: 36 + person3: + age: 14 + is_in_k12_school: true + person4: + age: 10 + is_in_k12_school: true + person5: + age: 5 + is_in_k12_school: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5] + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5] + households: + household: + members: [person1, person2, person3, person4, person5] + state_code: OK + output: + # Family size: 5 + # Monthly gross income: $800 + # Max gross income limit (185% of $933): $1,726 + # Under limit, eligible + # Work expense: $120 (<30 hrs) + # After work expense: $800 - $120 = $680 + # 50% disregard: $680 * 0.50 = $340 + # Countable earned: $340 + # Payment standard (family of 5): $422 + # Benefit: $422 - $340 = $82 (>= $10 minimum) + is_person_demographic_tanf_eligible: [false, false, true, true, true] + ok_tanf_income_eligible: true + ok_tanf_eligible: true + ok_tanf_countable_income: 340 + ok_tanf_payment_standard: 422 + ok_tanf: 82 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf.yaml new file mode 100644 index 00000000000..7a4834c749e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf.yaml @@ -0,0 +1,136 @@ +# Unit tests for Oklahoma TANF benefit calculation +# OAC 340:10-3-59: Benefit = Payment Standard - Countable Income +# Minimum benefit: $10 (if calculated > 0 but < $10, no payment issues) +# Maximum benefit: $650 (adults and/or children) or $720 (children only) +# https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-59 + +- name: Eligible - payment standard exceeds income + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 100 + ok_tanf_eligible: true + state_code: OK + output: + # 292 - 100 = 192 + ok_tanf: 192 + +- name: Documentation example - family of 3 with $700 earnings + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 230 + ok_tanf_eligible: true + state_code: OK + output: + # Payment standard $292 - Countable income $230 = $62 + ok_tanf: 62 + +- name: Eligible - payment equals income, zero benefit + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 292 + ok_tanf_eligible: true + state_code: OK + output: + # 292 - 292 = 0 + ok_tanf: 0 + +- name: Eligible - income exceeds payment standard + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 400 + ok_tanf_eligible: true + state_code: OK + output: + # 292 - 400 = max(0, -108) = 0 + ok_tanf: 0 + +- name: Ineligible - no benefit regardless of income + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 0 + ok_tanf_eligible: false + state_code: OK + output: + ok_tanf: 0 + +- name: Full payment standard - no income + period: 2024-01 + input: + ok_tanf_payment_standard: 361 + ok_tanf_countable_income: 0 + ok_tanf_eligible: true + state_code: OK + output: + # Full payment for family of 4 + ok_tanf: 361 + +- name: Benefit below minimum ($10) results in zero + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 285 + ok_tanf_eligible: true + state_code: OK + output: + # 292 - 285 = 7, which is less than $10 minimum, so no payment + ok_tanf: 0 + +- name: Benefit exactly at minimum threshold + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 282 + ok_tanf_eligible: true + state_code: OK + output: + # 292 - 282 = 10, meets minimum, benefit paid + ok_tanf: 10 + +- name: Benefit just above minimum threshold + period: 2024-01 + input: + ok_tanf_payment_standard: 292 + ok_tanf_countable_income: 280 + ok_tanf_eligible: true + state_code: OK + output: + # 292 - 280 = 12, above minimum + ok_tanf: 12 + +- name: Maximum benefit - family of 9+ (adults and children) + period: 2024-01 + input: + ok_tanf_payment_standard: 650 + ok_tanf_countable_income: 0 + ok_tanf_eligible: true + state_code: OK + output: + # Maximum benefit for adults and/or children cases + ok_tanf: 650 + +- name: Single person household benefit + period: 2024-01 + input: + ok_tanf_payment_standard: 180 + ok_tanf_countable_income: 50 + ok_tanf_eligible: true + state_code: OK + output: + # 180 - 50 = 130 + ok_tanf: 130 + +- name: Large family with some income + period: 2024-01 + input: + ok_tanf_payment_standard: 544 + ok_tanf_countable_income: 300 + ok_tanf_eligible: true + state_code: OK + output: + # Family of 7: 544 - 300 = 244 + ok_tanf: 244 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_countable_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_countable_earned_income.yaml new file mode 100644 index 00000000000..f9cd9b25839 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_countable_earned_income.yaml @@ -0,0 +1,203 @@ +# Unit tests for Oklahoma TANF countable earned income +# OAC 340:10-3-33: Work expense based on hours ($120 for <30 hrs, $240 for 30+ hrs) +# OAC 340:10-3-31.1: 50% earned income disregard (if gross <= $2,064) +# https://oklahoma.gov/okdhs/library/policy/current/oac-340/chapter-10/subchapter-3/parts-3/earned-income-disregard.html + +- name: No earned income + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 0 + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_countable_earned_income: 0 + +- name: Part-time worker (under 30 hrs) - $120 work expense + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 6_000 # $500/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Monthly gross earned: $500 + # Work expense: $120 (<30 hrs/week) + # After work expense: $500 - $120 = $380 + # 50% disregard: $380 * 0.50 = $190 + # Countable earned: $190 + ok_tanf_countable_earned_income: 190 + +- name: Full-time worker (30+ hrs) - $240 work expense + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 6_000 # $500/month + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Monthly gross earned: $500 + # Work expense: $240 (30+ hrs/week) + # After work expense: $500 - $240 = $260 + # 50% disregard: $260 * 0.50 = $130 + # Countable earned: $130 + ok_tanf_countable_earned_income: 130 + +- name: Earned income below work expense + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 1_200 # $100/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Monthly gross earned: $100 + # Work expense: $120 + # After work expense: max($100 - $120, 0) = $0 + # Countable earned: $0 + ok_tanf_countable_earned_income: 0 + +- name: Higher earned income - full time + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 12_000 # $1,000/month + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Monthly gross earned: $1,000 + # Work expense: $240 (30+ hrs/week) + # After work expense: $1,000 - $240 = $760 + # 50% disregard: $760 * 0.50 = $380 + # Countable earned: $380 + ok_tanf_countable_earned_income: 380 + +- name: Earned income exceeds EID cap - no 50% disregard + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 36_000 # $3,000/month (exceeds $2,064 cap) + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Monthly gross earned: $3,000 (> $2,064 EID cap) + # Per OAC 340:10-3-31.1: EID only applies if gross earned <= $2,064 + # Work expense: $240 + # After work expense: $3,000 - $240 = $2,760 + # 50% disregard: NOT APPLIED (over cap) + # Countable earned: $2,760 + ok_tanf_countable_earned_income: 2_760 + +- name: Earned income at EID cap - 50% disregard applies + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 24_768 # $2,064/month (at cap) + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Monthly gross earned: $2,064 (= $2,064 EID cap) + # Per OAC 340:10-3-31.1: EID applies at exactly $2,064 + # Work expense: $240 + # After work expense: $2,064 - $240 = $1,824 + # 50% disregard: $1,824 * 0.50 = $912 + # Countable earned: $912 + ok_tanf_countable_earned_income: 912 + +- name: Two workers - person-level work expense deduction + period: 2024-01 + input: + people: + adult1: + age: 30 + employment_income_before_lsr: 6_000 # $500/month + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 + adult2: + age: 28 + employment_income_before_lsr: 1_200 # $100/month (< work expense) + weekly_hours_worked_before_lsr: 10 # <30 hrs = $120 + child: + age: 5 + spm_units: + spm_unit: + members: [adult1, adult2, child] + households: + household: + members: [adult1, adult2, child] + state_code: OK + output: + # Adult1: $500 - $240 = $260 after work expense + # Adult2: max($100 - $120, 0) = $0 after work expense + # Total after work expense: $260 + # 50% disregard: $260 * 0.50 = $130 + # Countable earned: $130 + ok_tanf_countable_earned_income: 130 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_countable_income.yaml new file mode 100644 index 00000000000..adfbda5a533 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_countable_income.yaml @@ -0,0 +1,162 @@ +# Unit tests for Oklahoma TANF countable income calculation +# OAC 340:10-3-31.1, OAC 340:10-3-33 +# Work expense: $120 (<30 hrs/week), $240 (30+ hrs/week) +# Formula: Countable Income = (Gross Earned - Work Expense) * 0.50 + Gross Unearned +# https://oklahoma.gov/okdhs/library/policy/current/oac-340/chapter-10/subchapter-3/parts-3/earned-income-disregard.html + +- name: No income results in zero countable income + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 0 + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + ok_tanf_countable_income: 0 + +- name: Part-time earnings - $500 monthly + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 6_000 # $500/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # Gross earned: $500 + # After work expense: $500 - $120 = $380 + # 50% disregard: $380 * 0.50 = $190 + ok_tanf_countable_income: 190 + +- name: Full-time earnings - $500 monthly + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 6_000 # $500/month + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # Gross earned: $500 + # After work expense: $500 - $240 = $260 + # 50% disregard: $260 * 0.50 = $130 + ok_tanf_countable_income: 130 + +- name: Earnings below work expense deduction + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 1_200 # $100/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # Gross earned: $100 + # After work expense: max($100 - $120, 0) = $0 + # 50% disregard: $0 * 0.50 = $0 + ok_tanf_countable_income: 0 + +- name: Unearned income only (counted at full amount) + period: 2024-01 + input: + people: + person1: + pension_income: 3_600 # $300/month + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # No earned income, unearned at full: $300 + ok_tanf_countable_income: 300 + +- name: Combined earned and unearned income - full time + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 7_200 # $600/month + pension_income: 2_400 # $200/month + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # Gross earned: $600 + # After work expense: $600 - $240 = $360 + # 50% disregard: $360 * 0.50 = $180 + # Add unearned: $180 + $200 = $380 + ok_tanf_countable_income: 380 + +- name: Higher earnings - $1000 monthly full time + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 12_000 # $1,000/month + pension_income: 1_200 # $100/month + weekly_hours_worked_before_lsr: 40 # 30+ hrs = $240 deduction + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # Gross earned: $1,000 + # After work expense: $1,000 - $240 = $760 + # 50% disregard: $760 * 0.50 = $380 + # Add unearned: $380 + $100 = $480 + ok_tanf_countable_income: 480 + +- name: Edge case - earnings exactly equal to work expense + period: 2024-01 + input: + people: + person1: + employment_income_before_lsr: 1_440 # $120/month + weekly_hours_worked_before_lsr: 20 # <30 hrs = $120 deduction + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: OK + output: + # Gross earned: $120 + # After work expense: $120 - $120 = $0 + # 50% disregard: $0 * 0.50 = $0 + ok_tanf_countable_income: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_dependent_care_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_dependent_care_deduction.yaml new file mode 100644 index 00000000000..39228cf7943 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_dependent_care_deduction.yaml @@ -0,0 +1,109 @@ +# Unit tests for Oklahoma TANF dependent care deduction +# OAC 340:10-3-33(b): $200 for under age 2, $175 for age 2+ +# https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-33 +# NOTE: childcare_expenses is annual, so multiply monthly amount by 12 + +- name: No childcare expenses - no deduction + period: 2024-01 + input: + people: + child: + age: 1 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [child] + childcare_expenses: 0 + households: + household: + members: [child] + state_code: OK + output: + ok_tanf_dependent_care_deduction: 0 + +- name: Child under 2 - max $200 deduction + period: 2024-01 + input: + people: + child: + age: 1 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [child] + childcare_expenses: 300 * 12 # $300/month annual + households: + household: + members: [child] + state_code: OK + output: + # Max deduction for child under 2 is $200/month + # Expenses ($300/mo) > max ($200), so deduction = $200 + ok_tanf_dependent_care_deduction: 200 + +- name: Child age 2+ - max $175 deduction + period: 2024-01 + input: + people: + child: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [child] + childcare_expenses: 300 * 12 # $300/month annual + households: + household: + members: [child] + state_code: OK + output: + # Max deduction for child age 2+ is $175/month + # Expenses ($300/mo) > max ($175), so deduction = $175 + ok_tanf_dependent_care_deduction: 175 + +- name: Expenses less than max - deduct actual expenses + period: 2024-01 + input: + people: + child: + age: 1 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [child] + childcare_expenses: 150 * 12 # $150/month annual + households: + household: + members: [child] + state_code: OK + output: + # Max deduction for child under 2 is $200/month + # Expenses ($150/mo) < max ($200), so deduction = $150 + ok_tanf_dependent_care_deduction: 150 + +- name: Two children - combined deduction + period: 2024-01 + input: + people: + adult: + age: 30 + child1: + age: 1 + is_tax_unit_dependent: true + child2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [adult, child1, child2] + childcare_expenses: 500 * 12 # $500/month annual + households: + household: + members: [adult, child1, child2] + state_code: OK + output: + # Child1 (under 2): max $200 + # Child2 (age 2+): max $175 + # Total max: $375 + # Expenses ($500/mo) > max ($375), so deduction = $375 + ok_tanf_dependent_care_deduction: 375 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_eligible.yaml new file mode 100644 index 00000000000..bc07745145c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_eligible.yaml @@ -0,0 +1,119 @@ +# Unit tests for Oklahoma TANF eligibility determination +# OAC 340:10-3: Eligibility requires eligible child, income under limit, resources under $1,000 +# https://www.law.cornell.edu/regulations/oklahoma/title-340/chapter-10 + +- name: Eligible - has eligible child, income below limit, resources below limit + period: 2024-01 + input: + people: + adult: + is_person_demographic_tanf_eligible: false + child: + is_person_demographic_tanf_eligible: true + spm_units: + spm_unit: + members: [adult, child] + ok_tanf_income_eligible: true + ok_tanf_resources_eligible: true + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_eligible: true + +- name: Ineligible - no eligible child + period: 2024-01 + input: + people: + adult: + is_person_demographic_tanf_eligible: false + spm_units: + spm_unit: + members: [adult] + ok_tanf_income_eligible: true + ok_tanf_resources_eligible: true + households: + household: + members: [adult] + state_code: OK + output: + ok_tanf_eligible: false + +- name: Ineligible - income exceeds limit + period: 2024-01 + input: + people: + adult: + is_person_demographic_tanf_eligible: false + child: + is_person_demographic_tanf_eligible: true + spm_units: + spm_unit: + members: [adult, child] + ok_tanf_income_eligible: false + ok_tanf_resources_eligible: true + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_eligible: false + +- name: Ineligible - resources exceed limit + period: 2024-01 + input: + people: + adult: + is_person_demographic_tanf_eligible: false + child: + is_person_demographic_tanf_eligible: true + spm_units: + spm_unit: + members: [adult, child] + ok_tanf_income_eligible: true + ok_tanf_resources_eligible: false + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_eligible: false + +- name: Ineligible - fails all requirements + period: 2024-01 + input: + people: + adult: + is_person_demographic_tanf_eligible: false + spm_units: + spm_unit: + members: [adult] + ok_tanf_income_eligible: false + ok_tanf_resources_eligible: false + households: + household: + members: [adult] + state_code: OK + output: + ok_tanf_eligible: false + +- name: Ineligible - eligible child but both income and resources exceed limits + period: 2024-01 + input: + people: + adult: + is_person_demographic_tanf_eligible: false + child: + is_person_demographic_tanf_eligible: true + spm_units: + spm_unit: + members: [adult, child] + ok_tanf_income_eligible: false + ok_tanf_resources_eligible: false + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_income_eligible.yaml new file mode 100644 index 00000000000..6bf5ec0a510 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_income_eligible.yaml @@ -0,0 +1,97 @@ +# Unit tests for Oklahoma TANF income eligibility +# OAC 340:10-3-27: Gross income limit = 185% of State Standard of Need +# https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-27 + +- name: Family of 3 - income below 185% limit + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 12_000 # $1,000/month + child1: + age: 5 + child2: + age: 3 + spm_units: + spm_unit: + members: [adult, child1, child2] + households: + household: + members: [adult, child1, child2] + state_code: OK + output: + # Family size: 3 + # Need standard: $645 + # Gross income limit: $645 * 1.85 = $1,193 + # Monthly gross income: $1,000 < $1,193 + ok_tanf_income_eligible: true + +- name: Family of 3 - income above 185% limit + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 15_600 # $1,300/month + child1: + age: 5 + child2: + age: 3 + spm_units: + spm_unit: + members: [adult, child1, child2] + households: + household: + members: [adult, child1, child2] + state_code: OK + output: + # Family size: 3 + # Need standard: $645 + # Gross income limit: $645 * 1.85 = $1,193 + # Monthly gross income: $1,300 > $1,193 + ok_tanf_income_eligible: false + +- name: Family of 2 - at exact limit + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 11_076 # $923/month (exact limit) + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + households: + household: + members: [adult, child] + state_code: OK + output: + # Family size: 2 + # Need standard: $499 + # Gross income limit: $499 * 1.85 = $923 + # Monthly gross income: $923 = $923 + ok_tanf_income_eligible: true + +- name: Family of 1 - no income + period: 2024-01 + input: + people: + adult: + age: 30 + employment_income_before_lsr: 0 + spm_units: + spm_unit: + members: [adult] + households: + household: + members: [adult] + state_code: OK + output: + # Family size: 1 + # Need standard: $398 + # Gross income limit: $398 * 1.85 = $736 + # Monthly gross income: $0 < $736 + ok_tanf_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_payment_standard.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_payment_standard.yaml new file mode 100644 index 00000000000..c742ef28397 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_payment_standard.yaml @@ -0,0 +1,84 @@ +# Unit tests for Oklahoma TANF payment standard by family size +# OAC 340:10-3-59: Payment standards from Schedule IX +# Using "Adults and/or Children" rates (default for most cases) +# https://www.okdhslive.org/popups/IncomeStandardsPopup.aspx + +- name: Family size 1 + period: 2024-01 + input: + spm_unit_size: 1 + state_code: OK + output: + ok_tanf_payment_standard: 180 + +- name: Family size 2 + period: 2024-01 + input: + spm_unit_size: 2 + state_code: OK + output: + ok_tanf_payment_standard: 225 + +- name: Family size 3 + period: 2024-01 + input: + spm_unit_size: 3 + state_code: OK + output: + ok_tanf_payment_standard: 292 + +- name: Family size 4 + period: 2024-01 + input: + spm_unit_size: 4 + state_code: OK + output: + ok_tanf_payment_standard: 361 + +- name: Family size 5 + period: 2024-01 + input: + spm_unit_size: 5 + state_code: OK + output: + ok_tanf_payment_standard: 422 + +- name: Family size 6 + period: 2024-01 + input: + spm_unit_size: 6 + state_code: OK + output: + ok_tanf_payment_standard: 483 + +- name: Family size 7 + period: 2024-01 + input: + spm_unit_size: 7 + state_code: OK + output: + ok_tanf_payment_standard: 544 + +- name: Family size 8 + period: 2024-01 + input: + spm_unit_size: 8 + state_code: OK + output: + ok_tanf_payment_standard: 598 + +- name: Family size 9 - maximum + period: 2024-01 + input: + spm_unit_size: 9 + state_code: OK + output: + ok_tanf_payment_standard: 650 + +- name: Family size 10 - caps at 9+ rate + period: 2024-01 + input: + spm_unit_size: 10 + state_code: OK + output: + ok_tanf_payment_standard: 650 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml new file mode 100644 index 00000000000..79590f09a5e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/dhs/tanf/ok_tanf_resources_eligible.yaml @@ -0,0 +1,79 @@ +# Unit tests for Oklahoma TANF resources eligibility +# OAC 340:10-3-5: Maximum countable reserve is $1,000 +# https://www.law.cornell.edu/regulations/oklahoma/Okla-Admin-Code-SS-340-10-3-5 + +- name: Resources below $1,000 limit + period: 2024-01 + input: + people: + adult: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + spm_unit_assets: 500 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_resources_eligible: true + +- name: Resources at exact $1,000 limit + period: 2024-01 + input: + people: + adult: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + spm_unit_assets: 1_000 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_resources_eligible: true + +- name: Resources above $1,000 limit + period: 2024-01 + input: + people: + adult: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + spm_unit_assets: 1_500 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_resources_eligible: false + +- name: No resources + period: 2024-01 + input: + people: + adult: + age: 30 + child: + age: 5 + spm_units: + spm_unit: + members: [adult, child] + spm_unit_assets: 0 + households: + household: + members: [adult, child] + state_code: OK + output: + ok_tanf_resources_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/credits/eitc/ok_eitc.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/credits/eitc/ok_eitc.yaml index 77dac1dd8d9..21b24cb41a1 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/credits/eitc/ok_eitc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/credits/eitc/ok_eitc.yaml @@ -36,7 +36,7 @@ spm_unit: members: [person1, person2] snap: 0 - tanf: 0 + ok_tanf: 0 households: household: members: [person1, person2] diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_eligible.py new file mode 100644 index 00000000000..0cbd78b4c6d --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_eligible.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ok_tanf_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Oklahoma TANF" + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/title-340/chapter-10" + ) + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + # Use federal demographic eligibility (minor child or pregnant) + demographic_eligible = spm_unit("is_demographic_tanf_eligible", period) + # Per OAC 340:10-15: Must be US citizen or qualified alien + immigration_eligible = ( + add(spm_unit, period, ["is_citizen_or_legal_immigrant"]) > 0 + ) + income_eligible = spm_unit("ok_tanf_income_eligible", period) + resources_eligible = spm_unit("ok_tanf_resources_eligible", period) + + return ( + demographic_eligible + & immigration_eligible + & income_eligible + & resources_eligible + ) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_income_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_income_eligible.py new file mode 100644 index 00000000000..2ad0011020f --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_income_eligible.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ok_tanf_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Oklahoma TANF income eligible" + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-27" + ) + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs.tanf.income + + # Per OAC 340:10-3-27: Gross income limit = 185% of State Standard of Need + unit_size = spm_unit("spm_unit_size", period) + need_standard = p.need_standard.calc(unit_size) + gross_income_limit = need_standard * p.gross_income_limit_rate + + # Gross income test uses gross income (before disregards) + gross_income = add( + spm_unit, + period, + ["tanf_gross_earned_income", "tanf_gross_unearned_income"], + ) + + return gross_income <= gross_income_limit diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py new file mode 100644 index 00000000000..f2aa6009b63 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/eligibility/ok_tanf_resources_eligible.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ok_tanf_resources_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Oklahoma TANF resources eligible" + definition_period = MONTH + reference = "https://www.law.cornell.edu/regulations/oklahoma/Okla-Admin-Code-SS-340-10-3-5" + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs.tanf.resources + # Per OAC 340:10-3-5: Maximum countable reserve is $1,000 + resources = spm_unit("spm_unit_assets", period.this_year) + return resources <= p.limit diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_countable_earned_income.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_countable_earned_income.py new file mode 100644 index 00000000000..ad613cae57d --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_countable_earned_income.py @@ -0,0 +1,36 @@ +from policyengine_us.model_api import * + + +class ok_tanf_countable_earned_income(Variable): + value_type = float + entity = SPMUnit + label = "Oklahoma TANF countable earned income" + unit = USD + definition_period = MONTH + reference = "https://oklahoma.gov/okdhs/library/policy/current/oac-340/chapter-10/subchapter-3/parts-3/earned-income-disregard.html" + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + # NOTE: OAC 340:10-3-31.1 also provides a 3-month EID period where + # 100% of earned income is excluded. This applies once per rolling + # 12-month period when a recipient obtains employment. This 100% + # disregard is not currently implemented. + + p = parameters(period).gov.states.ok.dhs.tanf.income + + # Sum person-level earned income after work expense + # Per OAC 340:10-3-33(a): $120 for <30 hrs/week, $240 for 30+ hrs/week + after_work_expense = add( + spm_unit, + period, + ["ok_tanf_earned_income_after_work_expense_person"], + ) + + # Apply 50% EID if eligible (gross earned <= $2,064) + eid_eligible = spm_unit("ok_tanf_eid_eligible", period) + disregard_amount = where( + eid_eligible, + after_work_expense * p.disregard.rate, + 0, + ) + return max_(after_work_expense - disregard_amount, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_countable_income.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_countable_income.py new file mode 100644 index 00000000000..e77981399a5 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_countable_income.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ok_tanf_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Oklahoma TANF countable income" + unit = USD + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-59" + ) + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + # Per OAC 340:10-3-39: Unearned income counted at gross amount + income = add( + spm_unit, + period, + ["ok_tanf_countable_earned_income", "tanf_gross_unearned_income"], + ) + # Per OAC 340:10-3-33(b): Deduct dependent care expenses + dependent_care_deduction = spm_unit( + "ok_tanf_dependent_care_deduction", period + ) + return max_(income - dependent_care_deduction, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_dependent_care_deduction.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_dependent_care_deduction.py new file mode 100644 index 00000000000..338e9684448 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_dependent_care_deduction.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class ok_tanf_dependent_care_deduction(Variable): + value_type = float + entity = SPMUnit + label = "Oklahoma TANF dependent care deduction" + unit = USD + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-33" + ) + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + # Per OAC 340:10-3-33(b): Dependent care expenses may be deducted + # up to $200/month for dependents under age 2 + # up to $175/month for dependents age 2 and older + p = parameters(period).gov.states.ok.dhs.tanf.income + person = spm_unit.members + + # Get dependent status and age in years + dependent = person("is_tax_unit_dependent", period) + age = person("monthly_age", period) # Returns true age in years + + # Calculate maximum deduction per dependent based on age + max_deduction_per_dependent = p.deductions.dependent_care.calc(age) + total_max_deduction = spm_unit.sum( + max_deduction_per_dependent * dependent + ) + + # Cap at actual childcare expenses + childcare_expenses = spm_unit("childcare_expenses", period) + + return min_(childcare_expenses, total_max_deduction) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_earned_income_after_work_expense_person.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_earned_income_after_work_expense_person.py new file mode 100644 index 00000000000..4b64cba1012 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_earned_income_after_work_expense_person.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ok_tanf_earned_income_after_work_expense_person(Variable): + value_type = float + entity = Person + label = "Oklahoma TANF earned income after work expense per person" + unit = USD + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-33" + ) + defined_for = StateCode.OK + + def formula(person, period, parameters): + gross_earned = person("tanf_gross_earned_income", period) + work_expense = person("ok_tanf_work_expense_person", period) + return max_(gross_earned - work_expense, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_eid_eligible.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_eid_eligible.py new file mode 100644 index 00000000000..0bc68457168 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_eid_eligible.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ok_tanf_eid_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Oklahoma TANF earned income disregard" + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-31.1" + ) + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + # Per OAC 340:10-3-31.1(a): EID applies when gross earned income <= $2,064 + gross_earned = add(spm_unit, period, ["tanf_gross_earned_income"]) + p = parameters(period).gov.states.ok.dhs.tanf.income + return gross_earned <= p.disregard.cap diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_work_expense_person.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_work_expense_person.py new file mode 100644 index 00000000000..e9c7c32e513 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/income/ok_tanf_work_expense_person.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ok_tanf_work_expense_person(Variable): + value_type = float + entity = Person + label = "Oklahoma TANF work expense deduction per person" + unit = USD + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-33" + ) + defined_for = StateCode.OK + + def formula(person, period, parameters): + # Per OAC 340:10-3-33(a): Work expense based on weekly hours + # $120 for <30 hours/week, $240 for 30+ hours/week + p = parameters(period).gov.states.ok.dhs.tanf.income + weekly_hours = person("weekly_hours_worked", period.this_year) + + # Only apply work expense if person has earnings + has_earnings = person("tanf_gross_earned_income", period) > 0 + + work_expense = p.deductions.work_expense.calc(weekly_hours) + return where(has_earnings, work_expense, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/ok_tanf.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/ok_tanf.py new file mode 100644 index 00000000000..d5cf675d156 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/ok_tanf.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ok_tanf(Variable): + value_type = float + entity = SPMUnit + label = "Oklahoma TANF" + unit = USD + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-59" + ) + defined_for = "ok_tanf_eligible" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs.tanf + + payment_standard = spm_unit("ok_tanf_payment_standard", period) + countable_income = spm_unit("ok_tanf_countable_income", period) + + # Per OAC 340:10-3-59: Benefit = Payment Standard - Countable Income + benefit = max_(payment_standard - countable_income, 0) + + # Per OAC 340:10-3-59: Minimum benefit is $10; if less, no payment issues + return where(benefit >= p.benefit.minimum_benefit, benefit, 0) diff --git a/policyengine_us/variables/gov/states/ok/dhs/tanf/ok_tanf_payment_standard.py b/policyengine_us/variables/gov/states/ok/dhs/tanf/ok_tanf_payment_standard.py new file mode 100644 index 00000000000..3af51d045f1 --- /dev/null +++ b/policyengine_us/variables/gov/states/ok/dhs/tanf/ok_tanf_payment_standard.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ok_tanf_payment_standard(Variable): + value_type = float + entity = SPMUnit + label = "Oklahoma TANF payment standard" + unit = USD + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/regulations/oklahoma/OAC-340-10-3-59" + ) + defined_for = StateCode.OK + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ok.dhs.tanf.benefit + unit_size = spm_unit("spm_unit_size", period) + return p.payment_standard.calc(unit_size) diff --git a/policyengine_us/variables/gov/states/ok/tanf/ok_tanf.py b/policyengine_us/variables/gov/states/ok/tanf/ok_tanf.py deleted file mode 100644 index c11eb6947b1..00000000000 --- a/policyengine_us/variables/gov/states/ok/tanf/ok_tanf.py +++ /dev/null @@ -1,14 +0,0 @@ -from policyengine_us.model_api import * - - -class ok_tanf(Variable): - value_type = float - entity = SPMUnit - label = "Oklahoma TANF" - unit = USD - definition_period = YEAR - defined_for = StateCode.OK - - """ - def formula(spm_unit, period, parameters): - """ diff --git a/uv.lock b/uv.lock index eba54261b90..9e764e578ee 100644 --- a/uv.lock +++ b/uv.lock @@ -1534,7 +1534,7 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.471.0" +version = "1.474.0" source = { editable = "." } dependencies = [ { name = "microdf-python" },