diff --git a/CHANGELOG.md b/CHANGELOG.md index d2359d01..27253407 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 3.1.0 [#209](https://github.com/openfisca/openfisca-france-data/pull/209) + +New features + Introduce testing for income "inversion" (deduce gross from net) +Update features + Corrects the inversion functions + extends the inversion of unemployment benefit's taxation + ### 3.0.6 [#248](https://github.com/openfisca/openfisca-france-data/pull/248) * Technical changes - Correction d'une typo dans la PR précédente diff --git a/openfisca_france_data/common.py b/openfisca_france_data/common.py index 2507df29..369ce2e3 100644 --- a/openfisca_france_data/common.py +++ b/openfisca_france_data/common.py @@ -104,7 +104,7 @@ def create_salaire_de_base(individus, period = None, revenu_type = 'imposable', if name not in target: baremes_to_remove.append(name) - # We split since we cannot remove from dict while iterating + # We split since we cannot remove from dict while iterating for name in baremes_to_remove: del baremes_collection._children[name] @@ -400,10 +400,14 @@ def create_revenus_remplacement_bruts(individus, period, tax_benefit_system): individus.chomage_imposable.fillna(0, inplace = True) individus.retraite_imposable.fillna(0, inplace = True) + individus.salaire_net.fillna(0, inplace = True) parameters = tax_benefit_system.get_parameters_at_instant(period.start) csg = parameters.prelevements_sociaux.contributions_sociales.csg csg_deductible_chomage = csg.remplacement.allocations_chomage.deductible + pss = parameters.prelevements_sociaux.pss.plafond_securite_sociale_annuel + taux_abattement_csg_chomage = parameters.prelevements_sociaux.contributions_sociales.csg.remplacement.allocations_chomage.deductible.abattement.rates[0] + seuil_abattement_csg_chomage = parameters.prelevements_sociaux.contributions_sociales.csg.remplacement.allocations_chomage.deductible.abattement.thresholds[1] taux_plein = csg_deductible_chomage.taux_plein taux_reduit = csg_deductible_chomage.taux_reduit seuil_chomage_net_exoneration = ( @@ -412,17 +416,28 @@ def create_revenus_remplacement_bruts(individus, period, tax_benefit_system): (individus.taux_csg_remplacement == 2) / (1 - taux_reduit) + (individus.taux_csg_remplacement >= 3) / (1 - taux_plein) ) - ) + ) - individus.salaire_net exonere_csg_chomage = ( (individus.taux_csg_remplacement < 2) | (individus.chomage_imposable <= seuil_chomage_net_exoneration) ) + taux_csg_chomage = np.where( + individus.taux_csg_remplacement < 2, + 0, + (individus.taux_csg_remplacement == 2) * taux_reduit + + (individus.taux_csg_remplacement >= 3) * taux_plein + ) + threshold = seuil_abattement_csg_chomage * pss * (1 - (taux_csg_chomage * (1 - taux_abattement_csg_chomage))) + base_csg_chomage = np.where( + individus.chomage_imposable <= threshold, + individus.chomage_imposable * (1 - taux_abattement_csg_chomage) / (1 - (taux_csg_chomage * (1 - taux_abattement_csg_chomage))), + (individus.chomage_imposable - seuil_abattement_csg_chomage * taux_abattement_csg_chomage * pss) / (1 - taux_csg_chomage) + ) individus['chomage_brut'] = np.where( exonere_csg_chomage, individus.chomage_imposable, - (individus.taux_csg_remplacement == 2) * individus.chomage_imposable / (1 - taux_reduit) - + (individus.taux_csg_remplacement >= 3) * individus.chomage_imposable / (1 - taux_plein) - ) + individus.chomage_imposable + (base_csg_chomage * taux_csg_chomage) + ) assert individus['chomage_brut'].notnull().all() csg_deductible_retraite = parameters.prelevements_sociaux.contributions_sociales.csg.remplacement.pensions_retraite_invalidite.deductible diff --git a/openfisca_france_data/erfs_fpr/comparison.py b/openfisca_france_data/erfs_fpr/comparison.py index f67c5461..b5590f47 100644 --- a/openfisca_france_data/erfs_fpr/comparison.py +++ b/openfisca_france_data/erfs_fpr/comparison.py @@ -55,6 +55,17 @@ class ErfsFprtoInputComparator(AbstractComparator): "statut_occupation_logement", ] + from openfisca_france_data.erfs_fpr.get_survey_scenario import menage_projected_variables + + target_menage_projected_variables = [ + f"{menage_projected_variable}_menage" + for menage_projected_variable + in menage_projected_variables + ] + + default_target_variables += target_menage_projected_variables + + def compute_test_dataframes(self): erfs_fpr_survey_collection = SurveyCollection.load(collection = "erfs_fpr") # infer names of the survey and data tables diff --git a/openfisca_france_data/erfs_fpr/get_survey_scenario.py b/openfisca_france_data/erfs_fpr/get_survey_scenario.py index ed626143..9fc98a6c 100644 --- a/openfisca_france_data/erfs_fpr/get_survey_scenario.py +++ b/openfisca_france_data/erfs_fpr/get_survey_scenario.py @@ -33,6 +33,88 @@ ] +class erfs_fpr_plugin(Reform): + name = "ERFS-FPR ids plugin" + + def apply(self): + + for variable in variables_converted_to_annual: + class_name = f"{variable}_annuel" + label = f"{variable} sur l'année entière" + + def annual_formula_creator(variable): + def formula(individu, period): + result = individu(variable, period, options = [ADD]) + return result + + formula.__name__ = 'formula' + + return formula + + variable_instance = type(class_name, (Variable,), dict( + value_type = float, + entity = self.variables[variable].entity, + label = label, + definition_period = YEAR, + formula = annual_formula_creator(variable), + )) + + self.add_variable(variable_instance) + del variable_instance + + for variable in menage_projected_variables: + class_name = f"{variable}_menage" + label = f"{variable} agrégée à l'échelle du ménage" + + def projection_formula_creator(variable): + def formula(menage, period): + result_i = menage.members.foyer_fiscal(variable, period, options = [ADD]) + result = menage.sum(result_i, role = FoyerFiscal.DECLARANT_PRINCIPAL) + return result + + formula.__name__ = 'formula' + + return formula + + variable_instance = type(class_name, (Variable,), dict( + value_type = float, + entity = Menage, + label = label, + definition_period = YEAR, + formula = projection_formula_creator(variable), + )) + + self.add_variable(variable_instance) + del variable_instance + + + self.add_variable(idmen_original) + self.add_variable(noindiv) + + +from openfisca_france_data.model.id_variables import ( + idmen_original, + noindiv, + ) + +variables_converted_to_annual = [ + "salaire_imposable", + "chomage_imposable", + "retraite_imposable", + "salaire_net", + "chomage_net", + "retraite_nette", + "ppa", + ] + + +menage_projected_variables = [ + # "rev_financier_prelev_lib_imputes", + "revenu_categoriel_foncier", + "revenus_capitaux_prelevement_forfaitaire_unique_ir", + ] + + class erfs_fpr_plugin(Reform): name = "ERFS-FPR ids plugin" @@ -144,6 +226,7 @@ def get_survey_scenario( # S'il n'y a pas de données, on sait où les trouver. if data is None: input_data_table_by_entity = dict( + foyer_fiscal = f"foyer_fiscal_{year}", individu = f"individu_{year}", menage = f"menage_{year}", ) diff --git a/openfisca_france_data/erfs_fpr/input_data_builder/__init__.py b/openfisca_france_data/erfs_fpr/input_data_builder/__init__.py index 6fa75695..b17db879 100644 --- a/openfisca_france_data/erfs_fpr/input_data_builder/__init__.py +++ b/openfisca_france_data/erfs_fpr/input_data_builder/__init__.py @@ -49,7 +49,7 @@ def build(year: int, export_flattened_df_filepath: str = None) -> None: # - On merge les tables individus / menages # # Note : c'est ici où on objectivise les hypothèses, step 1 - log.info('\n [[[ Year {} - Step 1 / 5 ]]] \n'.format(year)) + log.info('\n [[[ Year {} - Step 1 / 6 ]]] \n'.format(year)) preprocessing.build_merged_dataframes(year = year) # Step 02 : Si on veut calculer les allocations logement, il faut faire le matching avec une autre enquête (ENL) @@ -62,7 +62,7 @@ def build(year: int, export_flattened_df_filepath: str = None) -> None: menage.build_variables_menage(year = year) # Step 03 : on commence par les variables indivuelles - log.info('\n [[[ Year {} - Step 3 / 5 ]]] \n'.format(year)) + log.info('\n [[[ Year {} - Step 3 / 6 ]]] \n'.format(year)) variables_individuelles.build_variables_individuelles(year = year) # Step 04 : ici on va constituer foyer et famille à partir d'invididu et ménage @@ -71,15 +71,18 @@ def build(year: int, export_flattened_df_filepath: str = None) -> None: # - On va faire des suppositions pour faire les familles # - On va faire les foyers fiscaux à partir des familles # - On va faire de suppositions pour faire les foyers fiscaux - log.info('\n [[[ Year {} - Step 4 / 5 ]]] \n'.format(year)) + log.info('\n [[[ Year {} - Step 4 / 6 ]]] \n'.format(year)) famille.build_famille(year = year) + log.info('\n [[[ Year {} - Step 5 / 6 ]]] \n'.format(year)) + foyer.build_variables_foyers_fiscal(year = year) + # Affreux ! On injectait tout dans un même DataFrame !!! # C'est très moche ! # # On crée une df par entité par période. # Elles sont stockées dans un fichier h5 - log.info('\n [[[ Year {} - Step 5 / 5 ]]] \n'.format(year)) + log.info('\n [[[ Year {} - Step 6 / 6 ]]] \n'.format(year)) final.create_input_data_frame(year = year, export_flattened_df_filepath = export_flattened_df_filepath) diff --git a/openfisca_france_data/erfs_fpr/input_data_builder/step_02_menage.py b/openfisca_france_data/erfs_fpr/input_data_builder/step_02_menage.py index 9b7a2f0e..17761801 100644 --- a/openfisca_france_data/erfs_fpr/input_data_builder/step_02_menage.py +++ b/openfisca_france_data/erfs_fpr/input_data_builder/step_02_menage.py @@ -6,7 +6,6 @@ from openfisca_survey_manager.temporary import temporary_store_decorator - log = logging.getLogger(__name__) diff --git a/openfisca_france_data/erfs_fpr/input_data_builder/step_03_variables_individuelles.py b/openfisca_france_data/erfs_fpr/input_data_builder/step_03_variables_individuelles.py index ff20b639..45cf585b 100644 --- a/openfisca_france_data/erfs_fpr/input_data_builder/step_03_variables_individuelles.py +++ b/openfisca_france_data/erfs_fpr/input_data_builder/step_03_variables_individuelles.py @@ -77,6 +77,7 @@ def create_variables_individuelles(individus, year, survey_year = None, revenu_t create_contrat_de_travail(individus, period = period, salaire_type = revenu_type) create_categorie_salarie(individus, period = period, survey_year = survey_year) create_categorie_non_salarie(individus) + # inversion des revenus pour retrouver le brut # pour les revenus de remplacement on a la csg et la crds dans l'erfs-fpr donc on peut avoir le brut directement create_revenus_remplacement_bruts(individus) diff --git a/openfisca_france_data/erfs_fpr/input_data_builder/step_05_foyer.py b/openfisca_france_data/erfs_fpr/input_data_builder/step_05_foyer.py new file mode 100644 index 00000000..21683d06 --- /dev/null +++ b/openfisca_france_data/erfs_fpr/input_data_builder/step_05_foyer.py @@ -0,0 +1,57 @@ +import logging +import pandas as pd + + +from openfisca_survey_manager.temporary import temporary_store_decorator # type: ignore + + +log = logging.getLogger(__name__) + + +@temporary_store_decorator(file_name = 'erfs_fpr') +def build_variables_foyers_fiscal(temporary_store = None, year = None): + + assert temporary_store is not None + assert year is not None + + individus = temporary_store['individus_{}'.format(year)] + menages = temporary_store['menages_{}'.format(year)] + + individus['idfoy'] = individus['idfam'].copy() + individus['quifoy'] = individus['quifam'].copy() + + foyers_fiscaux = individus[['idfoy','ident',]].drop_duplicates() + foyers_fiscaux = pd.merge( + menages[[ + 'ident', + 'rev_financier_prelev_lib_imputes', + 'rev_fonciers_bruts', + 'rev_valeurs_mobilieres_bruts', + 'wprm', + ]], + foyers_fiscaux, + how = 'inner', + on = 'ident' + ) + # première version pour splitter les revenus du capital du ménage dans les foyers fiscaux + # on attribue l'ensemble des revenus du capital du ménage au foyer avec la personne ayant les plus hauts revenus + # procédure à améliorer + idfoy = (individus + .sort_values( + [ + 'ident', + 'salaire_de_base', + 'traitement_indiciaire_brut', + 'retraite_brute' + ], + ascending = False + ) + .groupby('ident') + .first() + .idfoy + ) + foyers_fiscaux['revenu_categoriel_foncier'] = foyers_fiscaux['rev_fonciers_bruts'] * foyers_fiscaux.idfoy.isin(idfoy) + foyers_fiscaux['revenus_capitaux_prelevement_forfaitaire_unique_ir'] = foyers_fiscaux['rev_valeurs_mobilieres_bruts'] * foyers_fiscaux.idfoy.isin(idfoy) + foyers_fiscaux['rev_financier_prelev_lib_imputes'] = foyers_fiscaux['rev_financier_prelev_lib_imputes'] * foyers_fiscaux.idfoy.isin(idfoy) + + temporary_store[f"foyers_fiscaux_{year}"] = foyers_fiscaux diff --git a/openfisca_france_data/erfs_fpr/input_data_builder/step_06_final.py b/openfisca_france_data/erfs_fpr/input_data_builder/step_06_final.py index 48e06e7c..fe8f867a 100644 --- a/openfisca_france_data/erfs_fpr/input_data_builder/step_06_final.py +++ b/openfisca_france_data/erfs_fpr/input_data_builder/step_06_final.py @@ -47,7 +47,6 @@ def create_input_data_frame(temporary_store = None, year = None, export_flattene "primes_fonction_publique", "traitement_indiciaire_brut", ] - if year >= 2018: var_menages = [ 'idmen', diff --git a/openfisca_france_data/erfs_fpr/scenario.py b/openfisca_france_data/erfs_fpr/scenario.py index eef10cd5..46bfd926 100644 --- a/openfisca_france_data/erfs_fpr/scenario.py +++ b/openfisca_france_data/erfs_fpr/scenario.py @@ -28,6 +28,9 @@ class ErfsFprSurveyScenario(AbstractErfsSurveyScenario): "rag", "retraite_brute", "retraite_imposable", + # "rev_financier_prelev_lib_imputes", + "revenu_categoriel_foncier", + "revenus_capitaux_prelevement_forfaitaire_unique_ir", "ric", "rnc", "rpns_imposables", diff --git a/openfisca_france_data/felin/__init__.py b/openfisca_france_data/felin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/openfisca_france_data/felin/input_data_builder/create_variables_individuelles.py b/openfisca_france_data/felin/input_data_builder/create_variables_individuelles.py index 9a653369..09d217a4 100644 --- a/openfisca_france_data/felin/input_data_builder/create_variables_individuelles.py +++ b/openfisca_france_data/felin/input_data_builder/create_variables_individuelles.py @@ -20,11 +20,11 @@ def create_taux_csg_remplacement(individus, period, tax_benefit_system, sigma = def compute_taux_csg_remplacement(rfr, nbptr): parameters = tax_benefit_system.get_parameters_at_instant(period.start) seuils = parameters.prelevements_sociaux.contributions_sociales.csg.remplacement.seuils - seuil_exoneration = seuils.seuil_de_rfr_1 + (nbptr - 1) * seuils.seuil_rfr1.demi_part_suppl_rfr1 - seuil_reduction = seuils.seuil_de_rfr_2 + (nbptr - 1) * seuils.seuil_rfr2.demi_part_suppl_rfr2 + seuil_exoneration = seuils.seuil_rfr1.seuil_rfr1 + (nbptr - 1)*2 * seuils.seuil_rfr1.demi_part_suppl_rfr1 + seuil_reduction = seuils.seuil_rfr2.seuil_rfr2 + (nbptr - 1)*2 * seuils.seuil_rfr2.demi_part_suppl_rfr2 taux_csg_remplacement = 0.0 * rfr if period.start.year >= 2019: - seuil_taux_intermediaire = seuils.seuil_rfr3 + (nbptr - 1) * seuils.seuil_rfr3.demi_part_suppl_rfr3 + seuil_taux_intermediaire = seuils.seuil_rfr3.seuil_rfr3 + (nbptr - 1)*2 * seuils.seuil_rfr3.demi_part_suppl_rfr3 taux_csg_remplacement = np.where( rfr <= seuil_exoneration, 1, diff --git a/setup.py b/setup.py index fde2ac00..c82e7767 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name = "OpenFisca-France-Data", - version = "3.0.6", + version = "3.1.0", description = "OpenFisca-France-Data module to work with French survey data", long_description = long_description, long_description_content_type="text/markdown", diff --git a/tests/fixtures/formulas/af.yaml b/tests/fixtures/formulas/af.yaml index b6e90924..6c75f436 100644 --- a/tests/fixtures/formulas/af.yaml +++ b/tests/fixtures/formulas/af.yaml @@ -28,7 +28,7 @@ - id: "enfant2" age_en_mois: 2015-01: 9 * 12 - output_variables: + output: autonomie_financiere: 2015-01: - false diff --git a/tests/inversion/remplacement_2021.yaml b/tests/inversion/remplacement_2021.yaml new file mode 100644 index 00000000..dac08257 --- /dev/null +++ b/tests/inversion/remplacement_2021.yaml @@ -0,0 +1,97 @@ +- name: "Chomage avec RFR sous seuil 1, personne seule" + revkire: 11400 + nbp: 100 + chomage_imposable: 19000 # revkire < 11408 & nbp =1 : taux is taux_exonere (0), base == gross + chomage_brut_test: 19000 +- name: "Chomage avec RFR sous seuil 2, personne seule, exonération" + revkire: 11410 + nbp: 100 + chomage_imposable: 19000 # 11408 < revkire <= 14914 & nbp =1 : taux is taux_reduit BUT chomage_imposable < seuil d'exo so net == gross + chomage_brut_test: 19000 +- name: "Chomage avec RFR sous seuil 2, personne seule, salaire non nul mais exonération car faible" + revkire: + nbp: 100 + chomage_imposable: 6000 # + salaire_net: 6000 + chomage_brut_test: 6000 +- name: "Chomage avec RFR sous seuil 2, personne seule, mais salaire non nul alors pas d'exonération" + revkire: 11410 + nbp: 100 + chomage_imposable: 11551.98 # + salaire_net: 18000 + chomage_brut_test: 12000 +- name: "Chomage avec RFR sous seuil 2, personne seule, pas d'exonération" + revkire: 11410 + nbp: 100 + chomage_imposable: 20216 # 11408 < revkire <= 14914 & nbp =1 : taux is taux_reduit, chomage_imposable > seuil d'exo; applying abattement + chomage_brut_test: 21000 +- name: "Chomage avec RFR au-dessus seuil 2, personne seule, pas d'exonération" + revkire: 15000 + nbp: 100 + chomage_imposable: 20216 # 14914 < revkire & nbp =1 : taux is taux_plein, chomage_imposable > seuil d'exo; applying abattement + chomage_brut_test: 21000 +- name: "Chomage avec RFR sous seuil 1, couple, pas d'exonération" + revkire: 17498 # 17500 = 11408 + 3046*2 + nbp: 200 + chomage_imposable: 20000 # revkire < 17500 & nbp =2 : taux is taux_exonere (0), net == gross + chomage_brut_test: 20000 +- name: "Chomage avec RFR sous seuil 2, couple, pas d'exonération" + revkire: 17503 # 17500 = 11408 + 3046*2 + nbp: 200 + chomage_imposable: 20014 # revkire < 17500 & nbp =2 : taux is taux_reduit, chomage_imposable > seuil d'exo; applying abattement + chomage_brut_test: 20790 +- name: "Chomage avec RFR au dessus seuil 2, couple, pas d'exonération" + revkire: 22900 # 22878 = 14914 + 3982*2 + nbp: 200 + chomage_imposable: 20014 # revkire < 17500 & nbp =2 : taux is taux_reduit, chomage_imposable > seuil d'exo; applying abattement + chomage_brut_test: 20790 +- name: "Chomage avec RFR au dessus seuil 2, personne seule, alloc > 4 PSS" + revkire: 100000 + nbp: 100 + chomage_imposable: 173269.42176 # revkire < 11408 & nbp =1 : taux is taux_exonere (0), base == gross + chomage_brut_test: 180000 +- name: "Retraite avec RFR sous seuil 1, personne seule" + revkire: 11400 + nbp: 100 + retraite_imposable: 19000 + retraite_brute_test: 19000 +- name: "Retraite avec RFR sous seuil 1, personne seule" + revkire: 11400 + nbp: 100 + retraite_imposable: 20000 + retraite_brute_test: 20000 +- name: "Retraite avec RFR sous seuil 2, personne seule" + revkire: 11450 + nbp: 100 + retraite_imposable: 19000 + retraite_brute_test: 19750 # This checks that the chomage exoneration is indeed silent +- name: "Retraite avec RFR sous seuil 2, personne seule" + revkire: 11450 + nbp: 100 + retraite_imposable: 20000 + retraite_brute_test: 20790 # 20000/(1-0.038) +- name: "Retraite avec RFR sous seuil 3, personne seule" + revkire: 15000 + nbp: 100 + retraite_imposable: 20000 + retraite_brute_test: 20876 # 20000/(1-0.042) +- name: "Retraite avec RFR au dessus seuil 3, personne seule" + revkire: 24000 + nbp: 100 + retraite_imposable: 20000 + retraite_brute_test: 21254 # 20000/(1-0.059) +- name: "Retraite avec RFR sous seuil 2, couple" + revkire: 17503 # 17500 = 11408 + 3046*2 + nbp: 200 + retraite_imposable: 20000 + retraite_brute_test: 20790 # 20000/(1-0.038) +- name: "Retraite avec RFR sous seuil 3, couple" + revkire: 22900 # 22878 = 14914 + 3982*2 + nbp: 200 + retraite_imposable: 20000 + retraite_brute_test: 20876 # 20000/(1-0.042) +- name: "Retraite avec RFR au dessus seuil 3, couple" + revkire: 35510 # 35505 = 23147 + 2*6179 + nbp: 200 + retraite_imposable: 20000 + retraite_brute_test: 21254 # 20000/(1-0.059) diff --git a/tests/test_inversion.py b/tests/test_inversion.py new file mode 100644 index 00000000..167fc3c9 --- /dev/null +++ b/tests/test_inversion.py @@ -0,0 +1,59 @@ +import pandas as pd +from yaml import load, SafeLoader +import os +import re + +from openfisca_core.periods import * + +from openfisca_france import FranceTaxBenefitSystem + +from openfisca_france_data.felin.input_data_builder.create_variables_individuelles import create_taux_csg_remplacement +from openfisca_france_data.common import create_revenus_remplacement_bruts + +margin = 1 + +tax_benefit_system = FranceTaxBenefitSystem() +scenario = tax_benefit_system.new_scenario() + +## First part : upwards (start from *_taxable, inverse to *_gross) + +# Data creation + +cd = os.path.dirname(__file__) +path = os.path.join(cd, "inversion", "remplacement_2021.yaml") +year = re.match(".*([0-9]{4}).yaml", path).group(1) + +with open(path) as yaml: + individus = pd.DataFrame.from_dict(load(yaml, Loader=SafeLoader)) + +# Inverse incomes from net to gross : the tested functions + +create_taux_csg_remplacement(individus, period(year), tax_benefit_system) +create_revenus_remplacement_bruts(individus, period(year), tax_benefit_system) + +# Test against chomage_brut_test + +fails_chomage = [i for i in individus.index if abs(individus.loc[i]["chomage_brut"]-individus.loc[i]["chomage_brut_test"])>=margin] +fails_retraite = [i for i in individus.index if abs(individus.loc[i]["retraite_brute"]-individus.loc[i]["retraite_brute_test"])>=margin] + +message = "".join( + ["For test {}, found {} for chomage_brut, tested against {}.\n".format(i,individus.loc[i]["chomage_brut"],individus.loc[i]["chomage_brut_test"]) for i in fails_chomage]+ + ["For test {}, found {} for retraite_brute, tested against {}.\n".format(i,individus.loc[i]["retraite_brute"],individus.loc[i]["retraite_brute_test"]) for i in fails_retraite] + ) + +assert len(fails_chomage) + len(fails_retraite) ==0, "Some tests have failed.\n" + message + +## Second part : downwards (start from gross obtained from inversion, goes back to taxable) + +# Initialize the survey scenario with the gross (inverted) + +# init_single_entity(scenario, init_data) +# simulation = scenario.new_simulation() + +# # Computes *_taxable back from inverted *_gross + +# simulation.calculate('chomage_imposable', '2021-01') == 1000 +# simulation.calculate('csg_deductible_chomage', '2021-01') == 0 +# simulation.calculate('csg_imposable_chomage', '2021-01') == 0 +# simulation.calculate('crds_chomage', '2021-01') == 1 +