diff --git a/policyengine_taxsim/config/variable_mappings.yaml b/policyengine_taxsim/config/variable_mappings.yaml index 3e06d13..572fb26 100644 --- a/policyengine_taxsim/config/variable_mappings.yaml +++ b/policyengine_taxsim/config/variable_mappings.yaml @@ -54,6 +54,31 @@ policyengine_to_taxsim: group_order: 1 full_text_group: "Basic Output" group_column: 1 + special_cases: + - ak: + implemented: false + variable: na_pe + - nv: + implemented: false + variable: na_pe + - sd: + implemented: false + variable: na_pe + - tn: + implemented: false + variable: na_pe + - tx: + implemented: false + variable: na_pe + - fl: + implemented: false + variable: na_pe + - wy: + implemented: false + variable: na_pe + - wa: + implemented: false + variable: na_pe fica: variable: multiple_variable implemented: true @@ -357,8 +382,8 @@ policyengine_to_taxsim: full_text_group: "Federal Tax Calculation" group_column: 1 v30: - variable: na_pe - implemented: false + variable: household_net_income + implemented: true idtl: - full: 2 - full_text: 5 @@ -386,13 +411,6 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 - special_cases: - - mn: - implemented: false - variable: na_pe - - il: - implemented: true - variable: state_base_income v33: variable: state_exemptions implemented: false @@ -413,25 +431,43 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 - special_cases: + pre_simulation: - ms: - implemented: false - variable: na_pe + implemented: true + pre_variable: ms_files_separately + variables: + - ms_standard_deduction_indiv + - ms_standard_deduction_joint - ar: - implemented: false - variable: na_pe + implemented: true + pre_variable: ar_files_separately + variables: + - ar_standard_deduction_indiv + - ar_standard_deduction_joint - mt: - implemented: false - variable: na_pe + implemented: true + pre_variable: mt_files_separately + variables: + - mt_standard_deduction_indiv + - mt_standard_deduction_joint - de: - implemented: false - variable: na_pe + implemented: true + pre_variable: de_files_separately + variables: + - de_standard_deduction_indv + - de_standard_deduction_joint - ia: - implemented: false - variable: na_pe + implemented: true + pre_variable: ia_files_separately + variables: + - ia_standard_deduction_indiv + - ia_standard_deduction_joint - ky: - implemented: false - variable: na_pe + implemented: true + pre_variable: ky_files_separately + variables: + - ky_standard_deduction_indiv + - ky_standard_deduction_joint v35: variable: state_itemized_deductions implemented: true @@ -442,10 +478,43 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 - special_cases: - - il: - implemented: false - variable: na_pe + pre_simulation: + - ms: + implemented: true + pre_variable: ms_files_separately + variables: + - ms_itemized_deductions_indiv + - ms_itemized_deductions_joint + - ar: + implemented: true + pre_variable: ar_files_separately + variables: + - ar_itemized_deductions_indiv + - ar_itemized_deductions_joint + - mt: + implemented: true + pre_variable: mt_files_separately + variables: + - mt_itemized_deductions_indiv + - mt_itemized_deductions_joint + - ia: + implemented: true + pre_variable: ia_files_separately + variables: + - ia_itemized_deductions_indiv + - ia_itemized_deductions_joint + - ky: + implemented: true + pre_variable: ky_files_separately + variables: + - ky_itemized_deductions_indiv + - ky_itemized_deductions_joint + - de: + implemented: true + pre_variable: de_files_separately + variables: + - de_itemized_deductions_indv + - de_itemized_deductions_joint v36: variable: state_taxable_income implemented: true @@ -456,6 +525,43 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 + pre_simulation: + - ms: + implemented: true + pre_variable: ms_files_separately + variables: + - ms_taxable_income_indiv + - ms_taxable_income_joint + - ar: + implemented: true + pre_variable: ar_files_separately + variables: + - ar_taxable_income_indiv + - ar_taxable_income_joint + - mt: + implemented: true + pre_variable: mt_files_separately + variables: + - mt_taxable_income_indiv + - mt_taxable_income_joint + - ia: + implemented: true + pre_variable: ia_files_separately + variables: + - ia_taxable_income_indiv + - ia_taxable_income_joint + - ky: + implemented: true + pre_variable: ky_files_separately + variables: + - ky_taxable_income_indiv + - ky_taxable_income_joint + - de: + implemented: true + pre_variable: de_files_separately + variables: + - de_taxable_income_indv + - de_taxable_income_joint tax_before_credits: variable: state_income_tax_before_non_refundable_credits implemented: true @@ -465,6 +571,31 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 + pre_simulation: + - ar: + implemented: true + pre_variable: ar_files_separately + variables: + - ar_income_tax_before_non_refundable_credits_indiv + - ar_income_tax_before_non_refundable_credits_joint + - mt: + implemented: true + pre_variable: mt_files_separately + variables: + - mt_income_tax_before_non_refundable_credits_indiv + - mt_income_tax_before_non_refundable_credits_joint + - ky: + implemented: true + pre_variable: ky_files_separately + variables: + - ky_income_tax_before_non_refundable_credits_indiv + - ky_income_tax_before_non_refundable_credits_joint + - de: + implemented: true + pre_variable: de_files_separately + variables: + - de_income_tax_before_non_refundable_credits_indv + - de_income_tax_before_non_refundable_credits_joint v41: variable: na_pe implemented: false @@ -484,10 +615,6 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 - special_cases: - - mn: - implemented: false - variable: na_pe rent_credit: variable: na_pe implemented: false @@ -508,10 +635,6 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 - special_cases: - - il: - implemented: false - variable: na_pe v39: variable: state_eitc implemented: true @@ -540,10 +663,6 @@ policyengine_to_taxsim: group_order: 4 full_text_group: "State Tax Calculation" group_column: 1 - special_cases: - - mn: - implemented: false - variable: na_pe v40: variable: multiple_variables implemented: true @@ -555,7 +674,7 @@ policyengine_to_taxsim: full_text_group: "State Tax Calculation" group_column: 1 variables: - - state_non_refundable_credit + - state_non_refundable_credits - state_refundable_credits energy_fuel_credit2: variable: na_pe @@ -924,5 +1043,4 @@ taxsim_input_definition: - pbusinc: name: "27. Txpy/Spouse QBI w/o PO" - pprofinc: - name: "28. Txpy/Spouse SSTB w PO" - + name: "28. Txpy/Spouse SSTB w PO" \ No newline at end of file diff --git a/policyengine_taxsim/core/output_mapper.py b/policyengine_taxsim/core/output_mapper.py index f1c7cff..f9f3c21 100644 --- a/policyengine_taxsim/core/output_mapper.py +++ b/policyengine_taxsim/core/output_mapper.py @@ -9,6 +9,8 @@ def generate_non_description_output(taxsim_output, mappings, year, state_name, simulation, output_type, logs): outputs = [] for key, each_item in mappings.items(): + state_initial = state_name.lower() + if each_item['implemented']: if key == "taxsimid": taxsim_output[key] = taxsim_output["taxsimid"] @@ -18,23 +20,77 @@ def generate_non_description_output(taxsim_output, mappings, year, state_name, s taxsim_output[key] = get_state_number(state_name) elif 'variables' in each_item and len(each_item['variables']) > 0: pe_variables = each_item['variables'] - taxsim_output[key] = simulate_multiple(simulation, pe_variables, year) + + if 'special_cases' in each_item: + found_state = next((each for each in each_item['special_cases'] if state_initial in each), + None) + if found_state and found_state[state_initial]['implemented']: + pe_variable = found_state[state_initial]['variable'].replace("state", + state_initial) if "state" in \ + found_state[ + state_initial][ + 'variable'] else \ + found_state[state_initial]['variable'] + taxsim_output[key] = simulate(simulation, pe_variable, year) + outputs.append({'variable': pe_variable, 'value': taxsim_output[key]}) + else: + taxsim_output[key] = 0.0 + outputs.append({'variable': 'n/a', 'value': taxsim_output[key]}) + + else: + taxsim_output[key] = simulate_multiple(simulation, pe_variables, year, state_initial) + + for pe_variable in pe_variables: + outputs.append({'variable': pe_variable, 'value': taxsim_output[key]}) + else: pe_variable = each_item['variable'] - state_initial = state_name.lower() if "state" in pe_variable: pe_variable = pe_variable.replace("state", state_initial) for entry in each_item['idtl']: if output_type in entry.values(): + state_found = False if 'special_cases' in each_item: - found_state = next((each for each in each_item['special_cases'] if state_initial in each), None) + found_state = next((each for each in each_item['special_cases'] if state_initial in each), + None) if found_state and found_state[state_initial]['implemented']: - pe_variable = found_state[state_initial]['variable'].replace("state", state_initial) if "state" in found_state[state_initial]['variable'] else found_state[state_initial]['variable'] - taxsim_output[key] = simulate(simulation, pe_variable, year) - outputs.append({'variable': pe_variable, 'value': taxsim_output[key]}) + state_found = True + pe_variable = found_state[state_initial]['variable'].replace("state", + state_initial) if "state" in \ + found_state[ + state_initial][ + 'variable'] else \ + found_state[state_initial]['variable'] + taxsim_output[key] = simulate(simulation, pe_variable, year) + outputs.append({'variable': pe_variable, 'value': taxsim_output[key]}) + elif found_state and not found_state[state_initial]['implemented']: + state_found = True + taxsim_output[key] = 0.0 + outputs.append({'variable': 'n/a', 'value': taxsim_output[key]}) + + if 'pre_simulation' in each_item: + found_state = next((each for each in each_item['pre_simulation'] if state_initial in each), + None) + if found_state and found_state[state_initial]['implemented']: + state_found = True + pre_simulation_variable = found_state[state_initial]['pre_variable'] + use_indiv = simulate_to_decide(simulation, pre_simulation_variable, year) + variables = found_state[state_initial]['variables'] + + if use_indiv: + pe_variable = variables[0] + else: + pe_variable = variables[1] + + taxsim_output[key] = simulate(simulation, pe_variable, year) + outputs.append({'variable': pe_variable, 'value': taxsim_output[key]}) + + if not state_found: + taxsim_output[key] = simulate(simulation, pe_variable, year) + outputs.append({'variable': pe_variable, 'value': taxsim_output[key]}) file_name = f"{taxsim_output['taxsimid']}-{state_name}.yaml" generate_pe_tests_yaml(simulation.situation_input, outputs, file_name, logs) @@ -120,14 +176,39 @@ def generate_text_description_output(taxsim_input, mappings, year, state_name, s elif var_name == "state": value = f"{get_state_number(state_name)}{' ' * LEFT_MARGIN}{state_name}" elif 'variables' in each_item and len(each_item['variables']) > 0: - value = simulate_multiple(simulation, each_item['variables'], year) + value = simulate_multiple(simulation, each_item['variables'], year, state_initial) else: if 'special_cases' in each_item: found_state = next((each for each in each_item['special_cases'] if state_initial in each), None) if found_state and found_state[state_initial]['implemented']: - variable = found_state[state_initial]['variable'].replace("state", state_initial) if "state" in found_state[state_initial]['variable'] else found_state[state_initial]['variable'] - value = simulate(simulation, variable, year) - outputs.append({'variable': variable, 'value': value}) + variable = found_state[state_initial]['variable'].replace("state", + state_initial) if "state" in \ + found_state[ + state_initial][ + 'variable'] else \ + found_state[state_initial]['variable'] + value = simulate(simulation, variable, year) + + outputs.append({'variable': variable, 'value': value}) + continue + + if 'pre_simulation' in each_item: + found_state = next((each for each in each_item['pre_simulation'] if state_initial in each), + None) + if found_state and found_state[state_initial]['implemented']: + pre_simulation_variable = found_state[state_initial]['pre_variable'] + use_indiv = simulate_to_decide(simulation, pre_simulation_variable, year) + variables = found_state[state_initial]['variables'] + if use_indiv: + value = simulate(simulation, variables[0], year) + else: + value = simulate(simulation, variables[1], year) + + outputs.append({'variable': variable, 'value': value}) + + else: + value = simulate(simulation, variable, year) + outputs.append({'variable': variable, 'value': value}) # Format the base value if isinstance(value, (int, float)): @@ -138,14 +219,20 @@ def generate_text_description_output(taxsim_input, mappings, year, state_name, s # Format second column value if needed if has_second_column: if 'variables' in each_item and len(each_item['variables']) > 0: - second_value = simulate_multiple(simulation_1dollar_more, each_item['variables'], year) + second_value = simulate_multiple(simulation_1dollar_more, each_item['variables'], year, state_initial) else: if 'special_cases' in each_item: found_state = next((each for each in each_item['special_cases'] if state_initial in each), None) if found_state and found_state[state_initial]['implemented']: - variable = found_state[state_initial]['variable'].replace("state", state_initial) if "state" in found_state[state_initial]['variable'] else found_state[state_initial]['variable'] - second_value = simulate(simulation_1dollar_more, variable, year) + variable = found_state[state_initial]['variable'].replace("state", + state_initial) if "state" in \ + found_state[ + state_initial][ + 'variable'] else \ + found_state[state_initial]['variable'] + second_value = simulate(simulation_1dollar_more, variable, year) + continue if isinstance(second_value, (int, float)): formatted_second_value = f"{second_value:>8.1f}" @@ -316,14 +403,28 @@ def export_household(taxsim_input, policyengine_situation, logs): def simulate(simulation, variable, year): try: - return to_roundedup_number(simulation.calculate(variable, period=year)) + return to_roundedup_number(sum(simulation.calculate(variable, period=year))) except Exception as error: + print(error) return 0.00 -def simulate_multiple(simulation, variables, year): +def simulate_to_decide(simulation, variable, year) -> bool: try: - total = sum(to_roundedup_number(simulation.calculate(variable, period=year)) for variable in variables) + return simulation.calculate(variable, period=year)[0] except Exception as error: - total = 0.00 - return to_roundedup_number(total) + print(error) + return False + + +def simulate_multiple(simulation, variables, year, state): + try: + return to_roundedup_number( + sum( + sum(simulation.calculate(variable.replace("state", state), period=year)) + for variable in variables + ) + ) + except Exception as error: + print(error) + return 0.00