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..30e8a920d18 --- /dev/null +++ b/changelog.d/fix-ar-pr-casualty-loss.fixed.md @@ -0,0 +1 @@ +Exclude dependents' casualty losses from Arkansas returns, apply each separate-filing spouse's casualty reduction and AGI floor before proration, and limit Puerto Rico's casualty deductions to the two statutory items with the personal-property cap. diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/exclusion.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/exclusion.yaml index f305b0503da..debce7be6a3 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/exclusion.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/exclusion.yaml @@ -11,8 +11,10 @@ metadata: href: https://www.arkleg.state.ar.us/Acts/FTPDocument?path=%2FACTS%2F2009R%2FPublic%2F&file=372.pdf&ddBienniumSession=2009%2F2009R#page=5 - title: Act 372 of 2009, § 25 (effective for tax years beginning on or after January 1, 2009) href: https://www.arkleg.state.ar.us/Acts/FTPDocument?path=%2FACTS%2F2009R%2FPublic%2F&file=372.pdf&ddBienniumSession=2009%2F2009R#page=10 - - title: 26 U.S.C. § 165(h), 2008 edition (as in effect on January 1, 2009) - href: https://www.govinfo.gov/content/pkg/USCODE-2008-title26/html/USCODE-2008-title26-subtitleA-chap1-subchapB-partVI-sec165.htm + - title: 26 U.S.C. § 165(h)(1), 2011 edition (individual casualty loss limitation adopted by Ark. Code § 26-51-424(b)) + href: https://www.govinfo.gov/content/pkg/USCODE-2011-title26/pdf/USCODE-2011-title26-subtitleA-chap1-subchapB-partVI-sec165.pdf#page=1 + - title: 26 U.S.C. § 165(h)(5)(B), 2011 edition (joint-return spouses treated as one individual) + href: https://www.govinfo.gov/content/pkg/USCODE-2011-title26/pdf/USCODE-2011-title26-subtitleA-chap1-subchapB-partVI-sec165.pdf#page=2 - title: 2018 Arkansas Form AR4684, Line 11 href: https://www.dfa.arkansas.gov/wp-content/uploads/2018_Final_AR4684_BC_FI.pdf#page=1 - title: 2025 Arkansas Form AR4684, Line 11 diff --git a/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/income_floor.yaml b/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/income_floor.yaml index 1c368b1a9b9..e6735874551 100644 --- a/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/income_floor.yaml +++ b/policyengine_us/parameters/gov/states/ar/tax/income/deductions/itemized/casualty_loss/income_floor.yaml @@ -10,8 +10,10 @@ metadata: href: https://www.arkleg.state.ar.us/Acts/FTPDocument?path=%2FACTS%2F2009R%2FPublic%2F&file=372.pdf&ddBienniumSession=2009%2F2009R#page=5 - title: Act 372 of 2009, § 25 (effective for tax years beginning on or after January 1, 2009) href: https://www.arkleg.state.ar.us/Acts/FTPDocument?path=%2FACTS%2F2009R%2FPublic%2F&file=372.pdf&ddBienniumSession=2009%2F2009R#page=10 - - title: 26 U.S.C. § 165(h), 2008 edition (as in effect on January 1, 2009) - href: https://www.govinfo.gov/content/pkg/USCODE-2008-title26/html/USCODE-2008-title26-subtitleA-chap1-subchapB-partVI-sec165.htm + - title: 26 U.S.C. § 165(h)(2)(A)(ii), 2011 edition (individual casualty loss limitation adopted by Ark. Code § 26-51-424(b)) + href: https://www.govinfo.gov/content/pkg/USCODE-2011-title26/pdf/USCODE-2011-title26-subtitleA-chap1-subchapB-partVI-sec165.pdf#page=1 + - title: 26 U.S.C. § 165(h)(5)(B), 2011 edition (joint-return spouses treated as one individual) + href: https://www.govinfo.gov/content/pkg/USCODE-2011-title26/pdf/USCODE-2011-title26-subtitleA-chap1-subchapB-partVI-sec165.pdf#page=2 - title: 2025 Arkansas Form AR4684, Line 17 href: https://www.dfa.arkansas.gov/wp-content/uploads/2025_AR4684_Casualties_and_Thefts.pdf#page=1 - title: 2015 Arkansas Individual Income Tax Instructions, Form AR3 Line 18 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..9707015f16c 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,23 +55,110 @@ output: ar_casualty_loss_deduction_indiv: 0 -- name: 2025, losses of both spouses are treated as one casualty - # 12,000 + 8,000 - 100 - 10% * (30,000 + 20,000) = 14,900 - period: 2025 +- name: 2017, separate spouses each apply the casualty reduction and AGI floor + # (12,000 - 100 - 3,000) + (8,000 - 100 - 2,000) = 14,800. + period: 2017 input: people: person1: + age: 40 casualty_loss: 12_000 ar_agi_indiv: 30_000 person2: + age: 40 casualty_loss: 8_000 ar_agi_indiv: 20_000 tax_units: tax_unit: members: [person1, person2] + filing_status: JOINT households: household: members: [person1, person2] state_code: AR output: - ar_casualty_loss_deduction_indiv: 14_900 + ar_casualty_loss_deduction_indiv: 14_800 + +- name: 2025, a spouse without a casualty does not supply an additional AGI floor + # max(0, 12,000 - 100 - 3,000) + max(0, 0 - 100 - 2,000) = 8,900. + period: 2025 + input: + people: + person1: + age: 40 + casualty_loss: 12_000 + ar_agi_indiv: 30_000 + person2: + age: 40 + casualty_loss: 0 + ar_agi_indiv: 20_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_casualty_loss_deduction_indiv: 8_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 apply separate casualty limits and leave out a dependent's loss + # (12,000 - 100 - 3,000) + (8,000 - 100 - 2,000) = 14,800; + # 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_800 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 baf51c21542..7ebdf1c40ba 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 @@ -87,6 +87,56 @@ 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 + - name: A spouse's loss that makes the joint AGI negative does not raise the casualty loss deduction period: 2024 input: 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 2143354aae2..75a77418b7a 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 @@ -81,6 +81,60 @@ 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. Apply that spouse's casualty limitations: + # 20,100 - 100 - 10% * 40,000 = 16,000. + # AR3 lines 31-35 split the line 30 total by AGI share: + # 60% * 16,000 = 9,600 and 40% * 16,000 = 6,400. + 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: 16_000 + ar_itemized_deductions_indiv: [9_600, 6_400] + +- name: 2025, separate casualty limitations precede AR3 proration + # (12,000 - 100 - 3,000) + (8,000 - 100 - 2,000) = 14,800. + # AR3 prorates this total 60% and 40%: 8,880 and 5,920. + period: 2025 + input: + people: + person1: + age: 40 + casualty_loss: 12_000 + ar_agi_indiv: 30_000 + person2: + age: 40 + casualty_loss: 8_000 + ar_agi_indiv: 20_000 + tax_units: + tax_unit: + members: [person1, person2] + filing_status: JOINT + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_casualty_loss_deduction_indiv: 14_800 + ar_itemized_deductions_indiv: [8_880, 5_920] + - name: 2020 gambling loss deduction is prorated by AGI when married filing separately period: 2020 input: 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..4587e291076 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 @@ -8,8 +8,10 @@ and § 26-51-424(b) (26 U.S.C. § 165(h) as in effect on January 1, 2009); - they are non-negative, never exceed the expenses or the loss after the exclusion, rise with expenses or losses, and fall with Arkansas AGI; -- the joint and separate variants agree on the same inputs; +- the joint and separate variants agree for a single filer; +- separate spouses apply their casualty reduction and AGI floor individually; - 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. """ @@ -70,7 +72,7 @@ def misc_reference(expenses, agi): def casualty_reference(loss, agi, year): after_exclusion = np.maximum(0, loss - casualty_exclusion(year)) - return np.maximum(0, after_exclusion - CASUALTY_FLOOR * agi) + return np.maximum(0, after_exclusion - CASUALTY_FLOOR * np.maximum(agi, 0)) def assert_monotone(values, amount, agi): @@ -156,3 +158,118 @@ 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 + + +SPOUSE_INPUTS = [ + (0, -10_000), + (0, 0), + (0, 50_000), + (50, 10_000), + (5_100, 50_000), + (8_000, 20_000), + (12_000, 30_000), + (250_000, 1_000_000), +] + + +@pytest.mark.parametrize("year", [2017, 2025]) +def test_separate_spouses_apply_individual_casualty_limits(year): + """Separate filers each apply § 165(h)'s limits before AR3 proration. + + Cover unequal losses and AGIs, a spouse without a loss (including with + negative AGI), losses below their own floor, and invariance to dependent + losses. Joint filers keep one exclusion and the combined AGI floor under + § 165(h)(5)(B). + """ + grid = list(itertools.product(SPOUSE_INPUTS, SPOUSE_INPUTS, DEPENDENT_LOSSES)) + situation = {"people": {}, "tax_units": {}, "households": {}} + for i, (head_inputs, spouse_inputs, dependent_loss) in enumerate(grid): + head, spouse, dependent = f"h{i}", f"s{i}", f"d{i}" + for person, (loss, agi), is_head, is_spouse in ( + (head, head_inputs, True, False), + (spouse, spouse_inputs, False, True), + (dependent, (dependent_loss, 0), False, False), + ): + situation["people"][person] = { + "age": {year: 10 if person == dependent else 40}, + "is_tax_unit_head": {year: is_head}, + "is_tax_unit_spouse": {year: is_spouse}, + "is_tax_unit_dependent": {year: person == dependent}, + "casualty_loss": {year: loss}, + "ar_agi_joint": {year: agi}, + "ar_agi_indiv": {year: agi}, + } + situation["tax_units"][f"t{i}"] = { + "members": [head, spouse, dependent], + "filing_status": {year: "JOINT"}, + } + situation["households"][f"hh{i}"] = { + "members": [head, spouse, dependent], + "state_code": {year: "AR"}, + } + + head_loss = np.array([g[0][0] for g in grid], dtype=float) + head_agi = np.array([g[0][1] for g in grid], dtype=float) + spouse_loss = np.array([g[1][0] for g in grid], dtype=float) + spouse_agi = np.array([g[1][1] for g in grid], dtype=float) + expected = casualty_reference(head_loss, head_agi, year) + casualty_reference( + spouse_loss, spouse_agi, year + ) + sim = Simulation(situation=situation) + separate = sim.calculate("ar_casualty_loss_deduction_indiv", year) + joint = sim.calculate("ar_casualty_loss_deduction_joint", year) + np.testing.assert_allclose(separate, expected) + np.testing.assert_allclose( + joint, + casualty_reference(head_loss + spouse_loss, head_agi + spouse_agi, year), + ) + assert np.all(separate >= 0) + assert np.all(separate <= head_loss + spouse_loss) + # Each group differs only in dependent loss, so all results must agree. + dependent_results = separate.reshape(-1, len(DEPENDENT_LOSSES)) + assert np.all(dependent_results == dependent_results[:, :1]) + # Guard against a vacuous pass: the grid distinguishes the two methods. + assert np.any(separate > joint) and np.any(separate < joint) 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..4be0295c1f4 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 @@ -10,10 +10,15 @@ class ar_casualty_loss_deduction_indiv(Variable): reference = ( # Ark. Code § 26-51-424(b), as amended by Act 372 of 2009, § 17 "https://www.arkleg.state.ar.us/Acts/FTPDocument?path=%2FACTS%2F2009R%2FPublic%2F&file=372.pdf&ddBienniumSession=2009%2F2009R#page=5", - "https://www.govinfo.gov/content/pkg/USCODE-2008-title26/html/USCODE-2008-title26-subtitleA-chap1-subchapB-partVI-sec165.htm", + # Incorporated IRC § 165(h)(1)-(2) and (5)(B), 2011 edition + "https://www.govinfo.gov/content/pkg/USCODE-2011-title26/pdf/USCODE-2011-title26-subtitleA-chap1-subchapB-partVI-sec165.pdf#page=1", + "https://www.govinfo.gov/content/pkg/USCODE-2011-title26/pdf/USCODE-2011-title26-subtitleA-chap1-subchapB-partVI-sec165.pdf#page=2", # 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 +26,14 @@ 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"]) + # Incorporated IRC § 165(h)(1)-(2) applies the exclusion and AGI + # floor to each separate filer; only joint-return spouses count as + # one individual under § 165(h)(5)(B). The input records one + # casualty event per person. AR3 subsequently prorates the total + # itemized deductions by AGI in ar_itemized_deductions_indiv. + loss = tax_unit.members("casualty_loss", period) 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) + agi = max_(tax_unit.members("ar_agi_indiv", period), 0) + deduction = max_(0, loss_after_exclusion - p.income_floor * agi) + non_dependent = not_(tax_unit.members("is_tax_unit_dependent", period)) + return tax_unit.sum(deduction * non_dependent) 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 5116e6cfe8b..f4695831be8 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) # A spouse's loss can make the joint AGI total negative; floor it at # zero so a negative AGI cannot enlarge the deduction. 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