diff --git a/changelog.d/fix-ar-pr-casualty-loss.fixed.md b/changelog.d/fix-ar-pr-casualty-loss.fixed.md new file mode 100644 index 00000000000..9be96106f92 --- /dev/null +++ b/changelog.d/fix-ar-pr-casualty-loss.fixed.md @@ -0,0 +1 @@ +Leave dependents' casualty losses off the filer's Arkansas return, and limit the Puerto Rico casualty loss deductions to the principal residence and capped household personal property under P.R. Code Section 1033.15(a)(10), with new Puerto Rico inputs. diff --git a/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/personal_property_cap.yaml b/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/personal_property_cap.yaml new file mode 100644 index 00000000000..8cf332f9ad6 --- /dev/null +++ b/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/personal_property_cap.yaml @@ -0,0 +1,38 @@ +# SEPARATE means Puerto Rico filing status 3: spouses living together at the +# end of the year who file separately. A married person not living with the +# spouse files as an individual taxpayer under the $5,000 cap. +description: Puerto Rico limits the deduction for casualty losses of automobiles, furniture and other household goods to this amount, based on filing status. +metadata: + propagate_metadata_to_children: true + unit: currency-USD + period: year + label: Puerto Rico personal property casualty loss deduction cap + breakdown: + - filing_status + breakdown_label: + - Filing status + reference: + - title: P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(B)(i) (13 L.P.R.A. § 30135), as enacted by Act 1-2011 + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/0001-2011.pdf#page=189 + - title: P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(B)(i), OGP English compilation (Rev. June 18, 2026) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167 + - title: Código de Rentas Internas de Puerto Rico de 2011, Sección 1033.15(a)(10)(B)(i), OGP compilation (Rev. 28 de mayo de 2026) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/C%C3%B3digos/1-2011/1-2011.pdf#page=182 + - title: Act 1-2011, Section 6100.04(a)(1) (Subtitle A applies to taxable years starting after December 31, 2010) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/0001-2011.pdf#page=1313 + - title: 2023 Individual Income Tax Return Instructions Booklet, Schedule A Individual, Part I, line 5 + href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2023.pdf#page=26 + - title: 2024 Individual Income Tax Return Instructions Booklet, Schedule A Individual, Part I, line 5 + href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2024.pdf#page=26 + - title: 2025 Individual Income Tax Return Instructions Booklet, Schedule A Individual, Part I, line 5 + href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=26 +SINGLE: + 2011-01-01: 5_000 +JOINT: + 2011-01-01: 5_000 +SEPARATE: + 2011-01-01: 2_500 +HEAD_OF_HOUSEHOLD: + 2011-01-01: 5_000 +SURVIVING_SPOUSE: + 2011-01-01: 5_000 diff --git a/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/separate_percentage.yaml b/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/separate_percentage.yaml index 087fa8d0a2e..3b670df3c78 100644 --- a/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/separate_percentage.yaml +++ b/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/separate_percentage.yaml @@ -1,14 +1,29 @@ -description: Puerto Rico deducts this percentage of casualty loss for separate filers. +# SEPARATE means Puerto Rico filing status 3: spouses living together at the +# end of the year who file separately. A married person not living with the +# spouse files as an individual taxpayer and claims the whole loss. +description: Puerto Rico allows each spouse filing a separate return this share of the couple's casualty losses on the principal residence and on household personal property. +values: + 2011-01-01: 0.5 metadata: unit: /1 period: year - label: Puerto Rico casualty loss deduction separate filing status percentage + label: Puerto Rico casualty loss deduction separate filing share reference: - - title: P.R. Laws tit. 13, § 30135 (10)(A)(ii) - href: https://law.justia.com/codes/puerto-rico/title-thirteen/subtitle-17/part-ii/chapter-1005/subchapter-c/30135/ - - title: Gov. of Puerto Rico Individual Income Tax Return Form 482.0 4 - href: https://hacienda.pr.gov/sites/default/files/individuals_2024_rev._jul_12_24_9-30-24_informative.pdf#page=4 - - title: Individual Income Tax Return Instructions Booklet 2023 + - title: P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(A)(ii) (13 L.P.R.A. § 30135), as enacted by Act 1-2011 + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/0001-2011.pdf#page=188 + - title: P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(A)(ii), OGP English compilation (Rev. June 18, 2026) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167 + - title: P.R. Internal Revenue Code of 2011, Section 1021.03(a)(4) (50% attribution of Section 1033.15(a)(10) deductions), OGP English compilation (Rev. June 18, 2026) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=40 + - title: P.R. Internal Revenue Code of 2011, Section 1061.01(b)(2)(B) (separate returns follow Section 1021.03(a)(1)-(6)), OGP English compilation (Rev. June 18, 2026) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=321 + - title: Act 1-2011, Section 6100.04(a)(1) (Subtitle A applies to taxable years starting after December 31, 2010) + href: https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/0001-2011.pdf#page=1313 + - title: 2023 Individual Income Tax Return Instructions Booklet, Schedule A Individual, Part I, line 2 href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2023.pdf#page=24 -values: - 2023-01-01: 0.5 + - title: 2024 Individual Income Tax Return Instructions Booklet, Schedule A Individual, Part I, line 2 + href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2024.pdf#page=24 + - title: 2025 Individual Income Tax Return Instructions Booklet, filing status 3 (married filing separately) + href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=14 + - title: 2025 Individual Income Tax Return Instructions Booklet, Schedule A Individual, Part I, line 2 + href: https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=24 diff --git a/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/sources.yaml b/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/sources.yaml index 607ec6a0a1e..9890467285f 100644 --- a/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/sources.yaml +++ b/policyengine_us/parameters/gov/territories/pr/tax/income/taxable_income/deductions/sources.yaml @@ -2,6 +2,7 @@ description: Puerto Rico deductions from taxable income. values: 2023-01-01: - pr_casualty_loss_deduction + - pr_personal_property_casualty_loss_deduction - pr_charitable_deduction - pr_medical_expense_deduction - pr_mortgage_deduction diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.yaml index fb18b75ab45..49b23e3e497 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.yaml @@ -55,7 +55,7 @@ output: ar_casualty_loss_deduction_indiv: 0 -- name: 2025, losses of both spouses are treated as one casualty +- name: 2025, losses of both spouses from one casualty share one Form AR4684 # 12,000 + 8,000 - 100 - 10% * (30,000 + 20,000) = 14,900 period: 2025 input: @@ -75,3 +75,63 @@ state_code: AR output: ar_casualty_loss_deduction_indiv: 14_900 + +- name: 2025, a dependent's loss is not deductible on the filer's return + # 26 U.S.C. § 165(h), as adopted by Ark. Code § 26-51-424(b), allows the + # loss of the individual who sustained it, on that individual's return. + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + is_tax_unit_dependent: false + ar_agi_indiv: 30_000 + person2: + is_tax_unit_head: false + is_tax_unit_dependent: false + ar_agi_indiv: 20_000 + person3: + is_tax_unit_head: false + is_tax_unit_dependent: true + casualty_loss: 20_000 + ar_agi_indiv: 0 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + ar_casualty_loss_deduction_indiv: 0 + +- name: 2025, spouses' losses are pooled and a dependent's loss is left out + # 12,000 + 8,000 - 100 - 10% * (30,000 + 20,000) = 14,900; the dependent's + # 5,000 is excluded. + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + is_tax_unit_dependent: false + casualty_loss: 12_000 + ar_agi_indiv: 30_000 + person2: + is_tax_unit_head: false + is_tax_unit_dependent: false + casualty_loss: 8_000 + ar_agi_indiv: 20_000 + person3: + is_tax_unit_head: false + is_tax_unit_dependent: true + casualty_loss: 5_000 + ar_agi_indiv: 0 + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + ar_casualty_loss_deduction_indiv: 14_900 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml index 86cca44a96e..a012b5d9382 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.yaml @@ -86,3 +86,53 @@ state_code: AR output: ar_casualty_loss_deduction_joint: 14_500 + +- name: 2025, a dependent's loss is not deductible on the filer's return + # 26 U.S.C. § 165(h), as adopted by Ark. Code § 26-51-424(b), allows the + # loss of the individual who sustained it, on that individual's return. + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + is_tax_unit_dependent: false + ar_agi_joint: 50_000 + person2: + is_tax_unit_head: false + is_tax_unit_dependent: true + casualty_loss: 20_000 + ar_agi_joint: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_casualty_loss_deduction_joint: 0 + +- name: 2025, only the filer's own loss counts when a dependent also has one + # 12,000 - 100 - 10% * 50,000 = 6,900; the dependent's 3,000 is excluded. + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + is_tax_unit_dependent: false + casualty_loss: 12_000 + ar_agi_joint: 50_000 + person2: + is_tax_unit_head: false + is_tax_unit_dependent: true + casualty_loss: 3_000 + ar_agi_joint: 0 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_casualty_loss_deduction_joint: 6_900 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions_indiv.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions_indiv.yaml index 07780ebbf42..c6d36a9266b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions_indiv.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions_indiv.yaml @@ -80,3 +80,31 @@ state_code: AR output: ar_itemized_deductions_indiv: [590, 410] + +- name: A spouse's casualty loss is split by AGI share, not by owner + # Only the spouse had a loss. Form AR3 line 18: + # 20,100 - 100 - 10% * (60,000 + 40,000) = 10,000. + # AR3 lines 31-35 split the line 30 total by AGI share: + # 60% * 10,000 = 6,000 and 40% * 10,000 = 4,000. + period: 2025 + input: + people: + person1: + is_tax_unit_head: true + is_tax_unit_dependent: false + ar_agi_indiv: 60_000 + person2: + is_tax_unit_head: false + is_tax_unit_dependent: false + casualty_loss: 20_100 + ar_agi_indiv: 40_000 + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_casualty_loss_deduction_indiv: 10_000 + ar_itemized_deductions_indiv: [6_000, 4_000] diff --git a/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_casualty_loss_deduction.yaml new file mode 100644 index 00000000000..8440ebf8bbf --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_casualty_loss_deduction.yaml @@ -0,0 +1,92 @@ +- name: Case 1, separate filer claims half of the principal residence loss. + # Section 1033.15(a)(10)(A)(ii): 50% * 20,000 = 10,000 + period: 2024 + input: + pr_principal_residence_casualty_loss: 20_000 + filing_status: SEPARATE + state_code: PR + output: + pr_casualty_loss_deduction: 10_000 + +- name: Case 2, single filer deducts the whole principal residence loss. + period: 2024 + input: + pr_principal_residence_casualty_loss: 3_000 + filing_status: SINGLE + state_code: PR + output: + pr_casualty_loss_deduction: 3_000 + +- name: Case 3, a generic casualty or theft loss does not qualify. + # casualty_loss holds any personal casualty or theft loss (federal Form + # 4684). Puerto Rico allows only the principal residence loss, entered as + # pr_principal_residence_casualty_loss. + period: 2024 + input: + casualty_loss: 20_000 + filing_status: SINGLE + state_code: PR + output: + pr_casualty_loss_deduction: 0 + +- name: Case 4, a household goods loss is not a principal residence loss. + period: 2025 + input: + pr_personal_property_casualty_loss: 4_000 + filing_status: SINGLE + state_code: PR + output: + pr_casualty_loss_deduction: 0 + +- name: Case 5, joint filers have no cap or income floor. + # 18,000 + 12,000 = 30,000 + period: 2025 + input: + people: + person1: + age: 45 + pr_principal_residence_casualty_loss: 18_000 + person2: + age: 43 + pr_principal_residence_casualty_loss: 12_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: PR + output: + pr_casualty_loss_deduction: 30_000 + +- name: Case 6, a dependent's loss is left off the filer's return. + period: 2025 + input: + people: + person1: + age: 45 + pr_principal_residence_casualty_loss: 5_000 + person2: + age: 17 + is_tax_unit_dependent: true + pr_principal_residence_casualty_loss: 2_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [person1, person2] + state_code: PR + output: + pr_casualty_loss_deduction: 5_000 + +- name: Case 7, no deduction outside Puerto Rico. + period: 2025 + input: + pr_principal_residence_casualty_loss: 5_000 + filing_status: SINGLE + state_code: NY + output: + pr_casualty_loss_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_deduction.yaml new file mode 100644 index 00000000000..f6a26bd2bb4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_deduction.yaml @@ -0,0 +1,158 @@ +- name: Case 1, single filer below the cap. + period: 2025 + input: + pr_personal_property_casualty_loss: 3_000 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 3_000 + +- name: Case 2, single filer exactly at the cap. + period: 2025 + input: + pr_personal_property_casualty_loss: 5_000 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 5_000 + +- name: Case 3, single filer above the cap. + # Section 1033.15(a)(10)(B)(i): limited to $5,000 + period: 2025 + input: + pr_personal_property_casualty_loss: 8_000 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 5_000 + +- name: Case 4, head of household above the cap. + period: 2025 + input: + pr_personal_property_casualty_loss: 6_000 + filing_status: HEAD_OF_HOUSEHOLD + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 5_000 + +- name: Case 5, surviving spouse above the cap. + period: 2025 + input: + pr_personal_property_casualty_loss: 6_000 + filing_status: SURVIVING_SPOUSE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 5_000 + +- name: Case 6, joint filers share one $5,000 cap. + # 3,000 + 4,000 = 7,000, capped at 5,000 + period: 2025 + input: + people: + person1: + age: 45 + pr_personal_property_casualty_loss: 3_000 + person2: + age: 43 + pr_personal_property_casualty_loss: 4_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 5_000 + +- name: Case 7, separate filer is capped at $2,500. + # 50% * 8,000 = 4,000, capped at 2,500 + period: 2025 + input: + pr_personal_property_casualty_loss: 8_000 + filing_status: SEPARATE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 2_500 + +- name: Case 8, separate filer claims half of the couple's loss. + # Section 1021.03(a)(4) attributes (a)(10) deductions 50% to each spouse: + # 50% * 3,000 = 1,500, below the 2,500 cap + period: 2025 + input: + pr_personal_property_casualty_loss: 3_000 + filing_status: SEPARATE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 1_500 + +- name: Case 9, carryover from a prior year counts toward the annual cap. + # 2,000 + 2,500 = 4,500 + period: 2025 + input: + pr_personal_property_casualty_loss: 2_000 + pr_personal_property_casualty_loss_carryover: 2_500 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 4_500 + +- name: Case 10, carryover and current loss together are capped. + # 2,000 + 4,000 = 6,000, capped at 5,000 + period: 2025 + input: + pr_personal_property_casualty_loss: 2_000 + pr_personal_property_casualty_loss_carryover: 4_000 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 5_000 + +- name: Case 11, a generic casualty or theft loss does not qualify. + period: 2025 + input: + casualty_loss: 8_000 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 0 + +- name: Case 12, a principal residence loss is not a household goods loss. + period: 2025 + input: + pr_principal_residence_casualty_loss: 8_000 + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 0 + +- name: Case 13, a dependent's loss is left off the filer's return. + period: 2025 + input: + people: + person1: + age: 45 + pr_personal_property_casualty_loss: 1_000 + person2: + age: 17 + is_tax_unit_dependent: true + pr_personal_property_casualty_loss: 3_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: HEAD_OF_HOUSEHOLD + households: + household: + members: [person1, person2] + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 1_000 + +- name: Case 14, no deduction with no loss. + period: 2025 + input: + filing_status: SINGLE + state_code: PR + output: + pr_personal_property_casualty_loss_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/pr_casualty_loss_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/pr_casualty_loss_deduction.yaml deleted file mode 100644 index 84bdf91fcb2..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/pr_casualty_loss_deduction.yaml +++ /dev/null @@ -1,17 +0,0 @@ -- name: Separate filer - period: 2024 - input: - casualty_loss: 20_000 - filing_status: SEPARATE - state_code: PR - output: - pr_casualty_loss_deduction: 10_000 - -- name: Single filer - period: 2024 - input: - casualty_loss: 3_000 - filing_status: SINGLE - state_code: PR - output: - pr_casualty_loss_deduction: 3_000 diff --git a/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/pr_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/pr_deductions.yaml new file mode 100644 index 00000000000..4580501e88e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/territories/pr/tax/income/taxable_income/deductions/pr_deductions.yaml @@ -0,0 +1,14 @@ +- name: Case 1, both casualty loss deductions count toward the total. + # Schedule A Individual, Part I, line 2: 10,000 (no cap) + # Schedule A Individual, Part I, line 5: 7,000, capped at 5,000 + # 10,000 + 5,000 = 15,000 + period: 2025 + input: + pr_principal_residence_casualty_loss: 10_000 + pr_personal_property_casualty_loss: 7_000 + filing_status: SINGLE + state_code: PR + output: + pr_casualty_loss_deduction: 10_000 + pr_personal_property_casualty_loss_deduction: 5_000 + pr_deductions: 15_000 diff --git a/policyengine_us/tests/unit/test_ar_misc_casualty_deduction_properties.py b/policyengine_us/tests/unit/test_ar_misc_casualty_deduction_properties.py index f818d7b6b4b..1e593fb68a0 100644 --- a/policyengine_us/tests/unit/test_ar_misc_casualty_deduction_properties.py +++ b/policyengine_us/tests/unit/test_ar_misc_casualty_deduction_properties.py @@ -10,6 +10,7 @@ exclusion, rise with expenses or losses, and fall with Arkansas AGI; - the joint and separate variants agree on the same inputs; - they do not depend on the year across the federal TCJA suspension; +- a dependent's casualty loss never changes the filer's casualty deduction; - before 2018, the Arkansas miscellaneous deduction equals the federal one when Arkansas AGI equals federal AGI, since both apply one 2% floor. """ @@ -156,3 +157,46 @@ def test_misc_deduction_matches_federal_before_2018(year): sim.calculate("ar_misc_deduction_joint", year), sim.calculate("misc_deduction", year), ) + + +DEPENDENT_LOSSES = [0, 100, 5_000, 250_000] + + +@pytest.mark.parametrize("year", [2010, 2025]) +def test_casualty_loss_deduction_ignores_dependents_losses(year): + """26 U.S.C. § 165(h), as adopted by Ark. Code § 26-51-424(b), allows the + loss of the individual who sustained it, so a dependent's loss belongs on + the dependent's own return. Each tax unit holds a head and a dependent.""" + grid = list(itertools.product(AMOUNTS, AGIS, DEPENDENT_LOSSES)) + situation = {"people": {}, "tax_units": {}, "households": {}} + for i, (head_loss, agi, dependent_loss) in enumerate(grid): + head, dependent = f"h{i}", f"d{i}" + for person, loss, person_agi, is_dependent in ( + (head, head_loss, agi, False), + (dependent, dependent_loss, 0, True), + ): + situation["people"][person] = { + "age": {year: 10 if is_dependent else 40}, + "is_tax_unit_head": {year: not is_dependent}, + "is_tax_unit_dependent": {year: is_dependent}, + "casualty_loss": {year: loss}, + "ar_agi_joint": {year: person_agi}, + "ar_agi_indiv": {year: person_agi}, + } + situation["tax_units"][f"t{i}"] = {"members": [head, dependent]} + situation["households"][f"hh{i}"] = { + "members": [head, dependent], + "state_code": {year: "AR"}, + } + sim = Simulation(situation=situation) + head_loss = np.array([g[0] for g in grid], dtype=float) + agi = np.array([g[1] for g in grid], dtype=float) + expected = casualty_reference(head_loss, agi, year) + for variable in ( + "ar_casualty_loss_deduction_joint", + "ar_casualty_loss_deduction_indiv", + ): + np.testing.assert_allclose(sim.calculate(variable, year), expected) + # Guard against a vacuous pass: some dependents have losses that would + # raise the deduction if they were counted. + assert max(DEPENDENT_LOSSES) > 0 and expected.max() > 0 diff --git a/policyengine_us/tests/unit/test_pr_casualty_loss_deduction_properties.py b/policyengine_us/tests/unit/test_pr_casualty_loss_deduction_properties.py new file mode 100644 index 00000000000..d94ce614038 --- /dev/null +++ b/policyengine_us/tests/unit/test_pr_casualty_loss_deduction_properties.py @@ -0,0 +1,144 @@ +"""Properties of the Puerto Rico casualty loss deductions. + +Each test evaluates every point of an input grid in one vectorized +simulation, so the properties hold for all grid inputs rather than for a few +examples: + +- the deductions match a closed-form reference of P.R. Internal Revenue Code + of 2011 Section 1033.15(a)(10): (A) the principal residence loss in full, + or half for a spouse filing separately, with no cap; (B) the automobile and + household goods loss plus any carryover, capped at $5,000, or half of the + loss capped at $2,500 for a spouse filing separately; +- they are non-negative and stay within the loss and the cap, and (B) rises + with the loss and the carryover; +- the generic casualty_loss input, which holds any casualty or theft loss, + changes neither deduction; +- both deductions flow into pr_deductions. +""" + +import itertools + +import numpy as np +import pytest + +from policyengine_us import Simulation + +YEAR = 2025 +RESIDENCE_LOSSES = [0, 1, 2_500, 20_000] +PERSONAL_LOSSES = [0, 1, 2_500, 4_999, 5_000, 5_001, 10_000] +CARRYOVERS = [0, 1_000, 6_000] +FILING_STATUSES = [ + "SINGLE", + "JOINT", + "SEPARATE", + "HEAD_OF_HOUSEHOLD", + "SURVIVING_SPOUSE", +] +GENERIC_LOSSES = [0, 50_000] +GRID = list( + itertools.product( + RESIDENCE_LOSSES, + PERSONAL_LOSSES, + CARRYOVERS, + FILING_STATUSES, + GENERIC_LOSSES, + ) +) + +SEPARATE_SHARE = 0.5 +CAP = 5_000 +SEPARATE_CAP = 2_500 + + +def grid_simulation(): + """One single-person tax unit per grid point, all in Puerto Rico.""" + situation = {"people": {}, "tax_units": {}, "households": {}} + for i, (residence, personal, carryover, status, generic) in enumerate(GRID): + person = f"p{i}" + situation["people"][person] = { + "age": {YEAR: 40}, + "pr_principal_residence_casualty_loss": {YEAR: residence}, + "pr_personal_property_casualty_loss": {YEAR: personal}, + "casualty_loss": {YEAR: generic}, + } + situation["tax_units"][f"t{i}"] = { + "members": [person], + "filing_status": {YEAR: status}, + "pr_personal_property_casualty_loss_carryover": {YEAR: carryover}, + } + situation["households"][f"h{i}"] = { + "members": [person], + "state_code": {YEAR: "PR"}, + } + return Simulation(situation=situation) + + +@pytest.fixture(scope="module") +def out(): + """The grid's results, computed once and only read by the tests.""" + sim = grid_simulation() + return { + variable: sim.calculate(variable, YEAR) + for variable in ( + "pr_casualty_loss_deduction", + "pr_personal_property_casualty_loss_deduction", + "pr_deductions", + ) + } + + +def column(index): + values = [g[index] for g in GRID] + if isinstance(values[0], str): + return np.array(values) + return np.array(values, dtype=float) + + +def test_deductions_match_the_statute(out): + residence, personal, carryover, status = (column(i) for i in range(4)) + separate = status == "SEPARATE" + share = np.where(separate, SEPARATE_SHARE, 1) + cap = np.where(separate, SEPARATE_CAP, CAP) + np.testing.assert_allclose(out["pr_casualty_loss_deduction"], share * residence) + np.testing.assert_allclose( + out["pr_personal_property_casualty_loss_deduction"], + np.minimum(share * personal + carryover, cap), + ) + + +def test_deductions_are_bounded(out): + residence, status = column(0), column(3) + cap = np.where(status == "SEPARATE", SEPARATE_CAP, CAP) + line_2 = out["pr_casualty_loss_deduction"] + line_5 = out["pr_personal_property_casualty_loss_deduction"] + assert np.all(line_2 >= 0) and np.all(line_2 <= residence) + assert np.all(line_5 >= 0) and np.all(line_5 <= cap) + # Guard against a vacuous pass: the cap binds somewhere. + assert np.any(line_5 == cap) and np.any(line_5 < cap) + + +def test_personal_property_deduction_rises_with_loss_and_carryover(out): + line_5 = out["pr_personal_property_casualty_loss_deduction"] + table = line_5.reshape( + len(RESIDENCE_LOSSES), + len(PERSONAL_LOSSES), + len(CARRYOVERS), + len(FILING_STATUSES), + len(GENERIC_LOSSES), + ) + assert np.all(np.diff(table, axis=1) >= 0), "falls as the loss rises" + assert np.all(np.diff(table, axis=2) >= 0), "falls as the carryover rises" + + +def test_generic_casualty_loss_has_no_effect(out): + for variable, values in out.items(): + table = values.reshape(-1, len(GENERIC_LOSSES)) + np.testing.assert_allclose(table[:, 1], table[:, 0], err_msg=variable) + + +def test_both_deductions_flow_into_the_total(out): + np.testing.assert_allclose( + out["pr_deductions"], + out["pr_casualty_loss_deduction"] + + out["pr_personal_property_casualty_loss_deduction"], + ) diff --git a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.py b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.py index 42539b51cf3..4a65b524094 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_indiv.py @@ -14,6 +14,9 @@ class ar_casualty_loss_deduction_indiv(Variable): # 2025 Form AR3 instructions, Line 18, and Form AR4684 "https://www.dfa.arkansas.gov/wp-content/uploads/2025_AR1000F_and_AR1000NR_Instructions.pdf#page=21", "https://www.dfa.arkansas.gov/wp-content/uploads/2025_AR4684_Casualties_and_Thefts.pdf#page=1", + # 2025 Form AR3, Lines 18 and 30-35, and instructions for Lines 31-35 + "https://www.dfa.arkansas.gov/wp-content/uploads/2025_AR3_ItemizedDeduction.pdf#page=1", + "https://www.dfa.arkansas.gov/wp-content/uploads/2025_AR1000F_and_AR1000NR_Instructions.pdf#page=22", ) defined_for = StateCode.AR @@ -21,10 +24,25 @@ def formula(tax_unit, period, parameters): p = parameters( period ).gov.states.ar.tax.income.deductions.itemized.casualty_loss - # The model records one loss amount per person, not separate - # casualty events, so the tax unit's losses are treated as one - # casualty and the per-loss exclusion applies once. - loss = add(tax_unit, period, ["casualty_loss"]) + # A couple filing separately on the same return (status 4) files one + # Form AR3 with one set of Forms AR4684, one form per casualty event. + # AR4684 line 11 subtracts $100 once per event, whichever spouse owns + # the property, and lines 13-18 apply one 10% floor for the return. + # Line 17 cites AR1000F line 25 without naming a column; we use + # columns A plus B, as AR3 lines 2 and 23 do for the other AGI + # floors. AR3 lines 31-35 then split the whole itemized total, line + # 18 included, by AGI share (ar_itemized_deductions_indiv), not by + # who owned the property. The adopted 26 U.S.C. § 165(h)(5)(B) (2008 + # edition) treats only spouses on a joint return as one individual, + # and Treas. Reg. § 1.165-7(b)(4)(iii) applies the $100 to each + # spouse otherwise, but no Arkansas form or instruction computes the + # loss per spouse, so we follow the forms. The model records one loss + # amount per person, not separate casualty events, so the tax unit's + # losses are treated as one casualty and the exclusion applies once. + # A dependent's loss belongs on the dependent's own return under + # § 165(h) as adopted by § 26-51-424(b), even though ar_agi_indiv + # moves the dependent's net income to the head. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) loss_after_exclusion = max_(0, loss - p.exclusion) agi = add(tax_unit, period, ["ar_agi_indiv"]) return max_(0, loss_after_exclusion - p.income_floor * agi) diff --git a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py index 3224ce6f093..0605271f12c 100644 --- a/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py +++ b/policyengine_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_casualty_loss_deduction_joint.py @@ -24,7 +24,10 @@ def formula(tax_unit, period, parameters): # The model records one loss amount per person, not separate # casualty events, so the tax unit's losses are treated as one # casualty and the per-loss exclusion applies once. - loss = add(tax_unit, period, ["casualty_loss"]) + # A dependent's loss belongs on the dependent's own return under + # 26 U.S.C. § 165(h) as adopted by § 26-51-424(b), even though + # ar_agi_joint moves the dependent's net income to the head. + loss = tax_unit_non_dep_add(tax_unit, period, ["casualty_loss"]) loss_after_exclusion = max_(0, loss - p.exclusion) agi = add(tax_unit, period, ["ar_agi_joint"]) return max_(0, loss_after_exclusion - p.income_floor * agi) diff --git a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_casualty_loss_deduction.py b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_casualty_loss_deduction.py new file mode 100644 index 00000000000..0b9a78e73dd --- /dev/null +++ b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_casualty_loss_deduction.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class pr_casualty_loss_deduction(Variable): + value_type = float + entity = TaxUnit + label = "Puerto Rico casualty loss deduction on the principal residence" + unit = USD + definition_period = YEAR + reference = ( + # P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(A) + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167", + # Section 1033.05(a): an individual's other losses + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=137", + # 2025 Schedule A Individual, Part I, line 2 + "https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=24", + ) + defined_for = StateCode.PR + + def formula(tax_unit, period, parameters): + p = parameters( + period + ).gov.territories.pr.tax.income.taxable_income.deductions.casualty_loss + # Section 1033.15(a)(10)(A) covers only the principal residence, not + # every casualty or theft loss that the generic casualty_loss input + # holds. Section 1033.05(a) allows other losses of an individual only + # in a trade or business or a transaction entered into for profit. + # A dependent's loss belongs on the dependent's own return. + loss = tax_unit_non_dep_add( + tax_unit, period, ["pr_principal_residence_casualty_loss"] + ) + filing_status = tax_unit("filing_status", period) + separate = filing_status == filing_status.possible_values.SEPARATE + return where(separate, p.separate_percentage, 1) * loss diff --git a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss.py b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss.py new file mode 100644 index 00000000000..ffbcf6a449c --- /dev/null +++ b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class pr_personal_property_casualty_loss(Variable): + value_type = float + entity = Person + label = "Puerto Rico casualty loss on automobiles and household goods" + documentation = ( + "Loss on automobiles, furniture, fixtures and other household goods, " + "excluding jewelry and cash, caused by an earthquake, hurricane, storm, " + "tropical depression or flood in an area the Governor of Puerto Rico " + "designated a disaster area, where the taxpayer claimed the disaster " + "assistance benefits, and not compensated by insurance or otherwise. " + "Enter the loss once, on the head or spouse; a spouse filing a separate " + "return enters the couple's whole loss." + ) + unit = USD + definition_period = YEAR + reference = ( + # P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(B) + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167", + # 2025 Schedule A Individual, Part I, line 5 + "https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=26", + ) diff --git a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_carryover.py b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_carryover.py new file mode 100644 index 00000000000..6cf478a352a --- /dev/null +++ b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_carryover.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class pr_personal_property_casualty_loss_carryover(Variable): + value_type = float + entity = TaxUnit + label = "Puerto Rico personal property casualty loss carried over" + documentation = ( + "Personal property casualty loss from either of the two preceding " + "taxable years that the filer may carry over to this year. Hacienda's " + "instructions describe it as the part of the $5,000 ($2,500 if married " + "filing separately) allowance not claimed in the year of the loss. " + "It counts toward this year's annual cap." + ) + unit = USD + definition_period = YEAR + reference = ( + # P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(B)(i) + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167", + # 2025 Schedule A Individual, Part I, line 5 + "https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=26", + ) diff --git a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_deduction.py b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_deduction.py new file mode 100644 index 00000000000..8d08d7c8169 --- /dev/null +++ b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_personal_property_casualty_loss_deduction.py @@ -0,0 +1,38 @@ +from policyengine_us.model_api import * + + +class pr_personal_property_casualty_loss_deduction(Variable): + value_type = float + entity = TaxUnit + label = "Puerto Rico casualty loss deduction on automobiles and household goods" + unit = USD + definition_period = YEAR + reference = ( + # P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(B) + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167", + # Sections 1061.01(b)(2)(B) and 1021.03(a)(4): spouses filing + # separately split (a)(10) deductions 50/50 + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=321", + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=40", + # 2025 Schedule A Individual, Part I, line 5 + "https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=26", + ) + defined_for = StateCode.PR + + def formula(tax_unit, period, parameters): + p = parameters( + period + ).gov.territories.pr.tax.income.taxable_income.deductions.casualty_loss + # A dependent's loss belongs on the dependent's own return. + loss = tax_unit_non_dep_add( + tax_unit, period, ["pr_personal_property_casualty_loss"] + ) + filing_status = tax_unit("filing_status", period) + separate = filing_status == filing_status.possible_values.SEPARATE + # A spouse filing separately claims half of the couple's loss + # (Sections 1061.01(b)(2)(B) and 1021.03(a)(4)), up to the lower + # separate cap. A carryover from the two preceding years counts + # toward the same annual cap. + own_loss = where(separate, p.separate_percentage, 1) * loss + carryover = tax_unit("pr_personal_property_casualty_loss_carryover", period) + return min_(own_loss + carryover, p.personal_property_cap[filing_status]) diff --git a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_principal_residence_casualty_loss.py b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_principal_residence_casualty_loss.py new file mode 100644 index 00000000000..8ae515d9c03 --- /dev/null +++ b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/casualty_loss/pr_principal_residence_casualty_loss.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class pr_principal_residence_casualty_loss(Variable): + value_type = float + entity = Person + label = "Puerto Rico casualty loss on the principal residence" + documentation = ( + "Loss on the real property that was the taxpayer's principal residence " + "when the event occurred, caused by fire, hurricane, earthquake, storm, " + "tropical depression, flood or another casualty, and not compensated by " + "insurance or otherwise. Enter the loss once, on the head or spouse; a " + "spouse filing a separate return enters the couple's whole loss." + ) + unit = USD + definition_period = YEAR + reference = ( + # P.R. Internal Revenue Code of 2011, Section 1033.15(a)(10)(A)(i) + "https://bvirtualogp.pr.gov/ogp/Bvirtual/leyesreferencia/PDF/2-ingles/1-2011.pdf#page=167", + # 2025 Schedule A Individual, Part I, line 2 + "https://hacienda.pr.gov/sites/default/files/inst_individuals_2025.pdf#page=24", + ) diff --git a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/pr_casualty_loss_deduction.py b/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/pr_casualty_loss_deduction.py deleted file mode 100644 index 81035b9b663..00000000000 --- a/policyengine_us/variables/gov/territories/pr/tax/income/taxable_income/deductions/pr_casualty_loss_deduction.py +++ /dev/null @@ -1,27 +0,0 @@ -from policyengine_us.model_api import * - - -class pr_casualty_loss_deduction(Variable): - value_type = float - entity = TaxUnit - label = "Puerto Rico casualty loss deduction" - unit = USD - definition_period = YEAR - reference = "https://law.justia.com/codes/puerto-rico/title-thirteen/subtitle-17/part-ii/chapter-1005/subchapter-c/30135/" # (10) - defined_for = StateCode.PR - - def formula(tax_unit, period, parameters): - p = parameters( - period - ).gov.territories.pr.tax.income.taxable_income.deductions.casualty_loss - loss = add(tax_unit, period, ["casualty_loss"]) - filing_status = tax_unit("filing_status", period) - - return ( - where( - filing_status == filing_status.possible_values.SEPARATE, - p.separate_percentage, - 1, - ) - * loss - ) diff --git a/policyengine_us/variables/household/expense/tax/casualty_loss.py b/policyengine_us/variables/household/expense/tax/casualty_loss.py index 2a25f13edec..f1d32924ec0 100644 --- a/policyengine_us/variables/household/expense/tax/casualty_loss.py +++ b/policyengine_us/variables/household/expense/tax/casualty_loss.py @@ -5,5 +5,10 @@ class casualty_loss(Variable): value_type = float entity = Person label = "Casualty/theft loss" + documentation = ( + "Puerto Rico's casualty loss deductions do not use this amount. They " + "use pr_principal_residence_casualty_loss and " + "pr_personal_property_casualty_loss instead." + ) unit = USD definition_period = YEAR