diff --git a/CHANGELOG.md b/CHANGELOG.md index 17cdf5aab..4129c6320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.5] - 2024-11-21 00:30:00 + +### Added + +- Updated and fixed Arkansas parameters, variables and tests. + ## [0.3.4] - 2024-11-14 00:30:00 ### Added @@ -245,6 +251,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - First prototype version based off of openfisca-us and tax-calculator. +[0.3.5]: https://github.com/TheCGO/fiscalsim-us/compare/v0.3.5...v0.3.5 [0.3.4]: https://github.com/TheCGO/fiscalsim-us/compare/v0.3.3...v0.3.4 [0.3.3]: https://github.com/TheCGO/fiscalsim-us/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/TheCGO/fiscalsim-us/compare/v0.3.1...v0.3.2 diff --git a/changelog.yaml b/changelog.yaml index 4abc4d1ac..12c93323d 100644 --- a/changelog.yaml +++ b/changelog.yaml @@ -219,3 +219,8 @@ added: - Updated and fixed Louisiana parameters, variables and tests. date: 2024-11-14 00:30:00 +- bump: patch + changes: + added: + - Updated and fixed Arkansas parameters, variables and tests. + date: 2024-11-21 00:30:00 diff --git a/fiscalsim_us/parameters/gov/irs/income/exemption/traditional_distribution/age_threshold.yaml b/fiscalsim_us/parameters/gov/irs/income/exemption/traditional_distribution/age_threshold.yaml new file mode 100644 index 000000000..57141d588 --- /dev/null +++ b/fiscalsim_us/parameters/gov/irs/income/exemption/traditional_distribution/age_threshold.yaml @@ -0,0 +1,13 @@ +description: The exemption for traditional IRA distributions is limited to filers above this age. +values: + 2021-01-01: 59.5 + +metadata: + unit: currency-USD + period: year + label: Traditional IRA distribution age threshold + reference: + - title: Internal Revenue Services - IRA withdrawal rules + href: https://www.irs.gov/newsroom/what-if-i-withdraw-money-from-my-ira#:~:text=Generally%2C%20early%20withdrawal%20from%20an,premium%20after%20a%20job%20loss. + - title: Publication 590-B (2022), Distributions from Individual Retirement Arrangements (IRAs) - Traditional IRAs - What Acts Result in Penalties or Additional Taxes? - Early Distributions - Age 59½ Rule - After age 59½ and before age 72 + href: https://www.irs.gov/publications/p590b#en_US_2022_publink100090242 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/capital_gains/capital_loss_cap.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/capital_gains/capital_loss_cap.yaml index 25c051fef..0ea5ea45f 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/capital_gains/capital_loss_cap.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/capital_gains/capital_loss_cap.yaml @@ -12,7 +12,7 @@ metadata: - filing_status JOINT: 2022-01-01: 3_000 -WIDOW: +SURVIVING_SPOUSE: 2022-01-01: 3_000 HEAD_OF_HOUSEHOLD: 2022-01-01: 3_000 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_min_income.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_min_income.yaml index bc655b844..3fbbb97bc 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_min_income.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_min_income.yaml @@ -14,7 +14,7 @@ metadata: - filing_status JOINT: 2022-01-01: 27_292 -WIDOW: +SURVIVING_SPOUSE: 2022-01-01: 22_790 HEAD_OF_HOUSEHOLD: 2022-01-01: 22_790 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_phaseout_rate.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_phaseout_rate.yaml index 2f1dae26a..dc1bfecb5 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_phaseout_rate.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/high_dep_inc_tax_credit_phaseout_rate.yaml @@ -12,7 +12,7 @@ metadata: - filing_status JOINT: 2022-01-01: 7 -WIDOW: +SURVIVING_SPOUSE: 2022-01-01: 9 HEAD_OF_HOUSEHOLD: 2022-01-01: 9 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_min_income.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_min_income.yaml index 453d222f1..721eb37fe 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_min_income.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_min_income.yaml @@ -10,12 +10,12 @@ metadata: href: https://codes.findlaw.com/ar/title-26-taxation/ar-code-sect-26-51-301/ - title: Arkansas 2022 Tax Tables href: https://www.dfa.arkansas.gov/images/uploads/incomeTaxOffice/2022_TaxTables.pdf - + breakdown: - filing_status JOINT: 2022-01-01: 22_676 -WIDOW: +SURVIVING_SPOUSE: 2022-01-01: 19_118 HEAD_OF_HOUSEHOLD: 2022-01-01: 19_118 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_phaseout_rate.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_phaseout_rate.yaml index 24c2a80c3..7f1f446c6 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_phaseout_rate.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/low_income_credit/low_dep_inc_tax_credit_phaseout_rate.yaml @@ -8,12 +8,12 @@ metadata: reference: - title: Arkansas Code Title 26. Taxation § 26-51-301. Subsection f href: https://codes.findlaw.com/ar/title-26-taxation/ar-code-sect-26-51-301/ - + breakdown: - filing_status JOINT: 2022-01-01: 7 -WIDOW: +SURVIVING_SPOUSE: 2022-01-01: 6 HEAD_OF_HOUSEHOLD: 2022-01-01: 6 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/other_credits/political_contrib.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/other_credits/political_contrib.yaml index 7310c3758..307592ead 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/other_credits/political_contrib.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/credits/other_credits/political_contrib.yaml @@ -15,7 +15,7 @@ metadata: - filing_status JOINT: 2022-01-01: 100 -WIDOW: +SURVIVING_SPOUSE: 2022-01-01: 50 HEAD_OF_HOUSEHOLD: 2022-01-01: 50 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/high_income_rates.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/high_income_rates.yaml index b9e07f48d..e67961450 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/high_income_rates.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/high_income_rates.yaml @@ -21,9 +21,11 @@ brackets: 2023-01-01: 4_501 rate: 2022-01-01: 0.04 + 2024-01-01: 0.039 - threshold: 2022-01-01: 8_801 2023-01-01: 9_101 + 2024-01-01: .inf rate: 2022-01-01: 0.049 2023-01-01: 0.047 diff --git a/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/rates.yaml b/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/rates.yaml index 6fa12619c..29d3b0c45 100644 --- a/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/rates.yaml +++ b/fiscalsim_us/parameters/gov/states/ar/tax/income/rates/rates.yaml @@ -42,6 +42,7 @@ brackets: 2021-01-01: 0.05 2022-01-01: 0.049 2023-01-01: 0.047 + 2024-01-01: 0.039 - threshold: 2021-01-01: 39_700 2022-01-01: .inf diff --git a/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_low_income_credit.yaml b/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_low_income_credit.yaml index cfc81c2f2..91c5bec20 100644 --- a/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_low_income_credit.yaml +++ b/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_low_income_credit.yaml @@ -1,4 +1,4 @@ -- name: Single household with $11,180 taxable income +- name: Single household with $11,180 taxable income period: 2022 input: state_code: AR @@ -56,7 +56,7 @@ state_code: AR ar_taxable_income: 23_730 tax_unit_dependents: 2 - filing_status: WIDOW + filing_status: SURVIVING_SPOUSE ar_standard_deduction: 2_270 ar_itemized_deductions: 500 ar_agi: 26_000 @@ -69,7 +69,7 @@ state_code: AR ar_taxable_income: 21_730 tax_unit_dependents: 2 - filing_status: WIDOW + filing_status: SURVIVING_SPOUSE ar_standard_deduction: 2_270 ar_itemized_deductions: 500 ar_agi: 24_000 diff --git a/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_personal_credits.yaml b/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_personal_credits.yaml index ce85d2b87..2d65bb3e7 100644 --- a/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_personal_credits.yaml +++ b/fiscalsim_us/tests/policy/baseline/gov/states/ar/tax/income/credits/ar_personal_credits.yaml @@ -9,7 +9,7 @@ age_spouse: 0 ar_head_retirement_income: 0 ar_spouse_retirement_income: 0 - deaf_head: 0 + deaf_head: 0 deaf_spouse: 0 tax_unit_dependents: 0 ar_qual_dependents: 0 @@ -26,12 +26,12 @@ age_spouse: 56 ar_head_retirement_income: 0 ar_spouse_retirement_income: 0 - deaf_head: 0 + deaf_head: 0 deaf_spouse: 0 tax_unit_dependents: 1 ar_qual_dependents: 0 output: - ar_personal_credits: 87 + ar_personal_credits: 58 - name: Joint household, above 65, 0 dependents, no disabilities, no retirement income period: 2022 input: @@ -43,12 +43,12 @@ age_spouse: 87 ar_head_retirement_income: 0 ar_spouse_retirement_income: 0 - deaf_head: 0 + deaf_head: 0 deaf_spouse: 0 tax_unit_dependents: 0 ar_qual_dependents: 0 output: - ar_personal_credits: 174 + ar_personal_credits: 29 - name: Joint household, above 65, 0 dependents, no disabilities, with retirement income period: 2022 input: @@ -60,12 +60,12 @@ age_spouse: 87 ar_head_retirement_income: 20_000 ar_spouse_retirement_income: 20_000 - deaf_head: 0 + deaf_head: 0 deaf_spouse: 0 tax_unit_dependents: 0 ar_qual_dependents: 0 output: - ar_personal_credits: 116 + ar_personal_credits: 29 - name: Joint household, below 65, 2 dependents, 1 with disabilities, spouse is blind and deaf period: 2022 input: @@ -77,9 +77,9 @@ age_spouse: 39 ar_head_retirement_income: 0 ar_spouse_retirement_income: 0 - deaf_head: 0 + deaf_head: 0 deaf_spouse: 1 tax_unit_dependents: 2 ar_qual_dependents: 1 output: - ar_personal_credits: 674 + ar_personal_credits: 587 diff --git a/fiscalsim_us/variables/gov/states/al/tax/income/al_standard_deduction.py b/fiscalsim_us/variables/gov/states/al/tax/income/al_standard_deduction.py index aa882aac9..4dfdaf65e 100644 --- a/fiscalsim_us/variables/gov/states/al/tax/income/al_standard_deduction.py +++ b/fiscalsim_us/variables/gov/states/al/tax/income/al_standard_deduction.py @@ -21,8 +21,8 @@ def formula(tax_unit, period, parameters): threshold = p.phase_out.threshold[filing_status] al_agi = tax_unit("al_agi", period) # No "or fraction thereof" clause, so use integer (floor) division rather than ceiling. - excess_income = max(0, al_agi - threshold) + excess_income = max_(0, al_agi - threshold) increments = excess_income // increment reduction = increments * rate - return max(base_amount - reduction, min_amount) + return max_(base_amount - reduction, min_amount) diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/ar_high_income_reduction.py b/fiscalsim_us/variables/gov/states/ar/tax/income/ar_high_income_reduction.py index 6b5322e40..e49814bf2 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/ar_high_income_reduction.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/ar_high_income_reduction.py @@ -1,5 +1,5 @@ from fiscalsim_us.model_api import * -from numpy import round +import numpy as np class ar_high_income_reduction(Variable): @@ -25,17 +25,37 @@ def formula(tax_unit, period, parameters): def round_to_nearest_50(num): # Calculate the nearest multiple of 100 - nearest_multiple_of_100 = round(num / 100, 0) * 100 + nearest_multiple_of_100 = np.round(num / 100, 0) * 100 # Get the last two digits last_two_digits = num % 100 # Determine the closest ending in "50" - if last_two_digits <= 50 and last_two_digits >= 1: - rounded_income = nearest_multiple_of_100 + 50 - return rounded_income + if np.isscalar(num): + if last_two_digits <= 50 and last_two_digits >= 1: + rounded_income = nearest_multiple_of_100 + 50 + return rounded_income + else: + rounded_income = nearest_multiple_of_100 - 50 + return rounded_income else: - rounded_income = nearest_multiple_of_100 - 50 + rounded_income = np.zeros_like(num) + rounded_income[ + (last_two_digits <= 50) & (last_two_digits >= 1) + ] = ( + nearest_multiple_of_100[ + (last_two_digits <= 50) & (last_two_digits >= 1) + ] + + 50 + ) + rounded_income[ + (last_two_digits > 50) | (last_two_digits < 1) + ] = ( + nearest_multiple_of_100[ + (last_two_digits > 50) | (last_two_digits < 1) + ] + - 50 + ) return rounded_income std_ded = tax_unit("ar_standard_deduction", period) diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/ar_income_tax_before_non_refundable_credits.py b/fiscalsim_us/variables/gov/states/ar/tax/income/ar_income_tax_before_non_refundable_credits.py index 79bd40724..db7b403e5 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/ar_income_tax_before_non_refundable_credits.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/ar_income_tax_before_non_refundable_credits.py @@ -1,5 +1,5 @@ from fiscalsim_us.model_api import * -from numpy import round +import numpy as np class ar_income_tax_before_non_refundable_credits(Variable): @@ -21,31 +21,78 @@ def formula(tax_unit, period, parameters): def round_to_nearest_50(num): # Calculate the nearest multiple of 100 - nearest_multiple_of_100 = round(num / 100, 0) * 100 + nearest_multiple_of_100 = np.round(num / 100, 0) * 100 # Get the last two digits last_two_digits = num % 100 # Determine the closest ending in "50" - if last_two_digits <= 50 and last_two_digits >= 1: - rounded_income = nearest_multiple_of_100 + 50 - return rounded_income + if np.isscalar(num): + if last_two_digits <= 50 and last_two_digits >= 1: + rounded_income = nearest_multiple_of_100 + 50 + return rounded_income + else: + rounded_income = nearest_multiple_of_100 - 50 + return rounded_income else: - rounded_income = nearest_multiple_of_100 - 50 + rounded_income = np.zeros_like(num) + rounded_income[ + (last_two_digits <= 50) & (last_two_digits >= 1) + ] = ( + nearest_multiple_of_100[ + (last_two_digits <= 50) & (last_two_digits >= 1) + ] + + 50 + ) + rounded_income[ + (last_two_digits > 50) | (last_two_digits < 1) + ] = ( + nearest_multiple_of_100[ + (last_two_digits > 50) | (last_two_digits < 1) + ] + - 50 + ) return rounded_income rounded_taxable_income = round_to_nearest_50(taxable_income) - tax = round( - where( - taxable_income <= high_income_threshold, - p.rates.calc(rounded_taxable_income), - p.high_income_rates.calc(rounded_taxable_income), + if np.isscalar(rounded_taxable_income): + tax = np.round( + where( + taxable_income <= high_income_threshold, + p.rates.calc(rounded_taxable_income), + p.high_income_rates.calc(rounded_taxable_income), + ) + - litc + - high_income_reduction, + 0, + ) + else: + tax = np.zeros_like(rounded_taxable_income) + tax[taxable_income <= high_income_threshold] = np.round( + p.rates.calc( + rounded_taxable_income[ + taxable_income <= high_income_threshold + ] + ) + - litc[taxable_income <= high_income_threshold] + - high_income_reduction[ + taxable_income <= high_income_threshold + ], + 0, + ) + tax[taxable_income > high_income_threshold] = np.round( + p.high_income_rates.calc( + rounded_taxable_income[ + taxable_income > high_income_threshold + ] + ) + - litc[taxable_income > high_income_threshold] + - high_income_reduction[ + taxable_income > high_income_threshold + ], + 0, ) - - litc - - high_income_reduction, - 0, - ) lump_sum_dist_tax = tax_unit("ar_lump_sum_dist_tax", period) diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/ar_retirement_or_disability_benefits_exemption_person.py b/fiscalsim_us/variables/gov/states/ar/tax/income/ar_retirement_or_disability_benefits_exemption_person.py new file mode 100644 index 000000000..4ade9e3bf --- /dev/null +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/ar_retirement_or_disability_benefits_exemption_person.py @@ -0,0 +1,30 @@ +from fiscalsim_us.model_api import * + + +class ar_retirement_or_disability_benefits_exemption_person(Variable): + value_type = float + entity = Person + label = "Arkansas individual retirement or disability benefits exemption" + unit = USD + definition_period = YEAR + reference = "https://www.dfa.arkansas.gov/images/uploads/incomeTaxOffice/2022_AR1000F_and_AR1000NR_Instructions.pdf#page=13" + defined_for = StateCode.AR + + def formula(person, period, parameters): + p = parameters( + period + ).gov.irs.income.exemption.traditional_distribution + # Only head or spouse of the tax unit will have this exemption + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + disability_benefits_and_taxable_pensions = add( + person, period, ["disability_benefits", "taxable_pension_income"] + ) + # Filers over a certain age can deduct IRA distributions in addition to pension income + ira_age_eligible = person("age", period) >= p.age_threshold + age_eligible_ira_distributions = ira_age_eligible * person( + "taxable_ira_distributions", period + ) + return head_or_spouse * ( + disability_benefits_and_taxable_pensions + + age_eligible_ira_distributions + ) diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/capital_gains/ar_capital_gains.py b/fiscalsim_us/variables/gov/states/ar/tax/income/capital_gains/ar_capital_gains.py index ad760f35f..066a854de 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/capital_gains/ar_capital_gains.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/capital_gains/ar_capital_gains.py @@ -41,10 +41,10 @@ def formula(person, period, parameters): ar_st_gain < 0, where( ar_lt_gain + ar_st_gain >= 0, - min(max_taxable_gain, ar_lt_gain + ar_st_gain), + min_(max_taxable_gain, ar_lt_gain + ar_st_gain), ar_lt_gain + ar_st_gain, ), - min(ar_lt_gain, max_taxable_gain), + min_(ar_lt_gain, max_taxable_gain), ) ar_taxable_amount = where( diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_low_income_credit.py b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_low_income_credit.py index 0cd30e0b5..2fb1edfbd 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_low_income_credit.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_low_income_credit.py @@ -1,6 +1,5 @@ from fiscalsim_us.model_api import * import numpy as np -from numpy import round class ar_low_income_credit(Variable): @@ -49,17 +48,27 @@ def formula(tax_unit, period, parameters): def round_to_nearest_50(num): # Calculate the nearest multiple of 100 - nearest_multiple_of_100 = round(num / 100) * 100 + nearest_multiple_of_100 = np.round(num / 100) * 100 # Get the last two digits last_two_digits = num % 100 # Determine the closest ending in "50" - if last_two_digits <= 50: - rounded_income = nearest_multiple_of_100 + 50 - return rounded_income + if np.isscalar(num): + if last_two_digits <= 50: + rounded_income = nearest_multiple_of_100 + 50 + return rounded_income + else: + rounded_income = nearest_multiple_of_100 - 50 + return rounded_income else: - rounded_income = nearest_multiple_of_100 - 50 + rounded_income = np.zeros_like(num) + rounded_income[last_two_digits <= 50] = ( + nearest_multiple_of_100[last_two_digits <= 50] + 50 + ) + rounded_income[last_two_digits > 50] = ( + nearest_multiple_of_100[last_two_digits > 50] - 50 + ) return rounded_income std_ded = tax_unit("ar_standard_deduction", period) @@ -75,7 +84,7 @@ def round_to_nearest_50(num): # Calculate the tax liability on min_income min_tax_liability = tax_rate.calc(rounded_min_income) - min_tax_liability = round(min_tax_liability) + min_tax_liability = np.round(min_tax_liability) # Calculate the credit amount credit_amount = min_tax_liability * credit_rate @@ -93,14 +102,23 @@ def round_to_nearest_50(num): credit_amount -= phaseout_reduction # Ensure credit_amount does not go below 0 and that those who itemize or are married filing separately do not take the credit - credit_amount = where( - credit_amount < 0 - or std_ded < itm_ded - or filing_status == "SEPARATE", - 0, - credit_amount, - ) - - credit_amount = round(credit_amount, 0) + if np.isscalar(credit_amount): + credit_amount = where( + credit_amount < 0 + or std_ded < itm_ded + or filing_status == "SEPARATE", + 0, + credit_amount, + ) + else: + credit_amount[ + ( + (credit_amount < 0) + | (std_ded < itm_ded) + | (filing_status == "SEPARATE") + ) + ] = 0 + + credit_amount = np.round(credit_amount, 0) return credit_amount diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_personal_credits.py b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_personal_credits.py index 98b29696a..2dd8b7c3a 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_personal_credits.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/ar_personal_credits.py @@ -1,4 +1,5 @@ from fiscalsim_us.model_api import * +import numpy as np class ar_personal_credits(Variable): @@ -12,67 +13,44 @@ class ar_personal_credits(Variable): defined_for = StateCode.AR def formula(tax_unit, period, parameters): - personal_credit_amount = parameters( - period - ).gov.states.ar.tax.income.credits.personal.personal_credit_amount - filing_status = tax_unit("filing_status", period) - married_status = filing_status.possible_values.JOINT - self_and_spouse_credit = ( - where(filing_status == married_status, 2, 1) - * personal_credit_amount - ) - - blind_head = tax_unit("blind_head", period).astype(int) - blind_spouse = tax_unit("blind_spouse", period).astype(int) * 1 - blind_credit = (blind_head + blind_spouse) * personal_credit_amount - - age_threshold = parameters( - period - ).gov.states.ar.tax.income.credits.personal.age_threshold - aged_head = where( - tax_unit("age_head", period).astype(int) >= age_threshold, 1, 0 - ) - aged_spouse = where( - tax_unit("age_spouse", period).astype(int) >= age_threshold, 1, 0 - ) - aged_credit = (aged_head + aged_spouse) * personal_credit_amount - - head_retirement_income = tax_unit("ar_head_retirement_income", period) - spouse_retirement_income = tax_unit( - "ar_spouse_retirement_income", period - ) - aged_special_head = where( - aged_head == 1 and head_retirement_income <= 0, 1, 0 + p = parameters(period).gov.states.ar.tax.income.credits.personal + personal_credit_amount = p.personal_credit_amount + person = tax_unit.members + aged = person("age", period) >= p.age_threshold + receives_retirement_or_disability_exemption = ( + person( + "ar_retirement_or_disability_benefits_exemption_person", period + ) + > 0 ) - aged_special_spouse = where( - aged_spouse == 1 and spouse_retirement_income <= 0, 1, 0 - ) - - aged_special_credit = ( - aged_special_head + aged_special_spouse - ) * personal_credit_amount + aged_special = aged & ~receives_retirement_or_disability_exemption + # Only head and spouse are eligible for the personal credit amounts + head_or_spouse = person("is_tax_unit_head_or_spouse", period) + # Blind filers get an additional personal tax credit amount + blind = person("is_blind", period) + # Deaf filers get an additional personal tax credit amount + deaf = person("is_deaf", period) - # I created "is_deaf", "deaf_head", and "deaf_spouse" myself - deaf_head = tax_unit("deaf_head", period).astype(int) - deaf_spouse = tax_unit("deaf_spouse", period).astype(int) * 1 - deaf_credit = (deaf_head + deaf_spouse) * personal_credit_amount + # Widowed and head of household filers receive an additional credit + # amount + filing_status = tax_unit("filing_status", period) + statuses = filing_status.possible_values + widow = filing_status == statuses.SURVIVING_SPOUSE + hoh = filing_status == statuses.HEAD_OF_HOUSEHOLD + whoh_filing_status_eligible = widow | hoh - hoh_status = ( - filing_status.possible_values.HEAD_OF_HOUSEHOLD - or filing_status.possible_values.WIDOW - ) - hoh_credit = ( - where(filing_status == hoh_status, 1, 0) * personal_credit_amount - ) + personal_credit_count = tax_unit.sum( + head_or_spouse + * ( + 1 + + aged.astype(int) + + blind.astype(int) + + deaf.astype(int) + + aged_special.astype(int) + ) + ) + whoh_filing_status_eligible.astype(int) - personal_credit = ( - self_and_spouse_credit - + blind_credit - + aged_credit - + aged_special_credit - + deaf_credit - + hoh_credit - ) + personal_credit = personal_credit_count * personal_credit_amount dependents = tax_unit("tax_unit_dependents", period) dependent_credit_amount = parameters( diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_inflationary_relief_tax_credit.py b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_inflationary_relief_tax_credit.py index 97808ac81..b01c3823c 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_inflationary_relief_tax_credit.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_inflationary_relief_tax_credit.py @@ -22,7 +22,7 @@ def formula(tax_unit, period, parameters): reduction_start = p.reduction.start[filing_status] increment = p.reduction.increment[filing_status] reduction_per_increment = p.reduction.amount[filing_status] - excess = max(income - reduction_start, 0) + excess = max_(income - reduction_start, 0) increments = np.ceil(excess / increment) total_reduction_amount = increments * reduction_per_increment - return max(max_amount - total_reduction_amount, 0) + return max_(max_amount - total_reduction_amount, 0) diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_metabolic_disorder_credit.py b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_metabolic_disorder_credit.py index 1bf24774e..36cdd9577 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_metabolic_disorder_credit.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_metabolic_disorder_credit.py @@ -23,7 +23,7 @@ def formula(tax_unit, period, parameters): total_available = expenses + carryover - total_allowable_credit = min(maximum_credit, total_available) + total_allowable_credit = min_(maximum_credit, total_available) tax_due = tax_unit("ar_income_tax_before_non_refundable_credits", period) -tax_unit("ar_personal_credits", period) - tax_unit( @@ -40,6 +40,6 @@ def formula(tax_unit, period, parameters): - tax_unit("ar_cdcc", period) ) - credit = min(total_allowable_credit, tax_due) + credit = min_(total_allowable_credit, tax_due) return credit diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_stillborn_child_credit.py b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_stillborn_child_credit.py index 037e659f1..7cf86475a 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_stillborn_child_credit.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/credits/other_credits/ar_stillborn_child_credit.py @@ -12,7 +12,7 @@ class ar_stillborn_child_credit(Variable): defined_for = StateCode.AR def formula(tax_unit, period, parameters): - p = parameters(period).gov.states.ar.income.credits.other_credits + p = parameters(period).gov.states.ar.tax.income.credits.other_credits amount = p.stillbirth_credit diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions.py b/fiscalsim_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions.py index 72401c907..31f467b82 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/deductions/itemized/ar_itemized_deductions.py @@ -17,9 +17,9 @@ def formula(tax_unit, period, parameters): period ).gov.states.ar.tax.income.deductions.itemized.medical - agi_portion = max(0, agi * medical_threshold) + agi_portion = max_(0, agi * medical_threshold) - medical_deduction = max(0, medical_expense - agi_portion) + medical_deduction = max_(0, medical_expense - agi_portion) real_estate_tax = add(tax_unit, period, ["real_estate_taxes"]) @@ -50,7 +50,7 @@ def formula(tax_unit, period, parameters): misc_limit = agi * misc_limit_pct - misc_deductions = max(0, line_22 - misc_limit) + misc_deductions = max_(0, line_22 - misc_limit) other_misc_deductions = tax_unit("ar_other_misc_deductions", period) diff --git a/fiscalsim_us/variables/gov/states/ar/tax/income/lump_sum_dist/ar_lump_sum_dist_tax.py b/fiscalsim_us/variables/gov/states/ar/tax/income/lump_sum_dist/ar_lump_sum_dist_tax.py index b14d064d4..3c0fd8d86 100644 --- a/fiscalsim_us/variables/gov/states/ar/tax/income/lump_sum_dist/ar_lump_sum_dist_tax.py +++ b/fiscalsim_us/variables/gov/states/ar/tax/income/lump_sum_dist/ar_lump_sum_dist_tax.py @@ -81,11 +81,11 @@ def formula(tax_unit, period, parameters): line_4_max = p.min_allowance_multiple1_max line_4_multiple = p.min_allowance_multiple1 - line_4 = min(line_4_max, taxable_dist * line_4_multiple) + line_4 = min_(line_4_max, taxable_dist * line_4_multiple) min_allowance_subtraction = p.min_allowance_subtract - line_5 = max(0, taxable_dist - min_allowance_subtraction) + line_5 = max_(0, taxable_dist - min_allowance_subtraction) line_6_multiple = p.min_allowance_multiple2 @@ -108,7 +108,7 @@ def formula(tax_unit, period, parameters): # line_9_reduction = high_income_reduction(line_9) line_9_reduction = high_income_reduction.calc(line_9) - line_9_tax = round( + line_9_tax = round_( where( line_9 <= high_income_threshold, parameters(period).gov.states.ar.tax.income.rates.rates.calc( @@ -140,7 +140,7 @@ def formula(tax_unit, period, parameters): line_15_reduction = high_income_reduction.calc(line_15) - line_15_tax = round( + line_15_tax = round_( where( line_15 <= high_income_threshold, parameters(period).gov.states.ar.tax.income.rates.rates.calc( diff --git a/fiscalsim_us/variables/gov/states/mt/tax/income/deductions/itemized/mt_state_local_tax_deduction.py b/fiscalsim_us/variables/gov/states/mt/tax/income/deductions/itemized/mt_state_local_tax_deduction.py index 7fe46addc..ed5428e58 100644 --- a/fiscalsim_us/variables/gov/states/mt/tax/income/deductions/itemized/mt_state_local_tax_deduction.py +++ b/fiscalsim_us/variables/gov/states/mt/tax/income/deductions/itemized/mt_state_local_tax_deduction.py @@ -34,4 +34,4 @@ def formula(tax_unit, period, parameters): period ).gov.state.mt.tax.income.deductions.itemized.misc cap = salt.salt_cap[tax_unit("filing_status", period)] - return min(cap, salt_amount) + return min_(cap, salt_amount) diff --git a/fiscalsim_us/variables/gov/states/mt/tax/income/main/mt_taxable_income.py b/fiscalsim_us/variables/gov/states/mt/tax/income/main/mt_taxable_income.py index 5ff513a2a..dee03d28e 100644 --- a/fiscalsim_us/variables/gov/states/mt/tax/income/main/mt_taxable_income.py +++ b/fiscalsim_us/variables/gov/states/mt/tax/income/main/mt_taxable_income.py @@ -19,7 +19,7 @@ def formula(tax_unit, period, parameters): itm_ded = tax_unit("mt_itemized_deductions", period) deductions = where(itm_ded > std_ded, itm_ded, std_ded) exemptions = tax_unit("mt_exemptions", period) - return max( + return max_( 0, tax_unit("mt_agi", period) - deductions - exemptions, ) diff --git a/fiscalsim_us/variables/gov/states/tax/income/state_income_tax.py b/fiscalsim_us/variables/gov/states/tax/income/state_income_tax.py index a1ce6cea6..864ff028b 100644 --- a/fiscalsim_us/variables/gov/states/tax/income/state_income_tax.py +++ b/fiscalsim_us/variables/gov/states/tax/income/state_income_tax.py @@ -9,6 +9,7 @@ class state_income_tax(Variable): definition_period = YEAR adds = [ # state income tax variables listed in alphabetical order: + "ar_income_tax", "ca_income_tax", "co_income_tax", "dc_income_tax", diff --git a/fiscalsim_us/variables/gov/states/tax/income/state_income_tax_before_refundable_credits.py b/fiscalsim_us/variables/gov/states/tax/income/state_income_tax_before_refundable_credits.py index abade4ee9..563af106f 100644 --- a/fiscalsim_us/variables/gov/states/tax/income/state_income_tax_before_refundable_credits.py +++ b/fiscalsim_us/variables/gov/states/tax/income/state_income_tax_before_refundable_credits.py @@ -8,6 +8,7 @@ class state_income_tax_before_refundable_credits(Variable): unit = USD definition_period = YEAR adds = [ + "ar_income_tax_before_refundable_credits", "ca_income_tax_before_refundable_credits", "co_income_tax_before_refundable_credits", "dc_income_tax_before_refundable_credits", diff --git a/fiscalsim_us/variables/household/income/household/household_refundable_tax_credits.py b/fiscalsim_us/variables/household/income/household/household_refundable_tax_credits.py index 836775bc1..f63d50d1b 100644 --- a/fiscalsim_us/variables/household/income/household/household_refundable_tax_credits.py +++ b/fiscalsim_us/variables/household/income/household/household_refundable_tax_credits.py @@ -9,6 +9,7 @@ class household_refundable_tax_credits(Variable): unit = USD adds = [ "income_tax_refundable_credits", # Federal + "ar_refundable_credits", # Arkansas "ca_refundable_credits", # California "co_refundable_credits", # Colorado "dc_refundable_credits", # District of Columbia diff --git a/fiscalsim_us/variables/household/income/household/household_state_income_tax.py b/fiscalsim_us/variables/household/income/household/household_state_income_tax.py index 51d5622e2..48e031b03 100644 --- a/fiscalsim_us/variables/household/income/household/household_state_income_tax.py +++ b/fiscalsim_us/variables/household/income/household/household_state_income_tax.py @@ -9,6 +9,7 @@ class household_state_income_tax(Variable): unit = USD definition_period = YEAR adds = [ + "ar_income_tax_before_refundable_credits", "ca_income_tax_before_refundable_credits", "co_income_tax_before_refundable_credits", "dc_income_tax_before_refundable_credits", diff --git a/fiscalsim_us/variables/household/income/household/household_tax_before_refundable_credits.py b/fiscalsim_us/variables/household/income/household/household_tax_before_refundable_credits.py index f11aecbb3..5ee735618 100644 --- a/fiscalsim_us/variables/household/income/household/household_tax_before_refundable_credits.py +++ b/fiscalsim_us/variables/household/income/household/household_tax_before_refundable_credits.py @@ -12,6 +12,7 @@ class household_tax_before_refundable_credits(Variable): "employee_payroll_tax", "self_employment_tax", "income_tax_before_refundable_credits", # Federal. + "ar_income_tax_before_refundable_credits", "ca_income_tax_before_refundable_credits", "co_income_tax_before_refundable_credits", "dc_income_tax_before_refundable_credits", diff --git a/setup.py b/setup.py index e478525bf..7de3cb2d0 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name="fiscalsim-us", - version="0.3.4", + version="0.3.5", author="Richard W. Evans", author_email="rick@abundance.institute", long_description=readme,