diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..0fdce15941e 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - South Carolina TANF (Temporary Assistance for Needy Families) program diff --git a/policyengine_us/parameters/gov/states/sc/tanf/README.md b/policyengine_us/parameters/gov/states/sc/tanf/README.md new file mode 100644 index 00000000000..eb8aeb3f951 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/README.md @@ -0,0 +1 @@ +# Temporary Assistance for Needy Families diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/amount.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/amount.yaml new file mode 100644 index 00000000000..ae71efe23d7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/amount.yaml @@ -0,0 +1,11 @@ +description: South Carolina excludes this amount from earned income after the initial disregard period under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: 100 + +metadata: + unit: currency-USD + period: month + label: South Carolina TANF earned income disregard amount + reference: + - title: SC DSS TANF Policy Manual Section 8.12 + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=130 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/percentage/months.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/percentage/months.yaml new file mode 100644 index 00000000000..d80916562a5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/percentage/months.yaml @@ -0,0 +1,11 @@ +description: South Carolina applies the earned income percentage disregard for this number of months under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: 4 + +metadata: + unit: month + period: month + label: South Carolina TANF earned income percentage disregard applicable months + reference: + - title: SC DSS TANF Policy Manual Section 8.12 + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=130 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/percentage/rate.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/percentage/rate.yaml new file mode 100644 index 00000000000..97cf9e46956 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/disregard/percentage/rate.yaml @@ -0,0 +1,11 @@ +description: South Carolina excludes this share of earnings from countable income under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: 0.5 + +metadata: + unit: /1 + period: month + label: South Carolina TANF earned income disregard percentage + reference: + - title: SC DSS TANF Policy Manual Section 8.12 + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=130 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/earned/earned.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/earned.yaml new file mode 100644 index 00000000000..a4b18e1b009 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/earned/earned.yaml @@ -0,0 +1,12 @@ +description: South Carolina counts these income sources as earned income under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: + - employment_income_before_lsr + - self_employment_income_before_lsr +metadata: + unit: list + period: month + label: South Carolina TANF earned income + reference: + - title: SC DSS TANF Policy Manual Section 7.1 + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=101 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/gross_income_limit.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/gross_income_limit.yaml new file mode 100644 index 00000000000..7ffed0cd6ba --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/gross_income_limit.yaml @@ -0,0 +1,11 @@ +description: South Carolina limits gross income to this multiple of the need standard under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: 1.85 + +metadata: + unit: /1 + period: month + label: South Carolina TANF gross income limit + reference: + - title: SC DSS TANF Policy Manual Section 8.15 + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=132 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/need_standard/rate.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/need_standard/rate.yaml new file mode 100644 index 00000000000..94e28622b5b --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/need_standard/rate.yaml @@ -0,0 +1,13 @@ +description: South Carolina sets this share of the federal poverty guidelines as the need standard under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: 0.5 + +metadata: + unit: /1 + period: month + label: South Carolina TANF need standard + reference: + - title: S.C. Code Regs. § 114-1140(A)(2) + href: https://www.law.cornell.edu/regulations/south-carolina/R-114-1140 + - title: The South Carolina Department of Social Services TANF Policy Manual + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/income/unearned.yaml b/policyengine_us/parameters/gov/states/sc/tanf/income/unearned.yaml new file mode 100644 index 00000000000..04d46ca9f07 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/income/unearned.yaml @@ -0,0 +1,28 @@ +description: South Carolina counts these income sources as unearned income under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: + - partnership_s_corp_income + - farm_income + - farm_rent_income + - capital_gains + - taxable_interest_income + - rental_income + # Royalties included in rental income + - dividend_income + - taxable_pension_income + # Pension income includes annuities and endowment contracts + - debt_relief + # Decedent income + # Estate interest income + - taxable_unemployment_compensation + - taxable_social_security + - illicit_income + - taxable_retirement_distributions + - miscellaneous_income +metadata: + unit: list + period: month + label: South Carolina TANF unearned income + reference: + - title: SC DSS TANF Policy Manual Section 7.1 + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=101 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/payment/rate.yaml b/policyengine_us/parameters/gov/states/sc/tanf/payment/rate.yaml new file mode 100644 index 00000000000..e6228dad713 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/payment/rate.yaml @@ -0,0 +1,14 @@ +description: South Carolina uses this rate to calculate benefits under the Temporary Assistance for Needy Families program. +values: + 2016-10-01: 0.3372 + 2024-10-01: 0.4046 + +metadata: + unit: /1 + period: month + label: South Carolina TANF payment rate + reference: + - title: S.C. Code Regs. § 114-1140(A)(3) + href: https://www.law.cornell.edu/regulations/south-carolina/R-114-1140 + - title: The South Carolina Department of Social Services TANF Policy Manual + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131 diff --git a/policyengine_us/parameters/gov/states/sc/tanf/resources/limit.yaml b/policyengine_us/parameters/gov/states/sc/tanf/resources/limit.yaml new file mode 100644 index 00000000000..d14e13b9766 --- /dev/null +++ b/policyengine_us/parameters/gov/states/sc/tanf/resources/limit.yaml @@ -0,0 +1,13 @@ +description: South Carolina limits resources to this amount under the Temporary Assistance for Needy Families program. +values: + 1996-07-01: 2_500 + +metadata: + unit: currency-USD + period: month + label: South Carolina TANF household resource limit + reference: + - title: S.C. Code Regs. § 114-1140(C) + href: https://www.law.cornell.edu/regulations/south-carolina/R-114-1140 + - title: The South Carolina Department of Social Services TANF Policy Manual + href: https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=90 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/integration.yaml new file mode 100644 index 00000000000..c31683622b7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/integration.yaml @@ -0,0 +1,224 @@ +- name: Case 1, single parent of 2 children with no income. + absolute_error_margin: 0.1 + period: 2025-01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 0 + person2: + age: 10 + is_child_dependent: true + person3: + age: 8 + is_child_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_assets: 1_000 + households: + household: + members: [person1, person2, person3] + state_code: SC + output: + sc_tanf: 435.28 + # tanf_fpg for size 3 (2025-01, uses 2024-10 FPG) = 2151.67/month + # need_standard = 2151.67 * 0.5 = 1075.83 + # benefit = 1075.83 * 0.4046 = 435.49 + +- name: Case 2, single parent with earned income. + absolute_error_margin: 0.1 + period: 2025-01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 6_000 + person2: + age: 10 + is_child_dependent: true + person3: + age: 8 + is_child_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_assets: 1_000 + households: + household: + members: [person1, person2, person3] + state_code: SC + output: + sc_tanf: 334.13 + # monthly earned = 6,000/12 = 500 + # January (month 1) uses 50% disregard + # countable_earned = 500 * 0.5 = 250 + # countable_income = 250 + # need_standard = 1075.83 + # excess = 1075.83 - 250 = 825.83 + # benefit = 825.83 * 0.4046 = 334.13 + +- name: Case 3, income above gross limit. + period: 2025-01 + input: + people: + person1: + age: 40 + employment_income_before_lsr: 24_000 + person2: + age: 10 + is_child_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 1_000 + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_tanf: 0 + # monthly earned = 24,000/12 = 2,000 + # tanf_fpg for size 2 = 1703.33 + # need_standard = 851.67 + # gross_income_limit = 851.67 * 1.85 = 1575.58 + # 2,000 > 1,575.58 -> not eligible + +- name: Case 4, single pregnant person with no income. + period: 2025-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 25 + is_pregnant: true + employment_income_before_lsr: 0 + spm_units: + spm_unit: + members: [person1] + spm_unit_assets: 500 + households: + household: + members: [person1] + state_code: SC + output: + sc_tanf: 253.89 + # tanf_fpg for size 1 (2025-01) = 1255/month + # need_standard = 1255 * 0.5 = 627.50 + # benefit = 627.50 * 0.4046 = 253.89 + +- name: Case 5, unearned income only. + period: 2025-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + employment_income_before_lsr: 0 + taxable_social_security: 3_600 + person2: + age: 8 + is_child_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 500 + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_tanf: 223.20 + # monthly unearned = 3,600/12 = 300 + # tanf_fpg for size 2 = 1703.33 + # need_standard = 1703.33 * 0.5 = 851.67 + # countable_income = 0 (earned) + 300 (unearned) = 300 + # excess = 851.67 - 300 = 551.67 + # benefit = 551.67 * 0.4046 = 223.20 + +- name: Case 6, historical payment rate (pre-Oct 2024). + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + employment_income_before_lsr: 0 + person2: + age: 8 + is_child_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 500 + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_tanf: 277.07 + # tanf_fpg for size 2 (2024-01, uses 2023-10 FPG) = 1643.33/month + # need_standard = 1643.33 * 0.5 = 821.67 + # benefit = 821.67 * 0.3372 = 277.07 (old rate) + +- name: Case 7, two-parent household with 4 children (family of 6). + period: 2025-01 + absolute_error_margin: 1 + input: + people: + parent1: + age: 35 + employment_income_before_lsr: 0 + parent2: + age: 33 + employment_income_before_lsr: 0 + child1: + age: 14 + is_child_dependent: true + child2: + age: 12 + is_child_dependent: true + child3: + age: 8 + is_child_dependent: true + child4: + age: 5 + is_child_dependent: true + spm_units: + spm_unit: + members: [parent1, parent2, child1, child2, child3, child4] + spm_unit_assets: 1_000 + households: + household: + members: [parent1, parent2, child1, child2, child3, child4] + state_code: SC + output: + sc_tanf: 707 + # tanf_fpg for size 6 (2025-01) = 3496/month (from Section 8.15 table) + # need_standard = 3496 * 0.5 = 1748 + # benefit = 1748 * 0.4046 = 707.24 + +- name: Case 8, ineligible due to immigration status. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income_before_lsr: 0 + immigration_status: UNDOCUMENTED + person2: + age: 8 + is_child_dependent: true + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 500 + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_tanf: 0 + # Both members are undocumented, so no one qualifies as + # citizen or legal immigrant -> ineligible diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml new file mode 100644 index 00000000000..01f7c7cfc9a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf.yaml @@ -0,0 +1,38 @@ +- name: Case 1, no earned income is eligible for standard amount. + absolute_error_margin: 0.1 + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 0 + sc_tanf_eligible: true + spm_unit_size: 2 + output: + sc_tanf: 344.58 + # tanf_fpg for size 2 (2025-01, uses 2024-10 FPG) = 1703.33/month + # need_standard = 1703.33 * 0.5 = 851.67 + # benefit = 851.67 * 0.4046 = 344.59 + +- name: Case 2, not eligible. + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 1_000 + sc_tanf_eligible: false + spm_unit_size: 2 + output: + sc_tanf: 0 + +- name: Case 3, some countable income. + absolute_error_margin: 0.1 + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 500 + sc_tanf_eligible: true + spm_unit_size: 2 + output: + sc_tanf: 142.28 + # tanf_fpg for size 2 (2025-01) = 1703.33/month + # need_standard = 1703.33 * 0.5 = 851.67 + # excess = 851.67 - 500 = 351.67 + # benefit = 351.67 * 0.4046 = 142.31 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_countable_earned_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_countable_earned_income_person.yaml new file mode 100644 index 00000000000..4157a4b30f2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_countable_earned_income_person.yaml @@ -0,0 +1,41 @@ +- name: Case 1, no earned income. + period: 2025-01 + input: + state_code: SC + employment_income_before_lsr: 0 + output: + sc_tanf_countable_earned_income_person: 0 + +- name: Case 2, January uses 50% disregard. + period: 2025-01 + input: + state_code: SC + employment_income_before_lsr: 12_000 + output: + sc_tanf_countable_earned_income_person: 500 + # monthly_income = 12,000 / 12 = 1,000 + # January (month 1) <= 4: uses 50% disregard + # countable = 1,000 * 0.5 = 500 + +- name: Case 3, full year verification of two-phase disregard. + period: 2025 + input: + state_code: SC + employment_income_before_lsr: 12_000 + output: + sc_tanf_countable_earned_income_person: 9_200 + # Jan-Apr (4 months): 1,000 * 0.5 = 500/month → 2,000 + # May-Dec (8 months): max(1,000 - 100, 0) = 900/month → 7,200 + # Annual total: 2,000 + 7,200 = 9,200 + +- name: Case 4, low income where $100 disregard zeroes out income. + period: 2025 + input: + state_code: SC + employment_income_before_lsr: 600 + output: + sc_tanf_countable_earned_income_person: 100 + # monthly_income = 600 / 12 = 50 + # Jan-Apr (4 months): 50 * 0.5 = 25/month → 100 + # May-Dec (8 months): max(50 - 100, 0) = 0/month → 0 + # Annual total: 100 + 0 = 100 diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_countable_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_countable_income_eligible.yaml new file mode 100644 index 00000000000..ed35d4779a1 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_countable_income_eligible.yaml @@ -0,0 +1,44 @@ +- name: Case 1, no income is eligible. + period: 2025-01 + input: + state_code: SC + spm_unit_size: 2 + output: + sc_tanf_countable_income_eligible: true + +- name: Case 2, countable income below need standard. + period: 2025-01 + input: + state_code: SC + spm_unit_size: 2 + sc_tanf_countable_income: 800 + output: + sc_tanf_countable_income_eligible: true + # tanf_fpg for size 2 (2025-01) = 1703.33/month + # need_standard = 1703.33 * 0.5 = 851.67 + # 800 < 851.67 -> eligible + +- name: Case 3, countable income above need standard. + period: 2025-01 + input: + state_code: SC + spm_unit_size: 2 + sc_tanf_countable_income: 900 + output: + sc_tanf_countable_income_eligible: false + # need_standard = 851.67 + # 900 >= 851.67 -> not eligible + +- name: Case 4, countable income exactly at need standard. + period: 2025-01 + absolute_error_margin: 0.1 + input: + state_code: SC + spm_unit_size: 2 + sc_tanf_countable_income: 851.67 + output: + sc_tanf_countable_income_eligible: false + # tanf_fpg for size 2 = 1703.33 + # need_standard = 1703.33 * 0.5 = 851.67 + # 851.67 < 851.67 is FALSE (strict less than) + # -> not eligible diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_eligible.yaml new file mode 100644 index 00000000000..eae5b4ea2e1 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_eligible.yaml @@ -0,0 +1,39 @@ +- name: Case 1, eligible for all. + period: 2025-01 + input: + state_code: SC + is_demographic_tanf_eligible: true + sc_tanf_income_eligible: true + sc_tanf_resources_eligible: true + output: + sc_tanf_eligible: true + +- name: Case 2, not demographic eligible. + period: 2025-01 + input: + state_code: SC + is_demographic_tanf_eligible: false + sc_tanf_income_eligible: true + sc_tanf_resources_eligible: true + output: + sc_tanf_eligible: false + +- name: Case 3, not income eligible. + period: 2025-01 + input: + state_code: SC + is_demographic_tanf_eligible: true + sc_tanf_income_eligible: false + sc_tanf_resources_eligible: true + output: + sc_tanf_eligible: false + +- name: Case 4, not resources eligible. + period: 2025-01 + input: + state_code: SC + is_demographic_tanf_eligible: true + sc_tanf_income_eligible: true + sc_tanf_resources_eligible: false + output: + sc_tanf_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_gross_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_gross_income_eligible.yaml new file mode 100644 index 00000000000..dd0656ebf42 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_gross_income_eligible.yaml @@ -0,0 +1,47 @@ +- name: Case 1, no income is eligible. + period: 2025-01 + input: + state_code: SC + spm_unit_size: 2 + output: + sc_tanf_gross_income_eligible: true + +- name: Case 2, income below gross income limit. + period: 2025-01 + input: + state_code: SC + spm_unit_size: 2 + employment_income_before_lsr: 18_000 + output: + sc_tanf_gross_income_eligible: true + # monthly earned = 18,000 / 12 = 1,500 + # tanf_fpg for size 2 (2025-01) = 1703.33/month + # need_standard = 1703.33 * 0.5 = 851.67 + # gross_income_limit = 851.67 * 1.85 = 1575.58 + # 1,500 <= 1,575.58 -> eligible + +- name: Case 3, income above gross income limit. + period: 2025-01 + input: + state_code: SC + spm_unit_size: 2 + employment_income_before_lsr: 24_000 + output: + sc_tanf_gross_income_eligible: false + # monthly earned = 24,000 / 12 = 2,000 + # gross_income_limit = 1,575.58 + # 2,000 > 1,575.58 -> not eligible + +- name: Case 4, gross income exactly at limit. + period: 2025-01 + absolute_error_margin: 0.1 + input: + state_code: SC + spm_unit_size: 2 + sc_tanf_gross_income: 1_575.58 + output: + sc_tanf_gross_income_eligible: true + # tanf_fpg for size 2 = 1703.33 + # need_standard = 1703.33 * 0.5 = 851.665 + # gross_income_limit = 851.665 * 1.85 = 1575.58 + # 1575.58 <= 1575.58 -> eligible (uses <=) diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_income_eligible.yaml new file mode 100644 index 00000000000..da84d0c22da --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_income_eligible.yaml @@ -0,0 +1,49 @@ +- name: Case 1, no income is eligible. + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 0 + sc_tanf_gross_income: 0 + spm_unit_size: 2 + output: + sc_tanf_income_eligible: true + +- name: Case 2, did not pass the gross income test. + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 500 + sc_tanf_gross_income: 2_000 + spm_unit_size: 2 + output: + sc_tanf_income_eligible: false + # tanf_fpg for size 2 (2025-01) = 1703.33/month + # need_standard = 1703.33 * 0.5 = 851.67 + # gross_income_limit = 851.67 * 1.85 = 1575.58 + # gross_income 2,000 > 1,575.58 -> not eligible + +- name: Case 3, pass gross income test but higher than need standard. + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 900 + sc_tanf_gross_income: 1_200 + spm_unit_size: 2 + output: + sc_tanf_income_eligible: false + # need_standard = 851.67 + # gross_income_limit = 1,575.58 + # gross 1,200 < 1,575.58 -> passes gross test + # countable 900 >= 851.67 -> fails countable test + +- name: Case 4, pass both income tests. + period: 2025-01 + input: + state_code: SC + sc_tanf_countable_income: 800 + sc_tanf_gross_income: 1_000 + spm_unit_size: 2 + output: + sc_tanf_income_eligible: true + # gross 1,000 < 1,575.58 -> passes gross test + # countable 800 < 851.67 -> passes countable test diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml new file mode 100644 index 00000000000..c25f3d2b122 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/tanf/sc_tanf_resources_eligible.yaml @@ -0,0 +1,36 @@ +- name: Case 1, assets below the limit. + period: 2025-01 + input: + state_code: SC + spm_unit_assets: 2_000 + output: + sc_tanf_resources_eligible: true + # 2,000 <= 2,500 -> eligible + +- name: Case 2, assets above the limit. + period: 2025-01 + input: + state_code: SC + spm_unit_assets: 3_000 + output: + sc_tanf_resources_eligible: false + # 3,000 > 2,500 -> not eligible + +- name: Case 3, assets exactly at the limit. + period: 2025-01 + absolute_error_margin: 0.1 + input: + state_code: SC + spm_unit_assets: 2_500 + output: + sc_tanf_resources_eligible: true + # 2,500 <= 2,500 -> eligible (uses <=) + +- name: Case 4, no assets. + period: 2025-01 + input: + state_code: SC + spm_unit_assets: 0 + output: + sc_tanf_resources_eligible: true + # 0 <= 2,500 -> eligible diff --git a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_countable_income_eligible.py b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_countable_income_eligible.py new file mode 100644 index 00000000000..41c1eaed560 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_countable_income_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class sc_tanf_countable_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "South Carolina TANF countable income eligible" + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.sc.tanf.income + fpg = spm_unit("tanf_fpg", period) + need_standard = fpg * p.need_standard.rate + countable_income = spm_unit("sc_tanf_countable_income", period) + return countable_income < need_standard diff --git a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_eligible.py b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_eligible.py new file mode 100644 index 00000000000..55bbfbc7d8d --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_eligible.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class sc_tanf_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for the South Carolina TANF program" + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://www.law.cornell.edu/regulations/south-carolina/S.C.-Code-Regs.-114-1140" + + def formula(spm_unit, period, parameters): + demographic_eligible = spm_unit("is_demographic_tanf_eligible", period) + immigration_eligible = ( + add(spm_unit, period, ["is_citizen_or_legal_immigrant"]) > 0 + ) + income_eligible = spm_unit("sc_tanf_income_eligible", period) + resource_eligible = spm_unit("sc_tanf_resources_eligible", period) + return ( + demographic_eligible + & immigration_eligible + & income_eligible + & resource_eligible + ) diff --git a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_gross_income_eligible.py b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_gross_income_eligible.py new file mode 100644 index 00000000000..4b5b3fbbf12 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_gross_income_eligible.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class sc_tanf_gross_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "South Carolina TANF gross income eligible" + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.sc.tanf.income + fpg = spm_unit("tanf_fpg", period) + need_standard = fpg * p.need_standard.rate + gross_income_limit = need_standard * p.gross_income_limit + gross_income = spm_unit("sc_tanf_gross_income", period) + return gross_income <= gross_income_limit diff --git a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_income_eligible.py b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_income_eligible.py new file mode 100644 index 00000000000..5d876ad5601 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_income_eligible.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class sc_tanf_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "South Carolina TANF income eligible" + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + + def formula(spm_unit, period, parameters): + gross_income_eligible = spm_unit( + "sc_tanf_gross_income_eligible", period + ) + countable_income_eligible = spm_unit( + "sc_tanf_countable_income_eligible", period + ) + return gross_income_eligible & countable_income_eligible diff --git a/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py new file mode 100644 index 00000000000..218468a0447 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/eligibility/sc_tanf_resources_eligible.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class sc_tanf_resources_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "South Carolina TANF resources eligible" + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://www.law.cornell.edu/regulations/south-carolina/S.C.-Code-Regs.-114-1140" # Section (C) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.sc.tanf.resources + assets = spm_unit("spm_unit_assets", period.this_year) + return assets <= p.limit diff --git a/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_countable_earned_income_person.py b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_countable_earned_income_person.py new file mode 100644 index 00000000000..4ac9a3f8583 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_countable_earned_income_person.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class sc_tanf_countable_earned_income_person(Variable): + value_type = float + entity = Person + label = "South Carolina TANF countable earned income" + unit = USD + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=130" # Section 8.12 + + def formula(person, period, parameters): + p = parameters(period).gov.states.sc.tanf.income.earned.disregard + gross_earned_income = person("sc_tanf_gross_earned_income", period) + month = period.start.month + + # First 4 months (Jan-Apr): 50% disregard + # Remaining 8 months (May-Dec): $100 flat disregard + # Use calendar months as a proxy. The actual policy refers to + # "first 4 months of employment" which cannot be tracked. + initial_period = month <= p.percentage.months + initial_countable = gross_earned_income * (1 - p.percentage.rate) + ongoing_countable = max_(gross_earned_income - p.amount, 0) + + return where(initial_period, initial_countable, ongoing_countable) diff --git a/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_countable_income.py b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_countable_income.py new file mode 100644 index 00000000000..a949b41ed3f --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_countable_income.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class sc_tanf_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "South Carolina TANF countable income" + unit = USD + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + + adds = [ + "sc_tanf_countable_earned_income_person", + "sc_tanf_gross_unearned_income", + ] diff --git a/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_earned_income.py b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_earned_income.py new file mode 100644 index 00000000000..7c599d576d3 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_earned_income.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class sc_tanf_gross_earned_income(Variable): + value_type = float + entity = Person + label = "South Carolina TANF gross earned income" + unit = USD + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=100" # Section 7.1 + adds = "gov.states.sc.tanf.income.earned.earned" diff --git a/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_income.py b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_income.py new file mode 100644 index 00000000000..7f22abc303f --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_income.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class sc_tanf_gross_income(Variable): + value_type = float + entity = SPMUnit + label = "South Carolina TANF gross income" + unit = USD + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + + adds = [ + "sc_tanf_gross_earned_income", + "sc_tanf_gross_unearned_income", + ] diff --git a/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_unearned_income.py b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_unearned_income.py new file mode 100644 index 00000000000..36273d0a264 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/income/sc_tanf_gross_unearned_income.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class sc_tanf_gross_unearned_income(Variable): + value_type = float + entity = Person + label = "South Carolina TANF gross unearned income" + unit = USD + definition_period = MONTH + defined_for = StateCode.SC + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=100" # Section 7.1 + adds = "gov.states.sc.tanf.income.unearned" diff --git a/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py b/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py new file mode 100644 index 00000000000..8e7afa77df6 --- /dev/null +++ b/policyengine_us/variables/gov/states/sc/tanf/sc_tanf.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class sc_tanf(Variable): + value_type = float + entity = SPMUnit + label = "South Carolina TANF" + unit = USD + definition_period = MONTH + defined_for = "sc_tanf_eligible" + reference = "https://dss.sc.gov/media/ojqddxsk/tanf-policy-manual-volume-65.pdf#page=131" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.sc.tanf + # Compute need standard based on federal poverty guidelines + fpg = spm_unit("tanf_fpg", period) + need_standard = fpg * p.income.need_standard.rate + countable_income = spm_unit("sc_tanf_countable_income", period) + excess_income = need_standard - countable_income + return excess_income * p.payment.rate