openfisca / openfisca-france

French tax and benefit system for OpenFisca
https://openfisca.org/fr
256 stars 97 forks source link

Non prise en compte du plafonnement du QF dans le calcul de la TMI #1463

Open onsvoi opened 3 years ago

onsvoi commented 3 years ago

Hello hello !

Je suis le fan numéro un d'OpenFisca, mais je viens de rencontrer un problème.

Qu'ai-je fait ?

Calcule de TMI suivant plusieurs scenario avec 2,5 parts

À quoi m'attendais-je ?

Je m'attendais que le calcule de la TMI prenne en compte le plafonnement du QF

Que s'est-il passé en réalité ?

Le calcul de le TMI ne prends pas en compte ce plafonnement (cf exemple ci dessous)

Voici des informations qui peuvent aider à reproduire le problème :

Cas 1 : 2 parts avec QF juste sous la tranche des 41% : OK

1) openfisca latest curl --header "Content-Type: application/json" --data '{"individus":{"John":{"salaire_imposable":{"2020":134150}},"Jane":{"salaire_imposable":{"2020":28000}}},"menages":{"menage_1":{"personne_de_reference":["John"],"conjoint":["Jane"]}},"familles":{"famille_1":{"parents":["John","Jane"]}},"foyers_fiscaux":{"foyer_fiscal_1":{"declarants":["John","Jane"],"rni":{"2020":null},"nbptr":{"2020":null},"irpp":{"2020":null},"ir_taux_marginal":{"2020":null}}}}' https://fr.openfisca.org/api/latest/calculate

{"individus":{"John":{"salaire_imposable":{"2020":134150}},"Jane":{"salaire_imposable":{"2020":28000}}},"menages":{"menage_1":{"personne_de_reference":["John"],"conjoint":["Jane"]}},"familles":{"famille_1":{"parents":["John","Jane"]}},"foyers_fiscaux":{"foyer_fiscal_1":{"declarants":["John","Jane"],"rni":{"2020":146722.98},"nbptr":{"2020":2.0},"irpp":{"2020":-32052.0},"ir_taux_marginal":{"2020":0.3}}}}

RNI : 146 722.98 TMI : 0.3 IRPP : 32 052.0

2) simulateur des impôts (https://www3.impots.gouv.fr/simulateur/cgi-bin/calc-2020.cgi) RNI : 146 723 TMI : 0.3 IRPP : 32 305

Cas 2 : 2,5 avec un QF juste sous la tranche des 41% (si on tient pas compte du plafonnement du QF) : NOK

1) openfisca latest curl --header "Content-Type: application/json" --data '{"individus":{"John":{"salaire_imposable":{"2020":170840}},"Jane":{"salaire_imposable":{"2020":28000}},"Bob Mini":{}},"menages":{"menage_1":{"personne_de_reference":["John"],"conjoint":["Jane"],"enfants":["Bob Mini"]}},"familles":{"famille_1":{"parents":["John","Jane"],"enfants":["Bob Mini"]}},"foyers_fiscaux":{"foyer_fiscal_1":{"declarants":["John","Jane"],"rni":{"2020":null},"nbptr":{"2020":null},"irpp":{"2020":null},"ir_taux_marginal":{"2020":null},"personnes_a_charge":["Bob Mini"]}}}' https://fr.openfisca.org/api/latest/calculate {"individus":{"John":{"salaire_imposable":{"2020":170840}},"Jane":{"salaire_imposable":{"2020":28000}},"Bob Mini":{}},"menages":{"menage_1":{"personne_de_reference":["John"],"conjoint":["Jane"],"enfants":["Bob Mini"]}},"familles":{"famille_1":{"parents":["John","Jane"],"enfants":["Bob Mini"]}},"foyers_fiscaux":{"foyer_fiscal_1":{"declarants":["John","Jane"],"rni":{"2020":183413.0},"nbptr":{"2020":2.5},"irpp":{"2020":-45527.0},"ir_taux_marginal":{"2020":0.3},"personnes_a_charge":["Bob Mini"]}}}

RNI : 183 413.0 TMI : 0.3 IRPP : 45 527.0

2) simulateur des impôts (https://www3.impots.gouv.fr/simulateur/cgi-bin/calc-2020.cgi) RNI : 183 413 TMI : 0.41 IRPP : 45 527

Contexte

Je m'identifie plus en tant que :

bonjourmauko commented 3 years ago

Merci @onsvoi !

Effectivement, la formule du TMI ne prend pas en compte le plafonnement du quotient familial :

class ir_taux_marginal(Variable):
    value_type = float
    entity = FoyerFiscal
    label = "Taux marginal d'imposition à l'impôt sur le revenu"
    reference = "http://impotsurlerevenu.org/fonctionnement-de-l-impot/60-calculer-le-tmi.php"
    definition_period = YEAR

    def formula(foyer_fiscal, period, parameters):
        nbptr = foyer_fiscal('nbptr', period)
        taux_effectif = foyer_fiscal('taux_effectif', period)
        rni = foyer_fiscal('rni', period)
        bareme = parameters(period).impot_revenu.bareme
        return (taux_effectif == 0) * bareme.marginal_rates(rni / nbptr) + taux_effectif

Le problème que je vois pour que ce soit le cas c'est par contre l'implementation actuelle du nombre de parts : il me semble qu'on ne fait pas la différence aujourd'hui entre le nombre de parts des déclarants et les demi/parts supplémentaires.

@benjello @openfisca/france-contrib-ipp une idée ? Qu'est-ce qu'on doit considérer comme base de parts pour ce calcul ?

Pour référence la formule du nombre de parts :

class nbptr(Variable):
    value_type = float
    entity = FoyerFiscal
    label = "Nombre de parts"
    reference = "http://vosdroits.service-public.fr/particuliers/F2705.xhtml"
    definition_period = YEAR

    def formula(foyer_fiscal, period, parameters):
        '''
        Nombre de parts du foyer fiscal

        note 1 enfants et résidence alternée (formulaire 2041 GV page 10)

        quotient_familial.conj : nb part associées au conjoint d'un couple marié ou pacsé
        quotient_familial.enf1 : nb part 2 premiers enfants
        quotient_familial.enf2 : nb part enfants de rang 3 ou plus
        quotient_familial.inv1 : nb part supp enfants invalides (I, G)
        quotient_familial.inv2 : nb part supp adultes invalides (R)
        quotient_familial.not31 : nb part supp note 3 : cases W ou G pour veuf, celib ou div
        quotient_familial.not32 : nb part supp note 3 : personne seule ayant élevé des enfants
        quotient_familial.not41 : nb part supp adultes invalides (vous et/ou conjoint) note 4
        quotient_familial.not42 : nb part supp adultes anciens combattants (vous et/ou conjoint) note 4
        quotient_familial.not6 : nb part supp note 6
        quotient_familial.isol : demi-part parent isolé (T)
        quotient_familial.edcd : enfant issu du mariage avec conjoint décédé;
        '''
        nb_pac = foyer_fiscal('nb_pac', period)
        maries_ou_pacses = foyer_fiscal('maries_ou_pacses', period)
        celibataire_ou_divorce = foyer_fiscal('celibataire_ou_divorce', period)
        veuf = foyer_fiscal('veuf', period)
        jeune_veuf = foyer_fiscal('jeune_veuf', period)
        nbF = foyer_fiscal('nbF', period)
        nbG = foyer_fiscal('nbG', period)
        nbH = foyer_fiscal('nbH', period)
        nbI = foyer_fiscal('nbI', period)
        nbR = foyer_fiscal('nbR', period)
        nbJ = foyer_fiscal('nbJ', period)
        nbN = foyer_fiscal('nbN', period)  # noqa F841
        caseP = foyer_fiscal('caseP', period)
        caseW = foyer_fiscal('caseW', period)
        caseG = foyer_fiscal('caseG', period)
        caseE = foyer_fiscal('caseE', period)
        caseK = foyer_fiscal('caseK', period)
        caseN = foyer_fiscal('caseN', period)
        caseF = foyer_fiscal('caseF', period)
        caseS = foyer_fiscal('caseS', period)
        caseL = foyer_fiscal('caseL', period)
        caseT = foyer_fiscal('caseT', period.first_month)
        quotient_familial = parameters(period).impot_revenu.quotient_familial

        no_pac = nb_pac == 0  # Aucune personne à charge en garde exclusive
        has_pac = not_(no_pac)
        no_alt = nbH == 0  # Aucun enfant à charge en garde alternée
        has_alt = not_(no_alt)

        # # nombre de parts liées aux enfants à charge
        # que des enfants en résidence alternée
        enf1 = (no_pac & has_alt) * (quotient_familial.enf1 * min_(nbH, 2) * 0.5
                                     + quotient_familial.enf2 * max_(nbH - 2, 0) * 0.5)
        # pas que des enfants en résidence alternée
        enf2 = (has_pac & has_alt) * ((nb_pac == 1) * (quotient_familial.enf1 * min_(nbH, 1) * 0.5
            + quotient_familial.enf2 * max_(nbH - 1, 0) * 0.5) + (nb_pac > 1) * (quotient_familial.enf2 * nbH * 0.5))
        # pas d'enfant en résidence alternée
        enf3 = quotient_familial.enf1 * min_(nb_pac, 2) + quotient_familial.enf2 * max_((nb_pac - 2), 0)

        enf = enf1 + enf2 + enf3
        # # note 2 : nombre de parts liées aux invalides (enfant + adulte)
        n2 = quotient_familial.inv1 * (nbG + nbI / 2) + quotient_familial.inv2 * nbR

        # # note 3 : Pas de personne à charge
        # - invalide

        n31a = quotient_familial.not31a * (no_pac & no_alt & caseP)
        # - ancien combatant
        n31b = quotient_familial.not31b * (no_pac & no_alt & (caseW | caseG))
        n31 = max_(n31a, n31b)
        # - personne seule ayant élevé des enfants
        n32 = quotient_familial.not32 * (no_pac & no_alt & ((caseE | caseK | caseL) & not_(caseN)))
        n3 = max_(n31, n32)
        # # note 4 Invalidité de la personne ou du conjoint pour les mariés ou
        # # jeunes veuf(ve)s
        n4 = max_(quotient_familial.not41 * (1 * caseP + 1 * caseF), quotient_familial.not42 * (caseW | caseS))

        # # note 5
        #  - enfant du conjoint décédé
        n51 = quotient_familial.cdcd * (caseL & ((nbF + nbJ) > 0))
        #  - enfant autre et parent isolé
        n52 = quotient_familial.isol * caseT * (((no_pac & has_alt) * ((nbH == 1) * 0.5 + (nbH >= 2))) + 1 * has_pac)
        n5 = max_(n51, n52)

        # # note 6 invalide avec personne à charge
        n6 = quotient_familial.not6 * (caseP & (has_pac | has_alt))

        # # note 7 Parent isolé
        n7 = quotient_familial.isol * caseT * ((no_pac & has_alt) * ((nbH == 1) * 0.5 + (nbH >= 2)) + 1 * has_pac)

        # # Régime des mariés ou pacsés
        nb_parts_famille = 1 + quotient_familial.conj + enf + n2 + n4

        # # veufs  hors jeune_veuf
        nb_parts_veuf = 1 + quotient_familial.veuf * (has_pac | has_alt) + enf + n2 + n3 + n5 + n6

        # # celib div
        nb_parts_celib = 1 + enf + n2 + n3 + n6 + n7

        return (maries_ou_pacses | jeune_veuf) * nb_parts_famille + (veuf & not_(jeune_veuf)) * nb_parts_veuf + celibataire_ou_divorce * nb_parts_celib