Skip to content
Snippets Groups Projects
Commit 4aa20a39 authored by BENOIT MICHAUD's avatar BENOIT MICHAUD
Browse files

modifie contrefactuel allegement_general

parent 7e5f0227
Branches
No related tags found
1 merge request!58Allegement general pour PLFSS 2026
...@@ -5,7 +5,7 @@ from openfisca_core.reforms import Reform ...@@ -5,7 +5,7 @@ from openfisca_core.reforms import Reform
from ..inflaters import inflate_parameters from ..inflaters import inflate_parameters
from openfisca_france_reforms.contrefactuel_plf.allegement import allegement_general from openfisca_france_reforms.contrefactuel_plf.taux_allegement_general import taux_allegement_general
from openfisca_france_reforms.contrefactuel_plf.revalorisation_retraite_brute import retraite_brute, retraite_complementaire, retraite_de_base, retraite_de_base_n_1 from openfisca_france_reforms.contrefactuel_plf.revalorisation_retraite_brute import retraite_brute, retraite_complementaire, retraite_de_base, retraite_de_base_n_1
year_contrefactuel = 2026 year_contrefactuel = 2026
...@@ -244,7 +244,7 @@ class ContrefactuelPlf(Reform): ...@@ -244,7 +244,7 @@ class ContrefactuelPlf(Reform):
def apply(self): def apply(self):
self.modify_parameters(modifier_function=modify_parameters) self.modify_parameters(modifier_function=modify_parameters)
for variable in [allegement_general, retraite_brute, retraite_complementaire, retraite_de_base, retraite_de_base_n_1]: for variable in [taux_allegement_general, retraite_brute, retraite_complementaire, retraite_de_base, retraite_de_base_n_1]:
self.update_variable(variable) self.update_variable(variable)
def add_metadata(parameters, metadata: dict): def add_metadata(parameters, metadata: dict):
......
import logging
from numpy import busday_count, datetime64, logical_or as or_, logical_and as and_, timedelta64
from openfisca_core.periods import Period
from openfisca_france.model.base import *
log = logging.getLogger(__name__)
class allegement_general(Variable):
value_type = float
entity = Individu
label = 'Réduction générale des cotisations patronales (dite réduction Fillon)'
reference = 'https://www.service-public.fr/professionnels-entreprises/vosdroits/F24542'
definition_period = MONTH
calculate_output = calculate_output_add
set_input = set_input_divide_by_period
# Attention : cet allègement a des règles de cumul spécifiques
def formula_2005_07_01(individu, period, parameters):
stagiaire = individu('stagiaire', period)
apprenti = individu('apprenti', period)
allegement_mode_recouvrement = individu('allegement_general_mode_recouvrement', period)
exoneration_cotisations_employeur_jei = individu('exoneration_cotisations_employeur_jei', period)
exoneration_cotisations_employeur_tode = individu('exoneration_cotisations_employeur_tode', period)
non_cumulee = not_(exoneration_cotisations_employeur_jei + exoneration_cotisations_employeur_tode)
# switch on 3 possible payment options
allegement = switch_on_allegement_mode(
individu, period, parameters,
allegement_mode_recouvrement,
'allegement_general',
)
return allegement * not_(stagiaire) * not_(apprenti) * non_cumulee
def compute_allegement_general(individu, period, parameters):
'''
Exonération générale de cotisations patronales
https://www.service-public.fr/professionnels-entreprises/vosdroits/F24542
'''
assiette = individu('assiette_allegement', period)
smic_proratise = individu('smic_proratise', period)
effectif_entreprise = individu('effectif_entreprise', period)
# Calcul du taux
# Le montant maximum de l’allègement dépend de l’effectif de l’entreprise.
# Le montant est calculé chaque année civile, pour chaque salarié ;
# il est égal au produit de la totalité de la rémunération annuelle telle
# que visée à l’article L. 242-1 du code de la Sécurité sociale par un
# coefficient.
# Ce montant est majoré de 10 % pour les entreprises de travail temporaire
# au titre des salariés temporaires pour lesquels elle est tenue à
# l’obligation d’indemnisation compensatrice de congés payés.
allegement_general = parameters(period).prelevements_sociaux.reductions_cotisations_sociales.allegement_general
# Du 2003-07-01 au 2005-06-30
if date(2003, 7, 1) <= period.start.date <= date(2005, 6, 30):
seuil = allegement_general.entreprises_ayant_signe_un_accord_de_rtt_avant_le_30_06_2003.plafond
tx_max = allegement_general.entreprises_ayant_signe_un_accord_de_rtt_avant_le_30_06_2003.reduction_maximale
# Du 2005-07-01 au 2019-12-31
elif date(2005, 7, 1) <= period.start.date <= date(2019, 12, 31):
seuil = allegement_general.ensemble_des_entreprises.plafond
petite_entreprise = (effectif_entreprise < 20)
tx_max = (
allegement_general.ensemble_des_entreprises.entreprises_de_20_salaries_et_plus
* not_(petite_entreprise)
+ allegement_general.ensemble_des_entreprises.entreprises_de_moins_de_20_salaries
* petite_entreprise
)
# Après le 2019-12-31
else:
seuil = allegement_general.ensemble_des_entreprises.plafond
petite_entreprise = (effectif_entreprise < 50)
tx_max = (
allegement_general.ensemble_des_entreprises.entreprises_de_50_salaries_et_plus
* not_(petite_entreprise)
+ allegement_general.ensemble_des_entreprises.entreprises_de_moins_de_50_salaries
* petite_entreprise
)
if seuil <= 1:
return 0
if period.start.date >= date(2024,10,10):
prime_partage_valeur_exoneree = individu('prime_partage_valeur_exoneree', period, options=[DIVIDE])
assiette = assiette + prime_partage_valeur_exoneree
ratio_smic_salaire = smic_proratise / (assiette + 1e-16)
# règle d'arrondi: 4 décimales au dix-millième le plus proche
if period.start.date <= date(2025, 12, 31):
taux_allegement_general = round_(tx_max * min_(1, max_(seuil * ratio_smic_salaire - 1, 0) / (seuil - 1)), 4)
else:
puissance = 1.37 # TODO créer un paramètre
taux_allegement_general = round_(max_(min_(tx_max * ((1 / (seuil - 1) * max_(0, seuil * ratio_smic_salaire - 1)) ** puissance), tx_max), 0), 4)
# Montant de l'allegment
return taux_allegement_general * assiette
###############################
# Helper functions and classes
###############################
def switch_on_allegement_mode(individu, period, parameters, mode_recouvrement, variable_name):
'''
Switch on 3 possible payment options for allegements
Name of the computation method specific to the allegement
should precisely be the variable name prefixed with 'compute_'
'''
compute_function = globals()['compute_' + variable_name]
TypesAllegementModeRecouvrement = mode_recouvrement.possible_values
recouvrement_fin_annee = (mode_recouvrement == TypesAllegementModeRecouvrement.fin_d_annee)
recouvrement_anticipe = (mode_recouvrement == TypesAllegementModeRecouvrement.anticipe)
recouvrement_progressif = (mode_recouvrement == TypesAllegementModeRecouvrement.progressif)
return (
(recouvrement_fin_annee * compute_allegement_annuel(individu, period, parameters, variable_name, compute_function))
+ (recouvrement_anticipe * compute_allegement_anticipe(individu, period, parameters, variable_name, compute_function))
+ (recouvrement_progressif * compute_allegement_progressif(individu, period, parameters, variable_name, compute_function))
)
def compute_allegement_annuel(individu, period, parameters, variable_name, compute_function):
if period.start.month < 12:
return 0
if period.start.month == 12:
return sum(
compute_function(individu, sub_period, parameters)
for sub_period in period.this_year.get_subperiods(MONTH)
)
def compute_allegement_anticipe(individu, period, parameters, variable_name, compute_function):
if period.start.month < 12:
return compute_function(individu, period.first_month, parameters)
if period.start.month == 12:
cumul = individu(
variable_name,
Period(('month', period.start.offset('first-of', 'year'), 11)), options = [ADD])
return sum(
compute_function(individu, sub_period, parameters)
for sub_period in period.this_year.get_subperiods(MONTH)
) - cumul
def compute_allegement_progressif(individu, period, parameters, variable_name, compute_function):
if period.start.month == 1:
return compute_function(individu, period.first_month, parameters)
if period.start.month > 1:
up_to_this_month = Period(('month', period.start.offset('first-of', 'year'), period.start.month))
up_to_previous_month = Period(('month', period.start.offset('first-of', 'year'), period.start.month - 1))
cumul = individu(variable_name, up_to_previous_month, options = [ADD])
return sum(
compute_function(individu, sub_period, parameters)
for sub_period in up_to_this_month.get_subperiods(MONTH)
) - cumul
def taux_exo_cice(assiette_allegement, smic_proratise, cice):
taux_cice = ((assiette_allegement / (smic_proratise + 1e-16)) <= cice.plafond_smic) * cice.taux
return taux_cice
%% Cell type:code id:6f7f9288 tags:
``` python
from openfisca_france import FranceTaxBenefitSystem
from openfisca_core.simulation_builder import SimulationBuilder
from openfisca_france_reforms.contrefactuel_plf import ContrefactuelPlf
import logging
from numpy import busday_count, datetime64, logical_or as or_, logical_and as and_, timedelta64
from openfisca_core.periods import Period
from openfisca_france.model.base import *
from datetime import date
```
%% Cell type:markdown id:75852fc0 tags:
# Tax benefit system
%% Cell type:code id:bc209f8f tags:
``` python
# Appliquer la réforme sur le système de base
tax_benefit_system = ContrefactuelPlf(FranceTaxBenefitSystem())
parameters = tax_benefit_system.parameters
# Créer un simulateur
builder = SimulationBuilder()
```
%% Output
/home/b-michaud/leximpact/openfisca-france-reforms/.venv/lib/python3.11/site-packages/openfisca_france/model/prestations/aides_logement.py:5: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
import pkg_resources
%% Cell type:markdown id:472c6b25 tags:
# Valeur des paramètres
%% Cell type:code id:b0cd9ee3 tags:
``` python
# valeurs des paramètres
temp_period = "2026-01"
smic_mensuel = tax_benefit_system.get_parameters_at_instant(
temp_period
).marche_travail.salaire_minimum.smic.smic_b_mensuel
print(f"smic_mensuel : {smic_mensuel}")
```
%% Output
smic_mensuel : 1801.8
%% Cell type:markdown id:20c5780f tags:
# Cas-type
%% Cell type:code id:e0c053b5 tags:
``` python
# cas-type
smic_annuel = smic_mensuel * 12
cas_type_salaire_de_base = 125/100 * smic_annuel
cas_type_effectif_entreprise = 20
cas_type = {
"familles": {"Famille n°1": {"parents": ["Adulte 1"]}},
"foyers_fiscaux": {"Déclaration d’impôts n°1": {"declarants": ["Adulte 1"]}},
"individus": {
"Adulte 1": {
"date_naissance": {
2026: "1985-11-05"
},
"activite": {
2024: "actif",
2025: "actif",
2026: "actif"
},
"categorie_salarie": {
2024: "prive_non_cadre",
2025: "prive_non_cadre",
2026: "prive_non_cadre",
},
"contrat_de_travail": {
2024: "temps_plein",
2025: "temps_plein",
2026: "temps_plein",
},
"salaire_de_base": {
2024: cas_type_salaire_de_base,
2025: cas_type_salaire_de_base,
2026: cas_type_salaire_de_base
},
"effectif_entreprise": {
2024: cas_type_effectif_entreprise,
2025: cas_type_effectif_entreprise,
2026: cas_type_effectif_entreprise
}
}
},
"menages": {
"Logement principal n°1": {
"enfants": [],
"personne_de_reference": ["Adulte 1"],
}
},
}
```
%% Cell type:code id:618f4cde tags:
``` python
# cas_type = {
# "familles": {"Famille n°1": {"parents": ["Adulte 1"]}},
# "foyers_fiscaux": {"Déclaration d’impôts n°1": {"declarants": ["Adulte 1"]}},
# "individus": {
# "Adulte 1": {
# "date_naissance": {
# 2026: "1985-11-05"
# },
# "activite": {
# 2024: "actif",
# 2025: "actif",
# 2026: "actif"
# },
# "categorie_salarie": {
# 2024: "prive_non_cadre",
# 2025: "prive_non_cadre",
# 2026: "prive_non_cadre",
# },
# "contrat_de_travail": {
# 2024: "temps_plein",
# 2025: "temps_plein",
# 2026: "temps_plein",
# },
# "salaire_de_base": {
# 2024: cas_type_salaire_de_base,
# 2025: cas_type_salaire_de_base,
# 2026: cas_type_salaire_de_base
# },
# "effectif_entreprise": {
# 2024: cas_type_effectif_entreprise,
# 2025: cas_type_effectif_entreprise,
# 2026: cas_type_effectif_entreprise
# }
# }
# },
# "menages": {
# "Logement principal n°1": {
# "enfants": [],
# "personne_de_reference": ["Adulte 1"],
# }
# },
# }
```
%% Cell type:code id:c4bbbe99 tags:
``` python
# cas_type = {
# "familles": {
# "Famille n°1": {
# "enfants": [],
# "parents": ["Adulte 1"],
# "en_couple": {
# 2024: False,
# 2025: False,
# 2026: False
# }
# }
# },
# "foyers_fiscaux": {
# "Déclaration d’impôts n°1": {
# "declarants": ["Adulte 1"],
# "depcom_foyer": {
# 2024: "75107",
# 2025: "75107",
# 2026: "75107"
# },
# "personnes_a_charge": []
# }
# },
# "individus": {
# "Adulte 1": {
# "activite": {
# 2024: "actif",
# 2025: "actif",
# 2026: "actif"
# },
# "categorie_salarie": {
# 2024: "prive_non_cadre",
# 2025: "prive_non_cadre",
# 2026: "prive_non_cadre"
# },
# "contrat_de_travail": {
# 2024: "temps_plein",
# 2025: "temps_plein",
# 2026: "temps_plein"
# },
# "contrat_de_travail_type": {
# 2024: "cdi",
# 2025: "cdi",
# 2026: "cdi"
# },
# "effectif_entreprise": {
# 2024: 20,
# 2025: 20,
# 2026: 20
# },
# "date_naissance": {
# 2026: "1985-11-05"
# },
# "depcom_entreprise": {
# 2024: "75107",
# 2025: "75107",
# 2026: "75107"
# },
# "heures_remunerees_volume": {
# 2024: 1607,
# 2025: 1607,
# 2026: 1607
# },
# "invalidite": {
# 2024: False,
# 2025: False,
# 2026: False
# },
# "salaire_de_base": {
# 2024: "Math.round(smic * 1.25)",
# 2025: "Math.round(smic * 1.25)",
# 2026: "Math.round(smic * 1.25)"
# },
# "statut_marital": {
# 2024: "celibataire",
# 2025: "celibataire",
# 2026: "celibataire"
# },
# "pensions_alimentaires_percues": {
# 2026: 0
# }
# }
# },
# "menages": {
# "Logement principal n°1": {
# "depcom": {
# 2024: "75107",
# 2025: "75107",
# 2026: "75107"
# },
# "enfants": [],
# "personne_de_reference": ["Adulte 1"],
# "statut_occupation_logement": {
# 2024: "locataire_vide",
# 2025: "locataire_vide",
# 2026: "locataire_vide"
# },
# "loyer": {
# 2024: 7200,
# 2025: 7200,
# 2026: 7200
# }
# }
# }
# }
```
%% Cell type:markdown id:f8102708 tags:
# Simulation
%% Cell type:code id:200132fc tags:
``` python
simulation = SimulationBuilder()
simulation_cas_type = simulation.build_from_entities(tax_benefit_system, cas_type)
```
%% Cell type:markdown id:ac133ad2 tags:
# Résultats
%% Cell type:code id:373f29ca tags:
``` python
result_alleg_gen = simulation_cas_type.calculate_add("allegement_general", "2026")
print(f"result_alleg_gen : {result_alleg_gen}")
taux_allegement_general = simulation_cas_type.calculate_add("taux_allegement_general", "2026")
print(f"taux_allegement_general : {taux_allegement_general}")
taux_allegement_general = simulation_cas_type.calculate("taux_allegement_general", "2026-01")
print(f"taux_allegement_general : {taux_allegement_general}")
result_assiette = simulation_cas_type.calculate_add("assiette_allegement", "2026")
# print(f"assiette : {result_assiette}")
# print(f"% smic : {result_assiette / smic_annuel}")
result_alleg_mmid = simulation_cas_type.calculate_add("allegement_cotisation_maladie", "2026")
print(f"result_alleg_mmid : {result_alleg_mmid}")
```
%% Output
result_alleg_gen : [6759.4517]
taux_allegement_general : [3.0011995]
taux_allegement_general : [0.2501]
result_alleg_mmid : [0.]
%% Cell type:markdown id:4cd7484d tags:
# Brouillon
%% Cell type:code id:7f2c877c tags:
``` python
tx_max = 0.3573
print(f"effectif entreprise : {cas_type_effectif_entreprise}")
if cas_type_effectif_entreprise < 50:
tx_max = tax_benefit_system.get_parameters_at_instant(
temp_period
).prelevements_sociaux.reductions_cotisations_sociales.allegement_general.ensemble_des_entreprises.entreprises_de_moins_de_50_salaries
print(f"tx_max : {tx_max}")
else:
tx_max = tax_benefit_system.get_parameters_at_instant(
temp_period
).prelevements_sociaux.reductions_cotisations_sociales.allegement_general.ensemble_des_entreprises.entreprises_de_50_salaries_et_plus
print(f"tx_max : {tx_max}")
seuil = tax_benefit_system.get_parameters_at_instant(
temp_period
).prelevements_sociaux.reductions_cotisations_sociales.allegement_general.ensemble_des_entreprises.plafond
print(f"seuil : {seuil}")
ratio_smic_salaire = smic_annuel / cas_type_salaire_de_base
puissance = 1.37
taux_allegement_general = round_(max_(min_(tx_max * ((1 / (seuil - 1) * max_(0, seuil * ratio_smic_salaire - 1)) ** puissance), tx_max), 0), 4)
taux_allegement_general
```
%% Output
effectif entreprise : 20
tx_max : 0.3573
seuil : 3
0.2192
import logging
from numpy import busday_count, datetime64, logical_or as or_, logical_and as and_, timedelta64
from openfisca_core.periods import Period
from openfisca_france.model.base import *
log = logging.getLogger(__name__)
class taux_allegement_general(Variable):
value_type = float
entity = Individu
label = 'Assiette des allègements de cotisations sociales employeur'
definition_period = MONTH
set_input = set_input_divide_by_period
def formula(individu, period, parameters):
assiette = individu('assiette_allegement', period)
smic_proratise = individu('smic_proratise', period)
effectif_entreprise = individu('effectif_entreprise', period)
# Calcul du taux
# Le montant maximum de l’allègement dépend de l’effectif de l’entreprise.
# Le montant est calculé chaque année civile, pour chaque salarié ;
# il est égal au produit de la totalité de la rémunération annuelle telle
# que visée à l’article L. 242-1 du code de la Sécurité sociale par un
# coefficient.
# Ce montant est majoré de 10 % pour les entreprises de travail temporaire
# au titre des salariés temporaires pour lesquels elle est tenue à
# l’obligation d’indemnisation compensatrice de congés payés.
allegement_general = parameters(period).prelevements_sociaux.reductions_cotisations_sociales.allegement_general
# Du 2003-07-01 au 2005-06-30
if date(2003, 7, 1) <= period.start.date <= date(2005, 6, 30):
seuil = allegement_general.entreprises_ayant_signe_un_accord_de_rtt_avant_le_30_06_2003.plafond
tx_max = allegement_general.entreprises_ayant_signe_un_accord_de_rtt_avant_le_30_06_2003.reduction_maximale
# Du 2005-07-01 au 2019-12-31
elif date(2005, 7, 1) <= period.start.date <= date(2019, 12, 31):
seuil = allegement_general.ensemble_des_entreprises.plafond
petite_entreprise = (effectif_entreprise < 20)
tx_max = (
allegement_general.ensemble_des_entreprises.entreprises_de_20_salaries_et_plus
* not_(petite_entreprise)
+ allegement_general.ensemble_des_entreprises.entreprises_de_moins_de_20_salaries
* petite_entreprise
)
# Après le 2019-12-31
else:
seuil = allegement_general.ensemble_des_entreprises.plafond
petite_entreprise = (effectif_entreprise < 50)
tx_max = (
allegement_general.ensemble_des_entreprises.entreprises_de_50_salaries_et_plus
* not_(petite_entreprise)
+ allegement_general.ensemble_des_entreprises.entreprises_de_moins_de_50_salaries
* petite_entreprise
)
if seuil <= 1:
return 0
ratio_smic_salaire = smic_proratise / (assiette + 1e-16)
# règle d'arrondi: 4 décimales au dix-millième le plus proche
# cf. https://www2.assemblee-nationale.fr/static/17/Annexes-DL/PLFSS-2025/PLFSS2025-Annexe09.pdf p.32
puissance = 1 # TODO créer un paramètre ?
taux_allegement_general = round_(tx_max * min_(1, max_(seuil * ratio_smic_salaire - 1, 0) / (seuil - 1)) ** puissance, 4)
# Montant de l'allegment
return taux_allegement_general
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment