diff --git a/openfisca_france/model/prestations/bail_reel_solidaire.py b/openfisca_france/model/prestations/bail_reel_solidaire.py index 8adfdec1c4..fc2f0463db 100644 --- a/openfisca_france/model/prestations/bail_reel_solidaire.py +++ b/openfisca_france/model/prestations/bail_reel_solidaire.py @@ -1,53 +1,75 @@ from openfisca_france.model.base import * import os import csv - +import numpy as np ZONAGE_ABC = os.path.join( os.path.dirname(os.path.abspath(__file__)), '../../assets/zonage-communes/zonage-abc-juillet-2024.csv' - ) - +) +ZONES_ABC = ['A', 'Abis', 'B1', 'B2', 'C'] +NB_PERSONNES_MAX = 6 def preload_zone_abc(): if not os.path.exists(ZONAGE_ABC): return None + with open(ZONAGE_ABC, 'r', encoding='utf-8') as csvfile: reader = csv.DictReader(csvfile, delimiter=';') - return { - row['CODGEO']: row['Zone en vigueur depuis le 5 juillet 2024'] - for row in reader - } - + return {row['CODGEO']: row['Zone en vigueur depuis le 5 juillet 2024'] for row in reader} class bail_reel_solidaire(Variable): entity = Menage - value_type = float + value_type = bool reference = 'https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000032918488' label = 'Bail réel solidaire' definition_period = MONTH def formula(menage, period, parameters): - nb_personnes = menage.nb_persons()[0] - _zone_abc_by_depcom = preload_zone_abc() + def plafond_par_zone_et_composition(nb_personnes, plafonds_par_zones, zone): + plafond_zone = plafonds_par_zones[f'zone_{zone}'] + conditions = [ + nb_personnes == 1, + nb_personnes == 2, + nb_personnes == 3, + nb_personnes == 4, + nb_personnes == 5, + nb_personnes >= 6 + ] + plafonds = [ + plafond_zone['nb_personnes_1'], + plafond_zone['nb_personnes_2'], + plafond_zone['nb_personnes_3'], + plafond_zone['nb_personnes_4'], + plafond_zone['nb_personnes_5'], + plafond_zone['nb_personnes_6'] + ] + return select(conditions, plafonds) + + def plafond_supplementaire_par_zone(nb_personnes, plafonds_par_zones, zone): + return where(nb_personnes > NB_PERSONNES_MAX, + (nb_personnes - NB_PERSONNES_MAX) * plafonds_par_zones[f'zone_{zone}']['nb_personnes_supplementaires'], 0) - if _zone_abc_by_depcom is None: + zones_par_depcom = preload_zone_abc() + if not zones_par_depcom: return False + nb_personnes = menage.nb_persons() depcom = menage('depcom', period.first_month) - zone = _zone_abc_by_depcom.get(depcom[0].decode('utf-8')) + zones = np.array([zones_par_depcom.get(d.decode('utf-8'), None) for d in depcom]) - if zone is None: - return False + plafonds_par_zones = parameters(period).prestations_sociales.bail_reel_solidaire.plafonds_par_zones - params = parameters(period).prestations_sociales.bail_reel_solidaire.plafonds_par_zones[f'zone_{zone}'] - rfr = menage.sum(menage.members.foyer_fiscal('rfr', period.n_2), role = FoyerFiscal.DECLARANT_PRINCIPAL)[0] + plafond_base = select( + [zones == zone for zone in ZONES_ABC], + [plafond_par_zone_et_composition(nb_personnes, plafonds_par_zones, zone) for zone in ZONES_ABC] + ) - if nb_personnes > 6: - plafond_base = params.nb_personnes_6 - personnes_supp = nb_personnes - 6 - plafond = plafond_base + (personnes_supp * params.nb_personnes_supplementaires) - else: - plafond = getattr(params, f'nb_personnes_{nb_personnes}') + plafond_supp = select( + [zones == zone for zone in ZONES_ABC], + [plafond_supplementaire_par_zone(nb_personnes, plafonds_par_zones, zone) for zone in ZONES_ABC] + ) - return rfr <= plafond + rfr = menage.sum(menage.members.foyer_fiscal('rfr', period.n_2), role=FoyerFiscal.DECLARANT_PRINCIPAL) + + return where(zones != None, rfr <= (plafond_base + plafond_supp), False) diff --git a/tests/formulas/bail_reel_solidaire.yaml b/tests/formulas/bail_reel_solidaire.yaml index 1c5c359460..e1231114a1 100644 --- a/tests/formulas/bail_reel_solidaire.yaml +++ b/tests/formulas/bail_reel_solidaire.yaml @@ -1,3 +1,48 @@ +- name: Bail réel solidaire - Tests vectoriels + period: 2024-12 + input: + foyers_fiscaux: + foyer_fiscal_0: + declarants: [personne1] + foyer_fiscal_1: + declarants: [personne2, personne3] + foyer_fiscal_2: + declarants: [personne4, personne5] + personnes_a_charge: [enfant1, enfant2] + individus: + personne1: + salaire_imposable: + 2022: 35000 + personne2: + salaire_imposable: + 2022: 34000 + personne3: + salaire_imposable: + 2022: 32000 + personne4: + salaire_imposable: + 2022: 40000 + personne5: + salaire_imposable: + 2022: 48000 + enfant1: {} + enfant2: {} + menages: + menage_0: + depcom: '01401' # Zone A - Sergy + personne_de_reference: [personne1] + menage_1: + depcom: '01103' # Zone A - Chevry + personne_de_reference: [personne2] + conjoint: [personne3] + menage_2: + depcom: '75056' # Zone Abis - Paris + personne_de_reference: [personne4] + conjoint: [personne5] + enfants: [enfant1, enfant2] + output: + bail_reel_solidaire: [true, false, true] + - name: Bail réel solidaire - Zone A - Personne seule period: 2024-12 input: