iza-institute-of-labor-economics / gettsim

The GErman Taxes and Transfers SIMulator
https://gettsim.readthedocs.io/
GNU Affero General Public License v3.0
56 stars 33 forks source link

Correct calculation of Lohnsteuer for 2015 to 2023 #655

Closed JakobWegmann closed 1 year ago

JakobWegmann commented 1 year ago

What problem do you want to solve?

So far, the Lohnsteuer is only tested for 2022. This PR adds tests for additional years and expands the code if necessary. This also requires multiple changes in the generation of the test data in gettsim-code-for-picking which are collected in this PR.

Todo

JakobWegmann commented 1 year ago

@hmgaudecker: Some advice is needed :)

The Grundfreibetrag 2015 was changed in July 2015 for the calculation of the income tax 2015. This parameter change is implemented in eink_st.yaml as:

2015-01-01:
    deviation_from: previous
    note: Gesetz z. Anhebung des Gfb, des Kfb, des Kindergeldes und des Kiz
    reference: G. v. 15.07.2015, BGBl. Nr. 30 2015
    0:
      upper_threshold: 8472

However, the Lohnsteuer 2015 (except Dezember) was calculated based on the old Grundfreibetrag of 8354€.

So there are two possible solutions:

  1. Changing the date of the policy reform of the Grundfreibetrag to any day after the 1st of January 2015.
  2. Calculating the Lohnsteuer slightly wrong in 2015 (and consequently removing the tests of Lohnsteuer for 2015)

Some more context on option 1: Together with @MImmesberger we tried to implement solution 1. We change the date of the introduction to July 2015:

2015-01-01:
    deviation_from: previous
    note: Gesetz z. Anhebung des Gfb, des Kfb, des Kindergeldes und des Kiz
    reference: G. v. 15.07.2015, BGBl. Nr. 30 2015
    0:
      upper_threshold: 8472

However, then the test for unemployment benefits (arbeitsl_geld) fail. Do you know where the tests are coming from? Since the formula arbeitsl_geld_eink_vorj_proxy_m is not entirely accurate (using the income tax instead of the withholding tax) I presume the tests are not based on “official data”? So implementing option 1 would go hand in hand with removing the tests for unemployment benefits for 2015. (As the next PR I would correct the calculation of unemployment benefits. But I don't have any test data going back to 2015.)

I don't know whether there is a strict GETTSIM logic for tax rates. Should they be calculated at December 31 or January 1?

Do you prefer option 1 or 2? Or do you have other suggestions?

hmgaudecker commented 1 year ago

I would leave it as is for the moment, mark the test as xfail, and open an issue. Once we extend the DAG to also cover conversions of parameters, that will be easy to handle (I.e., add a processing step for Lohnsteuer, but not for Einkommensteuer).

Probably the right solution would be to change the dates of the reform. Would be good if you put your analysis in that issue, too!

MImmesberger commented 1 year ago

I marked the test data for 2015 with xfail in e5b7696. I had to write a new function to do this, let me know in case you know a better approach.

codecov[bot] commented 1 year ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Comparison is base (e87596f) 90.84% compared to head (22582d6) 91.02%.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## main #655 +/- ## ========================================== + Coverage 90.84% 91.02% +0.18% ========================================== Files 48 48 Lines 3123 3131 +8 ========================================== + Hits 2837 2850 +13 + Misses 286 281 -5 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

JakobWegmann commented 1 year ago

Fantastic!

I wrote Issue #656 to document that the tests for unemployment benefits in 2015 are deactivated right now.

Then I guess the PR is be ready for review.

I’m unsure about the duplicate of the calculation of beitr_satz_pflegev that appears in vorsorg_kv_option_b_ab_2018 and vorsorg_kv_option_b_ab_2015. Should that part be outsourced in a separate function that is then called by vorsorg_kv_option_b_ab_2018 and vorsorg_kv_option_b_ab_2015?

   if ges_pflegev_zusatz_kinderlos:
        beitr_satz_pflegev = (
            sozialv_beitr_params["beitr_satz"]["ges_pflegev"]["standard"]
            + sozialv_beitr_params["beitr_satz"]["ges_pflegev"]["zusatz_kinderlos"]
        )
    else:
        beitr_satz_pflegev = sozialv_beitr_params["beitr_satz"]["ges_pflegev"][
            "standard"
        ]
JakobWegmann commented 1 year ago

Extremely helpful comments, thank you!

MImmesberger commented 1 year ago

Thanks, looks good!

Regarding the new functions names, I'm not sure whether we want to have the date or a description of what the function does in the function name, e.g. vorsorg_kv_option_b_ab_2015 vs. vorsorg_kv_option_b_full_zusatzbeitrag or something along those lines. The existing naming scheme seems to be inconsistent, what is the direction we want to go? @hmgaudecker

hmgaudecker commented 1 year ago

A foolish consistency... :wink:

Seriously, no reason to be perfectly consistent there. Sometimes it is a regime change that can be summarised in two words; then a description of that is great. Sometimes it is much more complex, then the timing is easiest. After all, this will only affect the internal naming of functions, they will all be mapped to the same user-facing name in the end.

The only thing for the period-based naming is that if a function is not in effect anymore:

@dates_active(
    start="2015-01-01",
    end="2018-12-31",
    change_name="vorsorg_kv_option_b",
)
def vorsorg_kv_option_b_ab_2015(

it should be _ab_2015_bis_2018.

MImmesberger commented 1 year ago

From my point of view, the PR is ready to be merged. @hmgaudecker it would be great if you could take a look at the PR as I implemented some stuff myself. I'd like to point your attention at two things:

  1. In e5b7696 I marked the 2015 tests of the Lohnsteuer with xfail, comments regarding the implementation are welcome.
  2. In baf0a49 I split the function that calculates the relevant income for health insurance up in two functions to make the code for the Lohnsteuer calculation a bit cleaner.
JakobWegmann commented 1 year ago

Thank you Hans-Martin for all the improvements!

And also, Marvin, thank you for the implementation!