From 0beaf6eb317204fe88ba0b6e35d22e0d11714084 Mon Sep 17 00:00:00 2001 From: Denis Merigoux Date: Mon, 26 Sep 2022 17:29:05 +0200 Subject: [PATCH] Comparing with Catala! --- french_law/python/cnaf_cross_tester/input.py | 12 ++- french_law/python/cnaf_cross_tester/main.py | 99 ++++++++++++++++++- .../python/cnaf_cross_tester/pupeteer.py | 2 +- .../random_input_generator.py | 18 ++-- runtimes/python/catala/setup.py | 6 +- 5 files changed, 118 insertions(+), 19 deletions(-) diff --git a/french_law/python/cnaf_cross_tester/input.py b/french_law/python/cnaf_cross_tester/input.py index 7d486a56..7af059df 100644 --- a/french_law/python/cnaf_cross_tester/input.py +++ b/french_law/python/cnaf_cross_tester/input.py @@ -150,15 +150,21 @@ class Enfant(): return "Enfant(age={},remuneration_derniere_annee={})".format(self.age, self.remuneration_derniere_annee) +class Zone(Enum): + Zone1 = "75001" + Zone2 = "69001" + Zone3 = "46800" + + class CnafSimulatorInput(): def __init__(self, - code_postal: str, + zone: Zone, logement: Logement, loyer: int, seul_ou_couple: SeulOuCouple, enfants: List[Enfant], revenu_pris_en_compte: int): - self.code_postal = code_postal + self.zone = zone self.logement = logement self.loyer = loyer self.seul_ou_couple = seul_ou_couple @@ -167,7 +173,7 @@ class CnafSimulatorInput(): def __str__(self): return "-> Code postal : {}\n-> Logement : {}\n-> Loyer : {} €\n-> Seul of couple : {}\n-> Enfants:\n{}\n-> Revenus pris en compte : {} €".format( - self.code_postal, + self.zone.name, self.logement, self.loyer, self.seul_ou_couple.name, diff --git a/french_law/python/cnaf_cross_tester/main.py b/french_law/python/cnaf_cross_tester/main.py index d3b6cb97..51ed4279 100644 --- a/french_law/python/cnaf_cross_tester/main.py +++ b/french_law/python/cnaf_cross_tester/main.py @@ -1,11 +1,16 @@ -from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, SeulOuCouple +import datetime +from random import sample +from typing import List +from src.aides_logement import LogementFoyer, ModeOccupation_Code, Nationalite_Code, SituationFamiliale_Code, SituationGardeAlternee_Code, SituationObligationScolaire_Code, TypeBailleur_Code, ZoneDHabitation_Code +from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, LogementCrous, LogementMaisonRetraite, LogementResidenceSocialeFJT, SeulOuCouple, Zone from pupeteer import run_simulator +from src.api import EnfantAPL, InfosLocation, PersonneAChargeAPL, aides_logement # Output identical to the JS test of the housing benefits sample_input = CnafSimulatorInput( - code_postal="69001", + zone=Zone.Zone2, logement=AppartementOuMaison( AppartementOuMaisonType.Location, meuble=False), loyer=450, @@ -14,6 +19,92 @@ sample_input = CnafSimulatorInput( Enfant(age=8, remuneration_derniere_annee=0)], revenu_pris_en_compte=11_500 ) + + +def run_catala_by_converting_cnaf_input(sample_input: CnafSimulatorInput) -> float: + enfants: List[PersonneAChargeAPL] = [] + i = 0 + for enfant in sample_input.enfants: + enfants.append(EnfantAPL( + identifiant=i, + beneficie_titre_personnel_aide_personnelle_logement=False, + a_deja_ouvert_droit_aux_allocations_familiales=False, + date_de_naissance=datetime.date.today() - datetime.timedelta(days=366 * enfant.age), + remuneration_mensuelle=int( + enfant.remuneration_derniere_annee / 12), + obligation_scolaire=SituationObligationScolaire_Code.Avant if enfant.age < 3 else ( + SituationObligationScolaire_Code.Apres if enfant.age > 16 else SituationObligationScolaire_Code.Pendant), + situation_garde_alternee=SituationGardeAlternee_Code.PasDeGardeAlternee, + coefficient_garde_alternee=None + )) + i += 1 + + if isinstance(sample_input.logement, AppartementOuMaison): + mode_occupation = (ModeOccupation_Code.Locataire if sample_input.logement.typ( + ) == AppartementOuMaisonType.Location else ModeOccupation_Code.SousLocataire) + infos_specifiques = InfosLocation( + loyer_principal=sample_input.loyer, + beneficiaire_aide_adulte_ou_enfant_handicapes=False, + logement_est_chambre=False, + colocation=False, + agees_ou_handicap_adultes_hebergees_onereux_particuliers=False, + logement_meuble_d842_2=sample_input.logement.meuble_v, + ancien_loyer_et_apl_relogement=None, + type_bailleur=TypeBailleur_Code.BailleurPrive, + bailleur_conventionne=None, + reduction_loyer_solidarite=None + ) + elif isinstance(sample_input.logement, LogementCrous): + pass + elif isinstance(sample_input.logement, LogementFoyer): + pass + elif isinstance(sample_input.logement, LogementResidenceSocialeFJT): + pass + elif isinstance(sample_input.logement, LogementMaisonRetraite): + pass + else: # isinstance(sample_input.logement, LogementChambre): + pass + + housing_benefits_gross = aides_logement( + datetime.date.today(), + ressources_menage_prises_en_compte=sample_input.revenu_pris_en_compte, + date_naissance_demandeur=datetime.date(1992, 1, 1), + nationalite_demandeur=Nationalite_Code.Francaise, + patrimoine_produisant_revenu=0, + patrimoine_ne_produisant_pas_revenu=0, + personne_hebergee_centre_soins=False, + personne_rattache_foyer_fiscal_parent_ifi=False, + nombre_autres_occupants_logement_hors_menage=0, + enfant_a_naitre_apres_quatrieme_mois_grossesse=False, + situation_familiale=SituationFamiliale_Code.Celibataire if sample_input.seul_ou_couple == SeulOuCouple.Seul else SituationFamiliale_Code.Concubins, + date_mariage=None, + prestations_recues=[], + residence_principale=True, + logement_est_maison_de_retraite=True if isinstance( + sample_input.logement, LogementMaisonRetraite) else False, + logement_est_decent=True, + surface_logement_m_carres=10000, + zone=ZoneDHabitation_Code.Zone1 if sample_input.zone == Zone.Zone1 else ( + ZoneDHabitation_Code.Zone2 if sample_input.zone == Zone.Zone2 else ZoneDHabitation_Code.Zone3), + parts_logement_propriete_famille=None, + parts_logement_usufruits_famille=None, + date_naissance_et_conformite_sous_locataire_tiers=None, + personnes_a_charge=enfants, + mode_occupation=mode_occupation, + infos_specifiques=infos_specifiques) + + return round(housing_benefits_gross*0.995) # We take the CRDS + + print(sample_input) -housing_benefits = run_simulator(sample_input) -print("Aides au logement : {} €".format(housing_benefits)) +housing_benefits_catala = run_catala_by_converting_cnaf_input(sample_input) +print("Aides au logement (Catala): {} €".format(housing_benefits_catala)) +housing_benefits_cnaf = run_simulator(sample_input) +print("Aides au logement (CNAF) : {} €".format(housing_benefits_cnaf)) +delta = abs(housing_benefits_catala - housing_benefits_cnaf) +if delta == 0: + print("No difference!") + exit(0) +else: + print("There is a difference!") + exit(-1) diff --git a/french_law/python/cnaf_cross_tester/pupeteer.py b/french_law/python/cnaf_cross_tester/pupeteer.py index feba382f..ca7af7e9 100644 --- a/french_law/python/cnaf_cross_tester/pupeteer.py +++ b/french_law/python/cnaf_cross_tester/pupeteer.py @@ -33,7 +33,7 @@ def run_simulator(input: CnafSimulatorInput) -> int: code_postal_input = page.wait_for_selector('input[id="cpCommune"]') if code_postal_input is None: raise RuntimeError - code_postal_input.fill(input.code_postal) + code_postal_input.fill(input.zone.value) # Select first match page.wait_for_selector('a[class="ng-tns-c31-0"]') diff --git a/french_law/python/cnaf_cross_tester/random_input_generator.py b/french_law/python/cnaf_cross_tester/random_input_generator.py index 5923cde4..55e89758 100644 --- a/french_law/python/cnaf_cross_tester/random_input_generator.py +++ b/french_law/python/cnaf_cross_tester/random_input_generator.py @@ -1,5 +1,5 @@ import random -from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, Logement, LogementChambre, LogementCrous, LogementCrousType, LogementFoyer, LogementMaisonRetraite, LogementResidenceSocialeFJT, SeulOuCouple +from input import AppartementOuMaison, AppartementOuMaisonType, CnafSimulatorInput, Enfant, Logement, LogementChambre, LogementCrous, LogementCrousType, LogementFoyer, LogementMaisonRetraite, LogementResidenceSocialeFJT, SeulOuCouple, Zone def generate_random_child() -> Enfant: @@ -9,13 +9,13 @@ def generate_random_child() -> Enfant: def generate_random_input() -> CnafSimulatorInput: - zone = random.randint(1, 3) - if zone == 1: - code_postal = "75000" - elif zone == 2: - code_postal = "69000" - else: # zone == 3 - code_postal = "46800" + zone_i = random.randint(1, 3) + if zone_i == 1: + zone = Zone.Zone1 + elif zone_i == 2: + zone = Zone.Zone2 + else: # zone_i == 3 + zone = Zone.Zone3 loyer = random.randint(300, 1800) revenus_pris_en_compte = random.randint(0, 200) * 100 seul_ou_couple_i = random.randint(1, 2) @@ -57,7 +57,7 @@ def generate_random_input() -> CnafSimulatorInput: else: # typ_logement == 6: logement = LogementChambre(meuble) return CnafSimulatorInput( - code_postal=code_postal, + zone=zone, logement=logement, loyer=loyer, seul_ou_couple=seul_ou_couple, diff --git a/runtimes/python/catala/setup.py b/runtimes/python/catala/setup.py index 60684932..90d4e0d6 100644 --- a/runtimes/python/catala/setup.py +++ b/runtimes/python/catala/setup.py @@ -1,3 +1,5 @@ -from setuptools import setup +from setuptools import setup # type: ignore -setup() +setup(package_data={ + 'catala-runtime': ['py.typed'], +},)